119 lines
3.7 KiB
Markdown
119 lines
3.7 KiB
Markdown
# Gateway — BLE to MQTT
|
|
|
|
This component runs on a Raspberry Pi 4 and acts as the communication bridge
|
|
between the Nordic Thingy:52 sensor nodes and the rest of the system.
|
|
It reads environmental data from the nodes over BLE and publishes it to a
|
|
local MQTT broker (Mosquitto) in a structured JSON format.
|
|
|
|
## Role in the architecture
|
|
```
|
|
Thingy:52 nodes --> (BLE) --> Raspberry Pi --> (MQTT) --> Database / ML / Notifications
|
|
```
|
|
|
|
## Dependencies
|
|
|
|
Install the required Python libraries:
|
|
```bash
|
|
pip3 install bleak paho-mqtt --break-system-packages
|
|
```
|
|
|
|
Install and start the Mosquitto MQTT broker:
|
|
```bash
|
|
sudo apt install -y mosquitto mosquitto-clients
|
|
sudo systemctl enable mosquitto
|
|
sudo systemctl start mosquitto
|
|
```
|
|
|
|
## Usage
|
|
```bash
|
|
python3 gateway.py
|
|
```
|
|
|
|
At startup, the script asks for the room ID (e.g. C1, A2, B5).
|
|
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).
|
|
|
|
To run the gateway in the background and keep it running after closing SSH:
|
|
```bash
|
|
nohup python3 gateway.py > log.txt 2>&1 &
|
|
```
|
|
|
|
## MQTT topic structure
|
|
```
|
|
classroom/{room_id}/{node_id}
|
|
```
|
|
|
|
Example: `classroom/C1/C1_thingy1`
|
|
|
|
## Message format
|
|
|
|
Each message is published as a JSON object with the following structure:
|
|
```json
|
|
{
|
|
"timestamp": "2026-03-26T13:24:05.176072+00:00",
|
|
"room_id": "C1",
|
|
"node_id": "C1_thingy1",
|
|
"sensors": {
|
|
"co2_ppm": 400,
|
|
"temperature_c": 25.37,
|
|
"humidity_pct": 44
|
|
}
|
|
}
|
|
```
|
|
|
|
| Field | Type | Description |
|
|
|---|---|---|
|
|
| timestamp | string (ISO 8601 UTC) | Time of measurement, added by the gateway |
|
|
| room_id | string | Identifier of the monitored room |
|
|
| node_id | string | Identifier of the Thingy:52 node |
|
|
| co2_ppm | integer | eCO2 concentration in parts per million |
|
|
| temperature_c | float | Indoor air temperature in degrees Celsius |
|
|
| humidity_pct | integer | Relative humidity in percent |
|
|
|
|
## Output files
|
|
|
|
For each session, two local files are created in the gateway directory:
|
|
|
|
- `data_{room_id}.csv` — comma-separated file for local analysis
|
|
- `data_{room_id}.json` — JSON file following the database team format
|
|
|
|
## Publishing interval
|
|
|
|
The default publishing interval is 5 minutes (300 seconds).
|
|
This can be adjusted by modifying the `INTERVAL` variable in `gateway.py`.
|
|
|
|
## Utility scripts
|
|
|
|
- `scan.py` — scans for nearby BLE devices and prints their name and MAC address
|
|
- `check_uuid.py` — connects to Thingy:52 nodes and prints their advertised service UUIDs
|
|
|
|
## 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
|
|
|
|

|
|
|
|
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.
|