AN-307 LoRaWAN Audible/Visual Alarm User Guide

Device Information: Model AN-307, devEui ffffff100004c88a, gateway IP 192.168.31.193, Modbus Slave ID 3, BACnet Device ID 102

1 Protocol Overview

The AN-307 reports alarm status, alarm duration, 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 = 0x2A
0x3A 1 alarmStatus uint8 0=alarm OFF 1=alarm ON

JavaScript Decoder Example:

// AN-307 Audible/Visual Alarm — Fport 210 uplink decoder
function decodeUplink(bytes) {
  var i = 1, r = {};
  while (i < bytes.length) {
    var t = bytes[i++];
    switch (t) {
      case 0x01: r.model       = bytes[i++]; break;
      case 0x3A: r.alarmStatus = bytes[i++]; break; // 0=OFF  1=ON
      default:   i++; break;
    }
  }
  return r;
}
// Example payload (hex): 00 01 2A 3A 01
// → { model:42, alarmStatus:1 }

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 AN-307 supports timed alarm, indefinite alarm, and cancel alarm via Fport 210 downlink.

Fport: 2100x01 0x2A (model device header, Fport 210)

Packet format: 01 2A [CtrlByte] [D1? D0?] Duration D = alarm duration in seconds (uint16 BE, optional). Fport: 210 (same port as uplink, unlike other devices which use Fport 2).

CmdCode Packet Bytes Description
OFF 01 2A 00 Alarm OFF (stop alarm)
ON 01 2A 01 Alarm ON indefinitely (no timeout)
TIMED 01 2A 01 D1 D0 Alarm ON for D seconds (uint16 BE; e.g. 0x003C=60 s)

JavaScript Encoder Example:

// AN-307 Alarm — Fport 210 downlink encoder
function encodeDownlink(data) {
  // data.alarmState       : 0=off  1=on
  // data.durationSeconds  : uint16 (1–65535), optional; omit for indefinite alarm
  var H = [0x01, 0x2A];
  if (!data.alarmState && data.alarmState !== 1) { return []; }
  var on = Number(data.alarmState) ? 1 : 0;
  if (!on) { return H.concat([0x00]); }
  var d = Number(data.durationSeconds);
  if (d > 0 && d <= 65535) {
    return H.concat([0x01, (d >> 8) & 0xFF, d & 0xFF]);
  }
  return H.concat([0x01]);
}
// Examples:
//   encodeDownlink({alarmState:1})                    → [0x01,0x2A,0x01]
//   encodeDownlink({alarmState:1, durationSeconds:60})→ [0x01,0x2A,0x01,0x00,0x3C]
//   encodeDownlink({alarmState:0})                    → [0x01,0x2A,0x00]
⚠️ 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 EUIffffff100004c88a 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/ffffff100004c88a/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": "ffffff100004c88a",
  "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=ffffff100004c88a"
{
  "success": true,
  "result": {
    "alarmStatus": false,
    "model": "AN-307"
  }
}

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 3 --sensorType AN-307
Target: 192.168.31.193:502 | Slave ID: 3 | Sensor: AN-307
================================================================================================================================================================
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 C0E8           | 1775026408         | second
alarmStatus              | 9      | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmDurationSeconds     | 10     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | seconds
model                    | 35     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D33 3037 0000 ... | AN-307             | none
rssi                     | 47     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FF94                | -108.0             | none
snr                      | 48     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFF7                | -9.0               | none

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 3
  2. Menu Setup → Read/Write Definition, set Function Code = FC03, Start Address = 6, Length = 43
  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 102
Target: 192.168.31.193:47808 | BACnet ID: 102 | Scan: 10200-10299
------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------
BI   | 10202    | 2      | active                   | ffffff100004c88a.online
AI   | 10203    | 3      | 1775026432.00            | ffffff100004c88a.lastOnlineTime
BV   | 10204    | 4      | inactive                 | ffffff100004c88a.alarmStatus
AV   | 10205    | 5      | 0.00                     | ffffff100004c88a.alarmDurationSeconds
CV   | 10209    | 9      | AN-307                   | ffffff100004c88a.model
AI   | 10210    | 10     | -108.00                  | ffffff100004c88a.rssi
AI   | 10211    | 11     | -9.00                    | ffffff100004c88a.snr

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 102 in the device tree
  3. Browse AI/BI/AV/BV/CV objects to view real-time values

3 Sending Control Commands

The AN-307 supports timed alarm, indefinite alarm, and cancel alarm via Fport 210 downlink.

⚠️ 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.

