Milesight AM319: 9-in-1 LoRaWAN Air Quality Sensor with E-Ink
Milesight AM319 9-in-1 LoRaWAN IAQ sensor with E-Ink display: own ChirpStack/ThingsBoard decoder, decoded example, CO2, PM and HCHO monitoring.
- LoRaWAN
- Class A, OTAA
- Band / port
- EU868 / port 85
- Display
- 4.2 inch E-Ink, traffic-light status
- CO2 sensor
- NDIR, 0 to 5000 ppm
- Particulates
- PM2.5 and PM10, laser scatter
- Power
- Battery or USB Type-C
- Configuration
- NFC (Milesight ToolBox)
What the AM319 measures
CO2
NDIR sensor, 0 to 5000 ppm, with ABC or manual calibration.
Temperature & humidity
Comfort readings, temperature INT16 little-endian /10, humidity /2.
TVOC
Reported as an IAQ index (/100) or in micrograms per cubic metre, switchable.
HCHO and PM
Formaldehyde in mg/m³ (/100), PM2.5 and PM10 in micrograms per cubic metre.
Pressure, light, motion
Barometric pressure (/10), light level and a PIR occupancy flag.
Integration
Sensor / controller
Measures or controls in the field and sends LoRaWAN uplinks.
LoRaWAN gateway
Receives the radio packets and forwards them to the server.
ChirpStack
Network server: manages sessions and decodes the payload.
ThingsBoard / Grafana
Dashboards, alarms, rules and reports.
function decodeUplink(input) {
var bytes = input.bytes;
var data = {};
for (var i = 0; i < bytes.length; ) {
var channel = bytes[i++];
var type = bytes[i++];
if (channel === 0x01 && type === 0x75) { // battery (%)
data.battery = bytes[i]; i += 1;
} else if (channel === 0x03 && type === 0x67) { // temperature (°C)
data.temperature = readInt16LE(bytes, i) / 10; i += 2;
} else if (channel === 0x04 && type === 0x68) { // humidity (%RH)
data.humidity = bytes[i] / 2; i += 1;
} else if (channel === 0x05 && type === 0x00) { // PIR occupancy
data.pir = bytes[i] === 1 ? "trigger" : "idle"; i += 1;
} else if (channel === 0x06 && type === 0xcb) { // light level (0-10)
data.light_level = bytes[i]; i += 1;
} else if (channel === 0x07 && type === 0x7d) { // CO2 (ppm)
data.co2 = readUInt16LE(bytes, i); i += 2;
} else if (channel === 0x08 && type === 0x7d) { // TVOC (IAQ index, /100)
data.tvoc = readUInt16LE(bytes, i) / 100; i += 2;
} else if (channel === 0x08 && type === 0xe6) { // TVOC (µg/m³)
data.tvoc = readUInt16LE(bytes, i); i += 2;
} else if (channel === 0x09 && type === 0x73) { // pressure (hPa, /10)
data.pressure = readUInt16LE(bytes, i) / 10; i += 2;
} else if (channel === 0x0a && type === 0x7d) { // HCHO (mg/m³, /100)
data.hcho = readUInt16LE(bytes, i) / 100; i += 2;
} else if (channel === 0x0b && type === 0x7d) { // PM2.5 (µg/m³)
data.pm2_5 = readUInt16LE(bytes, i); i += 2;
} else if (channel === 0x0c && type === 0x7d) { // PM10 (µg/m³)
data.pm10 = readUInt16LE(bytes, i); i += 2;
} else {
break;
}
}
return { data: data };
}
function readUInt16LE(b, i) {
return ((b[i + 1] << 8) | b[i]) & 0xffff;
}
function readInt16LE(b, i) {
var v = readUInt16LE(b, i);
return v > 0x7fff ? v - 0x10000 : v;
}
Implemented from the published Milesight byte specification (Communication Protocol / User Guide).
Channel format: 01 75 battery, 03 67 temperature (INT16 little-endian, /10), 04 68 humidity (/2), 07 7d CO2 (ppm), 08 7d TVOC as IAQ index (/100) or 08 e6 TVOC in micrograms per cubic metre, 09 73 pressure (/10), 0a 7d HCHO (/100), 0b/0c 7d PM2.5/PM10. The TVOC channel switches between IAQ index and micrograms per cubic metre depending on the configured unit. The decoder is implemented from the published Milesight byte specification. Stored history frames (channels 20/21, type ce) and downlink responses use longer records, add those branches if you enable history retransmission. The same channel logic goes into a ThingsBoard uplink converter.
Uplink (hex)
0367E80004685D077D3002087D6400097390270B7D1900Decoded JSON
{ "temperature": 23.2, "humidity": 46.5, "co2": 560, "tvoc": 1, "pressure": 1012.8, "pm2_5": 25 }Use cases
Configuration & pitfalls
CO2 calibration
Choose ABC for unattended offices or manual/background calibration for sealed rooms. Document which mode you set so dashboard values stay traceable.
TVOC unit
TVOC is sent either as an IAQ index or in micrograms per cubic metre. Decide the unit before rollout, because the byte type changes (7d vs e6) and your decoder branch must match.
Power and warm-up
Battery extends runtime, but the PM laser and CO2 sensor draw more current. For dense reporting or continuous PM sampling, power the AM319 over USB Type-C.
E-Ink and child lock
The E-Ink display and on-device buttons are configurable over NFC. Enable the child lock in public spaces so the screen elements and buzzer cannot be changed at the device.
How merkaio supports your AM319
From sourcing to day-to-day operation, all from one partner on our own European infrastructure.
Pre-staging & provisioning
We configure the AM319, set keys, intervals and alarms, and ship it ready to deploy.
Own decoder
Payload codec for ChirpStack v4 and ThingsBoard, implemented from the Milesight specification.
Dashboard integration
Data lands in your ThingsBoard or Grafana, with alarms and reports.
Operations & monitoring
We run the LoRaWAN stack and dashboards on European infrastructure, you just use the data.
Frequently asked questions
Let's discuss your infrastructure. Digital and on-site.
Whether it's IoT platform development, hardware selection, managed hosting for ChirpStack, ThingsBoard, Grafana or NetBird VPN, or migration from a self-hosted setup - we'll find the right solution for your use case. Book a free 30-minute consultation, no commitment required.
Your contact
Timo Wevelsiep
Founder, merkaio
15 minutes, no commitment, directly with Timo.
Decoder for ChirpStack v4. merkaio is an independent integrator and is not affiliated with Milesight.