Milesight GS601: LoRaWAN Vape & Smoke Detector

Milesight GS601 LoRaWAN vape & smoke detector: own ChirpStack/ThingsBoard decoder, decoded example, vaping-index alarms and smart-school integration.

Milesight GS601
GS601Sensor
LoRaWAN
Class C, OTAA
Band / port
EU868 / port 85
Detection area
4 x 4 m, mount at 2.4 to 3 m
Sensors
TVOC, PM1.0/2.5/10, temperature, humidity
Privacy
No camera, no microphone
Local alerts
Buzzer + LED, tamper detection
Power
USB-C / mains powered
Measurements

What the GS601 measures

Vaping index

Composite 0 to 100 score (UINT8) that rises during a vaping or smoking event; the primary alarm value.

TVOC

Total volatile organic compounds in ppb (UINT16 LE), the main air-chemistry signal behind the vaping index.

Particulate matter

PM1.0, PM2.5 and PM10 in micrograms per cubic metre (each UINT16 LE).

Temperature & humidity

Onboard climate readings (temperature INT16 LE /10 in degrees C, humidity UINT16 LE /10 in % RH) for context and burning alarms.

Tamper & occupancy

Tamper-trigger flag (UINT8) plus optional occupancy status (0 vacant / 1 occupied).

Data into your dashboard

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.

ChirpStack v4 · decodeUplink
function decodeUplink(input) {
  var bytes = input.bytes;
  var data = {};

  for (var i = 0; i < bytes.length; ) {
    var id = bytes[i++];

    if (id === 0x00) {                                  // battery (%)
      data.battery = bytes[i]; i += 1;
    } else if (id === 0x01) {                           // vaping index (0..100)
      data.vaping_index = bytes[i]; i += 1;
    } else if (id === 0x03) {                           // PM1.0 (ug/m3)
      data.pm1_0 = readUInt16LE(bytes, i); i += 2;
    } else if (id === 0x05) {                           // PM2.5 (ug/m3)
      data.pm2_5 = readUInt16LE(bytes, i); i += 2;
    } else if (id === 0x07) {                           // PM10 (ug/m3)
      data.pm10 = readUInt16LE(bytes, i); i += 2;
    } else if (id === 0x09) {                           // temperature (C)
      data.temperature = readInt16LE(bytes, i) / 10; i += 2;
    } else if (id === 0x0b) {                           // humidity (%RH)
      data.humidity = readUInt16LE(bytes, i) / 10; i += 2;
    } else if (id === 0x0d) {                           // TVOC
      data.tvoc = readUInt16LE(bytes, i); i += 2;
    } else if (id === 0x0f) {                           // tamper status (0/1)
      data.tamper = bytes[i]; i += 1;
    } else if (id === 0x12) {                           // occupancy (0/1)
      data.occupancy = bytes[i]; i += 1;
    } else {
      break;  // alarm frames, raw TVOC blocks and config replies are deployment-specific
    }
  }
  return { data: data };
}

function readUInt16LE(b, i) {
  return (b[i + 1] << 8) | b[i];
}
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).

Command-id format: 00 battery (%), 01 vaping index, 03/05/07 PM1.0/PM2.5/PM10 (UINT16 LE), 09 temperature (INT16 LE, /10), 0b humidity (UINT16 LE, /10), 0d TVOC, 0f tamper, 12 occupancy. This is the periodic-report path, implemented from the published Milesight byte specification. Alarm frames (e.g. command id 02 for a vaping-index alarm) and raw TVOC blocks carry extra type bytes and are deployment-specific, so the loop breaks on unknown ids; we extend it for the alarm types you actually use. The same logic goes into a ThingsBoard uplink converter.

Uplink (hex)

00640114030500050800070C0009E1000BE0010D9600

Decoded JSON

{ "battery": 100, "vaping_index": 20, "pm1_0": 5, "pm2_5": 8, "pm10": 12, "temperature": 22.5, "humidity": 48, "tvoc": 150 }
From the field

Configuration & pitfalls

Class C power

The GS601 is a Class C device with continuous receive, so it runs on USB-C or mains, not on battery. Plan a power outlet at the mounting point.

Placement

Detection area is about 4 x 4 m at a mounting height of 2.4 to 3 m. Centre it over the monitored space and keep it clear of vents that flush the air.

Privacy by design

No camera and no microphone: it senses air chemistry only. This is the key selling point for restrooms and changing rooms, document it for stakeholders.

Alarm vs report frames

Periodic reports and event alarms use different command ids. Treat vaping-index alarm uplinks as priority events and decode the alarm type explicitly when you enable them.

Your partner

How merkaio supports your GS601

From sourcing to day-to-day operation, all from one partner on our own European infrastructure.

Pre-staging & provisioning

We configure the GS601, 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

Yes. It is a standard LoRaWAN device, no Milesight gateway or cloud required. You add the codec to the device profile and provision it via OTAA.
Yes, for both ChirpStack and ThingsBoard, implemented from the published Milesight byte specification. The periodic-report path is ready to use and we extend the alarm frames you enable.
No. The GS601 detects vaping and smoking purely from air chemistry (TVOC and particulate matter), so it can be placed in restrooms and changing rooms without recording images or audio.
It is a composite 0 to 100 index that combines the onboard TVOC and particulate readings. It rises during a vaping or smoking event and is the value most dashboards alert on.
It is a Class C device on LoRaWAN port 85. Class C keeps the receive window open, so it accepts downlinks (for example to silence the buzzer) in near real time and needs mains power.
Yes. The GS601 has an onboard buzzer and LED and a tamper sensor, so it can alert locally and flag tampering even before the uplink reaches your platform.
From the same series

Related devices

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.

Timo Wevelsiep

Your contact

Timo Wevelsiep

Founder, merkaio

15 minutes, no commitment, directly with Timo.

By submitting, you agree to our Privacy Policy.

Decoder for ChirpStack v4. merkaio is an independent integrator and is not affiliated with Milesight.