AN-122 LoRaWAN Beacon Tracker User Guide

Device Information: Model AN-122, devEui ffffff100004c8c2, gateway IP 192.168.31.193, Modbus Slave ID 8, BACnet Device ID 107

1 Protocol Overview

The AN-122 reports nearby beacon RSSI data, battery voltage/percentage, GPS location, and signal quality on Fport 210.

Payload format (Fport 210):

Byte Field Description
0 Reserved Always 0x00 (protocol version)
1 … N TLV pairs [Type(1 B)][Value(N B)] … repeating until end

Each Type byte determines the field name and the number of following value bytes:

Type Value Bytes Field Name Encoding Scale Unit Notes
0x01 1 model uint8 Model code = 0x57
0x93 1 batteryLevel uint8 % 0–100 % battery level
0x6D 1 packetType uint8 0x00=heartbeat 0x01=data report
0x77 1 tamperState uint8 0=normal 1=tampered
0xBA 1+N beaconData block 8-byte simple beacon block (length byte = 0x07); repeats up to 3 times; see sub-table below
0x3E 4 latitude int32 BE ÷10000000 ° e.g. 227439186 → 22.7439186°
0x43 4 longitude int32 BE ÷10000000 ° e.g. 1139290611 → 113.9290611°
0xC3 1 positionAccuracy uint8 ÷10 0–254 = accuracy ÷10; 255 = invalid
0x6B 2 tiltAngle uint16 BE ° Tilt angle in degrees
0xB8 1 batteryLowAlarm uint8 0=normal 1=battery low alarm event
0x03 1 tamperEvent uint8 0=normal 1=tamper event
0xA8 1 accelerationAlarm uint8 0=normal 1=acceleration alarm
0xC2 1 tiltAlarm uint8 0=normal 1=tilt alarm event

AN-122 0xBA Simple Beacon Block

Each 0xBA TLV occurrence carries data for one nearby beacon (up to 3 occurrences per packet). The value field is always 8 bytes (length byte = 0x07 + 7 data bytes):

Offset Bytes Field Encoding Notes
0 1 length uint8 Always 0x07
1 4 beaconId uint32 BE Last 4 bytes of beacon Bluetooth MAC address
5 1 refRssi int8 1 m reference RSSI (dBm, signed)
6 1 rssi int8 Received RSSI (dBm, signed)
7 1 batteryLevel uint8 0–100 %; 255 = invalid
The 0xBA TLV is repeated once per detected beacon (up to 3 times).
Parsed results appear as beacons[0], beacons[1], beacons[2] in the output object.

JavaScript Decoder Example:

// AN-122 Beacon Tracker — Fport 210 uplink decoder
function decodeUplink(bytes) {
  var i = 1, r = {};
  function u16(b,o){ return (b[o]<<8)|b[o+1]; }
  function i16(b,o){ var v=u16(b,o); return v>32767?v-65536:v; }
  function u32(b,o){ return ((b[o]<<24)|(b[o+1]<<16)|(b[o+2]<<8)|b[o+3])>>>0; }
  function i32(b,o){ var v=u32(b,o); return v>0x7FFFFFFF?v-0x100000000:v; }
  function i8(b,o) { var v=b[o]&0xFF; return v>127?v-256:v; }
  while (i < bytes.length) {
    var t = bytes[i++];
    switch (t) {
      case 0x01: r.model            = bytes[i++]; break;
      case 0x03: r.tamperEvent      = bytes[i++]; break;
      case 0x6B: r.tiltAngle        = u16(bytes,i); i+=2; break; // degrees
      case 0x6D: r.packetType       = bytes[i++]; break;
      case 0x77: r.tamperState      = bytes[i++]; break;
      case 0x93: r.batteryLevel     = bytes[i++]; break; // %
      case 0x3E: r.latitude  = i32(bytes,i)/10000000; i+=4; break;
      case 0x43: r.longitude = i32(bytes,i)/10000000; i+=4; break;
      case 0xA8: r.accelerationAlarm= bytes[i++]; break;
      case 0xB8: r.batteryLowAlarm  = bytes[i++]; break;
      case 0xC2: r.tiltAlarm        = bytes[i++]; break;
      case 0xC3: { var a=bytes[i++]; r.positionAccuracy=a===255?null:a/10; break; }
      case 0xBA: {
        // 8-byte simple beacon (length byte 0x07 + 7 bytes)
        var len = bytes[i++]; // = 0x07
        if (!r.beacons) r.beacons = [];
        var id = u32(bytes,i);
        r.beacons.push({
          idHex: id.toString(16).padStart(8,'0').toUpperCase(),
          refRssi: i8(bytes, i+4),
          rssi:    i8(bytes, i+5),
          batteryLevel: bytes[i+6]
        });
        i += len; break;
      }
      default: i++; break;
    }
  }
  return r;
}

Script download: LPP.zip

Compatibility note: LPP.js is developed and tested against ChirpStack v4.17.0. The ChirpStack JavaScript codec API may differ across versions — if you are running a different ChirpStack version, review and adjust the script as needed before deployment.
⚠️ The IP addresses (192.168.31.205 / 192.168.31.193), ChirpStack API token, Slave ID, BACnet Device ID, and devEui in the examples below are for demonstration only. Replace them with your actual gateway IP, ChirpStack API token, and device parameters.

