AN-201G LoRaWAN Strain Gauge Sensor User Guide

Device Information: Model AN-201G, devEui ffffff100004e9c8, gateway IP 192.168.31.205, Modbus Slave ID 10, BACnet Device ID 109

1 Protocol Overview

The AN-201G reports RS485 Modbus register data, battery voltage, 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 = 0x62
0x04 2 batteryVoltage uint16 BE ÷1000 V mV raw ÷1000 = V
0x7D 1 batteryVoltageState uint8 0=normal 1=low voltage
0x6D 1 packetType uint8 0x00=heartbeat 0x01=data report
0x79 4 timestamp uint32 BE s Device local Unix timestamp
0xDD 1 vibratingWireSensorModel uint8 Vibrating-wire sensor formula model code (used for strain derivation)
0xDC 4 frequency uint32 BE ÷100 Hz 1st occurrence = current frequency; 2nd occurrence = initial baseline frequency (optional)
0xAA 2 temperature int16 BE ÷10 °C 1st occurrence = current temp; 2nd occurrence = initial baseline temp (optional)
0x05 1 batteryLowEvent uint8 0=normal 1=low-voltage event (optional)

JavaScript Decoder Example:

// AN-201G Vibrating-Wire Strain Gauge — Fport 210 uplink decoder
function decodeUplink(bytes) {
  var i = 1, r = {}, freqCount = 0, tempCount = 0;
  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; }
  while (i < bytes.length) {
    var t = bytes[i++];
    switch (t) {
      case 0x01: r.model     = bytes[i++]; break;
      case 0x94: r.rs485Addr = bytes[i++]; break;
      case 0x04: r.batteryVoltage = u16(bytes,i)/1000; i+=2; break; // V
      case 0x05: r.batteryLowEvent= bytes[i++]; break;
      case 0xDC: {
        // 4-byte uint32 ÷100 = Hz; first = current, second = initial
        var hz = u32(bytes,i)/100; i+=4;
        if(freqCount===0){ r.frequency=hz; } else { r.initialFrequency=hz; }
        freqCount++; break;
      }
      case 0xAA: {
        // int16 ÷10 = °C; first = current, second = initial
        var tc = i16(bytes,i)/10; i+=2;
        if(tempCount===0){ r.temperature=tc; } else { r.initialTemperature=tc; }
        tempCount++; break;
      }
      case 0xDD: r.vibratingWireSensorModel = bytes[i++]; break;
      case 0x95: { var len=bytes[i++]; i+=len; break; } // Modbus block (optional)
      default:   i++; break;
    }
  }
  return r;
}
// → { model:98, rs485Addr:1, frequency:1234.56, temperature:25.3,
//     initialFrequency:1200.0, initialTemperature:20.0, ... }

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.

Gateway-Calculated Strain Output (not in raw payload)

The AN-201G does not report stress/strain values directly. The gateway's LPP.js decoder derives them from the raw frequency and temperature data using the vibrating-wire surface strain formula. The computed fields are available via all IoT Hub interfaces:

Formula (for sensor model code 0x01 — concrete/steel surface):

F  = f² / 1000          (frequency digit, where f is in Hz)
steelStructureStrain   = G × C × (F₁ − F₀)                  [µε]
concreteStructureStrain= steelStructureStrain + (Y₁ − Y₂) × (T₁ − T₀)  [µε]
Symbol Value Description
G 3.7 Gauge factor (µε/digit)
C 1.0 Average correction coefficient (from calibration sheet)
Y₁ 12.2 Steel thermal expansion coefficient (µε/°C)
Y₂ 10.4 Concrete thermal expansion coefficient (µε/°C)
f, F₁ current Current frequency (Hz) / digit
f₀, F₀ initial Baseline frequency (Hz) / digit set at commissioning
T₁ current Current temperature (°C), from Type 0xAA (1st occurrence)
T₀ initial Baseline temperature (°C), from Type 0xAA (2nd occurrence)

Access the derived strain values:

