7 IoT Hub Physical Model

The gateway features a built-in ChirpStack 4.17.0 LoRaWAN network server and IoT Hub physical model engine, offering five data access methods:

Protocol Port Direction Description
Modbus TCP 502 Read + Write Provided by IoT Hub; register mapping; suitable for industrial SCADA/PLC
BACnet BIP 47808 Read + Write Provided by IoT Hub; BACnet object mapping; suitable for building BMS
HTTP REST 8070 Read + Write Provided by IoT Hub; JSON format; suitable for Web/App integration
MQTT 1883 Subscribe + Publish (Read + Write) ChirpStack native; JSON event/command stream; suitable for real-time push and downlink control
ChirpStack REST API 8090 Read + Write + Manage ChirpStack native; device/application management, data query, and downlink command queue

Sections 7.1–7.25 use real sensors on two live gateways (192.168.31.205 and 192.168.31.193) to demonstrate Modbus TCP, BACnet BIP and HTTP read/write usage. Sections 7.26–7.27 cover ChirpStack native MQTT subscriptions/downlink control and the REST API (including downlink queue management). Section 7.28 provides a side-by-side comparison of all five data access methods.

Python Environment Setup (one-time, skip if already done)

All Python scripts in this chapter have been tested on Ubuntu 24.04 LTS. The scripts include a protocol layout signature (layout hash) that matches IoT Hub. Both dependency installation and script execution must use the same venv; otherwise a layout hash mismatch error will occur. Follow these steps:

Step 1: Verify Python 3 is installed

``bash
guo@ubuntu:~$ python3 --version
Python 3.12.3
`

If you see
command not found, first install Python 3:

`bash
sudo apt update
sudo apt install -y python3
`

**Step 2: Install the venv module**

Ubuntu 24.04 does **not** include
venv by default; install it separately:

`bash
sudo apt install -y python3-venv
`

**Step 3: Create the virtual environment**

Create a venv named
.venv in your working directory:

`bash
guo@ubuntu:~$ python3 -m venv .venv
`

**Step 4: Activate the virtual environment**

`bash
guo@ubuntu:~$ source .venv/bin/activate
(.venv) guo@ubuntu:~$
`

After successful activation, the
(.venv) prefix will appear in the command prompt.

**Step 5: Install dependencies inside the venv**

`bash
(.venv) guo@ubuntu:~$ pip3 install pymodbus==3.12.1
(.venv) guo@ubuntu:~$ pip3 install bacpypes3==0.0.106
`

**Step 6: Place the scripts in your working directory**

Download the following 4 scripts to the current directory(
~):

- [modbus_tcp_read.py](download/modbus_tcp_read.py) — Modbus TCP Read
- [modbus_tcp_write.py](download/modbus_tcp_write.py) — Modbus TCP Write
- [bacnet_read.py](download/bacnet_read.py) — BACnet BIP Read
- [bacnet_write.py](download/bacnet_write.py) — BACnet BIP Write

The environment is now ready. **These steps only need to be done once.** For subsequent uses, just activate the venv:

`bash
guo@ubuntu:~$ source .venv/bin/activate
(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --help
``

Test tool downloads:Modbus Poll 9.5.0.1507.zip · SetupYabe_v2.1.0.exe

7.1 Getting Data from the AN-301 Emergency Button

AN-301 is a LoRaWAN SOS emergency button that supports battery voltage monitoring, tamper detection, and emergency alarm. Pressing the button triggers an SOS event. Suitable for elder care and construction-site safety applications requiring emergency calls.

deviceinformation:devEui=ffffff100004bccc,Modbus Slave ID=6,BACnet Device ID=110,gateway IP=192.168.31.205

7.1.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 6(可configuration,range 2–201)。

7.1.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 6 --sensorType AN-301
Target: 192.168.31.205:502 | Slave ID: 6 | Sensor: AN-301
================================================================================================================================================================
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       | 69CB 75D6           | 1774941654         | second
batteryVoltage           | 9      | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0166                | 3.58               | volt
tamperStatus             | 10     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
tamperEvent              | 11     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
sosEvent                 | 12     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
sosEventTime             | 13     | 03  | UnixTime   | Big(ABCD)    | 2   | x1       | 0000 0000           | 0                  | second
mainVersion              | 15     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 23     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 31     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 39     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D33 3031 0000 ... | AN-301             | none
rssi                     | 51     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFD9                | -39.0              | none
snr                      | 52     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0003                | 3.0                | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774941654 second
batteryVoltage 9 Int16(S) 1 /100 3.58 volt
tamperStatus 10 Bit/Bool 1 x1 false none
tamperEvent 11 Int16 1 x1 0.0 none
sosEvent 12 Bit/Bool 1 x1 false none
sosEventTime 13 UnixTime 2 x1 0 second
model 39 String(24B) 12 x1 AN-301 none
rssi 51 Int16 1 x1 -39.0 none
snr 52 Int16 1 x1 3.0 none
7.1.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 6, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 47 (covers addresses 6–52), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.1.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.AN-301 Emergency Button Device ID=110, so object instances start from 11000.

7.1.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 110
Target: 192.168.31.205:47808 | BACnet ID: 110 | Scan: 11000-11099
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 11000    | 0      | 4D5A3204                 | ffffff100004bccc.protocolLayoutHash
CV   | 11001    | 1      | 20260101                 | ffffff100004bccc.profileVersion
BI   | 11002    | 2      | active                   | ffffff100004bccc.online
AI   | 11003    | 3      | 1774912896.00            | ffffff100004bccc.lastOnlineTime
AI   | 11004    | 4      | 3.58                     | ffffff100004bccc.batteryVoltage
BI   | 11005    | 5      | inactive                 | ffffff100004bccc.tamperStatus
AI   | 11006    | 6      | 0.00                     | ffffff100004bccc.tamperEvent
BI   | 11007    | 7      | inactive                 | ffffff100004bccc.sosEvent
AI   | 11008    | 8      | 0.00                     | ffffff100004bccc.sosEventTime
CV   | 11009    | 9      |                          | ffffff100004bccc.mainVersion
CV   | 11010    | 10     |                          | ffffff100004bccc.appVersion
CV   | 11011    | 11     |                          | ffffff100004bccc.hardwareVersion
CV   | 11012    | 12     | AN-301                   | ffffff100004bccc.model
AI   | 11013    | 13     | -39.00                   | ffffff100004bccc.rssi
AI   | 11014    | 14     | 3.00                     | ffffff100004bccc.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 11002 online active
AI 11003 lastOnlineTime 1774912896.00
AI 11004 batteryVoltage 3.58
BI 11005 tamperStatus inactive
AI 11006 tamperEvent 0.00
BI 11007 sosEvent inactive
AI 11008 sosEventTime 0.00
CV 11012 model AN-301
AI 11013 rssi -39.00
AI 11014 snr 3.00
7.1.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 110 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-11004); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.1.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff100004bccc" | jq .
{
  "devEui": "ffffff100004bccc",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 15:20:54",
  "params": {
    "batteryVoltage": 3.58,
    "tamperStatus": false,
    "sosEvent": false,
    "model": "AN-301"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -39,
    "snr": 3,
    "frequency": 481500000,
    "spreadingFactor": 9,
    "bandwidth": 125000,
    "fCnt": 376,
    "fPort": 210,
    "confirmed": false,
    "size": 10,
    "rawData": "5C780000000000000000"
  }
}
Note: devEui=ffffff100004bccc is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.2 Retrieving Data from the AN-303 Temperature & Humidity Sensor

AN-303 is a LoRaWAN temperature & humidity sensor that reports ambient temperature, humidity, and battery voltage in real time. Suitable for server rooms, warehouses, offices, and similar environmental monitoring applications.

deviceinformation:devEui=ffffff200000b703,Modbus Slave ID=9,BACnet Device ID=108,gateway IP=192.168.31.205

7.2.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 9(可configuration,range 2–201)。

7.2.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 9 --sensorType AN-303
Target: 192.168.31.205:502 | Slave ID: 9 | Sensor: AN-303
================================================================================================================================================================
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       | 69CB 41E8           | 1774928360         | second
temperature              | 9      | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0A0A                | 25.7               | celsius
temperatureState         | 10     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
humidity                 | 11     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 1676                | 57.5               | percent
humidityState            | 12     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
batteryVoltage           | 13     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0169                | 3.61               | volt
batteryVoltageState      | 14     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
tamper                   | 15     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
mainVersion              | 16     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 24     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 32     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 40     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D33 3033 0000 ... | AN-303             | none
rssi                     | 52     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFC0                | -64.0              | none
snr                      | 53     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000D                | 13.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774928360 second
temperature 9 Int16(S) 1 /100 25.7 celsius
temperatureState 10 Int16 1 x1 0.0 none
humidity 11 Int16(S) 1 /100 57.5 percent
humidityState 12 Int16 1 x1 0.0 none
batteryVoltage 13 Int16(S) 1 /100 3.61 volt
batteryVoltageState 14 Int16 1 x1 0.0 none
tamper 15 Int16 1 x1 1.0 none
model 40 String(24B) 12 x1 AN-303 none
rssi 52 Int16 1 x1 -64.0 none
snr 53 Int16 1 x1 13.0 none
7.2.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 9, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 48 (covers addresses 6–53), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.2.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.AN-303 Temperature & Humidity Sensor Device ID=108, so object instances start from 10800.

7.2.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 108
Target: 192.168.31.205:47808 | BACnet ID: 108 | Scan: 10800-10899
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 10800    | 0      | 1966B122                 | ffffff200000b703.protocolLayoutHash
CV   | 10801    | 1      | 20260101                 | ffffff200000b703.profileVersion
BI   | 10802    | 2      | active                   | ffffff200000b703.online
AI   | 10803    | 3      | 1774928384.00            | ffffff200000b703.lastOnlineTime
AI   | 10804    | 4      | 25.70                    | ffffff200000b703.temperature
AI   | 10805    | 5      | 0.00                     | ffffff200000b703.temperatureState
AI   | 10806    | 6      | 57.50                    | ffffff200000b703.humidity
AI   | 10807    | 7      | 0.00                     | ffffff200000b703.humidityState
AI   | 10808    | 8      | 3.61                     | ffffff200000b703.batteryVoltage
AI   | 10809    | 9      | 0.00                     | ffffff200000b703.batteryVoltageState
AI   | 10810    | 10     | 1.00                     | ffffff200000b703.tamper
CV   | 10811    | 11     |                          | ffffff200000b703.mainVersion
CV   | 10812    | 12     |                          | ffffff200000b703.appVersion
CV   | 10813    | 13     |                          | ffffff200000b703.hardwareVersion
CV   | 10814    | 14     | AN-303                   | ffffff200000b703.model
AI   | 10815    | 15     | -64.00                   | ffffff200000b703.rssi
AI   | 10816    | 16     | 13.00                    | ffffff200000b703.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 10802 online active
AI 10803 lastOnlineTime 1774928384.00
AI 10804 temperature 25.70
AI 10805 temperatureState 0.00
AI 10806 humidity 57.50
AI 10807 humidityState 0.00
AI 10808 batteryVoltage 3.61
AI 10809 batteryVoltageState 0.00
AI 10810 tamper 1.00
CV 10814 model AN-303
AI 10815 rssi -64.00
AI 10816 snr 13.00
7.2.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 108 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10804); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.2.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff200000b703" | jq .
{
  "devEui": "ffffff200000b703",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 11:39:26",
  "params": {
    "temperature": 25.7,
    "humidity": 57.5,
    "batteryVoltage": 3.61,
    "batteryVoltageState": 0,
    "tamper": 1,
    "model": "AN-303"
  },
  "rxParams": {
    "gatewayId": "0010502df4563610",
    "rssi": -64,
    "snr": 12,
    "frequency": 482700000,
    "spreadingFactor": 7,
    "bandwidth": 125000,
    "fCnt": 120832,
    "fPort": 210,
    "confirmed": true,
    "size": 18,
    "rawData": "000103040E157D007701100A0812023F0301"
  }
}
Note: devEui=ffffff200000b703 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.3 Retrieving Data from the AN-304 PIR Detector

AN-304 is a LoRaWAN passive infrared (PIR) detector that triggers an alarm when human infrared signals are detected. Suitable for intrusion alarm and security monitoring applications.

deviceinformation:devEui=ffffff100004bcc0,Modbus Slave ID=4,BACnet Device ID=103,gateway IP=192.168.31.205

7.3.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 4(可configuration,range 2–201)。

7.3.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 4 --sensorType AN-304
Target: 192.168.31.205:502 | Slave ID: 4 | Sensor: AN-304
================================================================================================================================================================
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       | 69CB AB1E           | 1774955294         | second
batteryVoltage           | 9      | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0166                | 3.58               | volt
batteryVoltageState      | 10     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
tamper                   | 11     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
tamperEvent              | 12     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
infraredEvent            | 13     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
mainVersion              | 14     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 22     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 30     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 38     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D33 3034 0000 ... | AN-304             | none
rssi                     | 50     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFD8                | -40.0              | none
snr                      | 51     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0007                | 7.0                | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774955294 second
batteryVoltage 9 Int16(S) 1 /100 3.58 volt
batteryVoltageState 10 Int16 1 x1 0.0 none
tamper 11 Int16 1 x1 1.0 none
tamperEvent 12 Int16 1 x1 1.0 none
infraredEvent 13 Int16 1 x1 1.0 none
model 38 String(24B) 12 x1 AN-304 none
rssi 50 Int16 1 x1 -40.0 none
snr 51 Int16 1 x1 7.0 none
7.3.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 4, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 46 (covers addresses 6–51), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.3.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset. The AN-304 PIR detector has Device ID=103, so object instances start from 10300.

7.3.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 103
Target: 192.168.31.205:47808 | BACnet ID: 103 | Scan: 10300-10399
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 10300    | 0      | 5F9D533A                 | ffffff100004bcc0.protocolLayoutHash
CV   | 10301    | 1      | 20260101                 | ffffff100004bcc0.profileVersion
BI   | 10302    | 2      | active                   | ffffff100004bcc0.online
AI   | 10303    | 3      | 1774926464.00            | ffffff100004bcc0.lastOnlineTime
AI   | 10304    | 4      | 3.58                     | ffffff100004bcc0.batteryVoltage
AI   | 10305    | 5      | 0.00                     | ffffff100004bcc0.batteryVoltageState
AI   | 10306    | 6      | 1.00                     | ffffff100004bcc0.tamper
AI   | 10307    | 7      | 1.00                     | ffffff100004bcc0.tamperEvent
AI   | 10308    | 8      | 1.00                     | ffffff100004bcc0.infraredEvent
CV   | 10309    | 9      |                          | ffffff100004bcc0.mainVersion
CV   | 10310    | 10     |                          | ffffff100004bcc0.appVersion
CV   | 10311    | 11     |                          | ffffff100004bcc0.hardwareVersion
CV   | 10312    | 12     | AN-304                   | ffffff100004bcc0.model
AI   | 10313    | 13     | -40.00                   | ffffff100004bcc0.rssi
AI   | 10314    | 14     | 7.00                     | ffffff100004bcc0.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 10302 online active
AI 10303 lastOnlineTime 1774926464.00
AI 10304 batteryVoltage 3.58
AI 10305 batteryVoltageState 0.00
AI 10306 tamper 1.00
AI 10307 tamperEvent 1.00
AI 10308 infraredEvent 1.00
CV 10312 model AN-304
AI 10313 rssi -40.00
AI 10314 snr 7.00
7.3.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 103 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10304); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.3.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff100004bcc0" | jq .
{
  "devEui": "ffffff100004bcc0",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 19:08:14",
  "params": {
    "batteryVoltage": 3.58,
    "batteryVoltageState": 0,
    "tamper": 1,
    "tamperEvent": 1,
    "infraredEvent": 1,
    "model": "AN-304"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -40,
    "snr": 7,
    "frequency": 482100000,
    "spreadingFactor": 8,
    "bandwidth": 125000,
    "fCnt": 4939,
    "fPort": 210,
    "confirmed": false,
    "size": 12,
    "rawData": "5C7800000000000000000000"
  }
}
Note: devEui=ffffff100004bcc0 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.4 Retrieving Data from the JTY-AN-503A Smoke Detector

JTY-AN-503A is a LoRaWAN photoelectric smoke detector that measures smoke concentration and triggers fire alarms, with a built-in self-test function. Suitable for fire early-warning applications.

deviceinformation:devEui=ffffff100004e970,Modbus Slave ID=5,BACnet Device ID=104,gateway IP=192.168.31.205

7.4.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 5(可configuration,range 2–201)。

7.4.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 5 --sensorType JTY-AN-503A
Target: 192.168.31.205:502 | Slave ID: 5 | Sensor: JTY-AN-503A
================================================================================================================================================================
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       | 69CB AD3F           | 1774955839         | second
temperature              | 9      | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0000                | 0.0                | celsius
batteryVoltage           | 10     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0135                | 3.09               | volt
batteryVoltageState      | 11     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
tamper                   | 12     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
tamperEvent              | 13     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
smokeEvent               | 14     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
smokeStatus              | 15     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
selfCheckEvent           | 16     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
mainVersion              | 17     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 25     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 33     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 41     | 03  | String(24B) | ASCII        | 12  | x1       | 4A54 592D 414E 2D35 ... | JTY-AN-503A        | none
rssi                     | 53     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFC6                | -58.0              | none
snr                      | 54     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000C                | 12.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774955839 second
temperature 9 Int16(S) 1 /100 0.0 celsius
batteryVoltage 10 Int16(S) 1 /100 3.09 volt
batteryVoltageState 11 Int16 1 x1 0.0 none
tamper 12 Int16 1 x1 1.0 none
tamperEvent 13 Int16 1 x1 0.0 none
smokeEvent 14 Int16 1 x1 0.0 none
smokeStatus 15 Int16 1 x1 0.0 none
selfCheckEvent 16 Int16 1 x1 0.0 none
model 41 String(24B) 12 x1 JTY-AN-503A none
rssi 53 Int16 1 x1 -58.0 none
snr 54 Int16 1 x1 12.0 none
7.4.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 5, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 49 (covers addresses 6–54), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.4.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.JTY-AN-503A Smoke Detector Device ID=104, so object instances start from 10400.

7.4.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 104
Target: 192.168.31.205:47808 | BACnet ID: 104 | Scan: 10400-10499
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 10400    | 0      | 29EC5993                 | ffffff100004e970.protocolLayoutHash
CV   | 10401    | 1      | 20260101                 | ffffff100004e970.profileVersion
BI   | 10402    | 2      | active                   | ffffff100004e970.online
AI   | 10403    | 3      | 1774926976.00            | ffffff100004e970.lastOnlineTime
AI   | 10404    | 4      | 0.00                     | ffffff100004e970.temperature
AI   | 10405    | 5      | 3.09                     | ffffff100004e970.batteryVoltage
AI   | 10406    | 6      | 0.00                     | ffffff100004e970.batteryVoltageState
AI   | 10407    | 7      | 1.00                     | ffffff100004e970.tamper
AI   | 10408    | 8      | 0.00                     | ffffff100004e970.tamperEvent
AI   | 10409    | 9      | 0.00                     | ffffff100004e970.smokeEvent
AI   | 10410    | 10     | 0.00                     | ffffff100004e970.smokeStatus
AI   | 10411    | 11     | 0.00                     | ffffff100004e970.selfCheckEvent
CV   | 10412    | 12     |                          | ffffff100004e970.mainVersion
CV   | 10413    | 13     |                          | ffffff100004e970.appVersion
CV   | 10414    | 14     |                          | ffffff100004e970.hardwareVersion
CV   | 10415    | 15     | JTY-AN-503A              | ffffff100004e970.model
AI   | 10416    | 16     | -58.00                   | ffffff100004e970.rssi
AI   | 10417    | 17     | 12.00                    | ffffff100004e970.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 10402 online active
AI 10403 lastOnlineTime 1774926976.00
AI 10404 temperature 0.00
AI 10405 batteryVoltage 3.09
AI 10406 batteryVoltageState 0.00
AI 10407 tamper 1.00
AI 10408 tamperEvent 0.00
AI 10409 smokeEvent 0.00
AI 10410 smokeStatus 0.00
AI 10411 selfCheckEvent 0.00
CV 10415 model JTY-AN-503A
AI 10416 rssi -58.00
AI 10417 snr 12.00
7.4.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 104 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10404); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.4.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff100004e970" | jq .
{
  "devEui": "ffffff100004e970",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 19:17:19",
  "params": {
    "batteryVoltage": 3.09,
    "batteryVoltageState": 0,
    "tamper": 1,
    "tamperEvent": 0,
    "smokeStatus": 0,
    "selfCheckEvent": 0,
    "model": "JTY-AN-503A"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -58,
    "snr": 12,
    "frequency": 482900000,
    "spreadingFactor": 10,
    "bandwidth": 125000,
    "fCnt": 118,
    "fPort": 210,
    "confirmed": false,
    "size": 12,
    "rawData": "5C7800000000000000000000"
  }
}
Note: devEui=ffffff100004e970 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.5 Retrieving Data from the W8004 Thermostat

W8004 is a LoRaWAN air-conditioner thermostat panel that supports remote control of temperature, fan speed, operating mode, and on/off state. Suitable for smart-building and hotel-room HVAC automation.

deviceinformation:devEui=ffffff1000047040,Modbus Slave ID=2,BACnet Device ID=101,gateway IP=192.168.31.205

The W8004 thermostat also supports control commands; see 7.6 Sending Control Commands to the W8004 Thermostat.

7.5.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 2(可configuration,range 2–201)。

7.5.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 2 --sensorType W8004
Target: 192.168.31.205:502 | Slave ID: 2 | Sensor: W8004
================================================================================================================================================================
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       | 69CB B162           | 1774956898         | second
powerState               | 9      | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
setTemperature           | 10     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 09C4                | 25.0               | celsius
workMode                 | 11     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
fanSpeed                 | 12     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0003                | 3.0                | none
temperature              | 13     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0B72                | 29.3               | celsius
humidity                 | 14     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0000                | 0.0                | percent
keyLockState             | 15     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
valveState               | 16     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
signalStrength           | 17     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
cumulativeOnTime         | 18     | 03  | Int16      | Big(ABCD)    | 1   | /10      | 0000                | 0.0                | minute
cumulativeValveOpenTime  | 19     | 03  | Int16      | Big(ABCD)    | 1   | /10      | 0000                | 0.0                | minute
mainVersion              | 20     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 28     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 36     | 03  | String(16B) | ASCII        | 8   | x1       | 3000 0000 0000 0000 ... | 0                  | none
model                    | 44     | 03  | String(24B) | ASCII        | 12  | x1       | 5738 3030 3400 0000 ... | W8004              | none
rssi                     | 56     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFC1                | -63.0              | none
snr                      | 57     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000D                | 13.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774956898 second
powerState 9 Bit/Bool 1 x1 true none
setTemperature 10 Int16(S) 1 /100 25.0 celsius
workMode 11 Int16 1 x1 1.0 none
fanSpeed 12 Int16 1 x1 3.0 none
temperature 13 Int16(S) 1 /100 29.3 celsius
humidity 14 Int16(S) 1 /100 0.0 percent
keyLockState 15 Int16 1 x1 0.0 none
valveState 16 Int16 1 x1 0.0 none
signalStrength 17 Int16 1 x1 0.0 none
cumulativeOnTime 18 Int16 1 /10 0.0 minute
cumulativeValveOpenTime 19 Int16 1 /10 0.0 minute
model 44 String(24B) 12 x1 W8004 none
rssi 56 Int16 1 x1 -63.0 none
snr 57 Int16 1 x1 13.0 none
7.5.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 2, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 52 (covers addresses 6–57), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.5.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset. The W8004 thermostat has Device ID=101, so object instances start from 10100.

7.5.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 101
Target: 192.168.31.205:47808 | BACnet ID: 101 | Scan: 10100-10199
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 10100    | 0      | FC63B2D7                 | ffffff1000047040.protocolLayoutHash
CV   | 10101    | 1      | 20260101                 | ffffff1000047040.profileVersion
BI   | 10102    | 2      | active                   | ffffff1000047040.online
AI   | 10103    | 3      | 1774928128.00            | ffffff1000047040.lastOnlineTime
BV   | 10104    | 4      | active                   | ffffff1000047040.powerState
AV   | 10105    | 5      | 25.00                    | ffffff1000047040.setTemperature
AV   | 10106    | 6      | 1.00                     | ffffff1000047040.workMode
AV   | 10107    | 7      | 3.00                     | ffffff1000047040.fanSpeed
AI   | 10108    | 8      | 29.30                    | ffffff1000047040.temperature
AI   | 10109    | 9      | 0.00                     | ffffff1000047040.humidity
BV   | 10110    | 10     | inactive                 | ffffff1000047040.keyLockState
BI   | 10111    | 11     | inactive                 | ffffff1000047040.valveState
AI   | 10112    | 12     | 0.00                     | ffffff1000047040.signalStrength
AI   | 10113    | 13     | 0.00                     | ffffff1000047040.cumulativeOnTime
AI   | 10114    | 14     | 0.00                     | ffffff1000047040.cumulativeValveOpenTime
CV   | 10115    | 15     |                          | ffffff1000047040.mainVersion
CV   | 10116    | 16     |                          | ffffff1000047040.appVersion
CV   | 10117    | 17     | 0                        | ffffff1000047040.hardwareVersion
CV   | 10118    | 18     | W8004                    | ffffff1000047040.model
AI   | 10119    | 19     | -63.00                   | ffffff1000047040.rssi
AI   | 10120    | 20     | 13.00                    | ffffff1000047040.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 10102 online active
AI 10103 lastOnlineTime 1774928128.00
BV 10104 powerState active
AV 10105 setTemperature 25.00
AV 10106 workMode 1.00
AV 10107 fanSpeed 3.00
AI 10108 temperature 29.30
AI 10109 humidity 0.00
BV 10110 keyLockState inactive
BI 10111 valveState inactive
AI 10112 signalStrength 0.00
AI 10113 cumulativeOnTime 0.00
AI 10114 cumulativeValveOpenTime 0.00
CV 10118 model W8004
AI 10119 rssi -63.00
AI 10120 snr 13.00
7.5.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 101 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10104); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.5.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff1000047040" | jq .
{
  "devEui": "ffffff1000047040",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 19:34:58",
  "params": {
    "powerState": true,
    "setTemperature": 25,
    "workMode": 1,
    "fanSpeed": 3,
    "temperature": 29.3,
    "humidity": 0,
    "keyLockState": 0,
    "valveState": 0,
    "hardwareVersion": "0",
    "model": "W8004"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -63,
    "snr": 13,
    "frequency": 482300000,
    "spreadingFactor": 7,
    "bandwidth": 125000,
    "fCnt": 7368,
    "fPort": 210,
    "confirmed": false,
    "size": 23,
    "rawData": "5C78000000000000000000000000000000000000000000"
  }
}
Note: devEui=ffffff1000047040 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.6 Controlling the W8004 Thermostat via Downlink

