RPI Parking Doors is a project developed to open the door/s of a car park (collective or private), by activating relay via a web application.
The project also includes a user management page, with the possibility to add (with expiration, or not), delete a user, and modify his password.
The operation is simple, when a user presses the "open door" button, a relay is activated for 10 seconds, which simulates a press on your gate emitter and therefore opens it.
A token is generated for each user at his creation, and set automatically in url (call guid
in query param) to stay
indefinitely connected
(to not sign in everytime we need to open a door) , it's not highly secure but sufficient and user-friendly for my use
case. The next step will be to implement Oauth.
Connect you raspberry and your relays board like describing here.
The relay must be connected to a raspberry pi, by default on pins 20 and 21.
If you only have one gate, you can block the button on the transmitter of your gate and simply replace the battery with a 5v power supply (which you would have fixed in place of the battery), which will power the transmitter only when the relay is in the closed position. If not, the relay will be in the open position the rest of the time, so your transmitter will no longer be powered.
If you have two gates, you can directly solder two wires on each side of each push button of your transmitter. The push button is just a switch, we can reproduce it by connecting a relay on both sides of the push button (by soldering it directly to the transmitter).
Open doors page | Users management page |
---|---|
- Clone this repository on your desktop
- Edit the
.env
files to customize your configuration (relays, port, label, title) if needed - Launch these commands to install dependencies and build the application :
npm install && npm run build
Now, you have in packages/backend/dist
folder the frontend and backend optimized generates files.
- On the Raspberry, install NodeJS 12 or higher
- Copy generates
dist
folder on your Raspberry - In Raspberry terminal, in
dist
folder, launch this command to install only production dependencies :
npm ci --only=production
- Start the application with this command in
dist
folder
SQLITE_DATABASE_PATH=./data/sqlite.db node ./backend/src/main
So now, your application is started.
Note :
- I advise you to move the sqlite.sb database in ramdisk (like describing here), to save your sd card
- I advise you to launch the application as systemd service like describing here
Note 2 : Good to know, the frontend files are served by the backend application
Edit backend .env
file to customize the configuration
Value | Descriptions |
---|---|
PORT=8888 | Port used by the backend in production |
STATE_ON=0 | Configure the default opened state for relay |
STATE_OFF=1 | Configure the default closes state for relay |
RELAYS=20,21 | Configure the relays pin plugged on the rpi |
SQLITE_DATABASE_PATH=./data/sqlite.db | Configure the path to the sqlite database, if an SQLITE_DATABASE_PATH env var is specified, this config will be override |
Edit front .env
file to customize the configuration
Value | Descriptions |
---|---|
Titles and labels configurations | Usefull to change language, or customize label, description in frontend |
This project uses React for the frontend and NodeJs with the Nestjs framework for the backend. The backend and frontend are in the same repository. Lerna is used to simplify project scripting. It uses a Sqlite database only to store and query the users of the application.
The project is fully covered by 100% unit testing and also by integration testing for the backend and frontend.
The frontend integration tests were developed with Cypress and the visual testing with cypress-plugin-snapshots plugin.
You can launch the web application locally in watch mode, simply by running in the root folder this commands
- Just the first time to download dependencies :
npm run install
- And launch the backend and frontend in dev mode:
npm run start:dev
Note, The onoff library is mocked on your local computer to allow local launching.
You can launch backend application in dev mode, et simply go to http://localhost:8888/swagger/ to see the API documentation
You can launch tests of frontend and backend with this commands at the root folder :
# unit tests with coverage
npm run test:cov
# e2e tests (launch cypress for the front in headless)
npm run test:e2e
I advise you to expose the application via HTTPS, I personally used nginx with a let's encrypt certificate, as describing here certbot.
My IP is not static, so I use the free no-ip service (which needs to be renewed every month, to prove that the domain is still in use), which I have configured with my router to give me a static domain for my not static ip.
I advise you to place sqlite database backend/data/sqlite.db
in memory and regularly save it in the file system, in
order to preserve the longevity of the SD card. To do it, we can simply launch one script at Raspberry startup to copy
data base into the ramdisk, then launch every day a second script to copy the database from ramdisk to filesystem.
To achieve that, we should :
-
Create a ramdisk at each Raspberry start, by editing the file
/etc/fstab
(withvim /etc/fstab
command for example) and add this line to the end :tmpfs /mnt/ramdisk tmpfs nodev,nosuid,size=200M 0 0
This will create at each startup a ramdisk of max 200M (you can see your available ram with this command
free -h
) -
Set this cron tasks, (launch this command to edit crontab :
crontab -e
) and add this 2 lines at the end of the file :@reboot sh /home/pi/rpi-parking-doors/packages/backend/scripts/add-database-file-in-ramdisk.sh @midnight sh /home/pi/rpi-parking-doors/packages/backend/scripts/save-database-from-ramdisk-in-fs.sh
The first line add the database in ramdisk at Raspberry startup, and the second save the database from ramdisk every night to filesystem
I advise you to create a systemd service for your application and launch it with systemctl, like describing here, to automatically restart the application if an error or crash occurred
For example this is my service configuration :
[Unit]
Description=rpi parking doors
After=network.target
[Service]
Type=simple
User=pi
ExecStart=/home/pi/.nvm/versions/node/v14.16.1/bin/node /home/pi/rpi-parking-doors/packages/backend/src/main
Environment="SQLITE_DATABASE_PATH=/mnt/ramdisk/sqlite.db"
Restart=always
[Install]
WantedBy=multi-user.target
I advise you to use log2ram to preserve your SD card.
- Implement an auth with Oauth2
- Improve design