2.1 ChirpStack MQTT Subscription

Subscribe to the MQTT topic to receive real-time uplink frames:

Application ID3ef9e6b9-ec54-4eda-86b8-a5fb46899f39 is the factory-default ChirpStack
application built into the gateway. Replace it with your actual application
ID if you have created a different one.

Gateway IP192.168.31.193 is the gateway WAN port IP shown as an
example. Replace it with your actual gateway IP address.

Device EUIffffff100004c8c2 is the EUI of the example device.
Replace it with the EUI shown in the gateway device list, or use +
as a wildcard to subscribe to all devices at once.
# Subscribe to one specific device
mosquitto_sub -h 192.168.31.193 -p 1883 \
  -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff100004c8c2/event/up"

# Subscribe to ALL devices on ALL applications (wildcard)
mosquitto_sub -h 192.168.31.193 -p 1883 \
  -u gateway -P mqtt88888888 \
  -t "application/+/device/+/event/up"

Example uplink payload (JSON):

{
  "devEui": "ffffff100004c8c2",
  "fPort": 210,
  "object": {
    ...  (decoded LPP fields)
  }
}

2.2 IoT Hub HTTP API

Send a GET request to retrieve the latest device state:

curl -s "http://192.168.31.193:8070/api/getStatus?devEui=ffffff100004c8c2"
{
  "success": true,
  "result": {
    "batteryLevel": 99,
    "tamper": 1,
    "latitude": 22.743225,
    "longitude": 113.929123,
    "positionAccuracy": 2.3,
    "beaconBatteryValid": false,
    "tiltAngle": 1,
    "batteryLowAlarm": false,
    "accelerationAlarm": false,
    "tiltAlarm": false,
    "model": "AN-122"
  }
}

2.3 IoT Hub Modbus TCP — Python Script

Script download: modbus_tcp_read.py

Use modbus_tcp_read.py to poll all registers at once:

python3 modbus_tcp_read.py --ip 192.168.31.193 --port 502 \
    --slaveId 8 --sensorType AN-122
Target: 192.168.31.193:502 | Slave ID: 8 | Sensor: AN-122
================================================================================================================================================================
Attribute                | Addr   | FC  | Format     | Order        | Cnt | Scale    | Raw(Hex)            | Value              | Unit
----------------------------------------------------------------------------------------------------------------------------------------------------------------
online                   | 6      | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
lastOnlineTime           | 7      | 03  | UnixTime   | Big(ABCD)    | 2   | x1       | 69CC CE99           | 1775029913         | second
batteryLevel             | 9      | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0063                | 99.0               | percent
tamper                   | 10     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
latitude                 | 11     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 41B5 F220           | 22.743225          | degrees
longitude                | 13     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 42E3 DBB6           | 113.929123         | degrees
positionAccuracy         | 15     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 4013 3333           | 2.30               | meter
beaconIdHex              | 17     | 03  | String(32B) | ASCII        | 16  | x1       | 0000 0000 0000 0000 ... |                    | none
beaconRefRssi            | 33     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
beaconRssi               | 34     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
beaconBatteryLevel       | 35     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | percent
beaconBatteryValid       | 36     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
... (20 fields total)

2.4 IoT Hub Modbus TCP — Modbus Poll

Tool download: Modbus Poll 9.5.0.1507.zip

  1. Open Modbus Poll, connect to 192.168.31.193:502, Slave ID 8
  2. Menu Setup → Read/Write Definition, set Function Code = FC03, Start Address = 6, Length = 74
  3. Click OK — values update in real-time

2.5 IoT Hub BACnet BIP — Python Script

Script download: bacnet_read.py

Use bacnet_read.py to read all BACnet objects:

python3 bacnet_read.py --ip 192.168.31.193 --port 47808 --id 107
Target: 192.168.31.193:47808 | BACnet ID: 107 | Scan: 10700-10799
------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------
BI   | 10702    | 2      | active                   | ffffff100004c8c2.online
AI   | 10703    | 3      | 1775029888.00            | ffffff100004c8c2.lastOnlineTime
AI   | 10704    | 4      | 99.00                    | ffffff100004c8c2.batteryLevel
AI   | 10705    | 5      | 1.00                     | ffffff100004c8c2.tamper
AI   | 10706    | 6      | 22.743225                | ffffff100004c8c2.latitude
AI   | 10707    | 7      | 113.929123               | ffffff100004c8c2.longitude
AI   | 10708    | 8      | 2.30                     | ffffff100004c8c2.positionAccuracy
CV   | 10709    | 9      |                          | ffffff100004c8c2.beaconIdHex
AI   | 10710    | 10     | 0.00                     | ffffff100004c8c2.beaconRefRssi
AI   | 10711    | 11     | 0.00                     | ffffff100004c8c2.beaconRssi
AI   | 10712    | 12     | 0.00                     | ffffff100004c8c2.beaconBatteryLevel
BI   | 10713    | 13     | inactive                 | ffffff100004c8c2.beaconBatteryValid
... (20 objects total)

2.6 IoT Hub BACnet BIP — YABE

Tool download: SetupYabe_v2.1.0.exe

  1. Open YABE, connect to 192.168.31.193:47808
  2. Expand Device 107 in the device tree
  3. Browse AI/BI/AV/BV/CV objects to view real-time values