The W8004 is a LoRaWAN thermostat for fan-coil control. The eight examples below cover power control, individual climate settings, combined settings, and touch-panel lock.

Device information: devEui=ffffff1000047040, Modbus Slave ID=2, BACnet Device ID=101, gateway IP=192.168.31.205

Example 1: Power ON

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 2 --sensorType W8004 power --value 1
Target: 192.168.31.205:502 | Slave ID: 2 | Sensor: W8004
Expected values:
  powerState: 1
Expected confirmed state:
  powerState: true
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 1
    powerState -> register 9 (4x40010) raw=1 signed=1
Observed values:
  powerState: true
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 2)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 101 --sensorType W8004 power --value 1
Target: 192.168.31.205:47808 | BACnet ID: 101 | Sensor: W8004
Expected values:
  powerState: 1
Expected confirmed state:
  powerState: true
Attempt 1/1: writing control values (default)...
YABE write guide:
  powerState -> object binary-value,10104 | property present-value | type=binary-value | write=active
Observed values:
  powerState: true
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 101
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000047040","params":{"powerState":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000047040",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000047040/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000047040/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":"W8004","powerState":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "W8004",
      "powerState": true
    }
  }
}

ChirpStack MQTT:

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

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000047040",
  "confirmed": false,
  "object": {
    "model": "W8004",
    "powerState": true
  }
}

Example 2: Power OFF

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 2 --sensorType W8004 power --value 0
Target: 192.168.31.205:502 | Slave ID: 2 | Sensor: W8004
Expected values:
  powerState: 0
Expected confirmed state:
  powerState: false
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 1
    powerState -> register 9 (4x40010) raw=0 signed=0
Observed values:
  powerState: false
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 2)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 101 --sensorType W8004 power --value 0
Target: 192.168.31.205:47808 | BACnet ID: 101 | Sensor: W8004
Expected values:
  powerState: 0
Expected confirmed state:
  powerState: false
Attempt 1/1: writing control values (default)...
YABE write guide:
  powerState -> object binary-value,10104 | property present-value | type=binary-value | write=inactive
Observed values:
  powerState: false
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 101
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000047040","params":{"powerState":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000047040",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000047040/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000047040/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":"W8004","powerState":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "W8004",
      "powerState": false
    }
  }
}

ChirpStack MQTT:

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

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000047040",
  "confirmed": false,
  "object": {
    "model": "W8004",
    "powerState": false
  }
}

Example 3: Set Target Temperature Only (26 °C)
The climate command writes setTemperature, workMode, and fanSpeed simultaneously. Unspecified parameters use their defaults (setTemperature=23.0 °C, workMode=1, fanSpeed=1). To change only one attribute without affecting the others, use the IoT Hub HTTP or ChirpStack methods below, which accept individual fields.

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 2 --sensorType W8004 climate --setTemperature 26 --workMode 1 --fanSpeed 1
Target: 192.168.31.205:502 | Slave ID: 2 | Sensor: W8004
Expected values:
  setTemperature: 26.0
  workMode: 1
  fanSpeed: 1
Expected confirmed state:
  setTemperature: 26.0
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 10 (4x40011) | Count: 3
    setTemperature -> register 10 (4x40011) raw=2600 signed=2600
    workMode -> register 11 (4x40012) raw=1 signed=1
    fanSpeed -> register 12 (4x40013) raw=1 signed=1
Observed values:
  setTemperature: 26.0
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 2)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 101 --sensorType W8004 climate --setTemperature 26 --workMode 1 --fanSpeed 1
Target: 192.168.31.205:47808 | BACnet ID: 101 | Sensor: W8004
Expected values:
  setTemperature: 26.0
  workMode: 1
  fanSpeed: 1
Expected confirmed state:
  setTemperature: 26.0
Attempt 1/1: writing control values (default)...
YABE write guide:
  setTemperature -> object analog-value,10105 | property present-value | type=analog-value | write=26.0
  workMode -> object analog-value,10106 | property present-value | type=analog-value | write=1
  fanSpeed -> object analog-value,10107 | property present-value | type=analog-value | write=1
Observed values:
  setTemperature: 26.0
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 101
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000047040","params":{"setTemperature":26}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000047040",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000047040/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000047040/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":"W8004","setTemperature":26}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "W8004",
      "setTemperature": 26
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000047040/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000047040","confirmed":false,"object":{"model":"W8004","setTemperature":26}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000047040",
  "confirmed": false,
  "object": {
    "model": "W8004",
    "setTemperature": 26
  }
}

Example 4: Set Work Mode Only (Cooling=1)
workMode values: 0=Auto, 1=Cooling, 2=Heating, 3=Ventilation/Fan-only. Via Python script, setTemperature and fanSpeed are also written using defaults.

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 2 --sensorType W8004 climate --setTemperature 23 --workMode 1 --fanSpeed 1
Target: 192.168.31.205:502 | Slave ID: 2 | Sensor: W8004
Expected values:
  setTemperature: 23.0
  workMode: 1
  fanSpeed: 1
Expected confirmed state:
  workMode: 1.0
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 10 (4x40011) | Count: 3
    setTemperature -> register 10 (4x40011) raw=2300 signed=2300
    workMode -> register 11 (4x40012) raw=1 signed=1
    fanSpeed -> register 12 (4x40013) raw=1 signed=1
Observed values:
  workMode: 1.0
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 2)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 101 --sensorType W8004 climate --setTemperature 23 --workMode 1 --fanSpeed 1
Target: 192.168.31.205:47808 | BACnet ID: 101 | Sensor: W8004
Expected values:
  setTemperature: 23.0
  workMode: 1
  fanSpeed: 1
Expected confirmed state:
  workMode: 1.0
Attempt 1/1: writing control values (default)...
YABE write guide:
  setTemperature -> object analog-value,10105 | property present-value | type=analog-value | write=23.0
  workMode -> object analog-value,10106 | property present-value | type=analog-value | write=1
  fanSpeed -> object analog-value,10107 | property present-value | type=analog-value | write=1
Observed values:
  workMode: 1.0
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 101
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000047040","params":{"workMode":1}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000047040",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000047040/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000047040/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":"W8004","workMode":1}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "W8004",
      "workMode": 1
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000047040/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000047040","confirmed":false,"object":{"model":"W8004","workMode":1}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000047040",
  "confirmed": false,
  "object": {
    "model": "W8004",
    "workMode": 1
  }
}

Example 5: Set Fan Speed Only (Medium=2)
fanSpeed values: 0=Auto, 1=Low, 2=Medium, 3=High, 4=Turbo.

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 2 --sensorType W8004 climate --setTemperature 23 --workMode 1 --fanSpeed 2
Target: 192.168.31.205:502 | Slave ID: 2 | Sensor: W8004
Expected values:
  setTemperature: 23.0
  workMode: 1
  fanSpeed: 2
Expected confirmed state:
  fanSpeed: 2.0
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 10 (4x40011) | Count: 3
    setTemperature -> register 10 (4x40011) raw=2300 signed=2300
    workMode -> register 11 (4x40012) raw=1 signed=1
    fanSpeed -> register 12 (4x40013) raw=2 signed=2
Observed values:
  fanSpeed: 2.0
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 2)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 101 --sensorType W8004 climate --setTemperature 23 --workMode 1 --fanSpeed 2
Target: 192.168.31.205:47808 | BACnet ID: 101 | Sensor: W8004
Expected values:
  setTemperature: 23.0
  workMode: 1
  fanSpeed: 2
Expected confirmed state:
  fanSpeed: 2.0
Attempt 1/1: writing control values (default)...
YABE write guide:
  setTemperature -> object analog-value,10105 | property present-value | type=analog-value | write=23.0
  workMode -> object analog-value,10106 | property present-value | type=analog-value | write=1
  fanSpeed -> object analog-value,10107 | property present-value | type=analog-value | write=2
Observed values:
  fanSpeed: 2.0
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 101
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000047040","params":{"fanSpeed":2}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000047040",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000047040/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000047040/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":"W8004","fanSpeed":2}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "W8004",
      "fanSpeed": 2
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000047040/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000047040","confirmed":false,"object":{"model":"W8004","fanSpeed":2}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000047040",
  "confirmed": false,
  "object": {
    "model": "W8004",
    "fanSpeed": 2
  }
}

Example 6: Set Temperature + Work Mode + Fan Speed Together (26 °C, Cooling, Medium)

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 2 --sensorType W8004 climate --setTemperature 26 --workMode 1 --fanSpeed 2
Target: 192.168.31.205:502 | Slave ID: 2 | Sensor: W8004
Expected values:
  setTemperature: 26.0
  workMode: 1
  fanSpeed: 2
Expected confirmed state:
  setTemperature: 26.0
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 10 (4x40011) | Count: 3
    setTemperature -> register 10 (4x40011) raw=2600 signed=2600
    workMode -> register 11 (4x40012) raw=1 signed=1
    fanSpeed -> register 12 (4x40013) raw=2 signed=2
Observed values:
  setTemperature: 26.0
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 2)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 101 --sensorType W8004 climate --setTemperature 26 --workMode 1 --fanSpeed 2
Target: 192.168.31.205:47808 | BACnet ID: 101 | Sensor: W8004
Expected values:
  setTemperature: 26.0
  workMode: 1
  fanSpeed: 2
Expected confirmed state:
  setTemperature: 26.0
Attempt 1/1: writing control values (default)...
YABE write guide:
  setTemperature -> object analog-value,10105 | property present-value | type=analog-value | write=26.0
  workMode -> object analog-value,10106 | property present-value | type=analog-value | write=1
  fanSpeed -> object analog-value,10107 | property present-value | type=analog-value | write=2
Observed values:
  setTemperature: 26.0
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 101
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000047040","params":{"setTemperature":26,"workMode":1,"fanSpeed":2}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000047040",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000047040/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000047040/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":"W8004","setTemperature":26,"workMode":1,"fanSpeed":2}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "W8004",
      "setTemperature": 26,
      "workMode": 1,
      "fanSpeed": 2
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000047040/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000047040","confirmed":false,"object":{"model":"W8004","setTemperature":26,"workMode":1,"fanSpeed":2}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000047040",
  "confirmed": false,
  "object": {
    "model": "W8004",
    "setTemperature": 26,
    "workMode": 1,
    "fanSpeed": 2
  }
}

Example 7: Lock Touch Panel (keyLockState ON)

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 2 --sensorType W8004 lock --value 1
Target: 192.168.31.205:502 | Slave ID: 2 | Sensor: W8004
Expected values:
  keyLockState: 1
Expected confirmed state:
  keyLockState: true
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 15 (4x40016) | Count: 1
    keyLockState -> register 15 (4x40016) raw=1 signed=1
Observed values:
  keyLockState: true
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 2)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 101 --sensorType W8004 lock --value 1
Target: 192.168.31.205:47808 | BACnet ID: 101 | Sensor: W8004
Expected values:
  keyLockState: 1
Expected confirmed state:
  keyLockState: true
Attempt 1/1: writing control values (default)...
YABE write guide:
  keyLockState -> object binary-value,10110 | property present-value | type=binary-value | write=active
Observed values:
  keyLockState: true
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 101
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000047040","params":{"keyLockState":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000047040",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000047040/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000047040/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":"W8004","keyLockState":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "W8004",
      "keyLockState": true
    }
  }
}

ChirpStack MQTT:

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

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000047040",
  "confirmed": false,
  "object": {
    "model": "W8004",
    "keyLockState": true
  }
}

Example 8: Unlock Touch Panel (keyLockState OFF)

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 2 --sensorType W8004 lock --value 0
Target: 192.168.31.205:502 | Slave ID: 2 | Sensor: W8004
Expected values:
  keyLockState: 0
Expected confirmed state:
  keyLockState: false
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 15 (4x40016) | Count: 1
    keyLockState -> register 15 (4x40016) raw=0 signed=0
Observed values:
  keyLockState: false
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 2)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 101 --sensorType W8004 lock --value 0
Target: 192.168.31.205:47808 | BACnet ID: 101 | Sensor: W8004
Expected values:
  keyLockState: 0
Expected confirmed state:
  keyLockState: false
Attempt 1/1: writing control values (default)...
YABE write guide:
  keyLockState -> object binary-value,10110 | property present-value | type=binary-value | write=inactive
Observed values:
  keyLockState: false
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 101
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000047040","params":{"keyLockState":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000047040",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000047040/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000047040/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":"W8004","keyLockState":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "W8004",
      "keyLockState": false
    }
  }
}

ChirpStack MQTT:

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

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000047040",
  "confirmed": false,
  "object": {
    "model": "W8004",
    "keyLockState": false
  }
}

7.7 Retrieving Data from the DS-501 Smart Plug

DS-501 is a LoRaWAN smart socket that supports remote on/off, voltage/current/power metering, timer control, and child-lock. Suitable for remote power management applications.

deviceinformation:devEui=ffffff1000048920,Modbus Slave ID=3,BACnet Device ID=102,gateway IP=192.168.31.205

The DS-501 smart socket also supports downlink control — see 7.8 Downlink Control for DS-501.

7.7.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 3(可configuration,range 2–201)。

7.7.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
================================================================================================================================================================
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       | 69CB AF35           | 1774956341         | second
ds501ControlTarget       | 9      | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
ds501ControlState        | 10     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
ds501ControlMode         | 11     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
ds501DelaySeconds        | 12     | 03  | Int32      | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.0                | seconds
ds501ScheduleTimestamp   | 14     | 03  | UnixTime   | Big(ABCD)    | 2   | x1       | 0000 0000           | 0                  | seconds
ds501RepeatDaily         | 16     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
switch                   | 17     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
lockState                | 18     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
voltage                  | 19     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 095A                | 239.4              | volt
current                  | 20     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0000                | 0.00               | ampere
activePower              | 21     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0000                | 0.00               | watt
energy                   | 22     | 03  | Float32    | Big(ABCD)    | 2   | /100     | 44D4 1FFF           | 16.97              | kilowatt_hour
timestamp                | 24     | 03  | Int32      | Big(ABCD)    | 2   | x1       | 69CB 3EC7           | 1774927559.0       | seconds
timerCloseEnabled        | 26     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
timerOpenEnabled         | 27     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
timerLockEnabled         | 28     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
timerUnlockEnabled       | 29     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
mainVersion              | 30     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 38     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 46     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 54     | 03  | String(24B) | ASCII        | 12  | x1       | 4453 2D35 3031 0000 ... | DS-501             | none
rssi                     | 66     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFBD                | -67.0              | none
snr                      | 67     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000D                | 13.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774956341 second
ds501ControlTarget 9 Int16 1 x1 0.0 none
ds501ControlState 10 Bit/Bool 1 x1 false none
ds501ControlMode 11 Int16 1 x1 0.0 none
ds501DelaySeconds 12 Int32 2 x1 0.0 seconds
ds501ScheduleTimestamp 14 UnixTime 2 x1 0 seconds
ds501RepeatDaily 16 Bit/Bool 1 x1 false none
switch 17 Bit/Bool 1 x1 true none
lockState 18 Int16 1 x1 1.0 none
voltage 19 Int16(S) 1 /10 239.4 volt
current 20 Int16(S) 1 /100 0.00 ampere
activePower 21 Int16(S) 1 /100 0.00 watt
energy 22 Float32 2 /100 16.97 kilowatt_hour
timestamp 24 Int32 2 x1 1774927559.0 seconds
timerCloseEnabled 26 Bit/Bool 1 x1 true none
timerOpenEnabled 27 Bit/Bool 1 x1 false none
timerLockEnabled 28 Bit/Bool 1 x1 false none
timerUnlockEnabled 29 Bit/Bool 1 x1 false none
model 54 String(24B) 12 x1 DS-501 none
rssi 66 Int16 1 x1 -67.0 none
snr 67 Int16 1 x1 13.0 none
7.7.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 3, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 62 (covers addresses 6–67), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.7.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.DS-501 Smart Socket Device ID=102, so object instances start from 10200.

7.7.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 102
Target: 192.168.31.205:47808 | BACnet ID: 102 | Scan: 10200-10299
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 10200    | 0      | 6CF1AE6A                 | ffffff1000048920.protocolLayoutHash
CV   | 10201    | 1      | 20260101                 | ffffff1000048920.profileVersion
BI   | 10202    | 2      | active                   | ffffff1000048920.online
AI   | 10203    | 3      | 1775028992.00            | ffffff1000048920.lastOnlineTime
AV   | 10204    | 4      | 0.00                     | ffffff1000048920.ds501ControlTarget
BV   | 10205    | 5      | inactive                 | ffffff1000048920.ds501ControlState
AV   | 10206    | 6      | 0.00                     | ffffff1000048920.ds501ControlMode
AV   | 10207    | 7      | 0.00                     | ffffff1000048920.ds501DelaySeconds
AV   | 10208    | 8      | 0.00                     | ffffff1000048920.ds501ScheduleTimestamp
BV   | 10209    | 9      | inactive                 | ffffff1000048920.ds501RepeatDaily
BV   | 10210    | 10     | active                   | ffffff1000048920.switch
BV   | 10211    | 11     | active                   | ffffff1000048920.lockState
AI   | 10212    | 12     | 241.80                   | ffffff1000048920.voltage
AI   | 10213    | 13     | 0.00                     | ffffff1000048920.current
AI   | 10214    | 14     | 0.00                     | ffffff1000048920.activePower
AI   | 10215    | 15     | 16.97                    | ffffff1000048920.energy
AI   | 10216    | 16     | 1775029120.00            | ffffff1000048920.timestamp
BI   | 10217    | 17     | inactive                 | ffffff1000048920.timerCloseEnabled
BI   | 10218    | 18     | inactive                 | ffffff1000048920.timerOpenEnabled
BI   | 10219    | 19     | inactive                 | ffffff1000048920.timerLockEnabled
BI   | 10220    | 20     | inactive                 | ffffff1000048920.timerUnlockEnabled
CV   | 10221    | 21     |                          | ffffff1000048920.mainVersion
CV   | 10222    | 22     |                          | ffffff1000048920.appVersion
CV   | 10223    | 23     |                          | ffffff1000048920.hardwareVersion
CV   | 10224    | 24     | DS-501                   | ffffff1000048920.model
AI   | 10225    | 25     | -75.00                   | ffffff1000048920.rssi
AI   | 10226    | 26     | 13.00                    | ffffff1000048920.snr
7.7.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 102 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10204); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.7.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff1000048920" | jq .
{
  "devEui": "ffffff1000048920",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 19:25:41",
  "params": {
    "ds501ControlState": false,
    "ds501RepeatDaily": false,
    "switch": true,
    "lockState": 1,
    "voltage": 239.4,
    "current": 0,
    "activePower": 0,
    "energy": 16.97,
    "timestamp": 1774927559,
    "timerCloseEnabled": true,
    "timerOpenEnabled": false,
    "timerLockEnabled": false,
    "timerUnlockEnabled": false,
    "model": "DS-501"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -67,
    "snr": 13,
    "frequency": 482100000,
    "spreadingFactor": 7,
    "bandwidth": 125000,
    "fCnt": 4004,
    "fPort": 210,
    "confirmed": false,
    "size": 31,
    "rawData": "5C780000000000000000000000000000000000000000000000000000000000"
  }
}
Note: devEui=ffffff1000048920 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.8 Sending Control Commands to the DS-501 Smart Plug

The DS-501 is a LoRaWAN smart plug. The eight examples below cover immediate switch, lock, delayed switch/lock, scheduled switch/lock, and timer cancellation.

Device information: devEui=ffffff1000048920, Modbus Slave ID=3, BACnet Device ID=102, gateway IP=192.168.31.205

Example 1a: Immediate Switch Connect / Disconnect — Connect / Close (ON)

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 switch --value 1
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 1
  ds501ControlMode: 0
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  switch: true
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds501ControlState -> register 10 (4x40011) raw=1 signed=1
    ds501ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds501RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch: true
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 switch --value 1
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 1
  ds501ControlMode: 0
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  switch: true
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=1
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=active
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=0
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=0
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=0
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=inactive
Observed values:
  switch: true
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":true,"ds501ControlState":true,"ds501ControlMode":false,"ds501DelaySeconds":false,"ds501ScheduleTimestamp":false,"ds501RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":1,"ds501ControlState":true,"ds501ControlMode":0,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 1,
      "ds501ControlState": true,
      "ds501ControlMode": 0,
      "ds501DelaySeconds": 0,
      "ds501ScheduleTimestamp": 0,
      "ds501RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":1,"ds501ControlState":true,"ds501ControlMode":0,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 1,
    "ds501ControlState": true,
    "ds501ControlMode": 0,
    "ds501DelaySeconds": 0,
    "ds501ScheduleTimestamp": 0,
    "ds501RepeatDaily": false
  }
}

Example 1b: Immediate Switch Connect / Disconnect — Disconnect / Open (OFF)

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 switch --value 0
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 0
  ds501ControlMode: 0
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  switch: false
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds501ControlState -> register 10 (4x40011) raw=0 signed=0
    ds501ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds501RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch: false
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 switch --value 0
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 0
  ds501ControlMode: 0
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  switch: false
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=1
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=inactive
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=0
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=0
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=0
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=inactive
Observed values:
  switch: false
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":true,"ds501ControlState":false,"ds501ControlMode":false,"ds501DelaySeconds":false,"ds501ScheduleTimestamp":false,"ds501RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":1,"ds501ControlState":false,"ds501ControlMode":0,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 1,
      "ds501ControlState": false,
      "ds501ControlMode": 0,
      "ds501DelaySeconds": 0,
      "ds501ScheduleTimestamp": 0,
      "ds501RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":1,"ds501ControlState":false,"ds501ControlMode":0,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 1,
    "ds501ControlState": false,
    "ds501ControlMode": 0,
    "ds501DelaySeconds": 0,
    "ds501ScheduleTimestamp": 0,
    "ds501RepeatDaily": false
  }
}

Example 2a: Immediate Lock / Unlock — Lock

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 lock --value 1
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 1
  ds501ControlMode: 0
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  lockState: true
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds501ControlState -> register 10 (4x40011) raw=1 signed=1
    ds501ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds501RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  lockState: true
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 lock --value 1
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 1
  ds501ControlMode: 0
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  lockState: true
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=254
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=active
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=0
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=0
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=0
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=inactive
Observed values:
  lockState: true
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":254,"ds501ControlState":true,"ds501ControlMode":false,"ds501DelaySeconds":false,"ds501ScheduleTimestamp":false,"ds501RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":254,"ds501ControlState":true,"ds501ControlMode":0,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 254,
      "ds501ControlState": true,
      "ds501ControlMode": 0,
      "ds501DelaySeconds": 0,
      "ds501ScheduleTimestamp": 0,
      "ds501RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":254,"ds501ControlState":true,"ds501ControlMode":0,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 254,
    "ds501ControlState": true,
    "ds501ControlMode": 0,
    "ds501DelaySeconds": 0,
    "ds501ScheduleTimestamp": 0,
    "ds501RepeatDaily": false
  }
}

Example 2b: Immediate Lock / Unlock — Unlock

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 lock --value 0
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 0
  ds501ControlMode: 0
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  lockState: false
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds501ControlState -> register 10 (4x40011) raw=0 signed=0
    ds501ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds501RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  lockState: false
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 lock --value 0
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 0
  ds501ControlMode: 0
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  lockState: false
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=254
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=inactive
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=0
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=0
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=0
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=inactive
Observed values:
  lockState: false
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":254,"ds501ControlState":false,"ds501ControlMode":false,"ds501DelaySeconds":false,"ds501ScheduleTimestamp":false,"ds501RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":254,"ds501ControlState":false,"ds501ControlMode":0,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 254,
      "ds501ControlState": false,
      "ds501ControlMode": 0,
      "ds501DelaySeconds": 0,
      "ds501ScheduleTimestamp": 0,
      "ds501RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":254,"ds501ControlState":false,"ds501ControlMode":0,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 254,
    "ds501ControlState": false,
    "ds501ControlMode": 0,
    "ds501DelaySeconds": 0,
    "ds501ScheduleTimestamp": 0,
    "ds501RepeatDaily": false
  }
}

Example 3a: Delayed Switch (after 5 s) — Connect / Close (ON)
The device will wait 5 seconds before executing the switch command.

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 switchDelay --value 1 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 1
  ds501ControlMode: 1
  ds501DelaySeconds: 5
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds501ControlState -> register 10 (4x40011) raw=1 signed=1
    ds501ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds501RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch: (pending)
Control completed in: 0.085s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 switchDelay --value 1 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 1
  ds501ControlMode: 1
  ds501DelaySeconds: 5
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=1
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=active
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=1
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=5
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=0
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=inactive
Observed values:
  switch: (pending)
Control completed in: 0.082s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":true,"ds501ControlState":true,"ds501ControlMode":true,"ds501DelaySeconds":5,"ds501ScheduleTimestamp":false,"ds501RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":1,"ds501ControlState":true,"ds501ControlMode":1,"ds501DelaySeconds":5,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 1,
      "ds501ControlState": true,
      "ds501ControlMode": 1,
      "ds501DelaySeconds": 5,
      "ds501ScheduleTimestamp": 0,
      "ds501RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":1,"ds501ControlState":true,"ds501ControlMode":1,"ds501DelaySeconds":5,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 1,
    "ds501ControlState": true,
    "ds501ControlMode": 1,
    "ds501DelaySeconds": 5,
    "ds501ScheduleTimestamp": 0,
    "ds501RepeatDaily": false
  }
}

Example 3b: Delayed Switch (after 5 s) — Disconnect / Open (OFF)

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 switchDelay --value 0 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 0
  ds501ControlMode: 1
  ds501DelaySeconds: 5
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds501ControlState -> register 10 (4x40011) raw=0 signed=0
    ds501ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds501RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch: (pending)
Control completed in: 0.085s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 switchDelay --value 0 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 0
  ds501ControlMode: 1
  ds501DelaySeconds: 5
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=1
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=inactive
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=1
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=5
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=0
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=inactive
Observed values:
  switch: (pending)
