CU606 LoRaWAN Air Quality Monitor User Guide
Device Information: Model CU606, devEui ffffff100004e982, gateway IP 192.168.31.193, Modbus Slave ID 4, BACnet Device ID 103
1 Protocol Overview
The CU606 reports CO2, PM2.5, TVOC, formaldehyde, temperature, humidity, atmospheric pressure, and signal quality on Fport 210.
1.1 Uplink Data Protocol (Fport 210)
Payload format (Fport 210):
| Byte | Field | Description |
|---|---|---|
| 0 | Reserved | Always 0x00 (protocol version) |
| 1 … N | TLV pairs | [Type(1 B)][Value(N B)] … repeating until end |
Each Type byte determines the field name and the number of following value bytes:
| Type | Value Bytes | Field Name | Encoding | Scale | Unit | Notes |
|---|---|---|---|---|---|---|
0x01 |
1 | model |
uint8 | — | — | Model code = 0x4B |
0x52 |
2 | pm25 |
uint16 BE | — | μg/m³ | PM2.5 concentration |
0x9F |
2 | formaldehyde |
uint16 BE | — | μg/m³ | Formaldehyde concentration |
0x49 |
2 | co2 |
uint16 BE | — | ppm | CO₂ concentration |
0xA0 |
2 | tvoc |
uint16 BE | — | μg/m³ | TVOC concentration |
0x10 |
2 | temperature |
int16 BE | ÷100 | °C | e.g. 0x09F6=2550 → 25.50 °C |
0x12 |
2 | humidity |
uint16 BE | ÷10 | %RH | e.g. 0x023F=575 → 57.5 %RH |
0x57 |
4 | atmosphericPressure |
uint32 BE | — | Pa | e.g. 101325 Pa |
0x04 |
2 | batteryVoltage |
uint16 BE | ÷1000 | V | mV raw ÷1000 = V |
JavaScript Decoder Example:
// CU606 Air Quality Monitor — Fport 210 uplink decoder
function decodeUplink(bytes) {
var i = 1, r = {};
function u16(b,o){ return (b[o]<<8)|b[o+1]; }
function i16(b,o){ var v=u16(b,o); return v>32767?v-65536:v; }
function u32(b,o){ return ((b[o]<<24)|(b[o+1]<<16)|(b[o+2]<<8)|b[o+3])>>>0; }
while (i < bytes.length) {
var t = bytes[i++];
switch (t) {
case 0x01: r.model = bytes[i++]; break;
case 0x04: r.batteryVoltage = u16(bytes,i)/1000; i+=2; break;
case 0x10: r.temperature = i16(bytes,i)/100; i+=2; break; // °C
case 0x12: r.humidity = u16(bytes,i)/10; i+=2; break; // %RH
case 0x49: r.co2 = u16(bytes,i); i+=2; break; // ppm
case 0x52: r.pm25 = u16(bytes,i); i+=2; break; // μg/m³
case 0x57: r.atmosphericPressure = u32(bytes,i); i+=4; break; // Pa
case 0x9F: r.formaldehyde = u16(bytes,i); i+=2; break; // μg/m³
case 0xA0: r.tvoc = u16(bytes,i); i+=2; break; // μg/m³
default: i++; break;
}
}
return r;
}
// Example payload (hex): 00 01 4B 52 00 12 49 01 90 A0 00 08 9F 00 05 10 09 F6 12 02 3F 57 00 01 86 A5
// → { model:75, pm25:18, co2:400, tvoc:8, formaldehyde:5, temperature:25.5, humidity:57.5, atmosphericPressure:100005 }
Script download: LPP.zip
Compatibility note: LPP.js is developed and tested against ChirpStack v4.17.0. The ChirpStack JavaScript codec API may differ across versions — if you are running a different ChirpStack version, review and adjust the script as needed before deployment.
2 Getting Uplink Data
⚠️ The IP addresses (192.168.31.205/192.168.31.193), ChirpStack API token, Slave ID, BACnet Device ID, and devEui in the examples below are for demonstration only. Replace them with your actual gateway IP, ChirpStack API token, and device parameters.
2.1 ChirpStack MQTT Subscription
Subscribe to the MQTT topic to receive real-time uplink frames:
Application ID —3ef9e6b9-ec54-4eda-86b8-a5fb46899f39is the factory-default ChirpStack
application built into the gateway. Replace it with your actual application
ID if you have created a different one.
Gateway IP —192.168.31.193is the gateway WAN port IP shown as an
example. Replace it with your actual gateway IP address.
Device EUI —ffffff100004e982is the EUI of the example device.
Replace it with the EUI shown in the gateway device list, or use+
as a wildcard to subscribe to all devices at once.
# Subscribe to one specific device
mosquitto_sub -h 192.168.31.193 -p 1883 \
-u gateway -P mqtt88888888 \
-t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff100004e982/event/up"
# Subscribe to ALL devices on ALL applications (wildcard)
mosquitto_sub -h 192.168.31.193 -p 1883 \
-u gateway -P mqtt88888888 \
-t "application/+/device/+/event/up"
Example uplink payload (JSON):
{
"devEui": "ffffff100004e982",
"fPort": 210,
"object": {
... (decoded LPP fields)
}
}
2.2 IoT Hub HTTP API
Send a GET request to retrieve the latest device state:
curl -s "http://192.168.31.193:8070/api/getStatus?devEui=ffffff100004e982"
{
"success": true,
"result": {
"temperature": 26.6,
"humidity": 53.5,
"co2": 642,
"pm25": 13,
"formaldehyde": 6,
"tvoc": 810,
"model": "CU606"
}
}
2.3 IoT Hub Modbus TCP — Python Script
Script download: modbus_tcp_read.py
Use modbus_tcp_read.py to poll all registers at once:
python3 modbus_tcp_read.py --ip 192.168.31.193 --port 502 \
--slaveId 4 --sensorType CU606
Target: 192.168.31.193:502 | Slave ID: 4 | Sensor: CU606
================================================================================================================================================================
Attribute | Addr | FC | Format | Order | Cnt | Scale | Raw(Hex) | Value | Unit
----------------------------------------------------------------------------------------------------------------------------------------------------------------
online | 6 | 03 | Bit/Bool | Big(ABCD) | 1 | x1 | 0001 | true | none
lastOnlineTime | 7 | 03 | UnixTime | Big(ABCD) | 2 | x1 | 69CC CE73 | 1775029875 | second
temperature | 9 | 03 | Int16(S) | Big(ABCD) | 1 | /100 | 0A64 | 26.6 | celsius
humidity | 10 | 03 | Int16(S) | Big(ABCD) | 1 | /100 | 14E6 | 53.5 | percent
batteryVoltage | 11 | 03 | Int16(S) | Big(ABCD) | 1 | /100 | 0000 | 0.00 | volt
batteryVoltageState | 12 | 03 | Int16 | Big(ABCD) | 1 | x1 | 0000 | 0.0 | none
co2 | 13 | 03 | Int16 | Big(ABCD) | 1 | x1 | 0282 | 642.0 | none
pm25 | 14 | 03 | Int16 | Big(ABCD) | 1 | x1 | 000D | 13.0 | none
formaldehyde | 15 | 03 | Int16 | Big(ABCD) | 1 | x1 | 0006 | 6.0 | none
tvoc | 16 | 03 | Int16 | Big(ABCD) | 1 | x1 | 032A | 810.0 | none
model | 41 | 03 | String(24B) | ASCII | 12 | x1 | 4355 3630 3600 0000 ... | CU606 | none
rssi | 53 | 03 | Int16 | Big(ABCD) | 1 | x1 | FFBF | -65.0 | none
... (13 fields total)
2.4 IoT Hub Modbus TCP — Modbus Poll
Tool download: Modbus Poll 9.5.0.1507.zip
- Open Modbus Poll, connect to
192.168.31.193:502, Slave ID4 - Menu Setup → Read/Write Definition, set Function Code = FC03, Start Address =
6, Length =49 - Click OK — values update in real-time
2.5 IoT Hub BACnet BIP — Python Script
Script download: bacnet_read.py
Use bacnet_read.py to read all BACnet objects:
python3 bacnet_read.py --ip 192.168.31.193 --port 47808 --id 103
Target: 192.168.31.193:47808 | BACnet ID: 103 | Scan: 10300-10399
------------------------------------------------------------
Type | Instance | Offset | Value | Object Name
------------------------------------------------------------
BI | 10302 | 2 | active | ffffff100004e982.online
AI | 10303 | 3 | 1775030016.00 | ffffff100004e982.lastOnlineTime
AI | 10304 | 4 | 26.60 | ffffff100004e982.temperature
AI | 10305 | 5 | 53.10 | ffffff100004e982.humidity
AI | 10306 | 6 | 0.00 | ffffff100004e982.batteryVoltage
AI | 10307 | 7 | 0.00 | ffffff100004e982.batteryVoltageState
AI | 10308 | 8 | 643.00 | ffffff100004e982.co2
AI | 10309 | 9 | 12.00 | ffffff100004e982.pm25
AI | 10310 | 10 | 6.00 | ffffff100004e982.formaldehyde
AI | 10311 | 11 | 838.00 | ffffff100004e982.tvoc
CV | 10315 | 15 | CU606 | ffffff100004e982.model
AI | 10316 | 16 | -63.00 | ffffff100004e982.rssi
... (13 objects total)
2.6 IoT Hub BACnet BIP — YABE
Tool download: SetupYabe_v2.1.0.exe
- Open YABE, connect to
192.168.31.193:47808 - Expand Device 103 in the device tree
- Browse AI/BI/AV/BV/CV objects to view real-time values