docs(gateway): add deployment checklist, systemd service and update README
This commit is contained in:
@@ -1,19 +1,20 @@
|
|||||||
# Gateway
|
# Gateway
|
||||||
|
|
||||||
BLE-to-MQTT gateway running on a Raspberry Pi 4. Discovers Nordic Thingy:52
|
BLE-to-MQTT gateway running on a Raspberry Pi 4. Listens to Nordic Thingy:52
|
||||||
sensor nodes, reads environmental data over BLE and publishes it to a local
|
sensor nodes broadcasting environmental data over BLE and publishes it to a
|
||||||
MQTT broker on each notification received.
|
remote MQTT broker on each reception.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
```
|
```
|
||||||
[Thingy #1] ──┐
|
[Thingy #1] ──┐
|
||||||
[Thingy #2] ──┼──(BLE)──> [Raspberry Pi / gateway.py] ──(MQTT)──> [Mosquitto]
|
[Thingy #2] ──┼──(BLE)──> [Raspberry Pi / gateway.py] ──(MQTT)──> [Broker]
|
||||||
[Thingy #n] ──┘
|
[Thingy #n] ──┘
|
||||||
```
|
```
|
||||||
The gateway discovers nodes automatically by filtering BLE advertising packets
|
|
||||||
on the Nordic Configuration service UUID (`ef680100`). Once connected, it
|
The gateway listens passively to BLE advertising packets and filters on the
|
||||||
subscribes to GATT notifications for temperature, humidity and CO2. Each
|
Nordic Configuration service UUID (`ef680100`). Each received packet is
|
||||||
received value triggers an immediate MQTT publication.
|
decoded following the firmware key/value specification and published
|
||||||
|
immediately to the MQTT broker.
|
||||||
|
|
||||||
## MQTT interface
|
## MQTT interface
|
||||||
|
|
||||||
@@ -27,33 +28,31 @@ Example: `gateway_lausanne_01/C4:64:02:60:D9:16/update`
|
|||||||
"timestamp": "2026-04-08T07:53:28Z",
|
"timestamp": "2026-04-08T07:53:28Z",
|
||||||
"temp": 25.37,
|
"temp": 25.37,
|
||||||
"humidity": 44,
|
"humidity": 44,
|
||||||
"co2_ppm": 400
|
"co2_ppm": 400,
|
||||||
|
"window_open": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Fields `temp`, `humidity` and `co2_ppm` are included only once the
|
Fields are included only if present in the advertising packet. Values outside
|
||||||
corresponding value has been received from the node. The CO2 sensor
|
the valid range defined in the firmware specification indicate a failed sensor
|
||||||
requires a warm-up period of approximately 60 seconds before returning
|
reading and are discarded.
|
||||||
valid readings.
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
All environment-specific parameters are defined in `config.json`:
|
A `config.example.json` template is provided. Copy it to `config.json` and
|
||||||
|
edit the values before running:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"gateway_id": "gateway_lausanne_01",
|
"gateway_id": "gateway_example",
|
||||||
"mqtt": {
|
"mqtt": {
|
||||||
"broker": "localhost",
|
"broker": "mqtt.example.com",
|
||||||
"port": 1883
|
"port": 8883,
|
||||||
|
"username": "your_username",
|
||||||
|
"tls": true
|
||||||
},
|
},
|
||||||
"ble": {
|
"ble": {
|
||||||
"service_uuid": "ef680100-9b35-4933-9b10-52ffa9740042",
|
"service_uuid": "ef680100-9b35-4933-9b10-52ffa9740042"
|
||||||
"characteristics": {
|
|
||||||
"temperature": "ef680201-9b35-4933-9b10-52ffa9740042",
|
|
||||||
"co2": "ef680204-9b35-4933-9b10-52ffa9740042",
|
|
||||||
"humidity": "ef680203-9b35-4933-9b10-52ffa9740042"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -65,12 +64,16 @@ identical across all deployments.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt install -y mosquitto mosquitto-clients
|
sudo apt install -y mosquitto mosquitto-clients
|
||||||
sudo systemctl enable mosquitto
|
sudo rfkill unblock bluetooth
|
||||||
sudo systemctl start mosquitto
|
sudo systemctl enable bluetooth
|
||||||
|
sudo bluetoothctl power on
|
||||||
|
|
||||||
python3 -m venv venv
|
python3 -m venv venv
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
cp config.example.json config.json
|
||||||
|
# Edit config.json with your gateway_id, broker address and username
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
@@ -78,6 +81,9 @@ pip install -r requirements.txt
|
|||||||
Set the MQTT password as an environment variable before running:
|
Set the MQTT password as an environment variable before running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
mkdir -p ~/secrets
|
||||||
|
echo "MQTT_PASSWORD=your_password" > ~/secrets/mqtt.env
|
||||||
|
chmod 600 ~/secrets/mqtt.env
|
||||||
export MQTT_PASSWORD="your_password"
|
export MQTT_PASSWORD="your_password"
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
python gateway.py
|
python gateway.py
|
||||||
@@ -85,10 +91,117 @@ python gateway.py
|
|||||||
|
|
||||||
The password is never stored in config files or source code.
|
The password is never stored in config files or source code.
|
||||||
|
|
||||||
|
## Systemd service
|
||||||
|
|
||||||
|
To run the gateway automatically on boot:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo cp gateway.service /etc/systemd/system/
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable gateway
|
||||||
|
sudo systemctl start gateway
|
||||||
|
```
|
||||||
|
|
||||||
|
Check status and logs:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl status gateway
|
||||||
|
sudo journalctl -u gateway -f
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment checklist
|
||||||
|
|
||||||
|
Follow these steps to deploy the gateway on a new Raspberry Pi.
|
||||||
|
|
||||||
|
**1. Connect to the Pi**
|
||||||
|
```bash
|
||||||
|
ssh pi@raspberrypi.local
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Update the system**
|
||||||
|
```bash
|
||||||
|
sudo apt update && sudo apt upgrade -y
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Check and enable Bluetooth**
|
||||||
|
```bash
|
||||||
|
sudo rfkill unblock bluetooth
|
||||||
|
sudo systemctl enable bluetooth
|
||||||
|
sudo systemctl start bluetooth
|
||||||
|
sudo bluetoothctl power on
|
||||||
|
# Expected: "Changing power on succeeded"
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. Install Mosquitto** (for local testing)
|
||||||
|
```bash
|
||||||
|
sudo apt install -y mosquitto mosquitto-clients
|
||||||
|
```
|
||||||
|
|
||||||
|
**5. Clone the repository**
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/PI-E2EEDA/Plein-de-eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-project.git
|
||||||
|
cd Plein-de-eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-project/gateway
|
||||||
|
```
|
||||||
|
|
||||||
|
**6. Create Python environment**
|
||||||
|
```bash
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
**7. Create configuration file**
|
||||||
|
```bash
|
||||||
|
cp config.example.json config.json
|
||||||
|
nano config.json
|
||||||
|
# Set a unique gateway_id for this Pi
|
||||||
|
# Example: "gateway_id": "gateway_fribourg_01"
|
||||||
|
```
|
||||||
|
|
||||||
|
**8. Create the secret file**
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/secrets
|
||||||
|
echo "MQTT_PASSWORD=your_password" > ~/secrets/mqtt.env
|
||||||
|
chmod 600 ~/secrets/mqtt.env
|
||||||
|
```
|
||||||
|
|
||||||
|
**9. Install the systemd service**
|
||||||
|
```bash
|
||||||
|
sudo cp gateway.service /etc/systemd/system/
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable gateway
|
||||||
|
sudo systemctl start gateway
|
||||||
|
```
|
||||||
|
|
||||||
|
**10. Verify everything works**
|
||||||
|
```bash
|
||||||
|
sudo systemctl status gateway
|
||||||
|
# Expected: "active (running)"
|
||||||
|
sudo journalctl -u gateway -f
|
||||||
|
# Expected: Gateway ID, MQTT connected, BLE scan started
|
||||||
|
```
|
||||||
|
|
||||||
|
**11. Test automatic restart**
|
||||||
|
```bash
|
||||||
|
sudo reboot
|
||||||
|
# After reboot, reconnect via SSH
|
||||||
|
sudo systemctl status gateway
|
||||||
|
# Expected: "active (running)" without any manual intervention
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validation checklist
|
||||||
|
- [ ] `active (running)` in systemctl status
|
||||||
|
- [ ] Correct gateway ID in logs
|
||||||
|
- [ ] MQTT connection established (`MQTT client connected`)
|
||||||
|
- [ ] TLS enabled (`TLS enabled`)
|
||||||
|
- [ ] BLE scan started (`BLE scan started`)
|
||||||
|
- [ ] Thingy:52 nodes detected in logs after power on
|
||||||
|
- [ ] Service restarts automatically after reboot
|
||||||
|
|
||||||
## Notes on the CO2 sensor
|
## Notes on the CO2 sensor
|
||||||
|
|
||||||
The Thingy:52 embeds a CCS811 sensor which measures eCO2 — an estimated
|
The Thingy:52 embeds a CCS811 sensor which measures eCO2 — an estimated
|
||||||
CO2 value derived from volatile organic compound (VOC) levels rather than
|
CO2 value derived from volatile organic compound (VOC) levels rather than
|
||||||
a direct CO2 measurement. Values should be interpreted as indicative trends.
|
a direct CO2 measurement. Values should be interpreted as indicative trends.
|
||||||
The sensor requires a burn-in period of 48 hours on first use, and a warm-up
|
The sensor requires a burn-in period of 48 hours on first use before
|
||||||
of approximately 20 minutes on each startup before readings stabilize.
|
readings stabilize.
|
||||||
|
|||||||
16
gateway/gateway.service
Normal file
16
gateway/gateway.service
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=BLE to MQTT Gateway
|
||||||
|
After=network.target bluetooth.target
|
||||||
|
Wants=bluetooth.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=pi
|
||||||
|
WorkingDirectory=/home/pi/Plein-de-eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-project/gateway
|
||||||
|
EnvironmentFile=/home/pi/secrets/mqtt.env
|
||||||
|
ExecStart=/home/pi/Plein-de-eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-project/gateway/venv/bin/python gateway.py
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
Reference in New Issue
Block a user