Control completed in: 0.082s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":true,"ds501ControlState":false,"ds501ControlMode":true,"ds501DelaySeconds":5,"ds501ScheduleTimestamp":false,"ds501RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":1,"ds501ControlState":false,"ds501ControlMode":1,"ds501DelaySeconds":5,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 1,
      "ds501ControlState": false,
      "ds501ControlMode": 1,
      "ds501DelaySeconds": 5,
      "ds501ScheduleTimestamp": 0,
      "ds501RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":1,"ds501ControlState":false,"ds501ControlMode":1,"ds501DelaySeconds":5,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 1,
    "ds501ControlState": false,
    "ds501ControlMode": 1,
    "ds501DelaySeconds": 5,
    "ds501ScheduleTimestamp": 0,
    "ds501RepeatDaily": false
  }
}

Example 4a: Scheduled Switch (2026-04-01 10:30 CST, repeat daily) — Connect / Close (ON)
Scheduled for 2026-04-01 10:30:00 CST (Unix timestamp 1775010600). Compute via: date -d '2026-04-01 10:30:00 +0800' +%s

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 switchSchedule --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 1
  ds501ControlMode: 2
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 1775010600
  ds501RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds501ControlState -> register 10 (4x40011) raw=1 signed=1
    ds501ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds501RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  switch: (pending)
Control completed in: 0.085s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 switchSchedule --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 1
  ds501ControlMode: 2
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 1775010600
  ds501RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=1
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=active
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=2
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=0
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=1775010600
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=active
Observed values:
  switch: (pending)
Control completed in: 0.082s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":true,"ds501ControlState":true,"ds501ControlMode":2,"ds501DelaySeconds":false,"ds501ScheduleTimestamp":1775010600,"ds501RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":1,"ds501ControlState":true,"ds501ControlMode":2,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":1775010600,"ds501RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 1,
      "ds501ControlState": true,
      "ds501ControlMode": 2,
      "ds501DelaySeconds": 0,
      "ds501ScheduleTimestamp": 1775010600,
      "ds501RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":1,"ds501ControlState":true,"ds501ControlMode":2,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":1775010600,"ds501RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 1,
    "ds501ControlState": true,
    "ds501ControlMode": 2,
    "ds501DelaySeconds": 0,
    "ds501ScheduleTimestamp": 1775010600,
    "ds501RepeatDaily": true
  }
}

Example 4b: Scheduled Switch (2026-04-01 10:30 CST, repeat daily) — Disconnect / Open (OFF)

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 switchSchedule --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 0
  ds501ControlMode: 2
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 1775010600
  ds501RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds501ControlState -> register 10 (4x40011) raw=0 signed=0
    ds501ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds501RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  switch: (pending)
Control completed in: 0.085s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 switchSchedule --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 0
  ds501ControlMode: 2
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 1775010600
  ds501RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=1
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=inactive
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=2
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=0
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=1775010600
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=active
Observed values:
  switch: (pending)
Control completed in: 0.082s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":true,"ds501ControlState":false,"ds501ControlMode":2,"ds501DelaySeconds":false,"ds501ScheduleTimestamp":1775010600,"ds501RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":1,"ds501ControlState":false,"ds501ControlMode":2,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":1775010600,"ds501RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 1,
      "ds501ControlState": false,
      "ds501ControlMode": 2,
      "ds501DelaySeconds": 0,
      "ds501ScheduleTimestamp": 1775010600,
      "ds501RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":1,"ds501ControlState":false,"ds501ControlMode":2,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":1775010600,"ds501RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 1,
    "ds501ControlState": false,
    "ds501ControlMode": 2,
    "ds501DelaySeconds": 0,
    "ds501ScheduleTimestamp": 1775010600,
    "ds501RepeatDaily": true
  }
}

Example 5a: Delayed Lock / Unlock (after 5 s) — Lock

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 lockDelay --value 1 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 1
  ds501ControlMode: 1
  ds501DelaySeconds: 5
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds501ControlState -> register 10 (4x40011) raw=1 signed=1
    ds501ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds501RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  lockState: (pending)
Control completed in: 0.085s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 lockDelay --value 1 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 1
  ds501ControlMode: 1
  ds501DelaySeconds: 5
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=254
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=active
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=1
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=5
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=0
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=inactive
Observed values:
  lockState: (pending)
Control completed in: 0.082s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":254,"ds501ControlState":true,"ds501ControlMode":true,"ds501DelaySeconds":5,"ds501ScheduleTimestamp":false,"ds501RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":254,"ds501ControlState":true,"ds501ControlMode":1,"ds501DelaySeconds":5,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 254,
      "ds501ControlState": true,
      "ds501ControlMode": 1,
      "ds501DelaySeconds": 5,
      "ds501ScheduleTimestamp": 0,
      "ds501RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":254,"ds501ControlState":true,"ds501ControlMode":1,"ds501DelaySeconds":5,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 254,
    "ds501ControlState": true,
    "ds501ControlMode": 1,
    "ds501DelaySeconds": 5,
    "ds501ScheduleTimestamp": 0,
    "ds501RepeatDaily": false
  }
}

Example 5b: Delayed Lock / Unlock (after 5 s) — Unlock

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 lockDelay --value 0 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 0
  ds501ControlMode: 1
  ds501DelaySeconds: 5
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds501ControlState -> register 10 (4x40011) raw=0 signed=0
    ds501ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds501RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  lockState: (pending)
Control completed in: 0.085s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 lockDelay --value 0 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 0
  ds501ControlMode: 1
  ds501DelaySeconds: 5
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=254
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=inactive
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=1
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=5
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=0
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=inactive
Observed values:
  lockState: (pending)
Control completed in: 0.082s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":254,"ds501ControlState":false,"ds501ControlMode":true,"ds501DelaySeconds":5,"ds501ScheduleTimestamp":false,"ds501RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":254,"ds501ControlState":false,"ds501ControlMode":1,"ds501DelaySeconds":5,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 254,
      "ds501ControlState": false,
      "ds501ControlMode": 1,
      "ds501DelaySeconds": 5,
      "ds501ScheduleTimestamp": 0,
      "ds501RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":254,"ds501ControlState":false,"ds501ControlMode":1,"ds501DelaySeconds":5,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 254,
    "ds501ControlState": false,
    "ds501ControlMode": 1,
    "ds501DelaySeconds": 5,
    "ds501ScheduleTimestamp": 0,
    "ds501RepeatDaily": false
  }
}

Example 6a: Scheduled Lock / Unlock (2026-04-01 10:30 CST, repeat daily) — Lock

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 lockSchedule --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 1
  ds501ControlMode: 2
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 1775010600
  ds501RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds501ControlState -> register 10 (4x40011) raw=1 signed=1
    ds501ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds501RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  lockState: (pending)
Control completed in: 0.085s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 lockSchedule --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 1
  ds501ControlMode: 2
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 1775010600
  ds501RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=254
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=active
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=2
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=0
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=1775010600
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=active
Observed values:
  lockState: (pending)
Control completed in: 0.082s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":254,"ds501ControlState":true,"ds501ControlMode":2,"ds501DelaySeconds":false,"ds501ScheduleTimestamp":1775010600,"ds501RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":254,"ds501ControlState":true,"ds501ControlMode":2,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":1775010600,"ds501RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 254,
      "ds501ControlState": true,
      "ds501ControlMode": 2,
      "ds501DelaySeconds": 0,
      "ds501ScheduleTimestamp": 1775010600,
      "ds501RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":254,"ds501ControlState":true,"ds501ControlMode":2,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":1775010600,"ds501RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 254,
    "ds501ControlState": true,
    "ds501ControlMode": 2,
    "ds501DelaySeconds": 0,
    "ds501ScheduleTimestamp": 1775010600,
    "ds501RepeatDaily": true
  }
}

Example 6b: Scheduled Lock / Unlock (2026-04-01 10:30 CST, repeat daily) — Unlock

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 lockSchedule --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 0
  ds501ControlMode: 2
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 1775010600
  ds501RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds501ControlState -> register 10 (4x40011) raw=0 signed=0
    ds501ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds501RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  lockState: (pending)
Control completed in: 0.085s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 lockSchedule --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 0
  ds501ControlMode: 2
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 1775010600
  ds501RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=254
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=inactive
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=2
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=0
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=1775010600
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=active
Observed values:
  lockState: (pending)
Control completed in: 0.082s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":254,"ds501ControlState":false,"ds501ControlMode":2,"ds501DelaySeconds":false,"ds501ScheduleTimestamp":1775010600,"ds501RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":254,"ds501ControlState":false,"ds501ControlMode":2,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":1775010600,"ds501RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 254,
      "ds501ControlState": false,
      "ds501ControlMode": 2,
      "ds501DelaySeconds": 0,
      "ds501ScheduleTimestamp": 1775010600,
      "ds501RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":254,"ds501ControlState":false,"ds501ControlMode":2,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":1775010600,"ds501RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 254,
    "ds501ControlState": false,
    "ds501ControlMode": 2,
    "ds501DelaySeconds": 0,
    "ds501ScheduleTimestamp": 1775010600,
    "ds501RepeatDaily": true
  }
}

Example 7: Cancel Switch Timer
Clears any pending delayed or scheduled connect/disconnect command for the socket.

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 cancelSwitchTimer
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 0
  ds501ControlMode: 3
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  switch: (unchanged)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds501ControlState -> register 10 (4x40011) raw=0 signed=0
    ds501ControlMode -> register 11 (4x40012) raw=3 signed=3
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds501RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch: (unchanged)
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 cancelSwitchTimer
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 1
  ds501ControlState: 0
  ds501ControlMode: 3
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  switch: (unchanged)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=1
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=inactive
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=3
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=0
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=0
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=inactive
Observed values:
  switch: (unchanged)
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":1,"ds501ControlState":false,"ds501ControlMode":3,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":1,"ds501ControlState":false,"ds501ControlMode":3,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 1,
      "ds501ControlState": false,
      "ds501ControlMode": 3,
      "ds501DelaySeconds": 0,
      "ds501ScheduleTimestamp": 0,
      "ds501RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":1,"ds501ControlState":false,"ds501ControlMode":3,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 1,
    "ds501ControlState": false,
    "ds501ControlMode": 3,
    "ds501DelaySeconds": 0,
    "ds501ScheduleTimestamp": 0,
    "ds501RepeatDaily": false
  }
}

Example 8: Cancel Lock Timer
Clears any pending delayed or scheduled lock/unlock command.

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 3 --sensorType DS-501 cancelLockTimer
Target: 192.168.31.205:502 | Slave ID: 3 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 0
  ds501ControlMode: 3
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  lockState: (unchanged)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds501ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds501ControlState -> register 10 (4x40011) raw=0 signed=0
    ds501ControlMode -> register 11 (4x40012) raw=3 signed=3
    ds501DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds501DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds501ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds501ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds501RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  lockState: (unchanged)
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, 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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 102 --sensorType DS-501 cancelLockTimer
Target: 192.168.31.205:47808 | BACnet ID: 102 | Sensor: DS-501
Expected values:
  ds501ControlTarget: 254
  ds501ControlState: 0
  ds501ControlMode: 3
  ds501DelaySeconds: 0
  ds501ScheduleTimestamp: 0
  ds501RepeatDaily: 0
Expected confirmed state:
  lockState: (unchanged)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds501ControlTarget -> object analog-value,10204 | property present-value | type=analog-value | write=254
  ds501ControlState -> object binary-value,10205 | property present-value | type=binary-value | write=inactive
  ds501ControlMode -> object analog-value,10206 | property present-value | type=analog-value | write=3
  ds501DelaySeconds -> object analog-value,10207 | property present-value | type=analog-value | write=0
  ds501ScheduleTimestamp -> object analog-value,10208 | property present-value | type=analog-value | write=0
  ds501RepeatDaily -> object binary-value,10209 | property present-value | type=binary-value | write=inactive
Observed values:
  lockState: (unchanged)
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, 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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000048920","params":{"ds501ControlTarget":254,"ds501ControlState":false,"ds501ControlMode":3,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000048920",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000048920/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000048920/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":"DS-501","ds501ControlTarget":254,"ds501ControlState":false,"ds501ControlMode":3,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-501",
      "ds501ControlTarget": 254,
      "ds501ControlState": false,
      "ds501ControlMode": 3,
      "ds501DelaySeconds": 0,
      "ds501ScheduleTimestamp": 0,
      "ds501RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000048920/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000048920","confirmed":false,"object":{"model":"DS-501","ds501ControlTarget":254,"ds501ControlState":false,"ds501ControlMode":3,"ds501DelaySeconds":0,"ds501ScheduleTimestamp":0,"ds501RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000048920",
  "confirmed": false,
  "object": {
    "model": "DS-501",
    "ds501ControlTarget": 254,
    "ds501ControlState": false,
    "ds501ControlMode": 3,
    "ds501DelaySeconds": 0,
    "ds501ScheduleTimestamp": 0,
    "ds501RepeatDaily": false
  }
}

7.9 Retrieving Data from the EF5600-DN1 Electrical Fire Monitor

EF5600-DN1 is a three-phase electrical fire monitoring detector that supports three-phase voltage/current/power/temperature/leakage-current monitoring and remote circuit-breaker control. Suitable for distribution cabinets and electrical safety monitoring.

deviceinformation:devEui=ffffff100004e99f,Modbus Slave ID=7,BACnet Device ID=106,gateway IP=192.168.31.205

The EF5600-DN1 also supports downlink control commands — see 7.10 Downlink Control for EF5600-DN1 for details.

7.9.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 7(可configuration,range 2–201)。

7.9.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 7 --sensorType EF5600-DN1
Target: 192.168.31.205:502 | Slave ID: 7 | Sensor: EF5600-DN1
================================================================================================================================================================
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       | 69CB 4173           | 1774928243         | second
ef5600CommandCode        | 9      | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
ef5600SettingAddress     | 10     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
ef5600SettingValueHigh   | 11     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
ef5600SettingValueLow    | 12     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
switch                   | 13     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
voltageA                 | 14     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 0924                | 234.0              | volt
voltageB                 | 15     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 091C                | 233.2              | volt
voltageC                 | 16     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 0927                | 234.3              | volt
voltageAvg               | 17     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 0922                | 233.8              | volt
currentA                 | 18     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 0000                | 0.0                | ampere
currentB                 | 19     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 0000                | 0.0                | ampere
currentC                 | 20     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 0000                | 0.0                | ampere
currentAvg               | 21     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 0000                | 0.0                | ampere
activePowerA             | 22     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.00               | watt
activePowerB             | 24     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.00               | watt
activePowerC             | 26     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.00               | watt
activePowerTotal         | 28     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.00               | watt
reactivePowerA           | 30     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.00               | none
reactivePowerB           | 32     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.00               | none
reactivePowerC           | 34     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.00               | none
reactivePowerTotal       | 36     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.00               | none
apparentPowerA           | 38     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.00               | none
apparentPowerB           | 40     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.00               | none
apparentPowerC           | 42     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.00               | none
apparentPowerTotal       | 44     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 3DA3 D70A           | 0.08               | none
powerFactorA             | 46     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 3F80 0000           | 1.000              | none
powerFactorB             | 48     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 3F80 0000           | 1.000              | none
powerFactorC             | 50     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 3F80 0000           | 1.000              | none
powerFactorTotal         | 52     | 03  | Float32    | Big(ABCD)    | 2   | x1       | BF80 0000           | -1.000             | none
activeEnergy             | 54     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 4126 6666           | 10.40              | kilowatt_hour
reactiveEnergy           | 56     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 3F4C CCCD           | 0.80               | none
apparentEnergy           | 58     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 41F9 999A           | 31.20              | none
leakageCurrent           | 60     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 0000                | 0.0                | milliampere
tempSensor1              | 61     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 0118                | 28.0               | celsius
tempSensor2              | 62     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 011D                | 28.5               | celsius
tempSensor3              | 63     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 0000                | 0.0                | celsius
tempSensor4              | 64     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 0000                | 0.0                | celsius
tempAvg                  | 65     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 008D                | 14.1               | celsius
envTemperature           | 66     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 010C                | 26.8               | celsius
envHumidity              | 67     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 02EB                | 74.7               | percent
electricalAlarm          | 68     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
electricalAlarmEvent     | 69     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
alarmOvercurrentA        | 70     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmOvercurrentB        | 71     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmOvercurrentC        | 72     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmOvercurrentAEvent   | 73     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmOvercurrentBEvent   | 74     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmOvercurrentCEvent   | 75     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmOvervoltageA        | 76     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmOvervoltageB        | 77     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmOvervoltageC        | 78     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmOvervoltageAEvent   | 79     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmOvervoltageBEvent   | 80     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmOvervoltageCEvent   | 81     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmUndervoltageA       | 82     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmUndervoltageB       | 83     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmUndervoltageC       | 84     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmUndervoltageAEvent  | 85     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmUndervoltageBEvent  | 86     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmUndervoltageCEvent  | 87     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmShortCircuit        | 88     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmShortCircuitEvent   | 89     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmTempSensor1         | 90     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmTempSensor2         | 91     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmTempSensor3         | 92     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmTempSensor4         | 93     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmTempSensor1Event    | 94     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmTempSensor2Event    | 95     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmTempSensor3Event    | 96     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmTempSensor4Event    | 97     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmLeakage             | 98     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
alarmLeakageEvent        | 99     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
mainVersion              | 100    | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 108    | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 116    | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 124    | 03  | String(24B) | ASCII        | 12  | x1       | 4546 3536 3030 2D44 ... | EF5600-DN1         | none
rssi                     | 136    | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFC2                | -62.0              | none
snr                      | 137    | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000E                | 14.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774928243 second
ef5600CommandCode 9 Int16 1 x1 0.0 none
ef5600SettingAddress 10 Int16 1 x1 0.0 none
ef5600SettingValueHigh 11 Int16 1 x1 0.0 none
ef5600SettingValueLow 12 Int16 1 x1 0.0 none
switch 13 Bit/Bool 1 x1 true none
voltageA 14 Int16(S) 1 /10 234.0 volt
voltageB 15 Int16(S) 1 /10 233.2 volt
voltageC 16 Int16(S) 1 /10 234.3 volt
voltageAvg 17 Int16(S) 1 /10 233.8 volt
currentA 18 Int16(S) 1 /10 0.0 ampere
currentB 19 Int16(S) 1 /10 0.0 ampere
currentC 20 Int16(S) 1 /10 0.0 ampere
currentAvg 21 Int16(S) 1 /10 0.0 ampere
activePowerA 22 Float32 2 x1 0.00 watt
activePowerB 24 Float32 2 x1 0.00 watt
activePowerC 26 Float32 2 x1 0.00 watt
activePowerTotal 28 Float32 2 x1 0.00 watt
reactivePowerA 30 Float32 2 x1 0.00 none
reactivePowerB 32 Float32 2 x1 0.00 none
reactivePowerC 34 Float32 2 x1 0.00 none
reactivePowerTotal 36 Float32 2 x1 0.00 none
apparentPowerA 38 Float32 2 x1 0.00 none
apparentPowerB 40 Float32 2 x1 0.00 none
apparentPowerC 42 Float32 2 x1 0.00 none
apparentPowerTotal 44 Float32 2 x1 0.08 none
powerFactorA 46 Float32 2 x1 1.000 none
powerFactorB 48 Float32 2 x1 1.000 none
powerFactorC 50 Float32 2 x1 1.000 none
powerFactorTotal 52 Float32 2 x1 -1.000 none
activeEnergy 54 Float32 2 x1 10.40 kilowatt_hour
reactiveEnergy 56 Float32 2 x1 0.80 none
apparentEnergy 58 Float32 2 x1 31.20 none
leakageCurrent 60 Int16(S) 1 /10 0.0 milliampere
tempSensor1 61 Int16(S) 1 /10 28.0 celsius
tempSensor2 62 Int16(S) 1 /10 28.5 celsius
tempSensor3 63 Int16(S) 1 /10 0.0 celsius
tempSensor4 64 Int16(S) 1 /10 0.0 celsius
tempAvg 65 Int16(S) 1 /10 14.1 celsius
envTemperature 66 Int16(S) 1 /10 26.8 celsius
envHumidity 67 Int16(S) 1 /10 74.7 percent
electricalAlarm 68 Bit/Bool 1 x1 false none
electricalAlarmEvent 69 Int16 1 x1 0.0 none
alarmOvercurrentA 70 Bit/Bool 1 x1 false none
alarmOvercurrentB 71 Bit/Bool 1 x1 false none
alarmOvercurrentC 72 Bit/Bool 1 x1 false none
alarmOvercurrentAEvent 73 Bit/Bool 1 x1 false none
alarmOvercurrentBEvent 74 Bit/Bool 1 x1 false none
alarmOvercurrentCEvent 75 Bit/Bool 1 x1 false none
alarmOvervoltageA 76 Bit/Bool 1 x1 false none
alarmOvervoltageB 77 Bit/Bool 1 x1 false none
alarmOvervoltageC 78 Bit/Bool 1 x1 false none
alarmOvervoltageAEvent 79 Bit/Bool 1 x1 false none
alarmOvervoltageBEvent 80 Bit/Bool 1 x1 false none
alarmOvervoltageCEvent 81 Bit/Bool 1 x1 false none
alarmUndervoltageA 82 Bit/Bool 1 x1 false none
alarmUndervoltageB 83 Bit/Bool 1 x1 false none
alarmUndervoltageC 84 Bit/Bool 1 x1 false none
alarmUndervoltageAEvent 85 Bit/Bool 1 x1 false none
alarmUndervoltageBEvent 86 Bit/Bool 1 x1 false none
alarmUndervoltageCEvent 87 Bit/Bool 1 x1 false none
alarmShortCircuit 88 Bit/Bool 1 x1 false none
alarmShortCircuitEvent 89 Bit/Bool 1 x1 false none
alarmTempSensor1 90 Bit/Bool 1 x1 false none
alarmTempSensor2 91 Bit/Bool 1 x1 false none
alarmTempSensor3 92 Bit/Bool 1 x1 false none
alarmTempSensor4 93 Bit/Bool 1 x1 false none
alarmTempSensor1Event 94 Bit/Bool 1 x1 false none
alarmTempSensor2Event 95 Bit/Bool 1 x1 false none
alarmTempSensor3Event 96 Bit/Bool 1 x1 false none
alarmTempSensor4Event 97 Bit/Bool 1 x1 false none
alarmLeakage 98 Bit/Bool 1 x1 false none
alarmLeakageEvent 99 Bit/Bool 1 x1 false none
model 124 String(24B) 12 x1 EF5600-DN1 none
rssi 136 Int16 1 x1 -62.0 none
snr 137 Int16 1 x1 14.0 none
7.9.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 7, Function Code to 03 Read Holding Registers
  3. Since Modbus FC03 can read a maximum of 125 registers per request, two Read/Write Definitions are required: - Definition 1: Start address 6, Count 125 (covers addresses 6–130) - Definition 2: Start address 131, Count 7 (covers addresses 131–137)

After clicking OK on both, Modbus Poll will simultaneously display the polling results in two windows

  1. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.9.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.EF5600-DN1 Electrical Fire Detector Device ID=106, so object instances start from 10600.