Script downloads: modbus_tcp_write.py · bacnet_write.py

Example 1: Timed Alarm (60 seconds)

Modbus TCP:

python3 modbus_tcp_write.py --ip 192.168.31.193 --port 502 --slaveId 3 --sensorType AN-307 alarm --value 1 --durationSeconds 60
Target: 192.168.31.193:502 | Slave ID: 3 | Sensor: AN-307
Expected values:
  alarmStatus: 1
  alarmDurationSeconds: 60
Expected confirmed state:
  alarmStatus: 1
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 2
    alarmStatus -> register 9 (4x40010) raw=1 signed=1
    alarmDurationSeconds -> register 10 (4x40011) raw=60 signed=60
Observed values:
  alarmStatus: 1
Link confirmation time: 1.138s
Control completed in: 1.149s
The script automatically writes registers and reads them back for verification. The Modbus Poll write guide section in the output can be used directly as a reference for manual writes in Modbus Poll.

Modbus Poll:

  1. Connect to the gateway (IP 192.168.31.193, Port 502, Slave ID 3)
  2. Menu Functions → 16 Write Multiple Registers
  3. Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
  4. Click Send to send the write command

BACnet BIP:

python3 bacnet_write.py --ip 192.168.31.193 --port 47808 --id 102 --sensorType AN-307 alarm --value 1 --durationSeconds 60
Target: 192.168.31.193:47808 | BACnet ID: 102 | Sensor: AN-307
Expected values:
  alarmStatus: 1
  alarmDurationSeconds: 60
Expected confirmed state:
  alarmStatus: 1
Attempt 1/1: writing control values (default)...
YABE write guide:
  alarmStatus -> object binary-value,10204 | property present-value | type=binary-value | write=active
  alarmDurationSeconds -> object analog-value,10205 | property present-value | type=analog-value | write=60
Observed values:
  alarmStatus: 1
Link confirmation time: 0.010s
Control completed in: 0.044s
The script automatically writes and reads back for verification. The YABE write guide section in the output can be used directly as a YABE manual-write reference.

YABE:

  1. Connect to the gateway (IP 192.168.31.193, Port 47808), expand Device 102
  2. Refer to the YABE write guide in the script output above to locate the corresponding object
  3. Right-click the object → Write Property, set the property to present-value, enter the target value, then click Write

IoT Hub HTTP:

Endpoint: POST http://192.168.31.193:8070/api/sendCommand
curl -s -X POST "http://192.168.31.193:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff100004c88a","params":{"alarmStatus":true,"alarmDurationSeconds":60}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff100004c88a",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.193:8090/api/devices/ffffff100004c88a/queue

curl -s -X POST 'http://192.168.31.193:8090/api/devices/ffffff100004c88a/queue' \
  -H 'accept: application/json' \
  -H 'Grpc-Metadata-Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{"flushQueue":true,"queueItem":{"confirmed":false,"isPending":false,"object":{"model":"AN-307","alarmStatus":true,"alarmDurationSeconds":60}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "AN-307",
      "alarmStatus": true,
      "alarmDurationSeconds": 60
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.193 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff100004c88a/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff100004c88a","confirmed":false,"object":{"model":"AN-307","alarmStatus":true,"alarmDurationSeconds":60}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff100004c88a",
  "confirmed": false,
  "object": {
    "model": "AN-307",
    "alarmStatus": true,
    "alarmDurationSeconds": 60
  }
}

Example 2: Indefinite Alarm (no timer)
When no alarmDurationSeconds is provided, the alarm will remain active indefinitely until an explicit cancel (alarmStatus=false) command is sent.

Modbus TCP:

python3 modbus_tcp_write.py --ip 192.168.31.193 --port 502 --slaveId 3 --sensorType AN-307 alarm --value 1
Target: 192.168.31.193:502 | Slave ID: 3 | Sensor: AN-307
Expected values:
  alarmStatus: 1
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC06 Write Single Register | Start register: 9 (4x40010) | Count: 1
    alarmStatus -> register 9 (4x40010) raw=1 signed=1
Observed values:
  alarmStatus: 1
Link confirmation time: 1.138s
Control completed in: 1.149s
The script automatically writes registers and reads them back for verification. The Modbus Poll write guide section in the output can be used directly as a reference for manual writes in Modbus Poll.

Modbus Poll:

  1. Connect to the gateway (IP 192.168.31.193, Port 502, Slave ID 3)
  2. Menu Functions → 16 Write Multiple Registers
  3. Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
  4. Click Send to send the write command

BACnet BIP:

