Milesight VS133: AI ToF People Counting Sensor (LoRaWAN)
Milesight VS133 AI ToF people counting sensor: own ChirpStack decoder framework for line in/out and region counts, plus smart-retail and footfall integration.
- LoRaWAN
- Class C, OTAA
- Technology
- 2nd-gen AI ToF depth sensor
- Accuracy
- Up to 99.8 %, anonymous (no images)
- Counting
- Line in/out, region presence, dwell time
- Mounting
- Overhead (ceiling), top-down view
- Power
- PoE 802.3af or DC (Class C)
- Configuration
- Web GUI, draw lines and regions
What the VS133 measures
Line crossings (in/out)
Bidirectional counts per drawn line, up to four lines.
Region presence
Live headcount inside up to four drawn regions.
Dwell time
Average and maximum dwell per region for queue and zone analysis.
Demographics
Optional adult vs child distinction and staff filtering, fully anonymous.
Occlusion alarm
Reports when the lens view is blocked, so gaps in data are explained.
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 = { lines: {}, regions: {} };
for (var i = 0; i < bytes.length; ) {
var channel = bytes[i++];
var type = bytes[i++];
// Device info on join / power-on (0xFF segments)
if (channel === 0xff) { i += deviceInfoLen(type); continue; }
// Line counters: channels 03/06/09/0C = total IN, 04/07/0A/0D = total OUT.
// Type 0xD2, value is UINT32 little-endian.
if (type === 0xd2 && isLineIn(channel)) {
line(data, lineIndex(channel, IN_BASE)).in = readUInt32LE(bytes, i);
i += 4; continue;
}
if (type === 0xd2 && isLineOut(channel)) {
line(data, lineIndex(channel, OUT_BASE)).out = readUInt32LE(bytes, i);
i += 4; continue;
}
// Per-line period (channels 05/08/0B/0E, type 0xCC): in + out UINT16 LE.
if (type === 0xcc && isLinePeriod(channel)) {
var ln = line(data, lineIndex(channel, PERIOD_BASE));
ln.period_in = readUInt16LE(bytes, i);
ln.period_out = readUInt16LE(bytes, i + 2);
i += 4; continue;
}
// Region headcount (channel 0F, type 0xE3): four UINT8 region counts.
if (channel === 0x0f && type === 0xe3) {
for (var r = 0; r < 4; r++) region(data, r + 1).count = bytes[i + r];
i += 4; continue;
}
// Region dwell (channel 10, type 0xE4): region id + avg + max (UINT16 LE).
if (channel === 0x10 && type === 0xe4) {
var rg = region(data, bytes[i]);
rg.avg_dwell = readUInt16LE(bytes, i + 1);
rg.max_dwell = readUInt16LE(bytes, i + 3);
i += 5; continue;
}
// Occlusion / lens-blocked alarm (channel 50, type 0xFC).
if (channel === 0x50 && type === 0xfc) {
data.occlusion_alarm = bytes[i + 2];
i += 3; continue;
}
// Unknown channel: stop. Region/child layout is deployment-specific.
break;
}
return { data: data };
}
var IN_BASE = 0x03, OUT_BASE = 0x04, PERIOD_BASE = 0x05;
function isLineIn(c) { return c === 0x03 || c === 0x06 || c === 0x09 || c === 0x0c; }
function isLineOut(c) { return c === 0x04 || c === 0x07 || c === 0x0a || c === 0x0d; }
function isLinePeriod(c) { return c === 0x05 || c === 0x08 || c === 0x0b || c === 0x0e; }
function lineIndex(c, base) { return (c - base) / 3 + 1; }
function line(data, n) {
var key = "line_" + n;
if (!data.lines[key]) data.lines[key] = {};
return data.lines[key];
}
function region(data, n) {
var key = "region_" + n;
if (!data.regions[key]) data.regions[key] = {};
return data.regions[key];
}
function readUInt16LE(b, i) { return (b[i + 1] << 8) | b[i]; }
function readUInt32LE(b, i) {
return ((b[i + 3] << 24) | (b[i + 2] << 16) | (b[i + 1] << 8) | b[i]) >>> 0;
}
function deviceInfoLen(type) {
// 0xFF segment lengths are firmware-specific (version, SN, downlink ACKs).
void type; return 1;
}
Implemented from the published Milesight byte specification (Communication Protocol / User Guide).
The VS133 payload is configuration-dependent: how many counting lines and regions you draw in the web GUI decides which channels appear, and multi-sensor (master plus child) setups add a second block of channels. This is a framework in the IPSO channel format, not a fixed drop-in: line counters arrive as UINT32 little-endian totals on channels 03/06/09/0C (in) and 04/07/0A/0D (out), region headcounts as four bytes on channel 0F, and region dwell time on channel 10. We implement and adapt it from the published Milesight byte specification against a real uplink from the deployment. As a Class C device the VS133 also accepts downlinks to set the report interval or clear counters.
Use cases
Smart retail footfall
Count visitors at entrances and zones to measure conversion and staffing.
MoreSmart office occupancy
Track meeting-room and floor usage to right-size space.
MoreQueue and dwell analytics
Region dwell time flags slow checkouts and crowded zones.
Configuration & pitfalls
Draw lines and regions first
Counting lines and zones are configured in the web GUI before rollout. The payload only carries the channels you enable, so finalise the layout, then map the decoder.
Overhead mounting height
The ToF field of view is fixed, so mounting height sets the covered width. Confirm ceiling height against the datasheet coverage table before ordering brackets.
Class C power, not battery
The VS133 runs on PoE or DC and keeps its receive window open continuously. Plan cabling and a PoE switch port, not a battery budget.
Master and child layout
Linked sensors covering a wide entrance report a second channel block (child counts). Document which node is master so totals are not double counted.
How merkaio supports your VS133
From sourcing to day-to-day operation, all from one partner on our own European infrastructure.
Pre-staging & provisioning
We configure the VS133, 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.