7.9.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 106
Target: 192.168.31.205:47808 | BACnet ID: 106 | Scan: 10600-10699
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 10600    | 0      | 083F6AA9                 | ffffff100004e99f.protocolLayoutHash
CV   | 10601    | 1      | 20260101                 | ffffff100004e99f.profileVersion
BI   | 10602    | 2      | active                   | ffffff100004e99f.online
AI   | 10603    | 3      | 1775029888.00            | ffffff100004e99f.lastOnlineTime
AV   | 10604    | 4      | 0.00                     | ffffff100004e99f.ef5600CommandCode
AV   | 10605    | 5      | 0.00                     | ffffff100004e99f.ef5600SettingAddress
AV   | 10606    | 6      | 0.00                     | ffffff100004e99f.ef5600SettingValueHigh
AV   | 10607    | 7      | 0.00                     | ffffff100004e99f.ef5600SettingValueLow
BV   | 10608    | 8      | active                   | ffffff100004e99f.switch
AI   | 10609    | 9      | 236.70                   | ffffff100004e99f.voltageA
AI   | 10610    | 10     | 235.80                   | ffffff100004e99f.voltageB
AI   | 10611    | 11     | 236.90                   | ffffff100004e99f.voltageC
AI   | 10612    | 12     | 236.50                   | ffffff100004e99f.voltageAvg
AI   | 10613    | 13     | 0.00                     | ffffff100004e99f.currentA
AI   | 10614    | 14     | 0.00                     | ffffff100004e99f.currentB
AI   | 10615    | 15     | 0.00                     | ffffff100004e99f.currentC
AI   | 10616    | 16     | 0.00                     | ffffff100004e99f.currentAvg
AI   | 10617    | 17     | 0.00                     | ffffff100004e99f.activePowerA
AI   | 10618    | 18     | 0.00                     | ffffff100004e99f.activePowerB
AI   | 10619    | 19     | 0.00                     | ffffff100004e99f.activePowerC
AI   | 10620    | 20     | 0.00                     | ffffff100004e99f.activePowerTotal
AI   | 10621    | 21     | 0.00                     | ffffff100004e99f.reactivePowerA
AI   | 10622    | 22     | 0.00                     | ffffff100004e99f.reactivePowerB
AI   | 10623    | 23     | 0.00                     | ffffff100004e99f.reactivePowerC
AI   | 10624    | 24     | 0.00                     | ffffff100004e99f.reactivePowerTotal
AI   | 10625    | 25     | 0.00                     | ffffff100004e99f.apparentPowerA
AI   | 10626    | 26     | 0.00                     | ffffff100004e99f.apparentPowerB
AI   | 10627    | 27     | 0.00                     | ffffff100004e99f.apparentPowerC
AI   | 10628    | 28     | 0.08                     | ffffff100004e99f.apparentPowerTotal
AI   | 10629    | 29     | 1.00                     | ffffff100004e99f.powerFactorA
AI   | 10630    | 30     | 1.00                     | ffffff100004e99f.powerFactorB
AI   | 10631    | 31     | 1.00                     | ffffff100004e99f.powerFactorC
AI   | 10632    | 32     | -1.00                    | ffffff100004e99f.powerFactorTotal
AI   | 10633    | 33     | 10.40                    | ffffff100004e99f.activeEnergy
AI   | 10634    | 34     | 0.80                     | ffffff100004e99f.reactiveEnergy
AI   | 10635    | 35     | 31.20                    | ffffff100004e99f.apparentEnergy
AI   | 10636    | 36     | 0.00                     | ffffff100004e99f.leakageCurrent
AI   | 10637    | 37     | 31.30                    | ffffff100004e99f.tempSensor1
AI   | 10638    | 38     | 32.30                    | ffffff100004e99f.tempSensor2
AI   | 10639    | 39     | 0.00                     | ffffff100004e99f.tempSensor3
AI   | 10640    | 40     | 0.00                     | ffffff100004e99f.tempSensor4
AI   | 10641    | 41     | 15.90                    | ffffff100004e99f.tempAvg
AI   | 10642    | 42     | 33.00                    | ffffff100004e99f.envTemperature
AI   | 10643    | 43     | 42.10                    | ffffff100004e99f.envHumidity
BI   | 10644    | 44     | inactive                 | ffffff100004e99f.electricalAlarm
AI   | 10645    | 45     | 0.00                     | ffffff100004e99f.electricalAlarmEvent
BI   | 10646    | 46     | inactive                 | ffffff100004e99f.alarmOvercurrentA
BI   | 10647    | 47     | inactive                 | ffffff100004e99f.alarmOvercurrentB
BI   | 10648    | 48     | inactive                 | ffffff100004e99f.alarmOvercurrentC
BI   | 10649    | 49     | inactive                 | ffffff100004e99f.alarmOvercurrentAEvent
BI   | 10650    | 50     | inactive                 | ffffff100004e99f.alarmOvercurrentBEvent
BI   | 10651    | 51     | inactive                 | ffffff100004e99f.alarmOvercurrentCEvent
BI   | 10652    | 52     | inactive                 | ffffff100004e99f.alarmOvervoltageA
BI   | 10653    | 53     | inactive                 | ffffff100004e99f.alarmOvervoltageB
BI   | 10654    | 54     | inactive                 | ffffff100004e99f.alarmOvervoltageC
BI   | 10655    | 55     | inactive                 | ffffff100004e99f.alarmOvervoltageAEvent
BI   | 10656    | 56     | inactive                 | ffffff100004e99f.alarmOvervoltageBEvent
BI   | 10657    | 57     | inactive                 | ffffff100004e99f.alarmOvervoltageCEvent
BI   | 10658    | 58     | inactive                 | ffffff100004e99f.alarmUndervoltageA
BI   | 10659    | 59     | inactive                 | ffffff100004e99f.alarmUndervoltageB
BI   | 10660    | 60     | inactive                 | ffffff100004e99f.alarmUndervoltageC
BI   | 10661    | 61     | inactive                 | ffffff100004e99f.alarmUndervoltageAEvent
BI   | 10662    | 62     | inactive                 | ffffff100004e99f.alarmUndervoltageBEvent
BI   | 10663    | 63     | inactive                 | ffffff100004e99f.alarmUndervoltageCEvent
BI   | 10664    | 64     | inactive                 | ffffff100004e99f.alarmShortCircuit
BI   | 10665    | 65     | inactive                 | ffffff100004e99f.alarmShortCircuitEvent
BI   | 10666    | 66     | inactive                 | ffffff100004e99f.alarmTempSensor1
BI   | 10667    | 67     | inactive                 | ffffff100004e99f.alarmTempSensor2
BI   | 10668    | 68     | inactive                 | ffffff100004e99f.alarmTempSensor3
BI   | 10669    | 69     | inactive                 | ffffff100004e99f.alarmTempSensor4
BI   | 10670    | 70     | inactive                 | ffffff100004e99f.alarmTempSensor1Event
BI   | 10671    | 71     | inactive                 | ffffff100004e99f.alarmTempSensor2Event
BI   | 10672    | 72     | inactive                 | ffffff100004e99f.alarmTempSensor3Event
BI   | 10673    | 73     | inactive                 | ffffff100004e99f.alarmTempSensor4Event
BI   | 10674    | 74     | inactive                 | ffffff100004e99f.alarmLeakage
BI   | 10675    | 75     | inactive                 | ffffff100004e99f.alarmLeakageEvent
CV   | 10676    | 76     |                          | ffffff100004e99f.mainVersion
CV   | 10677    | 77     |                          | ffffff100004e99f.appVersion
CV   | 10678    | 78     |                          | ffffff100004e99f.hardwareVersion
CV   | 10679    | 79     | EF5600-DN1               | ffffff100004e99f.model
AI   | 10680    | 80     | -69.00                   | ffffff100004e99f.rssi
AI   | 10681    | 81     | 14.00                    | ffffff100004e99f.snr
7.9.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 106 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10604); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.9.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff100004e99f" | jq .
{
  "devEui": "ffffff100004e99f",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 11:37:23",
  "params": {
    "switch": true,
    "voltageA": 234,
    "voltageB": 233.2,
    "voltageC": 234.3,
    "voltageAvg": 233.8,
    "currentA": 0,
    "currentB": 0,
    "currentC": 0,
    "currentAvg": 0,
    "activePowerA": 0,
    "activePowerB": 0,
    "activePowerC": 0,
    "activePowerTotal": 0,
    "reactivePowerA": 0,
    "reactivePowerB": 0,
    "reactivePowerC": 0,
    "reactivePowerTotal": 0,
    "apparentPowerA": 0,
    "apparentPowerB": 0,
    "apparentPowerC": 0,
    "apparentPowerTotal": 0.08,
    "powerFactorA": 1,
    "powerFactorB": 1,
    "powerFactorC": 1,
    "powerFactorTotal": -1,
    "activeEnergy": 10.4,
    "reactiveEnergy": 0.8,
    "apparentEnergy": 31.2,
    "leakageCurrent": 0,
    "tempSensor1": 28,
    "tempSensor2": 28.5,
    "tempSensor3": 0,
    "tempSensor4": 0,
    "tempAvg": 14.1,
    "envTemperature": 26.8,
    "envHumidity": 74.7,
    "electricalAlarm": false,
    "alarmOvercurrentA": false,
    "alarmOvercurrentB": false,
    "alarmOvercurrentC": false,
    "alarmOvercurrentAEvent": false,
    "alarmOvercurrentBEvent": false,
    "alarmOvercurrentCEvent": false,
    "alarmOvervoltageA": false,
    "alarmOvervoltageB": false,
    "alarmOvervoltageC": false,
    "alarmOvervoltageAEvent": false,
    "alarmOvervoltageBEvent": false,
    "alarmOvervoltageCEvent": false,
    "alarmUndervoltageA": false,
    "alarmUndervoltageB": false,
    "alarmUndervoltageC": false,
    "alarmUndervoltageAEvent": false,
    "alarmUndervoltageBEvent": false,
    "alarmUndervoltageCEvent": false,
    "alarmShortCircuit": false,
    "alarmShortCircuitEvent": false,
    "alarmTempSensor1": false,
    "alarmTempSensor2": false,
    "alarmTempSensor3": false,
    "alarmTempSensor4": false,
    "alarmTempSensor1Event": false,
    "alarmTempSensor2Event": false,
    "alarmTempSensor3Event": false,
    "alarmTempSensor4Event": false,
    "alarmLeakage": false,
    "alarmLeakageEvent": false,
    "model": "EF5600-DN1"
  },
  "rxParams": {
    "gatewayId": "0010502df4563610",
    "rssi": -62,
    "snr": 14,
    "frequency": 481700000,
    "spreadingFactor": 8,
    "bandwidth": 125000,
    "fCnt": 11687,
    "fPort": 210,
    "confirmed": false,
    "size": 114,
    "rawData": "00015B6D012201C70000C6660924091C092700000000000000000118011D00000000010C02EB00000000000000000000000080000000000000000000000000000000000000000000000000000000000000003DA3D70A3F8000003F8000003F800000BF800000412666663F4CCCCD41F9999A"
  }
}
Note: devEui=ffffff100004e99f is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.10 Sending Control Commands to the EF5600-DN1 Electrical Fire Monitor

The EF5600-DN1 is a LoRaWAN electrical fire monitor with a relay output. The two examples below control the relay open (breaker off) and close (breaker on).

Device information: devEui=ffffff100004e99f, Modbus Slave ID=7, BACnet Device ID=106, gateway IP=192.168.31.205

Example 1: Breaker Open (Relay OFF — cut power)

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 7 --sensorType EF5600-DN1 breakerOpen
Target: 192.168.31.205:502 | Slave ID: 7 | Sensor: EF5600-DN1
Expected values:
  ef5600CommandCode: 4
  ef5600SettingAddress: 0
  ef5600SettingValueHigh: 0
  ef5600SettingValueLow: 0
Expected confirmed state:
  switch: false
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 4
    ef5600CommandCode -> register 9 (4x40010) raw=4 signed=4
    ef5600SettingAddress -> register 10 (4x40011) raw=0 signed=0
    ef5600SettingValueHigh -> register 11 (4x40012) raw=0 signed=0
    ef5600SettingValueLow -> register 12 (4x40013) raw=0 signed=0
Observed values:
  switch: false
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 7)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 106 --sensorType EF5600-DN1 breakerOpen
Target: 192.168.31.205:47808 | BACnet ID: 106 | Sensor: EF5600-DN1
Expected values:
  ef5600CommandCode: 4
  ef5600SettingAddress: 0
  ef5600SettingValueHigh: 0
  ef5600SettingValueLow: 0
Expected confirmed state:
  switch: false
Attempt 1/1: writing control values (default)...
YABE write guide:
  ef5600CommandCode -> object analog-value,10604 | property present-value | type=analog-value | write=4
  ef5600SettingAddress -> object analog-value,10605 | property present-value | type=analog-value | write=0
  ef5600SettingValueHigh -> object analog-value,10606 | property present-value | type=analog-value | write=0
  ef5600SettingValueLow -> object analog-value,10607 | property present-value | type=analog-value | write=0
Observed values:
  switch: false
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 106
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff100004e99f","params":{"ef5600CommandCode":4,"ef5600SettingAddress":0,"ef5600SettingValueHigh":0,"ef5600SettingValueLow":0}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff100004e99f",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff100004e99f/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff100004e99f/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":"EF5600-DN1","command":"breakerOpen"}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "EF5600-DN1",
      "command": "breakerOpen"
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff100004e99f/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff100004e99f","confirmed":false,"object":{"model":"EF5600-DN1","command":"breakerOpen"}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff100004e99f",
  "confirmed": false,
  "object": {
    "model": "EF5600-DN1",
    "command": "breakerOpen"
  }
}

Example 2: Breaker Close (Relay ON — restore power)

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 7 --sensorType EF5600-DN1 breakerClose
Target: 192.168.31.205:502 | Slave ID: 7 | Sensor: EF5600-DN1
Expected values:
  ef5600CommandCode: 5
  ef5600SettingAddress: 0
  ef5600SettingValueHigh: 0
  ef5600SettingValueLow: 0
Expected confirmed state:
  switch: true
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 4
    ef5600CommandCode -> register 9 (4x40010) raw=5 signed=5
    ef5600SettingAddress -> register 10 (4x40011) raw=0 signed=0
    ef5600SettingValueHigh -> register 11 (4x40012) raw=0 signed=0
    ef5600SettingValueLow -> register 12 (4x40013) raw=0 signed=0
Observed values:
  switch: true
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 7)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 106 --sensorType EF5600-DN1 breakerClose
Target: 192.168.31.205:47808 | BACnet ID: 106 | Sensor: EF5600-DN1
Expected values:
  ef5600CommandCode: 5
  ef5600SettingAddress: 0
  ef5600SettingValueHigh: 0
  ef5600SettingValueLow: 0
Expected confirmed state:
  switch: true
Attempt 1/1: writing control values (default)...
YABE write guide:
  ef5600CommandCode -> object analog-value,10604 | property present-value | type=analog-value | write=5
  ef5600SettingAddress -> object analog-value,10605 | property present-value | type=analog-value | write=0
  ef5600SettingValueHigh -> object analog-value,10606 | property present-value | type=analog-value | write=0
  ef5600SettingValueLow -> object analog-value,10607 | property present-value | type=analog-value | write=0
Observed values:
  switch: true
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 106
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff100004e99f","params":{"ef5600CommandCode":5,"ef5600SettingAddress":0,"ef5600SettingValueHigh":0,"ef5600SettingValueLow":0}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff100004e99f",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff100004e99f/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff100004e99f/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":"EF5600-DN1","command":"breakerClose"}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "EF5600-DN1",
      "command": "breakerClose"
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff100004e99f/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff100004e99f","confirmed":false,"object":{"model":"EF5600-DN1","command":"breakerClose"}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff100004e99f",
  "confirmed": false,
  "object": {
    "model": "EF5600-DN1",
    "command": "breakerClose"
  }
}

7.11 Retrieving Data from the GB100 Smart Safety Helmet

GB100 is a LoRaWAN smart safety helmet with built-in GPS, barometer, and temperature sensor, supporting fall detection, helmet-off detection, impact detection, and other safety alerts. Suitable for construction sites and industrial safety applications.

deviceinformation:devEui=ffffff100004e9c3,Modbus Slave ID=8,BACnet Device ID=107,gateway IP=192.168.31.205

7.11.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 8(可configuration,range 2–201)。

7.11.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 8 --sensorType GB100
Target: 192.168.31.205:502 | Slave ID: 8 | Sensor: GB100
================================================================================================================================================================
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       | 69CB 9A0D           | 1774950925         | second
batteryLevel             | 9      | 03  | Int16      | Big(ABCD)    | 1   | x1       | 001D                | 29.0               | percent
atmosphericPressure      | 10     | 03  | Int32      | Big(ABCD)    | 2   | x1       | 0001 894D           | 100685.0           | pascal
altitude                 | 12     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 4241 3333           | 48.3               | meter
temperature              | 14     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0B40                | 28.8               | celsius
temperatureAlarmStatus   | 15     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
fallAlarmStatus          | 16     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
fallAlarmEvent           | 17     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
helmetRemovalAlarmStatus | 18     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
helmetRemovalAlarmEvent  | 19     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
electricityProximityAlarmStatus | 20     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
electricityProximityAlarmEvent | 21     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
impactAlarmStatus        | 22     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
impactAlarmEvent         | 23     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
silenceAlarmStatus       | 24     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
silenceAlarmEvent        | 25     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
heightAccessAlarmStatus  | 26     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
heightAccessAlarmEvent   | 27     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
latitude                 | 28     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 41B5 F3A5           | 22.743967          | degrees
longitude                | 30     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 42E3 DBC1           | 113.929207         | degrees
positionAccuracy         | 32     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 4086 6666           | 4.20               | meter
gpsAbsoluteTimestamp     | 34     | 03  | UnixTime   | Big(ABCD)    | 2   | x1       | 69CB 2677           | 1774921335         | second
gpsTimeValid             | 36     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
beaconIdHex              | 37     | 03  | String(32B) | ASCII        | 16  | x1       | 0000 0000 0000 0000 ... |                    | none
beaconRssi               | 53     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
beaconBatteryLevel       | 54     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | percent
beaconBatteryValid       | 55     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
batteryLowAlarm          | 56     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
temperatureEvent         | 57     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
sosEvent                 | 58     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
safetyAlarmActive        | 59     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
isHeartbeat              | 60     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
mainVersion              | 61     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 69     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 77     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 85     | 03  | String(24B) | ASCII        | 12  | x1       | 4742 3130 3000 0000 ... | GB100              | none
rssi                     | 97     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFD5                | -43.0              | none
snr                      | 98     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000A                | 10.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774950925 second
batteryLevel 9 Int16 1 x1 29.0 percent
atmosphericPressure 10 Int32 2 x1 100685.0 pascal
altitude 12 Float32 2 x1 48.3 meter
temperature 14 Int16(S) 1 /100 28.8 celsius
temperatureAlarmStatus 15 Int16 1 x1 0.0 none
fallAlarmStatus 16 Bit/Bool 1 x1 false none
fallAlarmEvent 17 Bit/Bool 1 x1 false none
helmetRemovalAlarmStatus 18 Bit/Bool 1 x1 false none
helmetRemovalAlarmEvent 19 Bit/Bool 1 x1 false none
electricityProximityAlarmStatus 20 Bit/Bool 1 x1 false none
electricityProximityAlarmEvent 21 Bit/Bool 1 x1 false none
impactAlarmStatus 22 Bit/Bool 1 x1 false none
impactAlarmEvent 23 Bit/Bool 1 x1 false none
silenceAlarmStatus 24 Bit/Bool 1 x1 false none
silenceAlarmEvent 25 Bit/Bool 1 x1 false none
heightAccessAlarmStatus 26 Bit/Bool 1 x1 false none
heightAccessAlarmEvent 27 Bit/Bool 1 x1 false none
latitude 28 Float32 2 x1 22.743967 degrees
longitude 30 Float32 2 x1 113.929207 degrees
positionAccuracy 32 Float32 2 x1 4.20 meter
gpsAbsoluteTimestamp 34 UnixTime 2 x1 1774921335 second
gpsTimeValid 36 Bit/Bool 1 x1 true none
beaconIdHex 37 String(32B) 16 x1 none
beaconRssi 53 Int16 1 x1 0.0 none
beaconBatteryLevel 54 Int16 1 x1 0.0 percent
beaconBatteryValid 55 Bit/Bool 1 x1 false none
batteryLowAlarm 56 Bit/Bool 1 x1 false none
temperatureEvent 57 Bit/Bool 1 x1 false none
sosEvent 58 Bit/Bool 1 x1 true none
safetyAlarmActive 59 Bit/Bool 1 x1 false none
isHeartbeat 60 Bit/Bool 1 x1 true none
model 85 String(24B) 12 x1 GB100 none
rssi 97 Int16 1 x1 -43.0 none
snr 98 Int16 1 x1 10.0 none
7.11.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 8, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 93 (covers addresses 6–98), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.11.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.GB100 Smart Safety Helmet Device ID=107, so object instances start from 10700.

7.11.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 107
Target: 192.168.31.205:47808 | BACnet ID: 107 | Scan: 10700-10799
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 10700    | 0      | 76110FB7                 | ffffff100004e9c3.protocolLayoutHash
CV   | 10701    | 1      | 20260101                 | ffffff100004e9c3.profileVersion
BI   | 10702    | 2      | active                   | ffffff100004e9c3.online
AI   | 10703    | 3      | 1774922112.00            | ffffff100004e9c3.lastOnlineTime
AI   | 10704    | 4      | 29.00                    | ffffff100004e9c3.batteryLevel
AI   | 10705    | 5      | 100685.00                | ffffff100004e9c3.atmosphericPressure
AI   | 10706    | 6      | 48.30                    | ffffff100004e9c3.altitude
AI   | 10707    | 7      | 28.80                    | ffffff100004e9c3.temperature
AI   | 10708    | 8      | 0.00                     | ffffff100004e9c3.temperatureAlarmStatus
BI   | 10709    | 9      | inactive                 | ffffff100004e9c3.fallAlarmStatus
BI   | 10710    | 10     | inactive                 | ffffff100004e9c3.fallAlarmEvent
BI   | 10711    | 11     | inactive                 | ffffff100004e9c3.helmetRemovalAlarmStatus
BI   | 10712    | 12     | inactive                 | ffffff100004e9c3.helmetRemovalAlarmEvent
BI   | 10713    | 13     | inactive                 | ffffff100004e9c3.electricityProximityAlarmStatus
BI   | 10714    | 14     | inactive                 | ffffff100004e9c3.electricityProximityAlarmEvent
BI   | 10715    | 15     | inactive                 | ffffff100004e9c3.impactAlarmStatus
BI   | 10716    | 16     | inactive                 | ffffff100004e9c3.impactAlarmEvent
BI   | 10717    | 17     | inactive                 | ffffff100004e9c3.silenceAlarmStatus
BI   | 10718    | 18     | inactive                 | ffffff100004e9c3.silenceAlarmEvent
BI   | 10719    | 19     | inactive                 | ffffff100004e9c3.heightAccessAlarmStatus
BI   | 10720    | 20     | inactive                 | ffffff100004e9c3.heightAccessAlarmEvent
AI   | 10721    | 21     | 22.743967                | ffffff100004e9c3.latitude
AI   | 10722    | 22     | 113.929207               | ffffff100004e9c3.longitude
AI   | 10723    | 23     | 4.20                     | ffffff100004e9c3.positionAccuracy
AI   | 10724    | 24     | 1774921344.00            | ffffff100004e9c3.gpsAbsoluteTimestamp
BI   | 10725    | 25     | active                   | ffffff100004e9c3.gpsTimeValid
CV   | 10726    | 26     |                          | ffffff100004e9c3.beaconIdHex
AI   | 10727    | 27     | 0.00                     | ffffff100004e9c3.beaconRssi
AI   | 10728    | 28     | 0.00                     | ffffff100004e9c3.beaconBatteryLevel
BI   | 10729    | 29     | inactive                 | ffffff100004e9c3.beaconBatteryValid
BI   | 10730    | 30     | inactive                 | ffffff100004e9c3.batteryLowAlarm
BI   | 10731    | 31     | inactive                 | ffffff100004e9c3.temperatureEvent
BI   | 10732    | 32     | active                   | ffffff100004e9c3.sosEvent
BI   | 10733    | 33     | inactive                 | ffffff100004e9c3.safetyAlarmActive
BI   | 10734    | 34     | active                   | ffffff100004e9c3.isHeartbeat
CV   | 10735    | 35     |                          | ffffff100004e9c3.mainVersion
CV   | 10736    | 36     |                          | ffffff100004e9c3.appVersion
CV   | 10737    | 37     |                          | ffffff100004e9c3.hardwareVersion
CV   | 10738    | 38     | GB100                    | ffffff100004e9c3.model
AI   | 10739    | 39     | -43.00                   | ffffff100004e9c3.rssi
AI   | 10740    | 40     | 10.00                    | ffffff100004e9c3.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 10702 online active
AI 10703 lastOnlineTime 1774922112.00
AI 10704 batteryLevel 29.00
AI 10705 atmosphericPressure 100685.00
AI 10706 altitude 48.30
AI 10707 temperature 28.80
AI 10708 temperatureAlarmStatus 0.00
BI 10709 fallAlarmStatus inactive
BI 10710 fallAlarmEvent inactive
BI 10711 helmetRemovalAlarmStatus inactive
BI 10712 helmetRemovalAlarmEvent inactive
BI 10713 electricityProximityAlarmStatus inactive
BI 10714 electricityProximityAlarmEvent inactive
BI 10715 impactAlarmStatus inactive
BI 10716 impactAlarmEvent inactive
BI 10717 silenceAlarmStatus inactive
BI 10718 silenceAlarmEvent inactive
BI 10719 heightAccessAlarmStatus inactive
BI 10720 heightAccessAlarmEvent inactive
AI 10721 latitude 22.743967
AI 10722 longitude 113.929207
AI 10723 positionAccuracy 4.20
AI 10724 gpsAbsoluteTimestamp 1774921344.00
BI 10725 gpsTimeValid active
CV 10726 beaconIdHex
AI 10727 beaconRssi 0.00
AI 10728 beaconBatteryLevel 0.00
BI 10729 beaconBatteryValid inactive
BI 10730 batteryLowAlarm inactive
BI 10731 temperatureEvent inactive
BI 10732 sosEvent active
BI 10733 safetyAlarmActive inactive
BI 10734 isHeartbeat active
CV 10738 model GB100
AI 10739 rssi -43.00
AI 10740 snr 10.00
7.11.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 107 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10704); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.11.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff100004e9c3" | jq .
{
  "devEui": "ffffff100004e9c3",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 17:55:25",
  "params": {
    "batteryLevel": 29,
    "atmosphericPressure": 100685,
    "altitude": 48.3,
    "temperature": 28.8,
    "temperatureAlarmStatus": 0,
    "fallAlarmStatus": false,
    "fallAlarmEvent": false,
    "helmetRemovalAlarmStatus": false,
    "helmetRemovalAlarmEvent": false,
    "electricityProximityAlarmStatus": false,
    "electricityProximityAlarmEvent": false,
    "impactAlarmStatus": false,
    "impactAlarmEvent": false,
    "silenceAlarmStatus": false,
    "silenceAlarmEvent": false,
    "heightAccessAlarmStatus": false,
    "heightAccessAlarmEvent": false,
    "latitude": 22.743967,
    "longitude": 113.929207,
    "positionAccuracy": 4.2,
    "gpsAbsoluteTimestamp": 1774921335,
    "gpsTimeValid": true,
    "beaconBatteryValid": false,
    "batteryLowAlarm": false,
    "temperatureEvent": false,
    "sosEvent": true,
    "safetyAlarmActive": false,
    "isHeartbeat": true,
    "model": "GB100"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -43,
    "snr": 10,
    "frequency": 482700000,
    "spreadingFactor": 7,
    "bandwidth": 125000,
    "fCnt": 1913,
    "fPort": 210,
    "confirmed": false,
    "size": 32,
    "rawData": "5C78000000000000000000000000000000000000000000000000000000000000"
  }
}
Note: devEui=ffffff100004e9c3 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.12 Retrieving Data from the AN-201G Vibrating Wire Strain Gauge

AN-201G is a LoRaWAN vibrating-wire strain gauge sensor for structural stress/strain monitoring in buildings, bridges, and similar structures. It reports frequency, frequency value, temperature, and calculated steel/concrete strain values.

deviceinformation:devEui=ffffff100004e9c8,Modbus Slave ID=10,BACnet Device ID=109,gateway IP=192.168.31.205

7.12.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 10(可configuration,range 2–201)。

7.12.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ 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       | 69CB 41F1           | 1774928369         | second
batteryVoltage           | 9      | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 015A                | 3.46               | volt
batteryVoltageState      | 10     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
timestamp                | 11     | 03  | Int32      | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.0                | seconds
vibratingWireSensorModel | 13     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
frequency                | 14     | 03  | Float32    | Big(ABCD)    | 2   | /100     | 47A7 4F80           | 856.63             | Hz
frequencyDigit           | 16     | 03  | Float32    | Big(ABCD)    | 2   | /100     | 478F 5280           | 733.81             | digit
temperature              | 18     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0AA0                | 27.2               | 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
initialTemperature       | 25     | 03  | Int16(S)   | Big(ABCD)    | 1   | /10      | 0114                | 27.6               | degrees_celsius
steelStructureStrain     | 26     | 03  | Float32    | Big(ABCD)    | 2   | /100     | 4150 0000           | 0.13               | microstrain
concreteStructureStrain  | 28     | 03  | Float32    | Big(ABCD)    | 2   | /100     | C26B FFFF           | -0.59              | microstrain
batteryLowAlarm          | 30     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
isHeartbeat              | 31     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
mainVersion              | 32     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 40     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 48     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 56     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D32 3031 4700 ... | AN-201G            | none
rssi                     | 68     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFD1                | -47.0              | none
snr                      | 69     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000B                | 11.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774928369 second
batteryVoltage 9 Int16(S) 1 /100 3.46 volt
batteryVoltageState 10 Int16 1 x1 0.0 none
timestamp 11 Int32 2 x1 0.0 seconds
vibratingWireSensorModel 13 Int16 1 x1 1.0 none
frequency 14 Float32 2 /100 856.63 Hz
frequencyDigit 16 Float32 2 /100 733.81 digit
temperature 18 Int16(S) 1 /100 27.2 celsius
correctionFactor 19 Float32 2 /10000 1.0000 none
initialFrequency 21 Float32 2 /100 856.61 Hz
initialFrequencyDigit 23 Float32 2 /100 733.78 digit
initialTemperature 25 Int16(S) 1 /10 27.6 degrees_celsius
steelStructureStrain 26 Float32 2 /100 0.13 microstrain
concreteStructureStrain 28 Float32 2 /100 -0.59 microstrain
batteryLowAlarm 30 Bit/Bool 1 x1 false none
isHeartbeat 31 Bit/Bool 1 x1 true none
model 56 String(24B) 12 x1 AN-201G none
rssi 68 Int16 1 x1 -47.0 none
snr 69 Int16 1 x1 11.0 none
7.12.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 10, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 64 (covers addresses 6–69), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.12.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset. The AN-201G vibrating wire strain gauge has Device ID=109, so object instances start from 10900.

7.12.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ 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
------------------------------------------------------------------------------------------------------------
CV   | 10900    | 0      | 3CBB017B                 | ffffff100004e9c8.protocolLayoutHash
CV   | 10901    | 1      | 20260101                 | ffffff100004e9c8.profileVersion
BI   | 10902    | 2      | active                   | ffffff100004e9c8.online
AI   | 10903    | 3      | 1774928384.00            | ffffff100004e9c8.lastOnlineTime
AI   | 10904    | 4      | 3.46                     | ffffff100004e9c8.batteryVoltage
AI   | 10905    | 5      | 0.00                     | ffffff100004e9c8.batteryVoltageState
AI   | 10906    | 6      | 0.00                     | ffffff100004e9c8.timestamp
AI   | 10907    | 7      | 1.00                     | ffffff100004e9c8.vibratingWireSensorModel
AI   | 10908    | 8      | 856.63                   | ffffff100004e9c8.frequency
AI   | 10909    | 9      | 733.81                   | ffffff100004e9c8.frequencyDigit
AI   | 10910    | 10     | 27.20                    | ffffff100004e9c8.temperature
AI   | 10911    | 11     | 1.00                     | ffffff100004e9c8.correctionFactor
AI   | 10912    | 12     | 856.61                   | ffffff100004e9c8.initialFrequency
AI   | 10913    | 13     | 733.78                   | ffffff100004e9c8.initialFrequencyDigit
AI   | 10914    | 14     | 27.60                    | ffffff100004e9c8.initialTemperature
AI   | 10915    | 15     | 0.13                     | ffffff100004e9c8.steelStructureStrain
AI   | 10916    | 16     | -0.59                    | ffffff100004e9c8.concreteStructureStrain
BI   | 10917    | 17     | inactive                 | ffffff100004e9c8.batteryLowAlarm
BI   | 10918    | 18     | active                   | ffffff100004e9c8.isHeartbeat
CV   | 10919    | 19     |                          | ffffff100004e9c8.mainVersion
CV   | 10920    | 20     |                          | ffffff100004e9c8.appVersion
CV   | 10921    | 21     |                          | ffffff100004e9c8.hardwareVersion
CV   | 10922    | 22     | AN-201G                  | ffffff100004e9c8.model
AI   | 10923    | 23     | -47.00                   | ffffff100004e9c8.rssi
AI   | 10924    | 24     | 11.00                    | ffffff100004e9c8.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 10902 online active
AI 10903 lastOnlineTime 1774928384.00
AI 10904 batteryVoltage 3.46
AI 10905 batteryVoltageState 0.00
AI 10906 timestamp 0.00
AI 10907 vibratingWireSensorModel 1.00
AI 10908 frequency 856.63
AI 10909 frequencyDigit 733.81
AI 10910 temperature 27.20
AI 10911 correctionFactor 1.00
AI 10912 initialFrequency 856.61
AI 10913 initialFrequencyDigit 733.78
AI 10914 initialTemperature 27.60
AI 10915 steelStructureStrain 0.13
AI 10916 concreteStructureStrain -0.59
BI 10917 batteryLowAlarm inactive
BI 10918 isHeartbeat active
CV 10922 model AN-201G
AI 10923 rssi -47.00
AI 10924 snr 11.00
7.12.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 109 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10904); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.12.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff100004e9c8" | jq .
{
  "devEui": "ffffff100004e9c8",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 11:39:29",
  "params": {
    "batteryVoltage": 3.46,
    "batteryVoltageState": 0,
    "timestamp": 0,
    "vibratingWireSensorModel": 1,
    "frequency": 856.63,
    "frequencyDigit": 733.81,
    "temperature": 27.2,
    "correctionFactor": 1,
    "initialFrequency": 856.61,
    "initialFrequencyDigit": 733.78,
    "initialTemperature": 27.6,
    "steelStructureStrain": 0.13,
    "concreteStructureStrain": -0.59,
    "batteryLowAlarm": false,
    "isHeartbeat": true,
    "model": "AN-201G"
  },
  "rxParams": {
    "gatewayId": "0010502df4563610",
    "rssi": -47,
    "snr": 11,
    "frequency": 481500000,
    "spreadingFactor": 9,
    "bandwidth": 125000,
    "fCnt": 8,
    "fPort": 210,
    "confirmed": false,
    "size": 33,
    "rawData": "000162040D817D006D007900000000DD01DC00014E9FAA0110DC00014E9DAA0114"
  }
}
Note: devEui=ffffff100004e9c8 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.13 Getting Data from the AN-204 Water Leak Sensor

AN-204 is a LoRaWAN water leakage sensor that immediately reports an alarm event and duration when water is detected. Suitable for server rooms, pipelines, basements, and other water-protection monitoring applications.

deviceinformation:devEui=ffffff1000048428,Modbus Slave ID=11,BACnet Device ID=111,gateway IP=192.168.31.205

7.13.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 11(可configuration,range 2–201)。

7.13.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 11 --sensorType AN-204
Target: 192.168.31.205:502 | Slave ID: 11 | Sensor: AN-204
================================================================================================================================================================
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       | 69CB B0E5           | 1774956773         | second
batteryVoltage           | 9      | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 010A                | 2.66               | volt
waterStatus              | 10     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
waterDuration            | 11     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | minute
batteryLowEvent          | 12     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
waterEvent               | 13     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
mainVersion              | 14     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 22     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 30     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 38     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D32 3034 0000 ... | AN-204             | none
rssi                     | 50     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFB4                | -76.0              | none
snr                      | 51     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000D                | 13.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774956773 second
batteryVoltage 9 Int16(S) 1 /100 2.66 volt
waterStatus 10 Bit/Bool 1 x1 false none
waterDuration 11 Int16 1 x1 0.0 minute
batteryLowEvent 12 Bit/Bool 1 x1 false none
waterEvent 13 Bit/Bool 1 x1 false none
model 38 String(24B) 12 x1 AN-204 none
rssi 50 Int16 1 x1 -76.0 none
snr 51 Int16 1 x1 13.0 none
7.13.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 11, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 46 (covers addresses 6–51), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.13.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.AN-204 Water Leakage Sensor Device ID=111, so object instances start from 11100.

7.13.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 111
Target: 192.168.31.205:47808 | BACnet ID: 111 | Scan: 11100-11199
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 11100    | 0      | BE4C1C28                 | ffffff1000048428.protocolLayoutHash
CV   | 11101    | 1      | 20260101                 | ffffff1000048428.profileVersion
BI   | 11102    | 2      | active                   | ffffff1000048428.online
AI   | 11103    | 3      | 1775029504.00            | ffffff1000048428.lastOnlineTime
AI   | 11104    | 4      | 2.66                     | ffffff1000048428.batteryVoltage
BI   | 11105    | 5      | inactive                 | ffffff1000048428.waterStatus
AI   | 11106    | 6      | 0.00                     | ffffff1000048428.waterDuration
BI   | 11107    | 7      | inactive                 | ffffff1000048428.batteryLowEvent
BI   | 11108    | 8      | inactive                 | ffffff1000048428.waterEvent
CV   | 11109    | 9      |                          | ffffff1000048428.mainVersion
CV   | 11110    | 10     |                          | ffffff1000048428.appVersion
CV   | 11111    | 11     |                          | ffffff1000048428.hardwareVersion
CV   | 11112    | 12     | AN-204                   | ffffff1000048428.model
AI   | 11113    | 13     | -69.00                   | ffffff1000048428.rssi
AI   | 11114    | 14     | 13.00                    | ffffff1000048428.snr
7.13.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 111 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-11104); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.13.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff1000048428" | jq .
{
  "devEui": "ffffff1000048428",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 19:32:53",
  "params": {
    "batteryVoltage": 2.66,
    "waterStatus": false,
    "waterDuration": 0,
    "batteryLowEvent": false,
    "waterEvent": false,
    "model": "AN-204"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -76,
    "snr": 13,
    "frequency": 481700000,
    "spreadingFactor": 7,
    "bandwidth": 125000,
    "fCnt": 5192,
    "fPort": 210,
    "confirmed": false,
    "size": 13,
    "rawData": "5C780000000000000000000000"
  }
}
Note: devEui=ffffff1000048428 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.14 Getting Data from the AN-113 Tilt Angle Sensor

AN-113 is a LoRaWAN tilt sensor that monitors device inclination in real time and supports acceleration and tilt alarms. Suitable for tower cranes, utility poles, slopes, and other tilt-monitoring applications.

deviceinformation:devEui=ffffff100004c8b3,Modbus Slave ID=12,BACnet Device ID=112,gateway IP=192.168.31.205

7.14.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 12(可configuration,range 2–201)。

7.14.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 12 --sensorType AN-113
Target: 192.168.31.205:502 | Slave ID: 12 | Sensor: AN-113
================================================================================================================================================================
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       | 69CB 416F           | 1774928239         | second
batteryVoltage           | 9      | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 01A2                | 4.18               | volt
batteryVoltageState      | 10     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
tamper                   | 11     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
tiltAngle                | 12     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0003                | 3.0                | degree
accelerationAlarm        | 13     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
tiltAlarm                | 14     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
batteryLowEvent          | 15     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
tamperEvent              | 16     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
mainVersion              | 17     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 25     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 33     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 41     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D31 3133 0000 ... | AN-113             | none
rssi                     | 53     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFD0                | -48.0              | none
snr                      | 54     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000C                | 12.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774928239 second
batteryVoltage 9 Int16(S) 1 /100 4.18 volt
batteryVoltageState 10 Int16 1 x1 0.0 none
tamper 11 Int16 1 x1 1.0 none
tiltAngle 12 Int16 1 x1 3.0 degree
accelerationAlarm 13 Bit/Bool 1 x1 false none
tiltAlarm 14 Bit/Bool 1 x1 false none
batteryLowEvent 15 Bit/Bool 1 x1 false none
tamperEvent 16 Int16 1 x1 0.0 none
model 41 String(24B) 12 x1 AN-113 none
rssi 53 Int16 1 x1 -48.0 none
snr 54 Int16 1 x1 12.0 none
7.14.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 12, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 49 (covers addresses 6–54), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.14.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.AN-113 Tilt Sensor Device ID=112, so object instances start from 11200.

7.14.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 112
Target: 192.168.31.205:47808 | BACnet ID: 112 | Scan: 11200-11299
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 11200    | 0      | 3C236440                 | ffffff100004c8b3.protocolLayoutHash
CV   | 11201    | 1      | 20260101                 | ffffff100004c8b3.profileVersion
BI   | 11202    | 2      | active                   | ffffff100004c8b3.online
AI   | 11203    | 3      | 1774928256.00            | ffffff100004c8b3.lastOnlineTime
AI   | 11204    | 4      | 4.18                     | ffffff100004c8b3.batteryVoltage
AI   | 11205    | 5      | 0.00                     | ffffff100004c8b3.batteryVoltageState
AI   | 11206    | 6      | 1.00                     | ffffff100004c8b3.tamper
AI   | 11207    | 7      | 3.00                     | ffffff100004c8b3.tiltAngle
BI   | 11208    | 8      | inactive                 | ffffff100004c8b3.accelerationAlarm
BI   | 11209    | 9      | inactive                 | ffffff100004c8b3.tiltAlarm
BI   | 11210    | 10     | inactive                 | ffffff100004c8b3.batteryLowEvent
AI   | 11211    | 11     | 0.00                     | ffffff100004c8b3.tamperEvent
CV   | 11212    | 12     |                          | ffffff100004c8b3.mainVersion
CV   | 11213    | 13     |                          | ffffff100004c8b3.appVersion
CV   | 11214    | 14     |                          | ffffff100004c8b3.hardwareVersion
CV   | 11215    | 15     | AN-113                   | ffffff100004c8b3.model
AI   | 11216    | 16     | -48.00                   | ffffff100004c8b3.rssi
AI   | 11217    | 17     | 12.00                    | ffffff100004c8b3.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 11202 online active
AI 11203 lastOnlineTime 1774928256.00
AI 11204 batteryVoltage 4.18
AI 11205 batteryVoltageState 0.00
AI 11206 tamper 1.00
AI 11207 tiltAngle 3.00
BI 11208 accelerationAlarm inactive
BI 11209 tiltAlarm inactive
BI 11210 batteryLowEvent inactive
AI 11211 tamperEvent 0.00
CV 11215 model AN-113
AI 11216 rssi -48.00
AI 11217 snr 12.00
7.14.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 112 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-11204); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.14.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff100004c8b3" | jq .
{
  "devEui": "ffffff100004c8b3",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 11:37:19",
  "params": {
    "batteryVoltage": 4.18,
    "batteryVoltageState": 0,
    "tamper": 1,
    "tiltAngle": 3,
    "accelerationAlarm": false,
    "tiltAlarm": false,
    "batteryLowEvent": false,
    "model": "AN-113"
  },
  "rxParams": {
    "gatewayId": "0010502df4563610",
    "rssi": -48,
    "snr": 12,
    "frequency": 481500000,
    "spreadingFactor": 9,
    "bandwidth": 125000,
    "fCnt": 412,
    "fPort": 210,
    "confirmed": false,
    "size": 19,
    "rawData": "00013C0410507D0077016D006B0003A800C200"
  }
}
Note: devEui=ffffff100004c8b3 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.15 Getting Data from the AN-308 Illuminance Sensor

AN-308 is a LoRaWAN illuminance sensor that measures ambient light intensity (lux). Suitable for smart lighting control and ambient light monitoring applications.

deviceinformation:devEui=ffffff100004c8be,Modbus Slave ID=13,BACnet Device ID=113,gateway IP=192.168.31.205

7.15.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 13(可configuration,range 2–201)。

7.15.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 13 --sensorType AN-308
Target: 192.168.31.205:502 | Slave ID: 13 | Sensor: AN-308
================================================================================================================================================================
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       | 69CB B057           | 1774956631         | second
batteryVoltage           | 9      | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 016D                | 3.65               | volt
batteryVoltageState      | 10     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
tamper                   | 11     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
illuminance              | 12     | 03  | Int32      | Big(ABCD)    | 2   | x1       | 0000 003F           | 63.0               | lux
batteryLowEvent          | 14     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
tamperEvent              | 15     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
mainVersion              | 16     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 24     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 32     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 40     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D33 3038 0000 ... | AN-308             | none
rssi                     | 52     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFBC                | -68.0              | none
snr                      | 53     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000B                | 11.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774956631 second
batteryVoltage 9 Int16(S) 1 /100 3.65 volt
batteryVoltageState 10 Int16 1 x1 0.0 none
tamper 11 Int16 1 x1 0.0 none
illuminance 12 Int32 2 x1 63.0 lux
batteryLowEvent 14 Bit/Bool 1 x1 false none
tamperEvent 15 Int16 1 x1 0.0 none
model 40 String(24B) 12 x1 AN-308 none
rssi 52 Int16 1 x1 -68.0 none
snr 53 Int16 1 x1 11.0 none
7.15.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 13, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 48 (covers addresses 6–53), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.15.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.AN-308 Illuminance Sensor Device ID=113, so object instances start from 11300.

7.15.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 113
Target: 192.168.31.205:47808 | BACnet ID: 113 | Scan: 11300-11399
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 11300    | 0      | 23B20934                 | ffffff100004c8be.protocolLayoutHash
CV   | 11301    | 1      | 20260101                 | ffffff100004c8be.profileVersion
BI   | 11302    | 2      | active                   | ffffff100004c8be.online
AI   | 11303    | 3      | 1774927872.00            | ffffff100004c8be.lastOnlineTime
AI   | 11304    | 4      | 3.65                     | ffffff100004c8be.batteryVoltage
AI   | 11305    | 5      | 0.00                     | ffffff100004c8be.batteryVoltageState
AI   | 11306    | 6      | 0.00                     | ffffff100004c8be.tamper
AI   | 11307    | 7      | 63.00                    | ffffff100004c8be.illuminance
BI   | 11308    | 8      | inactive                 | ffffff100004c8be.batteryLowEvent
AI   | 11309    | 9      | 0.00                     | ffffff100004c8be.tamperEvent
CV   | 11310    | 10     |                          | ffffff100004c8be.mainVersion
CV   | 11311    | 11     |                          | ffffff100004c8be.appVersion
CV   | 11312    | 12     |                          | ffffff100004c8be.hardwareVersion
CV   | 11313    | 13     | AN-308                   | ffffff100004c8be.model
AI   | 11314    | 14     | -68.00                   | ffffff100004c8be.rssi
AI   | 11315    | 15     | 11.00                    | ffffff100004c8be.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 11302 online active
AI 11303 lastOnlineTime 1774927872.00
AI 11304 batteryVoltage 3.65
AI 11305 batteryVoltageState 0.00
AI 11306 tamper 0.00
AI 11307 illuminance 63.00
BI 11308 batteryLowEvent inactive
AI 11309 tamperEvent 0.00
CV 11313 model AN-308
AI 11314 rssi -68.00
AI 11315 snr 11.00
7.15.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 113 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-11304); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.15.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff100004c8be" | jq .
{
  "devEui": "ffffff100004c8be",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 19:30:31",
  "params": {
    "batteryVoltage": 3.65,
    "batteryVoltageState": 0,
    "tamper": 0,
    "illuminance": 63,
    "batteryLowEvent": false,
    "model": "AN-308"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -68,
    "snr": 11,
    "frequency": 482300000,
    "spreadingFactor": 7,
    "bandwidth": 125000,
    "fCnt": 49423,
    "fPort": 210,
    "confirmed": false,
    "size": 15,
    "rawData": "5C7800000000000000000000000000"
  }
}
Note: devEui=ffffff100004c8be is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.16 Retrieving Data from the CM100 Beacon Receiver

CM100 is a LoRaWAN Bluetooth beacon receiver that scans nearby BLE beacons for ID, signal strength (RSSI), and battery level. Suitable for indoor personnel/asset positioning applications.

deviceinformation:devEui=ffffff100004d12a,Modbus Slave ID=14,BACnet Device ID=114,gateway IP=192.168.31.205

7.16.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 14(可configuration,range 2–201)。

7.16.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 14 --sensorType CM100
Target: 192.168.31.205:502 | Slave ID: 14 | Sensor: CM100
================================================================================================================================================================
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       | 69CB 92F0           | 1774949104         | second
batteryLevel             | 9      | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0007                | 7.0                | percent
beaconIdHex              | 10     | 03  | String(32B) | ASCII        | 16  | x1       | 3030 3636 3536 3245 ... | 0066562E           | none
beaconRssi               | 26     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFB0                | -80.0              | none
beaconBatteryLevel       | 27     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0064                | 100.0              | percent
beaconBatteryValid       | 28     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
batteryLowAlarm          | 29     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
sosEvent                 | 30     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
isHeartbeat              | 31     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
mainVersion              | 32     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 40     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 48     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 56     | 03  | String(24B) | ASCII        | 12  | x1       | 434D 3130 3000 0000 ... | CM100              | none
rssi                     | 68     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFAF                | -81.0              | none
snr                      | 69     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000C                | 12.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774949104 second
batteryLevel 9 Int16 1 x1 7.0 percent
beaconIdHex 10 String(32B) 16 x1 0066562E none
beaconRssi 26 Int16 1 x1 -80.0 none
beaconBatteryLevel 27 Int16 1 x1 100.0 percent
beaconBatteryValid 28 Bit/Bool 1 x1 true none
batteryLowAlarm 29 Bit/Bool 1 x1 false none
sosEvent 30 Bit/Bool 1 x1 false none
isHeartbeat 31 Bit/Bool 1 x1 false none
model 56 String(24B) 12 x1 CM100 none
rssi 68 Int16 1 x1 -81.0 none
snr 69 Int16 1 x1 12.0 none
7.16.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 14, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 64 (covers addresses 6–69), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.16.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset. The CM100 beacon receiver has Device ID=114, so object instances start from 11400.

7.16.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 114
Target: 192.168.31.205:47808 | BACnet ID: 114 | Scan: 11400-11499
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 11400    | 0      | 03713CE6                 | ffffff100004d12a.protocolLayoutHash
CV   | 11401    | 1      | 20260101                 | ffffff100004d12a.profileVersion
BI   | 11402    | 2      | active                   | ffffff100004d12a.online
AI   | 11403    | 3      | 1774920320.00            | ffffff100004d12a.lastOnlineTime
AI   | 11404    | 4      | 7.00                     | ffffff100004d12a.batteryLevel
CV   | 11405    | 5      | 0066562E                 | ffffff100004d12a.beaconIdHex
AI   | 11406    | 6      | -80.00                   | ffffff100004d12a.beaconRssi
AI   | 11407    | 7      | 100.00                   | ffffff100004d12a.beaconBatteryLevel
BI   | 11408    | 8      | active                   | ffffff100004d12a.beaconBatteryValid
BI   | 11409    | 9      | inactive                 | ffffff100004d12a.batteryLowAlarm
BI   | 11410    | 10     | inactive                 | ffffff100004d12a.sosEvent
BI   | 11411    | 11     | inactive                 | ffffff100004d12a.isHeartbeat
CV   | 11412    | 12     |                          | ffffff100004d12a.mainVersion
CV   | 11413    | 13     |                          | ffffff100004d12a.appVersion
CV   | 11414    | 14     |                          | ffffff100004d12a.hardwareVersion
CV   | 11415    | 15     | CM100                    | ffffff100004d12a.model
AI   | 11416    | 16     | -81.00                   | ffffff100004d12a.rssi
AI   | 11417    | 17     | 12.00                    | ffffff100004d12a.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 11402 online active
AI 11403 lastOnlineTime 1774920320.00
AI 11404 batteryLevel 7.00
CV 11405 beaconIdHex 0066562E
AI 11406 beaconRssi -80.00
AI 11407 beaconBatteryLevel 100.00
BI 11408 beaconBatteryValid active
BI 11409 batteryLowAlarm inactive
BI 11410 sosEvent inactive
BI 11411 isHeartbeat inactive
CV 11415 model CM100
AI 11416 rssi -81.00
AI 11417 snr 12.00
7.16.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP 192.168.31.205, Port 47808
  2. In the left device tree, expand Device 114 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-11404); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.16.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff100004d12a" | jq .
{
  "devEui": "ffffff100004d12a",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 17:25:04",
  "params": {
    "batteryLevel": 7,
    "beaconIdHex": "0066562E",
    "beaconRssi": -80,
    "beaconBatteryLevel": 100,
    "beaconBatteryValid": true,
    "batteryLowAlarm": false,
    "sosEvent": false,
    "isHeartbeat": false,
    "model": "CM100"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -81,
    "snr": 12,
    "frequency": 481500000,
    "spreadingFactor": 7,
    "bandwidth": 125000,
    "fCnt": 2182,
    "fPort": 210,
    "confirmed": false,
    "size": 114,
    "rawData": "5C7800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  }
}
Note: devEui=ffffff100004d12a is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.17 Retrieving Data from the AN-303 Temperature & Humidity Sensor (GW 193)

Same model as in Section 7.2, but connected to a second gateway at 192.168.31.193.

deviceinformation:devEui=ffffff200000b702,Modbus Slave ID=6,BACnet Device ID=105,gateway IP=192.168.31.193

7.17.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 6(可configuration,range 2–201)。

7.17.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.193 --port 502 --slaveId 6 --sensorType AN-303
Target: 192.168.31.193:502 | Slave ID: 6 | Sensor: AN-303
================================================================================================================================================================
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       | 69CB 4229           | 1774928425         | second
temperature              | 9      | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0A0A                | 25.7               | celsius
temperatureState         | 10     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
humidity                 | 11     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 1676                | 57.5               | percent
humidityState            | 12     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
batteryVoltage           | 13     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0169                | 3.61               | volt
batteryVoltageState      | 14     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
tamper                   | 15     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
mainVersion              | 16     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 24     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 32     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 40     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D33 3033 0000 ... | AN-303             | none
rssi                     | 52     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFDF                | -33.0              | none
snr                      | 53     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000D                | 13.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774928425 second
temperature 9 Int16(S) 1 /100 25.7 celsius
temperatureState 10 Int16 1 x1 0.0 none
humidity 11 Int16(S) 1 /100 57.5 percent
humidityState 12 Int16 1 x1 0.0 none
batteryVoltage 13 Int16(S) 1 /100 3.61 volt
batteryVoltageState 14 Int16 1 x1 0.0 none
tamper 15 Int16 1 x1 1.0 none
model 40 String(24B) 12 x1 AN-303 none
rssi 52 Int16 1 x1 -33.0 none
snr 53 Int16 1 x1 13.0 none
7.17.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.193、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 6, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 48 (covers addresses 6–53), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.17.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.AN-303 Temperature & Humidity Sensor (GW193) Device ID=105, so object instances start from 10500.

7.17.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 105
Target: 192.168.31.193:47808 | BACnet ID: 105 | Scan: 10500-10599
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 10500    | 0      | 1966B122                 | ffffff200000b702.protocolLayoutHash
CV   | 10501    | 1      | 20260101                 | ffffff200000b702.profileVersion
BI   | 10502    | 2      | active                   | ffffff200000b702.online
AI   | 10503    | 3      | 1774928384.00            | ffffff200000b702.lastOnlineTime
AI   | 10504    | 4      | 25.70                    | ffffff200000b702.temperature
AI   | 10505    | 5      | 0.00                     | ffffff200000b702.temperatureState
AI   | 10506    | 6      | 57.50                    | ffffff200000b702.humidity
AI   | 10507    | 7      | 0.00                     | ffffff200000b702.humidityState
AI   | 10508    | 8      | 3.61                     | ffffff200000b702.batteryVoltage
AI   | 10509    | 9      | 0.00                     | ffffff200000b702.batteryVoltageState
AI   | 10510    | 10     | 1.00                     | ffffff200000b702.tamper
CV   | 10511    | 11     |                          | ffffff200000b702.mainVersion
CV   | 10512    | 12     |                          | ffffff200000b702.appVersion
CV   | 10513    | 13     |                          | ffffff200000b702.hardwareVersion
CV   | 10514    | 14     | AN-303                   | ffffff200000b702.model
AI   | 10515    | 15     | -33.00                   | ffffff200000b702.rssi
AI   | 10516    | 16     | 13.00                    | ffffff200000b702.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 10502 online active
AI 10503 lastOnlineTime 1774928384.00
AI 10504 temperature 25.70
AI 10505 temperatureState 0.00
AI 10506 humidity 57.50
AI 10507 humidityState 0.00
AI 10508 batteryVoltage 3.61
AI 10509 batteryVoltageState 0.00
AI 10510 tamper 1.00
CV 10514 model AN-303
AI 10515 rssi -33.00
AI 10516 snr 13.00
7.17.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP 192.168.31.193,Port 47808
  2. In the left device tree, expand Device 105 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10504); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.17.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.193:8070/api/getStatus?devEui=ffffff200000b702" | jq .
{
  "devEui": "ffffff200000b702",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 11:40:25",
  "params": {
    "temperature": 25.7,
    "humidity": 57.5,
    "batteryVoltage": 3.61,
    "batteryVoltageState": 0,
    "tamper": 1,
    "model": "AN-303"
  },
  "rxParams": {
    "gatewayId": "0010502df4563612",
    "rssi": -33,
    "snr": 13,
    "frequency": 902900000,
    "spreadingFactor": 9,
    "bandwidth": 125000,
    "fCnt": 52187,
    "fPort": 210,
    "confirmed": true,
    "size": 18,
    "rawData": "000103040E157D007701100A0812023F0301"
  }
}
Note: devEui=ffffff200000b702 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.18 Getting Data from the AN-305 Door Contact Sensor

