Skip to content

A portable IoT CO2 tracker with GPS logging, a real-time LVGL UI, and a full backend solution using MQTT, LoRaWAN, Node-RED, and Grafana

Notifications You must be signed in to change notification settings

paclema/iot-co2Tracker

Repository files navigation

IoT-CO2Tracker

The IoT-CO2Tracker is a compact device that measures CO₂, temperature, and humidity. Initially developed on an ESP8266, it was later moved to an ESP32 using the IoT-PostBox board. The project also serves to validate the board's capabilities, though that is not its primary purpose.

An external GPS module can be connected via the serial port, allowing the device to publish both sensor readings and location data. This data is sent via LoRaWAN to The Things Network (TTN) for coverage and connectivity analysis, and over Wi-Fi using MQTT to your own broker. When needed, GPS tracks are logged to the onboard flash storage and can be downloaded for visualization through a built-in FTP server. The latest hardware revision includes a 2" TFT screen that displays live sensor values, connectivity, and battery status, with a user interface built on LVGL v9 and designed with SquareLine.

IoT-CO2Tracker


Communication flow

flowchart LR
	Device[iot-co2Tracker]
	Broker[(MQTT Broker)]
	GW[LoRaWAN Gateway]
	TTN[The Things Network]
	NR[Node-RED]
	HA[Home Assistant]
	DB[(InfluxDB)]
	G[Grafana]
	Flash[(LittleFS)]
	PC[PC]
	Viz[GPSVisualizer]

	Device -- MQTT (JSON) --> Broker
	Broker --> NR
	Device -- LoRaWAN (binary) --> GW --> TTN --> NR
	NR --> DB --> G
		NR -.->|update device*| HA

	Device -- GPS tracks --> Flash -- FTP download --> PC --> Viz
Loading

* planned (to be implemented)

MQTT

  • Topic: /iot-co2Tracker/<deviceId>/data

Example payload (without GPS):

{
	"CO2": 222,
	"temp": 33.02967834,
	"humidity": 30.82733154,
	"rssi_STA": -38,
	"vBat": 4.21023798,
	"vBus": 5.021749973,
	"PowerStatus": 2,
	"ChargingStatus": 2
}

Example payload (with GPS):

{
	"CO2": 229,
	"temp": 31.5396347,
	"humidity": 29.40368652,
	"lat": 51.27265917,
	"lng": 12.37718133,
	"date": 120925,
	"time": 15070704,
	"speed": 0.11112,
	"satellites": 4,
	"altitude": 197.6,
	"hdop": 8.33,
	"course": 120925,
	"rssi_STA": -54,
	"vBat": 4.116175175,
	"vBus": 0.01325,
	"PowerStatus": 3,
	"ChargingStatus": 1
}

LoRaWAN uplink

Field C type Bytes Units Notes
latitude uint32_t 4 degrees 24-bit value scaled to 4 bytes ((lat+90)/180*16777215)
longitude uint32_t 4 degrees 24-bit value scaled to 4 bytes ((lng+180)/360*16777215)
altitude uint16_t 2 m
hdop uint16_t 2 HDOP
speed uint16_t 2 km/h value = km/h × 100
satellites uint8_t 1 count
course uint16_t 2 degrees
time uint32_t 4 HHMMSScc local offset applied
vBat uint16_t 2 mV
vBus uint16_t 2 mV
CO2 uint16_t 2 ppm
temp uint16_t 2 °C value = °C × 100
hum uint16_t 2 % value = % × 100
powerStatus uint8_t 1 enum
chargingStatus uint8_t 1 enum

Notes

  • Multi-byte fields are big-endian (MSB first).
  • Latitude/Longitude use 24-bit effective values packed into 4 bytes (high byte may be 0).
  • Total payload length: 33 bytes.

Decoders: see formaters/ for TTN uplink decoders and field mapping.

TTN setup (OTAA, quick)

  1. Create an application co2Tracker and register a device.
  2. Set the device DEVEUI, APPEUI, and APPKEY to your config.json.
  3. Add the custom uplink decoder from formaters/custom to your TTN application.
  4. Join the device and verify uplinks in the TTN console under the Application live data tab.

FTP GPS logs

  • If the local_logs configuration is enabled in the config.json file, GPS log files will be created on the LittleFS partition. The file names will follow a specific naming convention, such as GPS_2025_9_10.csv.
  • Connect via FTP to the device server using the username and password configured in config.json to download the GPS log file.
  • CSV columns follow:
time,latitude,longitude,altitude,speed,hdop,satellites,course,vBat,vBus,PowerStatus,ChargingStatus,co2,temp,hum
18182040,51.27235567,12.37730017,115.1,31.503,1.06,12,162.6,3.98449,0.00795,1,2,239,22.34,57.10
18182553,51.27197583,12.37750567,115.6,31.540,1.06,12,162.8,3.98449,0.00795,1,2,232,22.34,57.15
18183040,51.27155317,12.37771250,116.4,29.595,1.06,12,167.4,3.98073,0.00795,1,2,221,22.36,57.19
18183541,51.27119583,12.37782367,117.2,29.058,1.15,12,167.5,3.98073,0.00795,1,2,207,22.38,57.31

GPSVisualizer_example

Software

Firmware

  • PlatformIO project (ESP32). FreeRTOS tasks for sensors, UI, and communications.
  • Libraries used:

UI

  • Made up to use an 2.0" GMT020-02 TFT OLED SPI LCD (non-touch) screen.
  • Uses LVGL v9.
  • Interface designed with SquareLine. The project can be found under SquareLineProject/.

Backend services


Hardware

Essentials

  • Board: IoT-PostBox (ESP32/ESP32-S2 with onboard RFM95W LoRa module)
  • Sensor: SCD30 (CO₂, temperature, humidity) over I²C
  • GPS (optional): u-blox M8N over serial
  • Display (optional): 2.0" GMT020-02 TFT OLED SPI LCD with ST7789V driver
  • Power: battery support with charging capabilities using IoT-PostBox

Pinout highlights (see boards/ and boards/variants/iotpostbox_v1/ for full mapping)

TODO: add pinout diagram

3D printable case


Build & flash

  1. Open the project using PlatformIO with VS Code.
  2. Configure services and device following the WebConfigServer style, editing the data/config/config.json and uploading the Filesystem Image to the device.
  3. Build and upload the firmware to an IoT-PostBox device.
  4. Use the device WebConfigServer UI web portal for advanced options.

Derived from iot_button#CO2_tracker

About

A portable IoT CO2 tracker with GPS logging, a real-time LVGL UI, and a full backend solution using MQTT, LoRaWAN, Node-RED, and Grafana

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages