Milesight AT101: LoRaWAN GPS & Wi-Fi Asset Tracker

Milesight AT101 LoRaWAN asset tracker: GNSS plus Wi-Fi positioning, own ChirpStack/ThingsBoard decoder, decoded example, geofencing and fleet integration.

Milesight AT101
AT101Sensor
LoRaWAN
Class A, OTAA
Positioning
GNSS (GPS/BeiDou) + Wi-Fi scan
Ingress protection
IP67
Sensors
Temperature, tilt, tamper
Battery
Up to 15 years (2 fixes/day)
Range
Up to 15 km rural, 2 km urban
Configuration
NFC / Bluetooth (Milesight ToolBox)
Measurements

What the AT101 measures

Location

Latitude/longitude from GNSS or Wi-Fi MAC scan, scaled by 1,000,000.

Motion status

Start, moving and stop states from the built-in accelerometer.

Geofence status

Inside, outside or unset against the configured virtual perimeter.

Temperature

On-board temperature with optional abnormal-temperature alarm.

Tilt and tamper

Device position (normal/tilt) and install/uninstall tamper events.

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 === 0x03 && type === 0x67) {     // temperature (°C)
      data.temperature = readInt16LE(bytes, i) / 10; i += 2;
    } else if (channel === 0x83 && type === 0x67) {     // temperature + alarm flag
      data.temperature = readInt16LE(bytes, i) / 10;
      data.temperature_alarm = bytes[i + 2] === 1 ? "abnormal" : "normal";
      i += 3;
    } else if ((channel === 0x04 || channel === 0x84) && type === 0x88) { // location
      data.latitude = readInt32LE(bytes, i) / 1000000;
      data.longitude = readInt32LE(bytes, i + 4) / 1000000;
      var status = bytes[i + 8];
      data.motion_status = MOTION[status & 0x0f];
      data.geofence_status = GEOFENCE[status >> 4];
      i += 9;
    } else if (channel === 0x05 && type === 0x00) {     // device position
      data.position = bytes[i] === 1 ? "tilt" : "normal"; i += 1;
    } else if (channel === 0x07 && type === 0x00) {     // tamper status
      data.tamper_status = bytes[i] === 1 ? "uninstall" : "install"; i += 1;
    } else if (channel === 0x06 && type === 0xd9) {     // Wi-Fi scan result
      var wifi = {
        mac: readMAC(bytes, i + 1),
        rssi: readInt8(bytes[i + 7])
      };
      data.wifi = data.wifi || [];
      if (wifi.mac !== "ff:ff:ff:ff:ff:ff") data.wifi.push(wifi);
      i += 9;
    } else {
      break;                                            // unknown channel
    }
  }
  return { data: data };
}

var MOTION = { 0: "unknown", 1: "start", 2: "moving", 3: "stop" };
var GEOFENCE = { 0: "inside", 1: "outside", 2: "unset", 3: "unknown" };

function readInt8(b) { return b > 0x7f ? b - 0x100 : b; }
function readInt16LE(b, i) {
  var v = (b[i + 1] << 8) | b[i];
  return v > 0x7fff ? v - 0x10000 : v;
}
function readUInt32LE(b, i) {
  return ((b[i + 3] << 24) | (b[i + 2] << 16) | (b[i + 1] << 8) | b[i]) >>> 0;
}
function readInt32LE(b, i) {
  var v = readUInt32LE(b, i);
  return v > 0x7fffffff ? v - 0x100000000 : v;
}
function readMAC(b, i) {
  var out = [];
  for (var k = 0; k < 6; k++) out.push(("0" + (b[i + k] & 0xff).toString(16)).slice(-2));
  return out.join(":");
}

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

Channel format: 01 75 battery (%), 03 67 temperature (INT16 little-endian, /10), 83 67 temperature with an abnormal-alarm flag, 04/84 88 location (latitude and longitude as INT32 little-endian, /1,000,000) plus a status byte where the low nibble is motion and the high nibble is geofence, 05 00 device position (tilt), 07 00 tamper. Implemented from the published Milesight byte specification. When the tracker is set to Wi-Fi positioning it sends 06 D9 scan results (BSSID list) instead of a GNSS fix, which a location backend resolves to coordinates. For ThingsBoard the same channel logic goes into an uplink converter.

Uplink (hex)

0175640367EB000488C283DE0256A0B00002050001070000

Decoded JSON

{ "battery": 100, "temperature": 23.5, "latitude": 48.137154, "longitude": 11.575382, "motion_status": "moving", "geofence_status": "inside", "position": "tilt", "tamper_status": "install" }
From the field

Configuration & pitfalls

GNSS vs Wi-Fi positioning

GNSS gives outdoor accuracy, Wi-Fi MAC scanning works indoors but needs a geolocation backend to resolve BSSIDs to coordinates. Pick the strategy per use case, the payload layout changes with it.

Reporting strategy

Periodic, motion-triggered and timing modes trade battery life against freshness. Motion mode saves power but only reports while assets move, plan dashboard timeouts accordingly.

Geofence setup

Center coordinates and radius are configured on the device. Outside or inside transitions arrive as a status byte, so dashboard rules should treat them as priority events.

GNSS fix timeout

A cold fix can take longer under poor sky view. Set a realistic positioning timeout so the tracker does not drain battery hunting for satellites indoors.

Your partner

How merkaio supports your AT101

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

Pre-staging & provisioning

We configure the AT101, 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 Class A 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 GNSS (GPS and BeiDou) with Wi-Fi access-point MAC scanning. GNSS gives outdoor accuracy, while Wi-Fi scanning helps indoors. Wi-Fi scan results are a list of BSSIDs that a geolocation backend resolves into coordinates.
Up to 15 years when the position is updated about twice a day. The interval is configurable from 1 to 1440 minutes, so the real lifetime depends on how often you report and which positioning mode you use.
Yes. You configure a center point and radius on the device, and the tracker reports an inside or outside status in the location uplink so your dashboard can alert when an asset leaves or returns to a zone.
It reports battery level, on-board temperature with an optional abnormal-temperature alarm, device tilt position, motion status from the accelerometer, and install/uninstall tamper events.
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.