AN-305 is a LoRaWAN door/window magnetic sensor that detects open/closed states. Suitable for access control, security, and smart-home applications.

deviceinformation:devEui=ffffff100004bcf0,Modbus Slave ID=2,BACnet Device ID=101,gateway IP=192.168.31.193

7.18.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 2(可configuration,range 2–201)。

7.18.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.193 --port 502 --slaveId 2 --sensorType AN-305
Target: 192.168.31.193:502 | Slave ID: 2 | Sensor: AN-305
================================================================================================================================================================
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       | 69CB ACBC           | 1774955708         | second
doorState                | 9      | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
batteryVoltage           | 10     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 012C                | 3.00               | volt
batteryVoltageState      | 11     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
tamperStatus             | 12     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
batteryLevel             | 13     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | percent
tamperEvent              | 14     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
doorEvent                | 15     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
mainVersion              | 16     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 24     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 32     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 40     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D33 3035 0000 ... | AN-305             | none
rssi                     | 52     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFAA                | -86.0              | none
snr                      | 53     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0008                | 8.0                | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774955708 second
doorState 9 Int16 1 x1 1.0 none
batteryVoltage 10 Int16(S) 1 /100 3.00 volt
batteryVoltageState 11 Int16 1 x1 0.0 none
tamperStatus 12 Bit/Bool 1 x1 true none
batteryLevel 13 Int16 1 x1 0.0 percent
tamperEvent 14 Int16 1 x1 0.0 none
doorEvent 15 Int16 1 x1 0.0 none
model 40 String(24B) 12 x1 AN-305 none
rssi 52 Int16 1 x1 -86.0 none
snr 53 Int16 1 x1 8.0 none
7.18.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.193、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 2, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 48 (covers addresses 6–53), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.18.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.AN-305 Door Sensor Device ID=101, so object instances start from 10100.

7.18.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.193 --port 47808 --id 101
Target: 192.168.31.193:47808 | BACnet ID: 101 | Scan: 10100-10199
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 10100    | 0      | 788B992B                 | ffffff100004bcf0.protocolLayoutHash
CV   | 10101    | 1      | 20260101                 | ffffff100004bcf0.profileVersion
BI   | 10102    | 2      | active                   | ffffff100004bcf0.online
AI   | 10103    | 3      | 1774926848.00            | ffffff100004bcf0.lastOnlineTime
BI   | 10104    | 4      | active                   | ffffff100004bcf0.doorState
AI   | 10105    | 5      | 3.00                     | ffffff100004bcf0.batteryVoltage
AI   | 10106    | 6      | 0.00                     | ffffff100004bcf0.batteryVoltageState
BI   | 10107    | 7      | active                   | ffffff100004bcf0.tamperStatus
AI   | 10108    | 8      | 0.00                     | ffffff100004bcf0.batteryLevel
AI   | 10109    | 9      | 0.00                     | ffffff100004bcf0.tamperEvent
AI   | 10110    | 10     | 0.00                     | ffffff100004bcf0.doorEvent
CV   | 10111    | 11     |                          | ffffff100004bcf0.mainVersion
CV   | 10112    | 12     |                          | ffffff100004bcf0.appVersion
CV   | 10113    | 13     |                          | ffffff100004bcf0.hardwareVersion
CV   | 10114    | 14     | AN-305                   | ffffff100004bcf0.model
AI   | 10115    | 15     | -86.00                   | ffffff100004bcf0.rssi
AI   | 10116    | 16     | 8.00                     | ffffff100004bcf0.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 10102 online active
AI 10103 lastOnlineTime 1774926848.00
BI 10104 doorState active
AI 10105 batteryVoltage 3.00
AI 10106 batteryVoltageState 0.00
BI 10107 tamperStatus active
AI 10108 batteryLevel 0.00
AI 10109 tamperEvent 0.00
AI 10110 doorEvent 0.00
CV 10114 model AN-305
AI 10115 rssi -86.00
AI 10116 snr 8.00
7.18.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP 192.168.31.193,Port 47808
  2. In the left device tree, expand Device 101 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10104); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.18.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.193:8070/api/getStatus?devEui=ffffff100004bcf0" | jq .
{
  "devEui": "ffffff100004bcf0",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 19:15:08",
  "params": {
    "doorState": 1,
    "batteryVoltage": 3,
    "batteryVoltageState": 0,
    "tamperStatus": true,
    "model": "AN-305"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -86,
    "snr": 8,
    "frequency": 905100000,
    "spreadingFactor": 9,
    "bandwidth": 125000,
    "fCnt": 1311,
    "fPort": 210,
    "confirmed": false,
    "size": 14,
    "rawData": "5C78000000000000000000000000"
  }
}
Note: devEui=ffffff100004bcf0 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.19 Retrieving Data from the AN-307 Audible/Visual Alarm

AN-307 is a LoRaWAN audible-visual alarm that supports remote trigger with configurable duration. Suitable for security-system integration and emergency notification applications.

deviceinformation:devEui=ffffff100004c88a,Modbus Slave ID=3,BACnet Device ID=102,gateway IP=192.168.31.193

The AN-307 audible/visual alarm also supports control commands; see 7.20 Sending Control Commands to the AN-307 Alarm.

7.19.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 3(可configuration,range 2–201)。

7.19.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ 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       | 69CB B1B6           | 1774956982         | 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
mainVersion              | 11     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 19     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 27     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 35     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D33 3037 0000 ... | AN-307             | none
rssi                     | 47     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFD4                | -44.0              | none
snr                      | 48     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000D                | 13.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774956982 second
alarmStatus 9 Bit/Bool 1 x1 false none
alarmDurationSeconds 10 Int16 1 x1 0.0 seconds
model 35 String(24B) 12 x1 AN-307 none
rssi 47 Int16 1 x1 -44.0 none
snr 48 Int16 1 x1 13.0 none
7.19.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.193、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 3, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 43 (covers addresses 6–48), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.19.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.AN-307 Audible-Visual Alarm Device ID=102, so object instances start from 10200.

7.19.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ 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
------------------------------------------------------------------------------------------------------------
CV   | 10200    | 0      | 3378E3FB                 | ffffff100004c88a.protocolLayoutHash
CV   | 10201    | 1      | 20260101                 | ffffff100004c88a.profileVersion
BI   | 10202    | 2      | active                   | ffffff100004c88a.online
AI   | 10203    | 3      | 1774928128.00            | ffffff100004c88a.lastOnlineTime
BV   | 10204    | 4      | inactive                 | ffffff100004c88a.alarmStatus
AV   | 10205    | 5      | 0.00                     | ffffff100004c88a.alarmDurationSeconds
CV   | 10206    | 6      |                          | ffffff100004c88a.mainVersion
CV   | 10207    | 7      |                          | ffffff100004c88a.appVersion
CV   | 10208    | 8      |                          | ffffff100004c88a.hardwareVersion
CV   | 10209    | 9      | AN-307                   | ffffff100004c88a.model
AI   | 10210    | 10     | -44.00                   | ffffff100004c88a.rssi
AI   | 10211    | 11     | 13.00                    | ffffff100004c88a.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 10202 online active
AI 10203 lastOnlineTime 1774928128.00
BV 10204 alarmStatus inactive
AV 10205 alarmDurationSeconds 0.00
CV 10209 model AN-307
AI 10210 rssi -44.00
AI 10211 snr 13.00
7.19.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP 192.168.31.193,Port 47808
  2. In the left device tree, expand Device 102 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10204); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.19.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.193:8070/api/getStatus?devEui=ffffff100004c88a" | jq .
{
  "devEui": "ffffff100004c88a",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 19:36:22",
  "params": {
    "alarmStatus": false,
    "model": "AN-307"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -44,
    "snr": 13,
    "frequency": 904700000,
    "spreadingFactor": 9,
    "bandwidth": 125000,
    "fCnt": 758,
    "fPort": 210,
    "confirmed": false,
    "size": 5,
    "rawData": "5C78000000"
  }
}
Note: devEui=ffffff100004c88a is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.20 Controlling the AN-307 Audible/Visual Alarm via Downlink

The AN-307 is a LoRaWAN sound and light alarm. The three examples below demonstrate timed alarm, indefinite alarm, and cancel alarm.

Device information: devEui=ffffff100004c88a, Modbus Slave ID=3, BACnet Device ID=102, gateway IP=192.168.31.193

Example 1: Timed Alarm (60 seconds)

Modbus TCP:

(.venv) guo@ubuntu:~$ 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: true
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: true
Link confirmation time: 0.130s
Control completed in: 0.141s
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:

(.venv) guo@ubuntu:~$ 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: true
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: true
Link confirmation time: 0.009s
Control completed in: 0.087s
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
(.venv) guo@ubuntu:~$ 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

(.venv) guo@ubuntu:~$ 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:

(.venv) guo@ubuntu:~$ 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
Expected confirmed state:
  alarmStatus: true
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 1
    alarmStatus -> register 9 (4x40010) raw=1 signed=1
Observed values:
  alarmStatus: true
Link confirmation time: 0.130s
Control completed in: 0.141s
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:

(.venv) guo@ubuntu:~$ 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
Expected confirmed state:
  alarmStatus: true
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: true
Link confirmation time: 0.009s
Control completed in: 0.087s
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
(.venv) guo@ubuntu:~$ 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

(.venv) guo@ubuntu:~$ 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:

(.venv) guo@ubuntu:~$ 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
Expected confirmed state:
  alarmStatus: false
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 1
    alarmStatus -> register 9 (4x40010) raw=0 signed=0
Observed values:
  alarmStatus: false
Link confirmation time: 0.130s
Control completed in: 0.141s
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:

(.venv) guo@ubuntu:~$ 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
Expected confirmed state:
  alarmStatus: false
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: false
Link confirmation time: 0.009s
Control completed in: 0.087s
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
(.venv) guo@ubuntu:~$ 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

(.venv) guo@ubuntu:~$ 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
  }
}

7.21 Retrieving Data from the CU606 Air Quality Sensor

CU606 is a LoRaWAN air quality sensor that simultaneously measures CO₂, PM2.5, formaldehyde (HCHO), and TVOC concentrations while reporting temperature and humidity data. Suitable for indoor air quality monitoring.

deviceinformation:devEui=ffffff100004e982,Modbus Slave ID=4,BACnet Device ID=103,gateway IP=192.168.31.193

7.21.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 4(可configuration,range 2–201)。

7.21.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.193 --port 502 --slaveId 4 --sensorType CU606
Target: 192.168.31.193:502 | Slave ID: 4 | Sensor: CU606
================================================================================================================================================================
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       | 69CB 4237           | 1774928439         | second
temperature              | 9      | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0A64                | 26.6               | celsius
humidity                 | 10     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 1860                | 62.4               | percent
batteryVoltage           | 11     | 03  | Int16(S)   | Big(ABCD)    | 1   | /100     | 0000                | 0.00               | volt
batteryVoltageState      | 12     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
co2                      | 13     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 01FE                | 510.0              | none
pm25                     | 14     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000C                | 12.0               | none
formaldehyde             | 15     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0005                | 5.0                | none
tvoc                     | 16     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 00E1                | 225.0              | none
mainVersion              | 17     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 25     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 33     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 41     | 03  | String(24B) | ASCII        | 12  | x1       | 4355 3630 3600 0000 ... | CU606              | none
rssi                     | 53     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFBE                | -66.0              | none
snr                      | 54     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0009                | 9.0                | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774928439 second
temperature 9 Int16(S) 1 /100 26.6 celsius
humidity 10 Int16(S) 1 /100 62.4 percent
batteryVoltage 11 Int16(S) 1 /100 0.00 volt
batteryVoltageState 12 Int16 1 x1 0.0 none
co2 13 Int16 1 x1 510.0 none
pm25 14 Int16 1 x1 12.0 none
formaldehyde 15 Int16 1 x1 5.0 none
tvoc 16 Int16 1 x1 225.0 none
model 41 String(24B) 12 x1 CU606 none
rssi 53 Int16 1 x1 -66.0 none
snr 54 Int16 1 x1 9.0 none
7.21.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.193、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 4, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 49 (covers addresses 6–54), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.21.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.CU606 Air Quality Sensor Device ID=103, so object instances start from 10300.

7.21.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.193 --port 47808 --id 103
Target: 192.168.31.193:47808 | BACnet ID: 103 | Scan: 10300-10399
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 10300    | 0      | 47E0EA12                 | ffffff100004e982.protocolLayoutHash
CV   | 10301    | 1      | 20260101                 | ffffff100004e982.profileVersion
BI   | 10302    | 2      | active                   | ffffff100004e982.online
AI   | 10303    | 3      | 1774928384.00            | ffffff100004e982.lastOnlineTime
AI   | 10304    | 4      | 26.60                    | ffffff100004e982.temperature
AI   | 10305    | 5      | 62.40                    | ffffff100004e982.humidity
AI   | 10306    | 6      | 0.00                     | ffffff100004e982.batteryVoltage
AI   | 10307    | 7      | 0.00                     | ffffff100004e982.batteryVoltageState
AI   | 10308    | 8      | 510.00                   | ffffff100004e982.co2
AI   | 10309    | 9      | 12.00                    | ffffff100004e982.pm25
AI   | 10310    | 10     | 5.00                     | ffffff100004e982.formaldehyde
AI   | 10311    | 11     | 225.00                   | ffffff100004e982.tvoc
CV   | 10312    | 12     |                          | ffffff100004e982.mainVersion
CV   | 10313    | 13     |                          | ffffff100004e982.appVersion
CV   | 10314    | 14     |                          | ffffff100004e982.hardwareVersion
CV   | 10315    | 15     | CU606                    | ffffff100004e982.model
AI   | 10316    | 16     | -66.00                   | ffffff100004e982.rssi
AI   | 10317    | 17     | 9.00                     | ffffff100004e982.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 10302 online active
AI 10303 lastOnlineTime 1774928384.00
AI 10304 temperature 26.60
AI 10305 humidity 62.40
AI 10306 batteryVoltage 0.00
AI 10307 batteryVoltageState 0.00
AI 10308 co2 510.00
AI 10309 pm25 12.00
AI 10310 formaldehyde 5.00
AI 10311 tvoc 225.00
CV 10315 model CU606
AI 10316 rssi -66.00
AI 10317 snr 9.00
7.21.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP 192.168.31.193,Port 47808
  2. In the left device tree, expand Device 103 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10304); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.21.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.193:8070/api/getStatus?devEui=ffffff100004e982" | jq .
{
  "devEui": "ffffff100004e982",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 11:40:39",
  "params": {
    "temperature": 26.6,
    "humidity": 62.4,
    "co2": 510,
    "pm25": 12,
    "formaldehyde": 5,
    "tvoc": 225,
    "model": "CU606"
  },
  "rxParams": {
    "gatewayId": "0011502df4563612",
    "rssi": -66,
    "snr": 9,
    "frequency": 904100000,
    "spreadingFactor": 9,
    "bandwidth": 125000,
    "fCnt": 38244,
    "fPort": 210,
    "confirmed": false,
    "size": 21,
    "rawData": "00014B52000C9F00054901FEA000E1100A67120270"
  }
}
Note: devEui=ffffff100004e982 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.22 Retrieving Data from the DS-103 Three-Way Switch

DS-103 is a LoRaWAN three-channel smart switch that independently controls three lights/loads, with delay and timer features. Suitable for lighting control and smart-home applications.

deviceinformation:devEui=ffffff1000054348,Modbus Slave ID=15,BACnet Device ID=105,gateway IP=192.168.31.205

The DS-103 three-channel switch also supports downlink control — see 7.23 Downlink Control for DS-103.

7.22.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 15(可configuration,range 2–201)。

7.22.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
================================================================================================================================================================
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       | 69CA CDF0           | 1774898672         | second
ds103ControlTarget       | 9      | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
ds103ControlState        | 10     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
ds103ControlMode         | 11     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
ds103DelaySeconds        | 12     | 03  | Int32      | Big(ABCD)    | 2   | x1       | 0000 0000           | 0.0                | seconds
ds103ScheduleTimestamp   | 14     | 03  | UnixTime   | Big(ABCD)    | 2   | x1       | 0000 0000           | 0                  | seconds
ds103RepeatDaily         | 16     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
lockState                | 17     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
switch1State             | 18     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
switch2State             | 19     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
switch3State             | 20     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
timestamp                | 21     | 03  | Int32      | Big(ABCD)    | 2   | x1       | 69C9 ED03           | 1774841091.0       | seconds
switchTimerStatus        | 23     | 03  | Int32      | Big(ABCD)    | 2   | x1       | 0000 0010           | 16.0               | none
timerCloseEnabled1       | 25     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
timerOpenEnabled1        | 26     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
timerCloseEnabled2       | 27     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
timerOpenEnabled2        | 28     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
timerCloseEnabled3       | 29     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
timerOpenEnabled3        | 30     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
timerLockEnabled         | 31     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
timerUnlockEnabled       | 32     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
mainVersion              | 33     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 41     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 49     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 57     | 03  | String(24B) | ASCII        | 12  | x1       | 4453 2D31 3033 0000 ... | DS-103             | none
rssi                     | 69     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFA8                | -88.0              | none
snr                      | 70     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000D                | 13.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774898672 second
ds103ControlTarget 9 Int16 1 x1 0.0 none
ds103ControlState 10 Bit/Bool 1 x1 false none
ds103ControlMode 11 Int16 1 x1 0.0 none
ds103DelaySeconds 12 Int32 2 x1 0.0 seconds
ds103ScheduleTimestamp 14 UnixTime 2 x1 0 seconds
ds103RepeatDaily 16 Bit/Bool 1 x1 false none
lockState 17 Int16 1 x1 1.0 none
switch1State 18 Bit/Bool 1 x1 true none
switch2State 19 Bit/Bool 1 x1 true none
switch3State 20 Bit/Bool 1 x1 true none
timestamp 21 Int32 2 x1 1774841091.0 seconds
switchTimerStatus 23 Int32 2 x1 16.0 none
timerCloseEnabled1 25 Bit/Bool 1 x1 false none
timerOpenEnabled1 26 Bit/Bool 1 x1 false none
timerCloseEnabled2 27 Bit/Bool 1 x1 false none
timerOpenEnabled2 28 Bit/Bool 1 x1 false none
timerCloseEnabled3 29 Bit/Bool 1 x1 true none
timerOpenEnabled3 30 Bit/Bool 1 x1 false none
timerLockEnabled 31 Bit/Bool 1 x1 false none
timerUnlockEnabled 32 Bit/Bool 1 x1 false none
model 57 String(24B) 12 x1 DS-103 none
rssi 69 Int16 1 x1 -88.0 none
snr 70 Int16 1 x1 13.0 none
7.22.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.205、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 15, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 65 (covers addresses 6–70), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.22.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.DS-103 3-Channel Switch Device ID=105, so object instances start from 10500.

7.22.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 105
Target: 192.168.31.205:47808 | BACnet ID: 105 | Scan: 10500-10599
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 10500    | 0      | EEFCF320                 | ffffff1000054348.protocolLayoutHash
CV   | 10501    | 1      | 20260101                 | ffffff1000054348.profileVersion
BI   | 10502    | 2      | active                   | ffffff1000054348.online
AI   | 10503    | 3      | 1775030016.00            | ffffff1000054348.lastOnlineTime
AV   | 10504    | 4      | 0.00                     | ffffff1000054348.ds103ControlTarget
BV   | 10505    | 5      | inactive                 | ffffff1000054348.ds103ControlState
AV   | 10506    | 6      | 0.00                     | ffffff1000054348.ds103ControlMode
AV   | 10507    | 7      | 0.00                     | ffffff1000054348.ds103DelaySeconds
AV   | 10508    | 8      | 0.00                     | ffffff1000054348.ds103ScheduleTimestamp
BV   | 10509    | 9      | inactive                 | ffffff1000054348.ds103RepeatDaily
BV   | 10510    | 10     | inactive                 | ffffff1000054348.lockState
BV   | 10511    | 11     | inactive                 | ffffff1000054348.switch1State
BV   | 10512    | 12     | inactive                 | ffffff1000054348.switch2State
BV   | 10513    | 13     | inactive                 | ffffff1000054348.switch3State
AI   | 10514    | 14     | 1775030016.00            | ffffff1000054348.timestamp
AI   | 10515    | 15     | 0.00                     | ffffff1000054348.switchTimerStatus
BV   | 10516    | 16     | inactive                 | ffffff1000054348.timerCloseEnabled1
BV   | 10517    | 17     | inactive                 | ffffff1000054348.timerOpenEnabled1
BV   | 10518    | 18     | inactive                 | ffffff1000054348.timerCloseEnabled2
BV   | 10519    | 19     | inactive                 | ffffff1000054348.timerOpenEnabled2
BV   | 10520    | 20     | inactive                 | ffffff1000054348.timerCloseEnabled3
BV   | 10521    | 21     | inactive                 | ffffff1000054348.timerOpenEnabled3
BI   | 10522    | 22     | inactive                 | ffffff1000054348.timerLockEnabled
BI   | 10523    | 23     | inactive                 | ffffff1000054348.timerUnlockEnabled
CV   | 10524    | 24     |                          | ffffff1000054348.mainVersion
CV   | 10525    | 25     |                          | ffffff1000054348.appVersion
CV   | 10526    | 26     |                          | ffffff1000054348.hardwareVersion
CV   | 10527    | 27     | DS-103                   | ffffff1000054348.model
AI   | 10528    | 28     | -48.00                   | ffffff1000054348.rssi
AI   | 10529    | 29     | 14.00                    | ffffff1000054348.snr
7.22.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP 192.168.31.205,Port 47808
  2. In the left device tree, expand Device 105 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10504); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.22.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff1000054348" | jq .
{
  "devEui": "ffffff1000054348",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 03:24:32",
  "params": {
    "ds103ControlState": false,
    "ds103RepeatDaily": false,
    "lockState": 1,
    "switch1State": true,
    "switch2State": true,
    "switch3State": true,
    "timestamp": 1774841091,
    "switchTimerStatus": 16,
    "timerCloseEnabled1": false,
    "timerOpenEnabled1": false,
    "timerCloseEnabled2": false,
    "timerOpenEnabled2": false,
    "timerCloseEnabled3": true,
    "timerOpenEnabled3": false,
    "timerLockEnabled": false,
    "timerUnlockEnabled": false,
    "model": "DS-103"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -88,
    "snr": 13,
    "frequency": 905100000,
    "spreadingFactor": 7,
    "bandwidth": 125000,
    "fCnt": 756,
    "fPort": 210,
    "confirmed": false,
    "size": 21,
    "rawData": "5C7800000000000000000000000000000000000000"
  }
}
Note: devEui=ffffff1000054348 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.23 Sending Control Commands to the DS-103 Three-Way Switch

The DS-103 is a LoRaWAN three-channel smart switch. The seventeen examples below cover per-channel and all-channel switch, lock, delay, schedule, and cancellation commands.

Device information: devEui=ffffff1000054348, Modbus Slave ID=15, BACnet Device ID=105, gateway IP=192.168.31.205

