W8004 LoRaWAN Thermostat Controller User Guide
Device Information: Model W8004, devEui ffffff1000047040, gateway IP 192.168.31.205, Modbus Slave ID 2, BACnet Device ID 101
1 Protocol Overview
The W8004 reports power state, setpoint temperature, work mode, fan speed, ambient temperature and humidity, key lock state, valve state, cumulative on-time, and signal quality on Fport 210.
1.1 Uplink Data Protocol (Fport 210)
Payload format (Fport 210):
| Byte | Field | Description |
|---|---|---|
| 0 | Reserved | Always 0x00 (protocol version) |
| 1 … N | TLV pairs | [Type(1 B)][Value(N B)] … repeating until end |
Each Type byte determines the field name and the number of following value bytes:
| Type | Value Bytes | Field Name | Encoding | Scale | Unit | Notes |
|---|---|---|---|---|---|---|
0x01 |
1 | model |
uint8 | — | — | Model code = 0x46 |
0x94 |
1 | rs485Addr |
uint8 | — | — | RS485 slave address of the thermostat |
0x95 |
1+N | modbusBlock |
block | — | — | 1-byte length N + N-byte Modbus register data; see sub-table below |
0x2D |
1+N | transparentSerial |
block | — | — | 1-byte length + raw Modbus RTU response frame (optional) |
W8004 0x95 Modbus Register Block
The block starts with a 2-byte Block ID (big-endian), followed by consecutive 16-bit register values (2 bytes each, big-endian):
Normal status block (Block ID = 0x0000):
| Register | Field | Encoding | Notes |
|---|---|---|---|
| 0x0000 | Hardware / Software version | uint16 | High byte = HW ver, Low byte = SW ver |
| 0x0001 | Device status bits | bitfield | Bit 0: 0=power on, 1=power off; Bit 1: key lock; Bit 2: 0=valve open, 1=closed |
| 0x0002 | Current temperature | int16 | ÷100 → °C |
| 0x0003 | Current humidity | uint16 | ÷100 → %RH |
| 0x0004 | Set temperature | int16 | ÷100 → °C |
| 0x0005 | Work mode | uint16 | 0=Auto 1=Cooling 2=Heating 3=Fan-only |
| 0x0006 | Fan speed | uint16 | 0=Auto 1=Low 2=Mid 3=High 4=Turbo |
| 0x0007 | Cumulative on-time | uint16 | ×10 → minutes |
| 0x0008 | Cumulative valve open-time | uint16 | ×10 → minutes |
Remote control status block (Block ID = 0xF000):
| Register | Field | Notes |
|---|---|---|
| 0xF000 | Remote power state | 0=off, 1=on |
| 0xF001 | Remote key lock state | 0=unlocked, 1=locked |
| 0xF004 | Wireless signal strength | 0–5 |
JavaScript Decoder Example:
// W8004 Thermostat — Fport 210 uplink decoder
function decodeUplink(bytes) {
var i = 1, r = {};
function u8(b,o) { return b[o]&0xFF; }
function u16(b,o) { return (b[o]<<8)|b[o+1]; }
function i16(b,o) { var v=u16(b,o); return v>32767?v-65536:v; }
while (i < bytes.length) {
var t = bytes[i++];
switch (t) {
case 0x01: r.model = bytes[i++]; break;
case 0x94: r.rs485Addr = bytes[i++]; break;
case 0x95: {
// Modbus register block: 1-byte length, then register pairs
var len = bytes[i++];
var end = i + len;
var blockId = (bytes[i]<<8)|bytes[i+1];
var reg = (blockId === 0xF000) ? 0xF000 : 0x0000;
var off = i + 2;
while (off + 1 < end) {
var val = u16(bytes, off);
var valS = val > 32767 ? val - 65536 : val;
if (reg === 0x0000) {
r.hwVersion = (val>>8)&0xFF; r.swVersion = val&0xFF;
} else if (reg === 0x0001) {
r.powerState = (val&0x01) ? 0 : 1; // bit0: 0=on
r.keyLockState = (val&0x02) ? 1 : 0;
r.valveState = (val&0x04) ? 1 : 0; // bit2: 0=open
} else if (reg === 0x0002) { r.temperature = valS/100; }
else if (reg === 0x0003) { r.humidity = val/100; }
else if (reg === 0x0004) { r.setTemperature = valS/100; }
else if (reg === 0x0005) { r.workMode = val&0xFF; }
else if (reg === 0x0006) { r.fanSpeed = val&0xFF; }
else if (reg === 0x0007) { r.cumulativeOnTime = val*10; }
else if (reg === 0x0008) { r.cumulativeValveOpenTime = val*10; }
else if (reg === 0xF000) { r.remotePowerState = val&0xFF; }
else if (reg === 0xF001) { r.remoteKeyLock = val&0xFF; }
else if (reg === 0xF004) { r.signalStrength = val&0xFF; }
off += 2; reg++;
}
i = end; break;
}
case 0x2D: { var len=bytes[i++]; i+=len; break; } // skip transparent serial
default: i++; break;
}
}
return r;
}
Script download: LPP.zip
Compatibility note: LPP.js is developed and tested against ChirpStack v4.17.0. The ChirpStack JavaScript codec API may differ across versions — if you are running a different ChirpStack version, review and adjust the script as needed before deployment.
1.2 Downlink Control Protocol
The W8004 supports power on/off, climate settings (temperature, work mode, fan speed), and touch-panel lock/unlock via Fport 2.
Fport: 2 — No fixed header; two packet formats (single vs. multiple register write)
Format A — single register write: 06 06 [Reg_H Reg_L] [Val_H Val_L] Byte 0=0x06 (instruction type), Byte 1=0x06 (Modbus FC06), then register address (2B BE) and 16-bit value (2B BE).
Format B — multiple consecutive registers write (FC10): 07 [SlaveAddr 0x10 StartReg_H StartReg_L RegCnt_H RegCnt_L ByteCnt Val0_H Val0_L... CRC_L CRC_H] Byte 0=0x07 (instruction type), followed by a complete Modbus RTU FC10 frame including CRC.
Control register address map:
| Register | Bytes | Description |
|---|---|---|
0x0004 |
06 06 00 04 [T_H T_L] |
Set temperature (int16, ×100 °C; e.g. 0x09C4=2500 → 25.00 °C) |
0x0005 |
06 06 00 05 00 [Mode] |
Set work mode (0=Auto 1=Cooling 2=Heating 3=Fan-only) |
0x0006 |
06 06 00 06 00 [Speed] |
Set fan speed (0=Auto 1=Low 2=Mid 3=High 4=Turbo) |
0xF000 |
06 06 F0 00 00 [State] |
Remote power ON/OFF (0=OFF 1=ON) |
0xF001 |
06 06 F0 01 00 [State] |
Remote key lock (0=unlock 1=lock) |
JavaScript Encoder Example:
// W8004 Thermostat — Fport 2 downlink encoder
// Returns Modbus-wrapped command bytes.
function encodeDownlink(data) {
// data.setTemperature : number (°C, e.g. 25.5)
// data.workMode : 0=Auto 1=Cooling 2=Heating 3=Fan-only
// data.fanSpeed : 0=Auto 1=Low 2=Mid 3=High 4=Turbo
// data.powerState : 0=OFF 1=ON
// data.keyLockState : 0=unlock 1=lock
var writes = [];
if (data.setTemperature !== undefined) {
var v = Math.round(Number(data.setTemperature) * 100);
writes.push({reg: 0x0004, val: v & 0xFFFF});
}
if (data.workMode !== undefined) writes.push({reg:0x0005, val: Number(data.workMode)&0xFF});
if (data.fanSpeed !== undefined) writes.push({reg:0x0006, val: Number(data.fanSpeed) &0xFF});
if (data.powerState !== undefined) writes.push({reg:0xF000, val: Number(data.powerState) ?1:0});
if (data.keyLockState !== undefined) writes.push({reg:0xF001, val: Number(data.keyLockState) ?1:0});
if (writes.length === 0) return [];
// Single register → Format A: 06 06 Reg_H Reg_L Val_H Val_L
if (writes.length === 1) {
var a = writes[0];
return [0x06, 0x06, (a.reg>>8)&0xFF, a.reg&0xFF, (a.val>>8)&0xFF, a.val&0xFF];
}
// Multiple → Format B: 07 [Modbus FC10 frame with CRC16]
writes.sort(function(a,b){return a.reg-b.reg;});
var start = writes[0].reg, cnt = writes.length, byteCount = cnt*2;
var slave = data.rs485Addr || 0x01;
var frame = [slave, 0x10, (start>>8)&0xFF, start&0xFF, 0x00, cnt, byteCount];
for (var i=0; i<writes.length; i++) {
frame.push((writes[i].val>>8)&0xFF, writes[i].val&0xFF);
}
// CRC16 (Modbus)
var crc = 0xFFFF;
for (var j=0; j<frame.length; j++) {
crc ^= frame[j];
for (var b=0; b<8; b++) { crc = (crc&1) ? ((crc>>>1)^0xA001) : (crc>>>1); }
}
frame.push(crc&0xFF, (crc>>8)&0xFF);
return [0x07].concat(frame);
}
// Examples:
// encodeDownlink({setTemperature:25}) → [0x06,0x06,0x00,0x04,0x09,0xC4]
// encodeDownlink({powerState:1}) → [0x06,0x06,0xF0,0x00,0x00,0x01]
// encodeDownlink({workMode:1, fanSpeed:2})→ [0x07, …FC10 frame…]
2 Getting Uplink Data
⚠️ The IP addresses (192.168.31.205/192.168.31.193), ChirpStack API token, Slave ID, BACnet Device ID, and devEui in the examples below are for demonstration only. Replace them with your actual gateway IP, ChirpStack API token, and device parameters.
2.1 ChirpStack MQTT Subscription
Subscribe to the MQTT topic to receive real-time uplink frames:
Application ID —3ef9e6b9-ec54-4eda-86b8-a5fb46899f39is the factory-default ChirpStack
application built into the gateway. Replace it with your actual application
ID if you have created a different one.
Gateway IP —192.168.31.205is the gateway WAN port IP shown as an
example. Replace it with your actual gateway IP address.
Device EUI —ffffff1000047040is the EUI of the example device.
Replace it with the EUI shown in the gateway device list, or use+
as a wildcard to subscribe to all devices at once.
# Subscribe to one specific device
mosquitto_sub -h 192.168.31.205 -p 1883 \
-u gateway -P mqtt88888888 \
-t "application/3ef9e6b9-ec54-4eda-86b8-a5fb46899f39/device/ffffff1000047040/event/up"
# Subscribe to ALL devices on ALL applications (wildcard)
mosquitto_sub -h 192.168.31.205 -p 1883 \
-u gateway -P mqtt88888888 \
-t "application/+/device/+/event/up"
Example uplink payload (JSON):
{
"devEui": "ffffff1000047040",
"fPort": 210,
"object": {
... (decoded LPP fields)
}
}
2.2 IoT Hub HTTP API
Send a GET request to retrieve the latest device state:
curl -s "http://192.168.31.205:8070/api/getStatus?devEui=ffffff1000047040"
{
"success": true,
"result": {
"powerState": true,
"setTemperature": 24,
"workMode": 2,
"fanSpeed": 1,
"temperature": 29.6,
"humidity": 0,
"keyLockState": 0,
"valveState": 0,
"hardwareVersion": "0",
"model": "W8004"
}
}
2.3 IoT Hub Modbus TCP — Python Script
Script download: modbus_tcp_read.py
Use modbus_tcp_read.py to poll all registers at once:
python3 modbus_tcp_read.py --ip 192.168.31.205 --port 502 \
--slaveId 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 | 69CC CC0B | 1775029259 | second
powerState | 9 | 03 | Bit/Bool | Big(ABCD) | 1 | x1 | 0001 | true | none
setTemperature | 10 | 03 | Int16(S) | Big(ABCD) | 1 | /100 | 0960 | 24.0 | celsius
workMode | 11 | 03 | Int16 | Big(ABCD) | 1 | x1 | 0002 | 2.0 | none
fanSpeed | 12 | 03 | Int16 | Big(ABCD) | 1 | x1 | 0001 | 1.0 | none
temperature | 13 | 03 | Int16(S) | Big(ABCD) | 1 | /100 | 0B90 | 29.6 | 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 | 0003 | 3.0 | none
cumulativeOnTime | 18 | 03 | Int16 | Big(ABCD) | 1 | /10 | 0000 | 0.0 | minute
... (16 fields total)
2.4 IoT Hub Modbus TCP — Modbus Poll
Tool download: Modbus Poll 9.5.0.1507.zip
- Open Modbus Poll, connect to
192.168.31.205:502, Slave ID2 - Menu Setup → Read/Write Definition, set Function Code = FC03, Start Address =
6, Length =52 - Click OK — values update in real-time
2.5 IoT Hub BACnet BIP — Python Script
Script download: bacnet_read.py
Use bacnet_read.py to read all BACnet objects:
python3 bacnet_read.py --ip 192.168.31.205 --port 47808 --id 101
Target: 192.168.31.205:47808 | BACnet ID: 101 | Scan: 10100-10199
------------------------------------------------------------
Type | Instance | Offset | Value | Object Name
------------------------------------------------------------
BI | 10102 | 2 | active | ffffff1000047040.online
AI | 10103 | 3 | 1775029248.00 | ffffff1000047040.lastOnlineTime
BV | 10104 | 4 | active | ffffff1000047040.powerState
AV | 10105 | 5 | 24.00 | ffffff1000047040.setTemperature
AV | 10106 | 6 | 2.00 | ffffff1000047040.workMode
AV | 10107 | 7 | 1.00 | ffffff1000047040.fanSpeed
AI | 10108 | 8 | 29.60 | ffffff1000047040.temperature
AI | 10109 | 9 | 0.00 | ffffff1000047040.humidity
BV | 10110 | 10 | inactive | ffffff1000047040.keyLockState
BI | 10111 | 11 | inactive | ffffff1000047040.valveState
AI | 10112 | 12 | 3.00 | ffffff1000047040.signalStrength
AI | 10113 | 13 | 0.00 | ffffff1000047040.cumulativeOnTime
... (16 objects total)
2.6 IoT Hub BACnet BIP — YABE
Tool download: SetupYabe_v2.1.0.exe
- Open YABE, connect to
192.168.31.205:47808 - Expand Device 101 in the device tree
- Browse AI/BI/AV/BV/CV objects to view real-time values
3 Sending Control Commands
The W8004 supports power on/off, climate settings (temperature, work mode, fan speed), and touch-panel lock/unlock via Fport 2.
⚠️ The IP addresses (192.168.31.205/192.168.31.193), ChirpStack API token, Slave ID, BACnet Device ID, and devEui in the examples below are for demonstration only. Replace them with your actual gateway IP, ChirpStack API token, and device parameters.
Script downloads: modbus_tcp_write.py · bacnet_write.py
Example 1: Power ON
Modbus TCP:
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
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
Batch 1: FC06 Write Single Register | Start register: 9 (4x40010) | Count: 1
powerState -> register 9 (4x40010) raw=1 signed=1
Observed values:
powerState: 1
Link confirmation time: 0.132s
Control completed in: 0.143s
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:
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
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: 1
Link confirmation time: 0.010s
Control completed in: 0.033s
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
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
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:
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
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
Batch 1: FC06 Write Single Register | Start register: 9 (4x40010) | Count: 1
powerState -> register 9 (4x40010) raw=0 signed=0
Observed values:
powerState: 0
Link confirmation time: 0.132s
Control completed in: 0.143s
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:
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
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: 0
Link confirmation time: 0.010s
Control completed in: 0.033s
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
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
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:
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
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
workMode: 1
fanSpeed: 1
Link confirmation time: 0.154s
Control completed in: 0.165s
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:
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
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
workMode: 1
fanSpeed: 1
Link confirmation time: 0.031s
Control completed in: 0.075s
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
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
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:
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
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:
setTemperature: 23.0
workMode: 1
fanSpeed: 1
Link confirmation time: 0.154s
Control completed in: 0.165s
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:
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
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:
setTemperature: 23.0
workMode: 1
fanSpeed: 1
Link confirmation time: 0.031s
Control completed in: 0.075s
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
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
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:
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
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:
setTemperature: 23.0
workMode: 1
fanSpeed: 2
Link confirmation time: 0.154s
Control completed in: 0.165s
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:
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
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:
setTemperature: 23.0
workMode: 1
fanSpeed: 2
Link confirmation time: 0.031s
Control completed in: 0.075s
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
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
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:
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
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
workMode: 1
fanSpeed: 2
Link confirmation time: 0.154s
Control completed in: 0.165s
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:
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
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
workMode: 1
fanSpeed: 2
Link confirmation time: 0.031s
Control completed in: 0.075s
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
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
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:
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
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
Batch 1: FC06 Write Single Register | Start register: 15 (4x40016) | Count: 1
keyLockState -> register 15 (4x40016) raw=1 signed=1
Observed values:
keyLockState: 1
Link confirmation time: 0.125s
Control completed in: 0.146s
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:
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
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: 1
Link confirmation time: 0.010s
Control completed in: 0.033s
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
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
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:
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
Attempt 1/1: writing control values (default)...
Modbus Poll write guide:
Batch 1: FC06 Write Single Register | Start register: 15 (4x40016) | Count: 1
keyLockState -> register 15 (4x40016) raw=0 signed=0
Observed values:
keyLockState: 0
Link confirmation time: 0.125s
Control completed in: 0.146s
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:
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
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: 0
Link confirmation time: 0.010s
Control completed in: 0.033s
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
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
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
}
}