python3 bacnet_write.py --ip 192.168.31.193 --port 47808 --id 102 --sensorType AN-307 alarm --value 1
Target: 192.168.31.193:47808 | BACnet ID: 102 | Sensor: AN-307
Expected values:
  alarmStatus: 1
Attempt 1/1: writing control values (default)...
YABE write guide:
  alarmStatus -> object binary-value,10204 | property present-value | type=binary-value | write=active
Observed values:
  alarmStatus: 1
Link confirmation time: 0.010s
Control completed in: 0.044s
The script automatically writes and reads back for verification. The YABE write guide section in the output can be used directly as a YABE manual-write reference.

YABE:

  1. Connect to the gateway (IP 192.168.31.193, Port 47808), expand Device 102
  2. Refer to the YABE write guide in the script output above to locate the corresponding object
  3. Right-click the object → Write Property, set the property to present-value, enter the target value, then click Write

IoT Hub HTTP:

Endpoint: POST http://192.168.31.193:8070/api/sendCommand
curl -s -X POST "http://192.168.31.193:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff100004c88a","params":{"alarmStatus":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff100004c88a",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.193:8090/api/devices/ffffff100004c88a/queue

curl -s -X POST 'http://192.168.31.193:8090/api/devices/ffffff100004c88a/queue' \
  -H 'accept: application/json' \
  -H 'Grpc-Metadata-Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{"flushQueue":true,"queueItem":{"confirmed":false,"isPending":false,"object":{"model":"AN-307","alarmStatus":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "AN-307",
      "alarmStatus": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.193 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff100004c88a/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff100004c88a","confirmed":false,"object":{"model":"AN-307","alarmStatus":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff100004c88a",
  "confirmed": false,
  "object": {
    "model": "AN-307",
    "alarmStatus": true
  }
}

Example 3: Cancel Alarm

Modbus TCP:

python3 modbus_tcp_write.py --ip 192.168.31.193 --port 502 --slaveId 3 --sensorType AN-307 alarm --value 0
Target: 192.168.31.193:502 | Slave ID: 3 | Sensor: AN-307
Expected values:
  alarmStatus: 0
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC06 Write Single Register | Start register: 9 (4x40010) | Count: 1
    alarmStatus -> register 9 (4x40010) raw=0 signed=0
Observed values:
  alarmStatus: 0
Link confirmation time: 1.138s
Control completed in: 1.149s
The script automatically writes registers and reads them back for verification. The Modbus Poll write guide section in the output can be used directly as a reference for manual writes in Modbus Poll.

Modbus Poll:

  1. Connect to the gateway (IP 192.168.31.193, Port 502, Slave ID 3)
  2. Menu Functions → 16 Write Multiple Registers
  3. Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
  4. Click Send to send the write command

BACnet BIP:

python3 bacnet_write.py --ip 192.168.31.193 --port 47808 --id 102 --sensorType AN-307 alarm --value 0
Target: 192.168.31.193:47808 | BACnet ID: 102 | Sensor: AN-307
Expected values:
  alarmStatus: 0
Attempt 1/1: writing control values (default)...
YABE write guide:
  alarmStatus -> object binary-value,10204 | property present-value | type=binary-value | write=inactive
Observed values:
  alarmStatus: 0
Link confirmation time: 0.010s
Control completed in: 0.044s
The script automatically writes and reads back for verification. The YABE write guide section in the output can be used directly as a YABE manual-write reference.

YABE:

  1. Connect to the gateway (IP 192.168.31.193, Port 47808), expand Device 102
  2. Refer to the YABE write guide in the script output above to locate the corresponding object
  3. Right-click the object → Write Property, set the property to present-value, enter the target value, then click Write

IoT Hub HTTP:

Endpoint: POST http://192.168.31.193:8070/api/sendCommand
curl -s -X POST "http://192.168.31.193:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff100004c88a","params":{"alarmStatus":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff100004c88a",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.193:8090/api/devices/ffffff100004c88a/queue

curl -s -X POST 'http://192.168.31.193:8090/api/devices/ffffff100004c88a/queue' \
  -H 'accept: application/json' \
  -H 'Grpc-Metadata-Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{"flushQueue":true,"queueItem":{"confirmed":false,"isPending":false,"object":{"model":"AN-307","alarmStatus":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "AN-307",
      "alarmStatus": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.193 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff100004c88a/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff100004c88a","confirmed":false,"object":{"model":"AN-307","alarmStatus":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff100004c88a",
  "confirmed": false,
  "object": {
    "model": "AN-307",
    "alarmStatus": false
  }
}