Example 1a: Left Switch Connect / Disconnect — Connect / Close

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switch --channel left --value 1
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 1
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch1State: true
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch1State: true
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switch --channel left --value 1
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 1
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch1State: true
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=1
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=0
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch1State: true
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":1,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":1,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 1,
      "ds103ControlState": true,
      "ds103ControlMode": 0,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":1,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 1,
    "ds103ControlState": true,
    "ds103ControlMode": 0,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 1b: Left Switch Connect / Disconnect — Disconnect / Open

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switch --channel left --value 0
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 0
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch1State: false
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch1State: false
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switch --channel left --value 0
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 0
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch1State: false
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=1
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=0
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch1State: false
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":1,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":1,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 1,
      "ds103ControlState": false,
      "ds103ControlMode": 0,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":1,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 1,
    "ds103ControlState": false,
    "ds103ControlMode": 0,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 2a: Middle Switch Connect / Disconnect — Connect / Close

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switch --channel middle --value 1
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 2
  ds103ControlState: 1
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch2State: true
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=2 signed=2
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch2State: true
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switch --channel middle --value 1
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 2
  ds103ControlState: 1
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch2State: true
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=2
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=0
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch2State: true
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":2,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":2,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 2,
      "ds103ControlState": true,
      "ds103ControlMode": 0,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":2,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 2,
    "ds103ControlState": true,
    "ds103ControlMode": 0,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 2b: Middle Switch Connect / Disconnect — Disconnect / Open

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switch --channel middle --value 0
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 2
  ds103ControlState: 0
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch2State: false
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=2 signed=2
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch2State: false
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switch --channel middle --value 0
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 2
  ds103ControlState: 0
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch2State: false
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=2
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=0
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch2State: false
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":2,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":2,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 2,
      "ds103ControlState": false,
      "ds103ControlMode": 0,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":2,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 2,
    "ds103ControlState": false,
    "ds103ControlMode": 0,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 3a: Right Switch Connect / Disconnect — Connect / Close

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switch --channel right --value 1
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 3
  ds103ControlState: 1
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch3State: true
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=3 signed=3
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch3State: true
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switch --channel right --value 1
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 3
  ds103ControlState: 1
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch3State: true
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=3
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=0
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch3State: true
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":3,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":3,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 3,
      "ds103ControlState": true,
      "ds103ControlMode": 0,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":3,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 3,
    "ds103ControlState": true,
    "ds103ControlMode": 0,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 3b: Right Switch Connect / Disconnect — Disconnect / Open

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switch --channel right --value 0
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 3
  ds103ControlState: 0
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch3State: false
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=3 signed=3
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch3State: false
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switch --channel right --value 0
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 3
  ds103ControlState: 0
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch3State: false
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=3
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=0
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch3State: false
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":3,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":3,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 3,
      "ds103ControlState": false,
      "ds103ControlMode": 0,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":3,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 3,
    "ds103ControlState": false,
    "ds103ControlMode": 0,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 4a: All Switch Connect / Disconnect — Connect / Close

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switch --channel all --value 1
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 255
  ds103ControlState: 1
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch1State: true
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=255 signed=255
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch1State: true
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switch --channel all --value 1
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 255
  ds103ControlState: 1
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch1State: true
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=255
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=0
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch1State: true
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":255,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":255,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 255,
      "ds103ControlState": true,
      "ds103ControlMode": 0,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":255,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 255,
    "ds103ControlState": true,
    "ds103ControlMode": 0,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 4b: All Switch Connect / Disconnect — Disconnect / Open

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switch --channel all --value 0
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 255
  ds103ControlState: 0
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch1State: false
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=255 signed=255
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch1State: false
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switch --channel all --value 0
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 255
  ds103ControlState: 0
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch1State: false
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=255
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=0
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch1State: false
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":255,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":255,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 255,
      "ds103ControlState": false,
      "ds103ControlMode": 0,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":255,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 255,
    "ds103ControlState": false,
    "ds103ControlMode": 0,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 5a: Lock / Unlock All Switches — Lock

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 lock --value 1
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 1
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  lockState: true
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  lockState: true
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 lock --value 1
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 1
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  lockState: true
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=254
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=0
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  lockState: true
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":254,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":254,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 254,
      "ds103ControlState": true,
      "ds103ControlMode": 0,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":254,"ds103ControlState":true,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 254,
    "ds103ControlState": true,
    "ds103ControlMode": 0,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 5b: Lock / Unlock All Switches — Unlock

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 lock --value 0
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 0
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  lockState: false
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=0 signed=0
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  lockState: false
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 lock --value 0
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 0
  ds103ControlMode: 0
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  lockState: false
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=254
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=0
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  lockState: false
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":254,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":254,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 254,
      "ds103ControlState": false,
      "ds103ControlMode": 0,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":254,"ds103ControlState":false,"ds103ControlMode":0,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 254,
    "ds103ControlState": false,
    "ds103ControlMode": 0,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 6a: Delayed Left Switch (after 5 s) — Connect / Close
The device will wait 5 seconds before executing the switch command.

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchDelay --channel left --value 1 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 1
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch1State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchDelay --channel left --value 1 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 1
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=1
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=1
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=5
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch1State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":1,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":1,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 1,
      "ds103ControlState": true,
      "ds103ControlMode": 1,
      "ds103DelaySeconds": 5,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":1,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 1,
    "ds103ControlState": true,
    "ds103ControlMode": 1,
    "ds103DelaySeconds": 5,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 6b: Delayed Left Switch (after 5 s) — Disconnect / Open

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchDelay --channel left --value 0 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 0
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch1State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchDelay --channel left --value 0 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 0
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=1
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=1
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=5
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch1State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":1,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":1,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 1,
      "ds103ControlState": false,
      "ds103ControlMode": 1,
      "ds103DelaySeconds": 5,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":1,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 1,
    "ds103ControlState": false,
    "ds103ControlMode": 1,
    "ds103DelaySeconds": 5,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 7a: Delayed Middle Switch (after 5 s) — Connect / Close
The device will wait 5 seconds before executing the switch command.

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchDelay --channel middle --value 1 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 2
  ds103ControlState: 1
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=2 signed=2
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch2State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchDelay --channel middle --value 1 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 2
  ds103ControlState: 1
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=2
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=1
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=5
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch2State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":2,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":2,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 2,
      "ds103ControlState": true,
      "ds103ControlMode": 1,
      "ds103DelaySeconds": 5,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":2,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 2,
    "ds103ControlState": true,
    "ds103ControlMode": 1,
    "ds103DelaySeconds": 5,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 7b: Delayed Middle Switch (after 5 s) — Disconnect / Open

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchDelay --channel middle --value 0 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 2
  ds103ControlState: 0
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=2 signed=2
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch2State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchDelay --channel middle --value 0 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 2
  ds103ControlState: 0
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=2
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=1
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=5
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch2State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":2,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":2,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 2,
      "ds103ControlState": false,
      "ds103ControlMode": 1,
      "ds103DelaySeconds": 5,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":2,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 2,
    "ds103ControlState": false,
    "ds103ControlMode": 1,
    "ds103DelaySeconds": 5,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 8a: Delayed Right Switch (after 5 s) — Connect / Close
The device will wait 5 seconds before executing the switch command.

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchDelay --channel right --value 1 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 3
  ds103ControlState: 1
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=3 signed=3
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch3State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchDelay --channel right --value 1 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 3
  ds103ControlState: 1
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=3
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=1
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=5
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch3State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":3,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":3,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 3,
      "ds103ControlState": true,
      "ds103ControlMode": 1,
      "ds103DelaySeconds": 5,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":3,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 3,
    "ds103ControlState": true,
    "ds103ControlMode": 1,
    "ds103DelaySeconds": 5,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 8b: Delayed Right Switch (after 5 s) — Disconnect / Open

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchDelay --channel right --value 0 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 3
  ds103ControlState: 0
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=3 signed=3
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch3State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchDelay --channel right --value 0 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 3
  ds103ControlState: 0
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=3
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=1
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=5
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch3State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":3,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":3,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 3,
      "ds103ControlState": false,
      "ds103ControlMode": 1,
      "ds103DelaySeconds": 5,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":3,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 3,
    "ds103ControlState": false,
    "ds103ControlMode": 1,
    "ds103DelaySeconds": 5,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 9a: Delayed All Switch (after 5 s) — Connect / Close
The device will wait 5 seconds before executing the switch command.

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchDelay --channel all --value 1 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 255
  ds103ControlState: 1
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=255 signed=255
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch1State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchDelay --channel all --value 1 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 255
  ds103ControlState: 1
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=255
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=1
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=5
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch1State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":255,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":255,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 255,
      "ds103ControlState": true,
      "ds103ControlMode": 1,
      "ds103DelaySeconds": 5,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":255,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 255,
    "ds103ControlState": true,
    "ds103ControlMode": 1,
    "ds103DelaySeconds": 5,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 9b: Delayed All Switch (after 5 s) — Disconnect / Open

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchDelay --channel all --value 0 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 255
  ds103ControlState: 0
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=255 signed=255
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch1State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchDelay --channel all --value 0 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 255
  ds103ControlState: 0
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=255
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=1
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=5
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch1State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":255,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":255,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 255,
      "ds103ControlState": false,
      "ds103ControlMode": 1,
      "ds103DelaySeconds": 5,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":255,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 255,
    "ds103ControlState": false,
    "ds103ControlMode": 1,
    "ds103DelaySeconds": 5,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 10a: Scheduled Daily Left Switch (2026-04-01 10:30 CST) — Connect / Close
Scheduled for 2026-04-01 10:30:00 CST (timestamp 1775010600), repeat daily. Compute via: date -d '2026-04-01 10:30:00 +0800' +%s

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchSchedule --channel left --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 1
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds103RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  switch1State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchSchedule --channel left --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 1
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=1
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=2
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=1775010600
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=active
Observed values:
  switch1State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":1,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":1,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 1,
      "ds103ControlState": true,
      "ds103ControlMode": 2,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 1775010600,
      "ds103RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":1,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 1,
    "ds103ControlState": true,
    "ds103ControlMode": 2,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 1775010600,
    "ds103RepeatDaily": true
  }
}

Example 10b: Scheduled Daily Left Switch (2026-04-01 10:30 CST) — Disconnect / Open

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchSchedule --channel left --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 0
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds103RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  switch1State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchSchedule --channel left --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 0
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=1
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=2
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=1775010600
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=active
Observed values:
  switch1State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":1,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":1,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 1,
      "ds103ControlState": false,
      "ds103ControlMode": 2,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 1775010600,
      "ds103RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":1,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 1,
    "ds103ControlState": false,
    "ds103ControlMode": 2,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 1775010600,
    "ds103RepeatDaily": true
  }
}

Example 11a: Scheduled Daily Middle Switch (2026-04-01 10:30 CST) — Connect / Close
Scheduled for 2026-04-01 10:30:00 CST (timestamp 1775010600), repeat daily. Compute via: date -d '2026-04-01 10:30:00 +0800' +%s

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchSchedule --channel middle --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 2
  ds103ControlState: 1
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=2 signed=2
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds103RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  switch2State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchSchedule --channel middle --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 2
  ds103ControlState: 1
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=2
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=2
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=1775010600
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=active
Observed values:
  switch2State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":2,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":2,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 2,
      "ds103ControlState": true,
      "ds103ControlMode": 2,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 1775010600,
      "ds103RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":2,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 2,
    "ds103ControlState": true,
    "ds103ControlMode": 2,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 1775010600,
    "ds103RepeatDaily": true
  }
}

Example 11b: Scheduled Daily Middle Switch (2026-04-01 10:30 CST) — Disconnect / Open

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchSchedule --channel middle --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 2
  ds103ControlState: 0
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=2 signed=2
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds103RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  switch2State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchSchedule --channel middle --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 2
  ds103ControlState: 0
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=2
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=2
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=1775010600
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=active
Observed values:
  switch2State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":2,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":2,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 2,
      "ds103ControlState": false,
      "ds103ControlMode": 2,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 1775010600,
      "ds103RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":2,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 2,
    "ds103ControlState": false,
    "ds103ControlMode": 2,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 1775010600,
    "ds103RepeatDaily": true
  }
}

Example 12a: Scheduled Daily Right Switch (2026-04-01 10:30 CST) — Connect / Close
Scheduled for 2026-04-01 10:30:00 CST (timestamp 1775010600), repeat daily. Compute via: date -d '2026-04-01 10:30:00 +0800' +%s

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchSchedule --channel right --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 3
  ds103ControlState: 1
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=3 signed=3
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds103RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  switch3State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchSchedule --channel right --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 3
  ds103ControlState: 1
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=3
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=2
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=1775010600
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=active
Observed values:
  switch3State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":3,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":3,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 3,
      "ds103ControlState": true,
      "ds103ControlMode": 2,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 1775010600,
      "ds103RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":3,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 3,
    "ds103ControlState": true,
    "ds103ControlMode": 2,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 1775010600,
    "ds103RepeatDaily": true
  }
}

Example 12b: Scheduled Daily Right Switch (2026-04-01 10:30 CST) — Disconnect / Open

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchSchedule --channel right --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 3
  ds103ControlState: 0
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=3 signed=3
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds103RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  switch3State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchSchedule --channel right --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 3
  ds103ControlState: 0
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=3
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=2
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=1775010600
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=active
Observed values:
  switch3State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":3,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":3,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 3,
      "ds103ControlState": false,
      "ds103ControlMode": 2,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 1775010600,
      "ds103RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":3,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 3,
    "ds103ControlState": false,
    "ds103ControlMode": 2,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 1775010600,
    "ds103RepeatDaily": true
  }
}

Example 13a: Scheduled Daily All Switch (2026-04-01 10:30 CST) — Connect / Close
Scheduled for 2026-04-01 10:30:00 CST (timestamp 1775010600), repeat daily. Compute via: date -d '2026-04-01 10:30:00 +0800' +%s

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchSchedule --channel all --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 255
  ds103ControlState: 1
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=255 signed=255
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds103RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  switch1State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchSchedule --channel all --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 255
  ds103ControlState: 1
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=255
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=2
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=1775010600
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=active
Observed values:
  switch1State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":255,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":255,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 255,
      "ds103ControlState": true,
      "ds103ControlMode": 2,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 1775010600,
      "ds103RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":255,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 255,
    "ds103ControlState": true,
    "ds103ControlMode": 2,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 1775010600,
    "ds103RepeatDaily": true
  }
}

Example 13b: Scheduled Daily All Switch (2026-04-01 10:30 CST) — Disconnect / Open

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 switchSchedule --channel all --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 255
  ds103ControlState: 0
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=255 signed=255
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds103RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  switch1State: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 switchSchedule --channel all --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 255
  ds103ControlState: 0
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=255
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=2
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=1775010600
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=active
Observed values:
  switch1State: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":255,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":255,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 255,
      "ds103ControlState": false,
      "ds103ControlMode": 2,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 1775010600,
      "ds103RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":255,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 255,
    "ds103ControlState": false,
    "ds103ControlMode": 2,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 1775010600,
    "ds103RepeatDaily": true
  }
}

Example 14a: Delayed Lock / Unlock (after 5 s) — Lock

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 lockDelay --value 1 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 1
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  lockState: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 lockDelay --value 1 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 1
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=254
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=1
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=5
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  lockState: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":254,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":254,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 254,
      "ds103ControlState": true,
      "ds103ControlMode": 1,
      "ds103DelaySeconds": 5,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":254,"ds103ControlState":true,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 254,
    "ds103ControlState": true,
    "ds103ControlMode": 1,
    "ds103DelaySeconds": 5,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 14b: Delayed Lock / Unlock (after 5 s) — Unlock

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 lockDelay --value 0 --delaySeconds 5
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 0
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=1 signed=1
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=5 signed=5
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  lockState: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 lockDelay --value 0 --delaySeconds 5
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 0
  ds103ControlMode: 1
  ds103DelaySeconds: 5
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=254
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=1
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=5
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  lockState: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":254,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":254,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 254,
      "ds103ControlState": false,
      "ds103ControlMode": 1,
      "ds103DelaySeconds": 5,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":254,"ds103ControlState":false,"ds103ControlMode":1,"ds103DelaySeconds":5,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 254,
    "ds103ControlState": false,
    "ds103ControlMode": 1,
    "ds103DelaySeconds": 5,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 15a: Scheduled Daily Lock / Unlock (2026-04-01 10:30 CST) — Lock

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 lockSchedule --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 1
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds103ControlState -> register 10 (4x40011) raw=1 signed=1
    ds103ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds103RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  lockState: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 lockSchedule --value 1 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 1
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=254
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=active
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=2
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=1775010600
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=active
Observed values:
  lockState: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":254,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":254,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 254,
      "ds103ControlState": true,
      "ds103ControlMode": 2,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 1775010600,
      "ds103RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":254,"ds103ControlState":true,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 254,
    "ds103ControlState": true,
    "ds103ControlMode": 2,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 1775010600,
    "ds103RepeatDaily": true
  }
}

Example 15b: Scheduled Daily Lock / Unlock (2026-04-01 10:30 CST) — Unlock

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 lockSchedule --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 0
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=2 signed=2
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=27084 signed=27084
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=33576 signed=-31960
    ds103RepeatDaily -> register 16 (4x40017) raw=1 signed=1
Observed values:
  lockState: (pending)
Control completed in: 0.085s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 lockSchedule --value 0 --scheduleTimestamp 1775010600 --repeatDaily
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 0
  ds103ControlMode: 2
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 1775010600
  ds103RepeatDaily: 1
Expected confirmed state:
  (pending — takes effect after delay/schedule time expires)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=254
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=2
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=1775010600
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=active
Observed values:
  lockState: (pending)
Control completed in: 0.082s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":254,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":254,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 254,
      "ds103ControlState": false,
      "ds103ControlMode": 2,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 1775010600,
      "ds103RepeatDaily": true
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":254,"ds103ControlState":false,"ds103ControlMode":2,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":1775010600,"ds103RepeatDaily":true}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 254,
    "ds103ControlState": false,
    "ds103ControlMode": 2,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 1775010600,
    "ds103RepeatDaily": true
  }
}

Example 16: Cancel Switch Timer (example: left channel)
Cancels any pending delayed or scheduled connect/disconnect command for the specified channel. Change --channel left/middle/right/all to target a different channel.

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 cancelSwitchTimer --channel left
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 0
  ds103ControlMode: 3
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch1State: (unchanged)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=1 signed=1
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=3 signed=3
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  switch1State: (unchanged)
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 cancelSwitchTimer --channel left
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 1
  ds103ControlState: 0
  ds103ControlMode: 3
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  switch1State: (unchanged)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=1
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=3
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  switch1State: (unchanged)
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":1,"ds103ControlState":false,"ds103ControlMode":3,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":1,"ds103ControlState":false,"ds103ControlMode":3,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 1,
      "ds103ControlState": false,
      "ds103ControlMode": 3,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":1,"ds103ControlState":false,"ds103ControlMode":3,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 1,
    "ds103ControlState": false,
    "ds103ControlMode": 3,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

Example 17: Cancel Lock Timer
Cancels any pending delayed or scheduled lock/unlock command.

Modbus TCP:

(.venv) guo@ubuntu:~$ python3 modbus_tcp_write.py --ip 192.168.31.205 --port 502 --slaveId 15 --sensorType DS-103 cancelLockTimer
Target: 192.168.31.205:502 | Slave ID: 15 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 0
  ds103ControlMode: 3
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  lockState: (unchanged)
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
  Batch 1: FC16 Write Multiple Registers | Start register: 9 (4x40010) | Count: 8
    ds103ControlTarget -> register 9 (4x40010) raw=254 signed=254
    ds103ControlState -> register 10 (4x40011) raw=0 signed=0
    ds103ControlMode -> register 11 (4x40012) raw=3 signed=3
    ds103DelaySeconds -> register 12 (4x40013) raw=0 signed=0
    ds103DelaySeconds -> register 13 (4x40014) raw=0 signed=0
    ds103ScheduleTimestamp -> register 14 (4x40015) raw=0 signed=0
    ds103ScheduleTimestamp -> register 15 (4x40016) raw=0 signed=0
    ds103RepeatDaily -> register 16 (4x40017) raw=0 signed=0
Observed values:
  lockState: (unchanged)
Link confirmation time: 0.130s
Control completed in: 0.141s
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.205, Port 502, Slave ID 15)
  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:

(.venv) guo@ubuntu:~$ python3 bacnet_write.py --ip 192.168.31.205 --port 47808 --id 105 --sensorType DS-103 cancelLockTimer
Target: 192.168.31.205:47808 | BACnet ID: 105 | Sensor: DS-103
Expected values:
  ds103ControlTarget: 254
  ds103ControlState: 0
  ds103ControlMode: 3
  ds103DelaySeconds: 0
  ds103ScheduleTimestamp: 0
  ds103RepeatDaily: 0
Expected confirmed state:
  lockState: (unchanged)
Attempt 1/1: writing control values (default)...
YABE write guide:
  ds103ControlTarget -> object analog-value,10504 | property present-value | type=analog-value | write=254
  ds103ControlState -> object binary-value,10505 | property present-value | type=binary-value | write=inactive
  ds103ControlMode -> object analog-value,10506 | property present-value | type=analog-value | write=3
  ds103DelaySeconds -> object analog-value,10507 | property present-value | type=analog-value | write=0
  ds103ScheduleTimestamp -> object analog-value,10508 | property present-value | type=analog-value | write=0
  ds103RepeatDaily -> object binary-value,10509 | property present-value | type=binary-value | write=inactive
Observed values:
  lockState: (unchanged)
Link confirmation time: 0.009s
Control completed in: 0.087s
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.205, Port 47808), expand Device 105
  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.205:8070/api/sendCommand
(.venv) guo@ubuntu:~$ curl -s -X POST "http://192.168.31.205:8070/api/sendCommand" \
  -H "Content-Type: application/json" \
  -d '{"devEui":"ffffff1000054348","params":{"ds103ControlTarget":254,"ds103ControlState":false,"ds103ControlMode":3,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'
{
  "success": true,
  "result": {
    "devEui": "ffffff1000054348",
    "status": "buffered"
  }
}

ChirpStack REST API:

Endpoint: POST http://192.168.31.205:8090/api/devices/ffffff1000054348/queue

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000054348/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":"DS-103","ds103ControlTarget":254,"ds103ControlState":false,"ds103ControlMode":3,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}}'
{
  "id": "4e8b2c17-5f93-4a01-b8d0-2c91ef345678"
}

Formatted JSON payload:

{
  "flushQueue": true,
  "queueItem": {
    "confirmed": false,
    "isPending": false,
    "object": {
      "model": "DS-103",
      "ds103ControlTarget": 254,
      "ds103ControlState": false,
      "ds103ControlMode": 3,
      "ds103DelaySeconds": 0,
      "ds103ScheduleTimestamp": 0,
      "ds103RepeatDaily": false
    }
  }
}

ChirpStack MQTT:

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000054348/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000054348","confirmed":false,"object":{"model":"DS-103","ds103ControlTarget":254,"ds103ControlState":false,"ds103ControlMode":3,"ds103DelaySeconds":0,"ds103ScheduleTimestamp":0,"ds103RepeatDaily":false}}'

Formatted JSON payload:

{
  "flushQueue": true,
  "devEui": "ffffff1000054348",
  "confirmed": false,
  "object": {
    "model": "DS-103",
    "ds103ControlTarget": 254,
    "ds103ControlState": false,
    "ds103ControlMode": 3,
    "ds103DelaySeconds": 0,
    "ds103ScheduleTimestamp": 0,
    "ds103RepeatDaily": false
  }
}

7.24 Retrieving Data from the AN-306 Radar Presence Detector

AN-306 is a LoRaWAN millimeter-wave radar presence detector that senses whether a space is occupied (static or moving). Suitable for smart lighting and energy-saving management.

deviceinformation:devEui=ffffff100004bd16,Modbus Slave ID=7,BACnet Device ID=106,gateway IP=192.168.31.193

7.24.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 7(可configuration,range 2–201)。

7.24.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ python3 modbus_tcp_read.py --ip 192.168.31.193 --port 502 --slaveId 7 --sensorType AN-306
Target: 192.168.31.193:502 | Slave ID: 7 | Sensor: AN-306
================================================================================================================================================================
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       | 69CB 4181           | 1774928257         | second
presence                 | 9      | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
tamper                   | 10     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
presenceEvent            | 11     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
tamperEvent              | 12     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
isHeartbeat              | 13     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0001                | true               | none
mainVersion              | 14     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 22     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 30     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 38     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D33 3036 0000 ... | AN-306             | none
rssi                     | 50     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFC7                | -57.0              | none
snr                      | 51     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000B                | 11.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774928257 second
presence 9 Bit/Bool 1 x1 true none
tamper 10 Int16 1 x1 0.0 none
presenceEvent 11 Int16 1 x1 1.0 none
tamperEvent 12 Int16 1 x1 0.0 none
isHeartbeat 13 Bit/Bool 1 x1 true none
model 38 String(24B) 12 x1 AN-306 none
rssi 50 Int16 1 x1 -57.0 none
snr 51 Int16 1 x1 11.0 none
7.24.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.193、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 7, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 46 (covers addresses 6–51), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.24.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.AN-306 Radar Presence Detector Device ID=106, so object instances start from 10600.

7.24.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ python3 bacnet_read.py --ip 192.168.31.193 --port 47808 --id 106
Target: 192.168.31.193:47808 | BACnet ID: 106 | Scan: 10600-10699
------------------------------------------------------------------------------------------------------------
Type | Instance | Offset | Value                    | Object Name
------------------------------------------------------------------------------------------------------------
CV   | 10600    | 0      | 89760F1D                 | ffffff100004bd16.protocolLayoutHash
CV   | 10601    | 1      | 20260101                 | ffffff100004bd16.profileVersion
BI   | 10602    | 2      | active                   | ffffff100004bd16.online
AI   | 10603    | 3      | 1774928256.00            | ffffff100004bd16.lastOnlineTime
BI   | 10604    | 4      | active                   | ffffff100004bd16.presence
AI   | 10605    | 5      | 0.00                     | ffffff100004bd16.tamper
AI   | 10606    | 6      | 1.00                     | ffffff100004bd16.presenceEvent
AI   | 10607    | 7      | 0.00                     | ffffff100004bd16.tamperEvent
BI   | 10608    | 8      | active                   | ffffff100004bd16.isHeartbeat
CV   | 10609    | 9      |                          | ffffff100004bd16.mainVersion
CV   | 10610    | 10     |                          | ffffff100004bd16.appVersion
CV   | 10611    | 11     |                          | ffffff100004bd16.hardwareVersion
CV   | 10612    | 12     | AN-306                   | ffffff100004bd16.model
AI   | 10613    | 13     | -57.00                   | ffffff100004bd16.rssi
AI   | 10614    | 14     | 11.00                    | ffffff100004bd16.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 10602 online active
AI 10603 lastOnlineTime 1774928256.00
BI 10604 presence active
AI 10605 tamper 0.00
AI 10606 presenceEvent 1.00
AI 10607 tamperEvent 0.00
BI 10608 isHeartbeat active
CV 10612 model AN-306
AI 10613 rssi -57.00
AI 10614 snr 11.00
7.24.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP 192.168.31.193,Port 47808
  2. In the left device tree, expand Device 106 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10604); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.24.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.193:8070/api/getStatus?devEui=ffffff100004bd16" | jq .
{
  "devEui": "ffffff100004bd16",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 11:37:37",
  "params": {
    "presence": true,
    "tamper": 0,
    "presenceEvent": 1,
    "isHeartbeat": true,
    "model": "AN-306"
  },
  "rxParams": {
    "gatewayId": "0011502df4563612",
    "rssi": -57,
    "snr": 11,
    "frequency": 905100000,
    "spreadingFactor": 9,
    "bandwidth": 125000,
    "fCnt": 36930,
    "fPort": 210,
    "confirmed": false,
    "size": 9,
    "rawData": "0001446D007700BD01"
  }
}
Note: devEui=ffffff100004bd16 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.25 Retrieving Data from the AN-122 Beacon Tracker