Interface Field Address / Instance Unit Notes
MQTT JSON steelStructureStrain JSON key µε gateway adds to decoded JSON
MQTT JSON concreteStructureStrain JSON key µε gateway adds to decoded JSON
HTTP JSON steelStructureStrain JSON key µε /api/getStatus response
HTTP JSON concreteStructureStrain JSON key µε /api/getStatus response
Modbus TCP steelStructureStrain Hold. Reg 26 (FC03, Float32 BE, ×100) µε 2 registers
Modbus TCP concreteStructureStrain Hold. Reg 28 (FC03, Float32 BE, ×100) µε 2 registers
BACnet BIP steelStructureStrain AI 10915 (Device ID=109, offset 15) µε Analog Input
BACnet BIP concreteStructureStrain AI 10916 (Device ID=109, offset 16) µε Analog Input
frequencyDigit (reg 16, AI 10909) and initialFrequencyDigit (reg 23, AI 10913)
are also exposed for reference.
⚠️ 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.205 is the gateway WAN port IP shown as an
example. Replace it with your actual gateway IP address.

Device EUIffffff100004e9c8 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.205 -p 1883 \
  -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff100004e9c8/event/up"

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

Example uplink payload (JSON):

{
  "devEui": "ffffff100004e9c8",
  "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.205:8070/api/getStatus?devEui=ffffff100004e9c8"
{
  "success": true,
  "result": {
    "batteryVoltage": 3.53,
    "batteryVoltageState": 0,
    "timestamp": 1775015242,
    "vibratingWireSensorModel": 1,
    "frequency": 859.92,
    "frequencyDigit": 739.46,
    "temperature": 26.8,
    "correctionFactor": 1,
    "initialFrequency": 856.61,
    "initialFrequencyDigit": 733.78,
    "initialTemperature": 27.6,
    "steelStructureStrain": 21.02,
    "concreteStructureStrain": 19.58,
    "batteryLowAlarm": false,
    "isHeartbeat": true,
    "model": "AN-201G"
  }
}

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.205 --port 502 \
    --slaveId 10 --sensorType AN-201G
Target: 192.168.31.205:502 | Slave ID: 10 | Sensor: AN-201G
================================================================================================================================================================
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 9537           | 1775015223         | second
batteryVoltage           | 9      | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0161                | 3.53               | volt
batteryVoltageState      | 10     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
timestamp                | 11     | 03  | Int32      | Big(ABCD)    | 2   | x1       | 69CC 954A           | 1775015242.0       | seconds
vibratingWireSensorModel | 13     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
frequency                | 14     | 03  | Float32    | Big(ABCD)    | 2   | /100     | 47A7 F400           | 859.92             | Hz
frequencyDigit           | 16     | 03  | Float32    | Big(ABCD)    | 2   | /100     | 4790 6D00           | 739.46             | digit
temperature              | 18     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0A78                | 26.8               | celsius
correctionFactor         | 19     | 03  | Float32    | Big(ABCD)    | 2   | /10000   | 461C 4000           | 1.0000             | none
initialFrequency         | 21     | 03  | Float32    | Big(ABCD)    | 2   | /100     | 47A7 4E80           | 856.61             | Hz
initialFrequencyDigit    | 23     | 03  | Float32    | Big(ABCD)    | 2   | /100     | 478F 5100           | 733.78             | digit
... (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.205:502, Slave ID 10
  2. Menu Setup → Read/Write Definition, set Function Code = FC03, Start Address = 6, Length = 64
  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.205 --port 47808 --id 109
Target: 192.168.31.205:47808 | BACnet ID: 109 | Scan: 10900-10999
------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------
BI   | 10902    | 2      | active                   | ffffff100004e9c8.online
AI   | 10903    | 3      | 1775015168.00            | ffffff100004e9c8.lastOnlineTime
AI   | 10904    | 4      | 3.53                     | ffffff100004e9c8.batteryVoltage
AI   | 10905    | 5      | 0.00                     | ffffff100004e9c8.batteryVoltageState
AI   | 10906    | 6      | 1775015296.00            | ffffff100004e9c8.timestamp
AI   | 10907    | 7      | 1.00                     | ffffff100004e9c8.vibratingWireSensorModel
AI   | 10908    | 8      | 859.92                   | ffffff100004e9c8.frequency
AI   | 10909    | 9      | 739.46                   | ffffff100004e9c8.frequencyDigit
AI   | 10910    | 10     | 26.80                    | ffffff100004e9c8.temperature
AI   | 10911    | 11     | 1.00                     | ffffff100004e9c8.correctionFactor
AI   | 10912    | 12     | 856.61                   | ffffff100004e9c8.initialFrequency
AI   | 10913    | 13     | 733.78                   | ffffff100004e9c8.initialFrequencyDigit
... (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.205:47808
  2. Expand Device 109 in the device tree
  3. Browse AI/BI/AV/BV/CV objects to view real-time values