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 alayout hash mismatcherror will occur. Follow these steps:
Step 1: Verify Python 3 is installed
``bash`
guo@ubuntu:~$ python3 --version
Python 3.12.3command not found
If you see, first install Python 3:`bash`
sudo apt update
sudo apt install -y python3venv
**Step 2: Install the venv module**
Ubuntu 24.04 does **not** includeby default; install it separately:`bash`
sudo apt install -y python3-venv.venv
**Step 3: Create the virtual environment**
Create a venv namedin 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:~$(.venv)
After successful activation, theprefix 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
6, Function Code to03 Read Holding Registers - Set start address to
6, Count to47(covers addresses 6–52), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 110 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-11004); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
9, Function Code to03 Read Holding Registers - Set start address to
6, Count to48(covers addresses 6–53), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 108 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10804); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
4, Function Code to03 Read Holding Registers - Set start address to
6, Count to46(covers addresses 6–51), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 103 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10304); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
5, Function Code to03 Read Holding Registers - Set start address to
6, Count to49(covers addresses 6–54), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 104 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10404); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
2, Function Code to03 Read Holding Registers - Set start address to
6, Count to52(covers addresses 6–57), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 101 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10104); the right panel will display the present-value as the current value
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID2) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 101 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID2) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 101 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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)
Theclimatecommand writessetTemperature,workMode, andfanSpeedsimultaneously. 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID2) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 101 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID2) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 101 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID2) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 101 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID2) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 101 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID2) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 101 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID2) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 101 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
3, Function Code to03 Read Holding Registers - Set start address to
6, Count to62(covers addresses 6–67), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 102 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10204); the right panel will display the present-value as the current value
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
7, Function Code to03 Read Holding Registers - Since Modbus FC03 can read a maximum of 125 registers per request, two Read/Write Definitions are required: - Definition 1: Start address
6, Count125(covers addresses 6–130) - Definition 2: Start address131, Count7(covers addresses 131–137)
After clicking OK on both, Modbus Poll will simultaneously display the polling results in two windows
- 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 106 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10604); the right panel will display the present-value as the current value
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID7) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 106 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID7) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 106 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
8, Function Code to03 Read Holding Registers - Set start address to
6, Count to93(covers addresses 6–98), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 107 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10704); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
10, Function Code to03 Read Holding Registers - Set start address to
6, Count to64(covers addresses 6–69), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 109 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10904); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
11, Function Code to03 Read Holding Registers - Set start address to
6, Count to46(covers addresses 6–51), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 111 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-11104); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
12, Function Code to03 Read Holding Registers - Set start address to
6, Count to49(covers addresses 6–54), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 112 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-11204); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
13, Function Code to03 Read Holding Registers - Set start address to
6, Count to48(covers addresses 6–53), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 113 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-11304); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
14, Function Code to03 Read Holding Registers - Set start address to
6, Count to64(covers addresses 6–69), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add device), select BACnet/IP, enter IP
192.168.31.205, Port47808 - In the left device tree, expand Device 114 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-11404); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.193、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
6, Function Code to03 Read Holding Registers - Set start address to
6, Count to48(covers addresses 6–53), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP
192.168.31.193,Port47808 - In the left device tree, expand Device 105 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10504); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.193、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
2, Function Code to03 Read Holding Registers - Set start address to
6, Count to48(covers addresses 6–53), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP
192.168.31.193,Port47808 - In the left device tree, expand Device 101 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10104); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.193、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
3, Function Code to03 Read Holding Registers - Set start address to
6, Count to43(covers addresses 6–48), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP
192.168.31.193,Port47808 - In the left device tree, expand Device 102 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10204); the right panel will display the present-value as the current value
- 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:
- Connect to the gateway (IP
192.168.31.193, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.193, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.193, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.193, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.193, Port502, Slave ID3) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.193, Port47808), expand Device 102 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.193、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
4, Function Code to03 Read Holding Registers - Set start address to
6, Count to49(covers addresses 6–54), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP
192.168.31.193,Port47808 - In the left device tree, expand Device 103 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10304); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.205、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
15, Function Code to03 Read Holding Registers - Set start address to
6, Count to65(covers addresses 6–70), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP
192.168.31.205,Port47808 - In the left device tree, expand Device 105 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10504); the right panel will display the present-value as the current value
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Connect to the gateway (IP
192.168.31.205, Port502, Slave ID15) - Menu Functions → 16 Write Multiple Registers
- Refer to the Modbus Poll write guide in the script output above for the Register Address and value to enter
- 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:
- Connect to the gateway (IP
192.168.31.205, Port47808), expand Device 105 - Refer to the YABE write guide in the script output above to locate the corresponding object
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.193、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
7, Function Code to03 Read Holding Registers - Set start address to
6, Count to46(covers addresses 6–51), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP
192.168.31.193,Port47808 - In the left device tree, expand Device 106 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10604); the right panel will display the present-value as the current value
- 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:
- Go to Connection → Connect, select Modbus TCP/IP, enter IP
192.168.31.193、Port502 - In the menu Setup → Read/Write Definition, set Slave ID to
8, Function Code to03 Read Holding Registers - Set start address to
6, Count to74(covers addresses 6–79), click OK to begin polling - 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:
- Launch YABE, click the green + button (Add Device), select BACnet/IP, enter IP
192.168.31.193,Port47808 - In the left device tree, expand Device 107 to view the Analog Input, Binary Input, Character Value, and other object lists
- Click on a specific object (e.g., AI-10704); the right panel will display the present-value as the current value
- 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 concreteapplicationIdordevEuifor 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:
- Create a new connection, enter: - Host:
192.168.31.205(192.168.31.193) - Port:1883- Username:gateway- Password:mqtt88888888 - Click Connect
- Subscribe to topic
application/+/device/+/event/+ - When a device reports data, JSON messages are displayed in real time
7.26.4 Sending Downlink Control Commands via ChirpStack MQTT
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}}'
Themodelfield is required — it tells the IoT Hub LPP codec which encoder to use. Useconfirmed: trueif 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
- Open the gateway page: Network → Built-in NS → Status, scroll down to LoRaWAN Server Operations
- Click Copy Token to copy the current Bearer Token to the clipboard
- You can also create a long-term API Key in the ChirpStack UI at
http://{gatewayIP}:8080→ API 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 ascreatedAt,updatedAt,deviceProfileId,deviceStatus, andtags.
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:
- Open a browser and navigate to
http://192.168.31.205:8090(orhttp://192.168.31.193:8090) - Click the Authorize button at the top of the page
- In the dialog box, paste the Bearer Token (copied from the gateway page; see 7.27.1)
- Expand DeviceService → List devices, enter
applicationIdas3ef9e6b9-ec54-4eda-86b8-a5fb46899f39, then click Execute - 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.
7.27.5 Sending Downlink Control Commands via ChirpStack REST API
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. Themodelfield 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 |