AN-122 is a LoRaWAN + BLE beacon tracker with built-in GPS and Bluetooth beacon detection, supporting tilt monitoring and tamper alerts. Suitable for asset tracking and vehicle management applications.

deviceinformation:devEui=ffffff100004c8c2,Modbus Slave ID=8,BACnet Device ID=107,gateway IP=192.168.31.193

7.25.1 Using Modbus TCP

The IoT Hub Modbus TCP service defaults to port 502. When more than 200 devices are connected, ports 502–511 are automatically assigned (viewable on the gateway Web page under "IoT Hub Device List"). Read using function code FC03 (Read Holding Registers), Slave ID = 8(可configuration,range 2–201)。

7.25.1.1 Using the Python pymodbus Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: modbus_tcp_read.py

Example::

(.venv) guo@ubuntu:~$ 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       | 69CB B1B4           | 1774956980         | second
batteryLevel             | 9      | 03  | Int16      | Big(ABCD)    | 1   | x1       | 005D                | 93.0               | percent
tamper                   | 10     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | none
latitude                 | 11     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 41B5 F388           | 22.743912          | degrees
longitude                | 13     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 42E3 DBA6           | 113.929001         | degrees
positionAccuracy         | 15     | 03  | Float32    | Big(ABCD)    | 2   | x1       | 4019 999A           | 2.40               | 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
tiltAngle                | 37     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0001                | 1.0                | degree
batteryLowAlarm          | 38     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
tamperEvent              | 39     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 0000                | 0.0                | none
accelerationAlarm        | 40     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
tiltAlarm                | 41     | 03  | Bit/Bool   | Big(ABCD)    | 1   | x1       | 0000                | false              | none
mainVersion              | 42     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
appVersion               | 50     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
hardwareVersion          | 58     | 03  | String(16B) | ASCII        | 8   | x1       | 0000 0000 0000 0000 ... |                    | none
model                    | 66     | 03  | String(24B) | ASCII        | 12  | x1       | 414E 2D31 3232 0000 ... | AN-122             | none
rssi                     | 78     | 03  | Int16      | Big(ABCD)    | 1   | x1       | FFAE                | -82.0              | none
snr                      | 79     | 03  | Int16      | Big(ABCD)    | 1   | x1       | 000A                | 10.0               | none

Key Field Descriptions:

Field Register Address Data Type Count Scale Example Value Unit
online 6 Bit/Bool 1 x1 true none
lastOnlineTime 7 UnixTime 2 x1 1774956980 second
batteryLevel 9 Int16 1 x1 93.0 percent
tamper 10 Int16 1 x1 1.0 none
latitude 11 Float32 2 x1 22.743912 degrees
longitude 13 Float32 2 x1 113.929001 degrees
positionAccuracy 15 Float32 2 x1 2.40 meter
beaconIdHex 17 String(32B) 16 x1 none
beaconRefRssi 33 Int16 1 x1 0.0 none
beaconRssi 34 Int16 1 x1 0.0 none
beaconBatteryLevel 35 Int16 1 x1 0.0 percent
beaconBatteryValid 36 Bit/Bool 1 x1 false none
tiltAngle 37 Int16 1 x1 1.0 degree
batteryLowAlarm 38 Bit/Bool 1 x1 false none
tamperEvent 39 Int16 1 x1 0.0 none
accelerationAlarm 40 Bit/Bool 1 x1 false none
tiltAlarm 41 Bit/Bool 1 x1 false none
model 66 String(24B) 12 x1 AN-122 none
rssi 78 Int16 1 x1 -82.0 none
snr 79 Int16 1 x1 10.0 none
7.25.1.2 Using Modbus Poll

Download: Modbus Poll 9.5.0.1507.zip

Steps:

  1. Go to Connection → Connect, select Modbus TCP/IP, enter IP 192.168.31.193、Port 502
  2. In the menu Setup → Read/Write Definition, set Slave ID to 8, Function Code to 03 Read Holding Registers
  3. Set start address to 6, Count to 74 (covers addresses 6–79), click OK to begin polling
  4. Refer to the Data Type column in the "Key Field Descriptions" table above: e.g., Int16(S) = Signed 16-bit, Float32 = 32-bit Float, etc.
Note:In Modbus Poll, address 6 is displayed as 40007 (4x address = Register Address + 1). The /100 scale means the raw value must be divided by 100.

7.25.2 Using BACnet BIP

The IoT Hub BACnet BIP service uses default port 47808. Each device's BACnet object instance = Device ID × 100 + offset.AN-122 Beacon Tracker Device ID=107, so object instances start from 10700.

7.25.2.1 Using the Python bacpypes3 Script

Activate the venv first (source .venv/bin/activate); for setup details see the beginning of this chapter

Script download: bacnet_read.py

Example::

(.venv) guo@ubuntu:~$ 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
------------------------------------------------------------------------------------------------------------
CV   | 10700    | 0      | 6B241A37                 | ffffff100004c8c2.protocolLayoutHash
CV   | 10701    | 1      | 20260101                 | ffffff100004c8c2.profileVersion
BI   | 10702    | 2      | active                   | ffffff100004c8c2.online
AI   | 10703    | 3      | 1774928128.00            | ffffff100004c8c2.lastOnlineTime
AI   | 10704    | 4      | 93.00                    | ffffff100004c8c2.batteryLevel
AI   | 10705    | 5      | 1.00                     | ffffff100004c8c2.tamper
AI   | 10706    | 6      | 22.743912                | ffffff100004c8c2.latitude
AI   | 10707    | 7      | 113.929001               | ffffff100004c8c2.longitude
AI   | 10708    | 8      | 2.40                     | 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
AI   | 10714    | 14     | 1.00                     | ffffff100004c8c2.tiltAngle
BI   | 10715    | 15     | inactive                 | ffffff100004c8c2.batteryLowAlarm
AI   | 10716    | 16     | 0.00                     | ffffff100004c8c2.tamperEvent
BI   | 10717    | 17     | inactive                 | ffffff100004c8c2.accelerationAlarm
BI   | 10718    | 18     | inactive                 | ffffff100004c8c2.tiltAlarm
CV   | 10719    | 19     |                          | ffffff100004c8c2.mainVersion
CV   | 10720    | 20     |                          | ffffff100004c8c2.appVersion
CV   | 10721    | 21     |                          | ffffff100004c8c2.hardwareVersion
CV   | 10722    | 22     | AN-122                   | ffffff100004c8c2.model
AI   | 10723    | 23     | -82.00                   | ffffff100004c8c2.rssi
AI   | 10724    | 24     | 10.00                    | ffffff100004c8c2.snr

Key Object Descriptions:

Object Type Instance Number Field Example Value
BI 10702 online active
AI 10703 lastOnlineTime 1774928128.00
AI 10704 batteryLevel 93.00
AI 10705 tamper 1.00
AI 10706 latitude 22.743912
AI 10707 longitude 113.929001
AI 10708 positionAccuracy 2.40
CV 10709 beaconIdHex
AI 10710 beaconRefRssi 0.00
AI 10711 beaconRssi 0.00
AI 10712 beaconBatteryLevel 0.00
BI 10713 beaconBatteryValid inactive
AI 10714 tiltAngle 1.00
BI 10715 batteryLowAlarm inactive
AI 10716 tamperEvent 0.00
BI 10717 accelerationAlarm inactive
BI 10718 tiltAlarm inactive
CV 10722 model AN-122
AI 10723 rssi -82.00
AI 10724 snr 10.00
7.25.2.2 Using YABE

Download: SetupYabe_v2.1.0.exe

Steps:

  1. Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP 192.168.31.193,Port 47808
  2. In the left device tree, expand Device 107 to view the Analog Input, Binary Input, Character Value, and other object lists
  3. Click on a specific object (e.g., AI-10704); the right panel will display the present-value as the current value
  4. The object instance numbers correspond one-to-one with the Instance column in the script output above.

7.25.3 Using HTTP

IoT Hub provides an HTTP GET interface to query the latest device status. Default port: 8070, endpoint: /api/getStatus.

The following examples are demonstrated on Ubuntu 24.04 LTS using curl and jq (JSON formatting tool):

(.venv) guo@ubuntu:~$ curl -s "http://192.168.31.193:8070/api/getStatus?devEui=ffffff100004c8c2" | jq .
{
  "devEui": "ffffff100004c8c2",
  "online": true,
  "version": "20260101",
  "time": "2026-03-31 19:36:20",
  "params": {
    "batteryLevel": 93,
    "tamper": 1,
    "latitude": 22.743912,
    "longitude": 113.929001,
    "positionAccuracy": 2.4,
    "beaconBatteryValid": false,
    "tiltAngle": 1,
    "batteryLowAlarm": false,
    "accelerationAlarm": false,
    "tiltAlarm": false,
    "model": "AN-122"
  },
  "rxParams": {
    "gatewayId": "",
    "rssi": -82,
    "snr": 10,
    "frequency": 904900000,
    "spreadingFactor": 8,
    "bandwidth": 125000,
    "fCnt": 38571,
    "fPort": 210,
    "confirmed": false,
    "size": 24,
    "rawData": "5C7800000000000000000000000000000000000000000000"
  }
}
Note: devEui=ffffff100004c8c2 is the unique identifier of this LoRaWAN device, viewable in the gateway Web UI under IoT Hub → Device List.

7.26 ChirpStack MQTT: Data Subscription and Downlink Control

The gateway has a built-in Mosquitto MQTT Broker. ChirpStack publishes all device uplink events (join, uplink, ack, error, etc.) to MQTT in real time. This is suitable for scenarios requiring real-time push (e.g., Node-RED, custom backend processes).

MQTT connection information (applicable to both gateways):

parameters
Protocol MQTT(TCP)
Port 1883
Username gateway
Password mqtt88888888
Topic application/+/device/+/event/+
Replace the IP above with the target gateway's WAN IP to connect. The username and password can be viewed or modified in the gateway Web UI under Network → Built-in NS → Status.

7.26.1 Using the mosquitto_sub Command-Line Tool

Install mosquitto-clients on Ubuntu 24.04 LTS:

sudo apt update
sudo apt install -y mosquitto-clients

Subscribe to all uplink events from all devices on 192.168.31.205:

guo@ubuntu:~$ mosquitto_sub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/+/device/+/event/+" -v

Wait a moment — when the device reports data, it will be printed in real time. Sample output (AN-303 temperature & humidity sensor uplink):

application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff200000b703/event/up
{"deduplicationId":"...","time":"2026-03-30T10:37:00+00:00",
 "deviceInfo":{
   "tenantId":"af1374c6-87f5-4986-93cd-57857e412930",
   "applicationId":"3ef9e6b9-ec54-4eda-86b8-a5fb46899f39",
   "applicationName":"all_sensor",
   "deviceProfileName":"AN-303",
   "deviceName":"ffffff200000b703",
   "devEui":"ffffff200000b703"
 },
 "fPort":210,"confirmed":true,
 "object":{
   "temperature":25.7,
   "humidity":57.5,
   "batteryVoltage":3.61,
   "tamper":1,
   "model":"AN-303"
 },
 "rxInfo":[{"gatewayId":"0010502df4563610","rssi":-59,"snr":13}],
 "txInfo":{"frequency":481700000,"modulation":{"lora":{"bandwidth":125000,"spreadingFactor":7}}}}
Topic Format Description:application/{applicationId}/device/{devEui}/event/{eventType}

- up — device uplink data (most commonly used)
- join — devicejoinevent
- ack — downlink acknowledgment
- error — errorevent

Use the + wildcard to match all applications and devices, or specify a concrete applicationId or devEui for filtering.

Subscribe to all device events on 192.168.31.193 (same method, just replace the IP):

guo@ubuntu:~$ mosquitto_sub -h 192.168.31.193 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/+/device/+/event/+" -v

7.26.2 Using Python paho-mqtt Script

Please first activate the venv (source .venv/bin/activate), then install dependencies:

(.venv) guo@ubuntu:~$ pip3 install paho-mqtt

Example script (save as mqtt_subscribe.py):

import json
import paho.mqtt.client as mqtt

BROKER = "192.168.31.205"   # Replace with the target gateway IP
PORT = 1883
USERNAME = "gateway"
PASSWORD = "mqtt88888888"

def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print(f"已connect到 {BROKER}:{PORT}")
        client.subscribe("application/+/device/+/event/up")
    else:
        print(f"Connection failed, return code: {rc}")

def on_message(client, userdata, msg):
    payload = json.loads(msg.payload)
    dev_eui = payload.get("deviceInfo", {}).get("devEui", "unknown")
    profile = payload.get("deviceInfo", {}).get("deviceProfileName", "")
    obj = payload.get("object", {})
    print(f"[{profile}] devEui={dev_eui} => {json.dumps(obj, ensure_ascii=False)}")

client = mqtt.Client()
client.username_pw_set(USERNAME, PASSWORD)
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, PORT, 60)
client.loop_forever()

Runtime output:

(.venv) guo@ubuntu:~$ python3 mqtt_subscribe.py
已connect到 192.168.31.205:1883
[AN-303] devEui=ffffff200000b703 => {"temperature": 25.7, "humidity": 57.5, "batteryVoltage": 3.61, "model": "AN-303"}
[W8004] devEui=ffffff1000047040 => {"powerState": true, "setTemperature": 26, "workMode": 1, "fanSpeed": 1, "temperature": 29.6, "model": "W8004"}
[GB100] devEui=ffffff100004e9c3 => {"batteryLevel": 32, "temperature": 28.1, "latitude": 22.744444, "longitude": 113.930229, "model": "GB100"}
...

7.26.3 Using the MQTTX GUI Tool

Download: MQTTX is a cross-platform MQTT client supporting Windows/macOS/Linux.

Steps:

  1. Create a new connection, enter: - Host: 192.168.31.205 (192.168.31.193) - Port: 1883 - Username: gateway - Password: mqtt88888888
  2. Click Connect
  3. Subscribe to topic application/+/device/+/event/+
  4. When a device reports data, JSON messages are displayed in real time

In addition to subscribing to device data, ChirpStack MQTT also supports sending downlink control commands by publishing to the topic:

application/{applicationId}/device/{devEui}/command/down

The MQTT credentials are gateway / mqtt88888888. Both gateways share application ID 3ef9e6b9-ec54-4eda-86b8-a5fb46899f39.

The following examples use mosquitto_pub. Install if needed: sudo apt install -y mosquitto-clients.

Example 1 — Control AN-307 Audible/Visual Alarm (gateway 192.168.31.193, devEui ffffff100004c88a):

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":5}}'

Example 2 — Control W8004 Thermostat (gateway 192.168.31.205, devEui ffffff1000047040):

mosquitto_pub -h 192.168.31.205 -p 1883 -u gateway -P mqtt88888888 \
  -t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000047040/command/down" \
  -m '{"flushQueue":true,"devEui":"ffffff1000047040","confirmed":false,"object":{"model":"W8004","setTemperature":25,"workMode":1,"fanSpeed":1}}'
The model field is required — it tells the IoT Hub LPP codec which encoder to use. Use confirmed: true if delivery confirmation is needed (increases airtime). For more device-specific examples see 7.6 (W8004), 7.8 (DS-501), 7.10 (EF5600-DN1), and 7.20 (AN-307).

7.27 ChirpStack REST API: Device Query and Downlink Control

The built-in ChirpStack on port 8090 provides a RESTful API for querying device lists, retrieving device details, managing applications, device configuration profiles, and sending downlink control commands via the device queue.

API connectinformation:

parameters
Base URL http://{gatewayIP}:8090/api/
Authentication Method HTTP Header Grpc-Metadata-Authorization: Bearer {token}
Data Format JSON

7.27.1 Getting the API Token

  1. Open the gateway page: Network → Built-in NS → Status, scroll down to LoRaWAN Server Operations
  2. Click Copy Token to copy the current Bearer Token to the clipboard
  3. You can also create a long-term API Key in the ChirpStack UI at http://{gatewayIP}:8080API Keys
Warning: The Token copied from the gateway page has an expiration time. For long-term script use, create an API Key on the ChirpStack page.

7.27.2 Querying the Device List

Using 192.168.31.205 as the example gateway, query all LoRaWAN devices on this gateway:

guo@ubuntu:~$ curl -s -X GET \
  "http://192.168.31.205:8090/api/devices?limit=100&offset=0&applicationId=3ef9e6b9-ec54-4eda-86b8-a5fb46899f39&orderBy=NAME" \
  -H "accept: application/json" \
  -H "Grpc-Metadata-Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjaGlycHN0YWNrIiwiZXhwIjoxNzc0OTI0MTgwLCJpc3MiOiJjaGlycHN0YWNrIiwic3ViIjoiMWViMzM1NjYtZjljMy00OThjLWFlMmEtMWIyZjRkMWY5ZmFmIiwidHlwIjoidXNlciJ9.6e6Fm3JUcwDXh_kKHDil_1Vap4Td45hl3Zko8-fwaJM" | jq .

Return result (13 devices):

{
  "totalCount": 13,
  "result": [
    {
      "devEui": "ffffff1000047040",
      "lastSeenAt": "2026-03-30T10:35:00.367758Z",
      "name": "ffffff1000047040",
      "deviceProfileName": "W8004"
    },
    {
      "devEui": "ffffff1000048428",
      "lastSeenAt": "2026-03-30T10:30:26.173600Z",
      "name": "ffffff1000048428",
      "deviceProfileName": "AN-204"
    },
    {
      "devEui": "ffffff1000048920",
      "lastSeenAt": "2026-03-30T10:25:41.306810Z",
      "name": "ffffff1000048920",
      "deviceProfileName": "DS-501"
    },
    {
      "devEui": "ffffff100004bcc0",
      "lastSeenAt": "2026-03-30T09:58:44.225941Z",
      "name": "ffffff100004bcc0",
      "deviceProfileName": "AN-304"
    },
    {
      "devEui": "ffffff100004bccc",
      "lastSeenAt": "2026-03-30T07:20:47.076872Z",
      "name": "ffffff100004bccc",
      "deviceProfileName": "AN-301"
    },
    {
      "devEui": "ffffff100004c8b3",
      "lastSeenAt": "2026-03-30T10:36:36.203184Z",
      "name": "ffffff100004c8b3",
      "deviceProfileName": "AN-113"
    },
    {
      "devEui": "ffffff100004c8be",
      "lastSeenAt": "2026-03-30T10:30:30.689739Z",
      "name": "ffffff100004c8be",
      "deviceProfileName": "AN-308"
    },
    {
      "devEui": "ffffff100004d12a",
      "lastSeenAt": "2026-03-30T10:25:04.395603Z",
      "name": "ffffff100004d12a",
      "deviceProfileName": "CM100"
    },
    {
      "devEui": "ffffff100004e970",
      "lastSeenAt": "2026-03-30T03:17:45.834236Z",
      "name": "ffffff100004e970",
      "deviceProfileName": "JTY-AN-503A"
    },
    {
      "devEui": "ffffff100004e99f",
      "lastSeenAt": "2026-03-30T10:33:44.339330Z",
      "name": "ffffff100004e99f",
      "deviceProfileName": "EF5600-DN1"
    },
    {
      "devEui": "ffffff100004e9c3",
      "lastSeenAt": "2026-03-30T10:36:16.635028Z",
      "name": "ffffff100004e9c3",
      "deviceProfileName": "GB100"
    },
    {
      "devEui": "ffffff100004e9c8",
      "lastSeenAt": "2026-03-30T03:27:42.570043Z",
      "name": "ffffff100004e9c8",
      "deviceProfileName": "AN-201G"
    },
    {
      "devEui": "ffffff200000b703",
      "lastSeenAt": "2026-03-30T10:37:00.000221Z",
      "name": "ffffff200000b703",
      "deviceProfileName": "AN-303"
    }
  ]
}

Using the 192.168.31.193 gateway as an example (same method, use the corresponding gateway Token):

guo@ubuntu:~$ curl -s -X GET \
  "http://192.168.31.193:8090/api/devices?limit=100&offset=0&applicationId=3ef9e6b9-ec54-4eda-86b8-a5fb46899f39&orderBy=NAME" \
  -H "accept: application/json" \
  -H "Grpc-Metadata-Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjaGlycHN0YWNrIiwiZXhwIjoxNzc0OTI3NTgxLCJpc3MiOiJjaGlycHN0YWNrIiwic3ViIjoiMWViMzM1NjYtZjljMy00OThjLWFlMmEtMWIyZjRkMWY5ZmFmIiwidHlwIjoidXNlciJ9.10aOzIsxB0k6POwzmJq9XenZ-DIszNps7Q1ULANou54" | jq .

Return result (6 devices):

{
  "totalCount": 6,
  "result": [
    {
      "devEui": "ffffff100004bcf0",
      "lastSeenAt": "2026-03-30T10:14:22.863654Z",
      "name": "ffffff100004bcf0",
      "deviceProfileName": "AN-304"
    },
    {
      "devEui": "ffffff100004bd16",
      "lastSeenAt": "2026-03-30T10:38:10.269233Z",
      "name": "ffffff100004bd16",
      "deviceProfileName": "AN-306"
    },
    {
      "devEui": "ffffff100004c88a",
      "lastSeenAt": "2026-03-30T10:35:07.915664Z",
      "name": "ffffff100004c88a",
      "deviceProfileName": "AN-307"
    },
    {
      "devEui": "ffffff100004c8c2",
      "lastSeenAt": "2026-03-30T10:37:04.706553Z",
      "name": "ffffff100004c8c2",
      "deviceProfileName": "AN-122"
    },
    {
      "devEui": "ffffff100004e982",
      "lastSeenAt": "2026-03-30T10:37:37.596304Z",
      "name": "ffffff100004e982",
      "deviceProfileName": "CU606"
    },
    {
      "devEui": "ffffff200000b702",
      "lastSeenAt": "2026-03-30T10:38:42.286140Z",
      "name": "ffffff200000b702",
      "deviceProfileName": "AN-303"
    }
  ]
}
Note: The response above is abbreviated; the actual response also includes fields such as createdAt, updatedAt, deviceProfileId, deviceStatus, and tags.

7.27.3 Querying a Single Device

Using W8004 (devEui=ffffff1000047040) as an example:

guo@ubuntu:~$ curl -s -X GET \
  "http://192.168.31.205:8090/api/devices/ffffff1000047040" \
  -H "accept: application/json" \
  -H "Grpc-Metadata-Authorization: Bearer {token}" | jq .

7.27.4 Using the Swagger API Page

ChirpStack has a built-in interactive API documentation page (Swagger UI) on port 8090 where all APIs can be tested directly in the browser:

Steps:

  1. Open a browser and navigate to http://192.168.31.205:8090 (or http://192.168.31.193:8090)
  2. Click the Authorize button at the top of the page
  3. In the dialog box, paste the Bearer Token (copied from the gateway page; see 7.27.1)
  4. Expand DeviceServiceList devices, enter applicationId as 3ef9e6b9-ec54-4eda-86b8-a5fb46899f39, then click Execute
  5. The JSON response will be displayed at the bottom of the page
API Reference: For the full ChirpStack v4 API list, see the ChirpStack REST API Official Documentation.

ChirpStack REST API supports adding commands to a device's downlink queue via POST /api/devices/{devEui}/queue. Use flushQueue: true to clear pending commands before enqueuing. The Bearer Token is obtained in 7.27.1.

Example 1 — Control AN-307 Audible/Visual Alarm (gateway 192.168.31.193, devEui ffffff100004c88a):

(.venv) guo@ubuntu:~$ 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":5}}}'
{
  "id": "12d48a80-1357-4f76-b4e3-10a6bd9c9a91"
}

Example 2 — Control W8004 Thermostat (gateway 192.168.31.205, devEui ffffff1000047040):

(.venv) guo@ubuntu:~$ curl -s -X POST 'http://192.168.31.205:8090/api/devices/ffffff1000047040/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":"W8004","setTemperature":25,"workMode":1,"fanSpeed":1}}}'
{
  "id": "c7a91b3f-2e54-49d1-a8c9-0b123456789a"
}
Replace <token> with the Bearer Token from 7.27.1. The model field is required — the IoT Hub LPP codec uses it to select the correct encoder. For all controllable device examples see 7.6 (W8004), 7.8 (DS-501), 7.10 (EF5600-DN1), and 7.20 (AN-307).

7.28 Comparison of the Five Data Access Methods

Feature Modbus TCP BACnet BIP HTTP (IoT Hub) MQTT (ChirpStack) REST API (ChirpStack)
Port 502 47808 8070 1883 8090
Data format Registers (binary) BACnet objects JSON JSON JSON
Read data ✅ FC03 polling ✅ ReadProperty ✅ GET ✅ subscription push ✅ GET
Control Downlink ✅ FC16 Write ✅ WriteProperty ✅ POST ✅ mosquitto_pub ✅ POST
Real-time Push ❌ Polling required ❌ Polling required ❌ Polling required ✅ Real-time ❌ Polling required
Device Management ✅ Full CRUD
Use Case Industrial SCADA/PLC Building BMS Web/App Dev Real-time data stream Platform integration & management
Client Tool Modbus Poll YABE curl / Postman MQTTX / mosquitto_sub curl / Swagger UI