Milesight VS330: LoRaWAN Restroom Occupancy Sensor

Milesight VS330 LoRaWAN restroom occupancy sensor: own ChirpStack/ThingsBoard decoder, decoded example, cubicle occupancy and smart-restroom integration.

Milesight VS330
VS330Sensor
LoRaWAN
Class A, OTAA
Detection
PIR + ToF (time-of-flight)
Band / port
EU868 / port 85
Tilt range
Rotatable probe 0 to 75 degrees
Accuracy
Over 99.5 % with self-calibration
Privacy
No camera, GDPR compliant, fully anonymous
Configuration
NFC (Milesight ToolBox)
Measurements

What the VS330 measures

Occupancy

Vacant or occupied per cubicle, derived from combined PIR motion and ToF distance.

Distance

ToF distance to the detected object in millimetres (UINT16).

Calibration status

Reports whether the self-calibration step succeeded or failed.

Battery level

Reported as a percentage, with local storage and retransmission.

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 channel = bytes[i++];
    var type = bytes[i++];

    if (channel === 0x01 && type === 0x75) {          // battery (%)
      data.battery = bytes[i]; i += 1;
    } else if (channel === 0x02 && type === 0x82) {   // distance (mm, UINT16 LE)
      data.distance = readUInt16LE(bytes, i); i += 2;
    } else if (channel === 0x03 && type === 0x8e) {   // occupancy
      data.occupancy = bytes[i] === 1 ? "occupied" : "vacant"; i += 1;
    } else if (channel === 0x04 && type === 0x8e) {   // calibration status
      data.calibration_status = bytes[i] === 1 ? "success" : "failed"; i += 1;
    } else {
      break;
    }
  }
  return { data: data };
}

function readUInt16LE(b, i) {
  return ((b[i + 1] << 8) | b[i]) & 0xffff;
}

Implemented from the published Milesight byte specification (Communication Protocol / User Guide).

Channel format: 01 75 battery (%), 02 82 distance (UINT16 little-endian, mm), 03 8E occupancy (0 vacant / 1 occupied), 04 8E calibration status (0 failed / 1 success). Version and serial-number frames on channel FF are skipped by the break on an unknown channel. Implemented from the published Milesight byte specification. For ThingsBoard the same channel logic goes into an uplink converter.

Uplink (hex)

01756402822C01038E01

Decoded JSON

{ "battery": 100, "distance": 300, "occupancy": "occupied" }
Where it fits

Use cases

Smart restroom

Live cubicle availability on door panels and cleaning dashboards.

More

Facility management

Usage-based cleaning schedules instead of fixed rounds.

Workplace analytics

Anonymous occupancy data for space planning and comfort.

From the field

Configuration & pitfalls

NFC setup

Keys, reporting interval and the cubicle install height are set over NFC with the Milesight ToolBox before rollout.

Mounting angle

The probe rotates 0 to 75 degrees. Aim it at the cubicle floor area so the ToF beam covers the seat without hitting the door, or you get false occupancy.

Self-calibration

On install the sensor learns the empty-cubicle distance. Re-run calibration if you move the unit or change the layout, and watch the calibration_status field.

Damp environments

The PCBA has a conformal coating against moisture, but still position the unit away from direct splash and steam to keep ToF readings stable.

Your partner

How merkaio supports your VS330

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

Pre-staging & provisioning

We configure the VS330, 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 same channel logic goes into a ThingsBoard uplink converter.
It combines a PIR sensor for human motion with a ToF sensor that measures the distance to objects below it. There is no camera and no image is captured, so it is fully anonymous and GDPR compliant.
It is a Class A device on LoRaWAN port 85. Each uplink can carry occupancy, distance, calibration status and the battery level.
Milesight states over 99.5 percent accuracy thanks to the embedded self-calibration algorithm that combines the PIR and ToF readings.
Occupancy is vacant or occupied (channel 03 8E). Calibration status is success or failed (channel 04 8E) and tells you whether the empty-cubicle baseline was learned correctly.
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.