docs(gateway): add README with architecture and MQTT interface

Assisted-by: Claude:claude-sonnet-4-6 — ASCII architecture diagram
This commit is contained in:
DjeAvd
2026-04-08 09:33:11 +01:00
committed by Klagarge
parent 2a7546fe8b
commit a5b64aeb3d

View File

@@ -1,118 +1,91 @@
# Gateway — BLE to MQTT # Gateway
This component runs on a Raspberry Pi 4 and acts as the communication bridge BLE-to-MQTT gateway running on a Raspberry Pi 4. Discovers Nordic Thingy:52
between the Nordic Thingy:52 sensor nodes and the rest of the system. sensor nodes, reads environmental data over BLE and publishes it to a local
It reads environmental data from the nodes over BLE and publishes it to a MQTT broker on each notification received.
local MQTT broker (Mosquitto) in a structured JSON format.
## Architecture
## Role in the architecture Thingy:52 nodes Raspberry Pi MQTT broker
``` [Thingy #1] --+
Thingy:52 nodes --> (BLE) --> Raspberry Pi --> (MQTT) --> Database / ML / Notifications |
``` [Thingy #2] --+--> (BLE) --> [gateway.py] --> (MQTT) --> [Mosquitto]
|
## Dependencies [Thingy #n] --+
Install the required Python libraries: The gateway discovers nodes automatically by filtering BLE advertising packets
```bash on the Nordic Configuration service UUID (`ef680100`). Once connected, it
pip3 install bleak paho-mqtt --break-system-packages subscribes to GATT notifications for temperature, humidity and CO2. Each
``` received value triggers an immediate MQTT publication.
Install and start the Mosquitto MQTT broker: ## MQTT interface
```bash
sudo apt install -y mosquitto mosquitto-clients **Topic:** `{gateway_id}/{thingy_mac}/update`
sudo systemctl enable mosquitto
sudo systemctl start mosquitto Example: `gateway_lausanne_01/C4:64:02:60:D9:16/update`
```
**Payload:**
## Usage ```json
```bash {
python3 gateway.py "timestamp": "2026-04-08T07:53:28Z",
``` "temp": 25.37,
"humidity": 44,
At startup, the script asks for the room ID (e.g. C1, A2, B5). "co2_ppm": 400
It then automatically discovers all Thingy:52 nodes in range by filtering }
BLE advertising packets on the Nordic Configuration service UUID (ef680100). ```
Each detected node is assigned a name based on the room ID and a counter
(e.g. C1_thingy1, C1_thingy2). Fields `temp`, `humidity` and `co2_ppm` are included only once the
corresponding value has been received from the node. The CO2 sensor
To run the gateway in the background and keep it running after closing SSH: requires a warm-up period of approximately 60 seconds before returning
```bash valid readings.
nohup python3 gateway.py > log.txt 2>&1 &
``` ## Configuration
## MQTT topic structure All environment-specific parameters are defined in `config.json`:
```
classroom/{room_id}/{node_id} ```json
``` {
"gateway_id": "gateway_lausanne_01",
Example: `classroom/C1/C1_thingy1` "mqtt": {
"broker": "localhost",
## Message format "port": 1883
},
Each message is published as a JSON object with the following structure: "ble": {
```json "service_uuid": "ef680100-9b35-4933-9b10-52ffa9740042",
{ "characteristics": {
"timestamp": "2026-03-26T13:24:05.176072+00:00", "temperature": "ef680201-9b35-4933-9b10-52ffa9740042",
"room_id": "C1", "co2": "ef680204-9b35-4933-9b10-52ffa9740042",
"node_id": "C1_thingy1", "humidity": "ef680203-9b35-4933-9b10-52ffa9740042"
"sensors": { }
"co2_ppm": 400, }
"temperature_c": 25.37, }
"humidity_pct": 44 ```
}
} Each deployed gateway has its own `config.json`. The source code remains
``` identical across all deployments.
| Field | Type | Description | ## Installation
|---|---|---|
| timestamp | string (ISO 8601 UTC) | Time of measurement, added by the gateway | ```bash
| room_id | string | Identifier of the monitored room | sudo apt install -y mosquitto mosquitto-clients
| node_id | string | Identifier of the Thingy:52 node | sudo systemctl enable mosquitto
| co2_ppm | integer | eCO2 concentration in parts per million | sudo systemctl start mosquitto
| temperature_c | float | Indoor air temperature in degrees Celsius |
| humidity_pct | integer | Relative humidity in percent | python3 -m venv venv
source venv/bin/activate
## Output files pip install -r requirements.txt
```
For each session, two local files are created in the gateway directory:
## Usage
- `data_{room_id}.csv` — comma-separated file for local analysis
- `data_{room_id}.json` — JSON file following the database team format ```bash
source venv/bin/activate
## Publishing interval python gateway.py
```
The default publishing interval is 5 minutes (300 seconds).
This can be adjusted by modifying the `INTERVAL` variable in `gateway.py`. ## Notes on the CO2 sensor
## Utility scripts The Thingy:52 embeds a CCS811 sensor which measures eCO2 — an estimated
CO2 value derived from volatile organic compound (VOC) levels rather than
- `scan.py` — scans for nearby BLE devices and prints their name and MAC address a direct CO2 measurement. Values should be interpreted as indicative trends.
- `check_uuid.py` — connects to Thingy:52 nodes and prints their advertised service UUIDs The sensor requires a burn-in period of 48 hours on first use, and a warm-up
of approximately 20 minutes on each startup before readings stabilize.
## Notes on the CO2 sensor
The Thingy:52 uses a CCS811 sensor which measures eCO2 (equivalent CO2),
estimated from volatile organic compound (VOC) levels rather than directly
measuring CO2 concentration. Values should be interpreted as indicative trends
rather than precise measurements, particularly during the first 24 to 48 hours
of operation while the sensor calibrates.
## Overnight test results
An overnight test was conducted with 2 Thingy:52 nodes placed in two separate
rooms (windows closed, 7h session, 5 minute interval).
- Room 1: 4 occupants (2 adults, 2 children)
- Room 2: unoccupied
![Overnight measurements](mesures_nuit.png)
CO2 rose progressively from 400 ppm to a peak of 1071 ppm in the occupied room,
consistent with human respiration in a confined space. The unoccupied room
remained stable between 400 and 465 ppm, confirming that variations in Room 1
are directly linked to human presence.
Note: the CCS811 sensor measures eCO2 estimated from VOC levels, not direct CO2.
Occasional spikes (e.g. 877 ppm at 02:45, 1071 ppm at 03:05) may be caused by
factors such as perspiration or movement near the sensor and should be interpreted
with caution.