物联网 · 盛世宏博 · RS485联动控制

恒湿消毒净化一体机走 Modbus RTU 时,平台角色分两层:
核心原则:启停不一定是“写 1/写 0 到某个寄存器”,要看厂家把“开机”做成线圈还是保持寄存器里的运行模式字。
设备把“主机启停”映射成线圈地址,比如:
FF 00 = ON 00 00 = OFF 报文(从站地址 1,线圈地址 0x0000 开机):
01 05 00 00 FF 00 8C 3A关机:
01 05 00 00 00 00 CD CA⚠️ 05 功能码里“开”不是 00 01,是 FF 00;“关”是 00 00。发 00 01 很多设备不认。
设备把运行模式放在保持寄存器里,比如:
开机写 1:
01 06 00 01 00 01 19 CA解释:
01 从站地址 06 写单个保持寄存器 00 01 寄存器偏移(40002 → 偏移 1) 00 01 写入值 1 设备成功会原样回显这一帧;回显不一致 = 没写进去。
平台点击“启动”
↓
1. 白名单校验:该寄存器是否允许写
↓
2. 构造 RTU 帧(地址+功能码+地址+值+CRC)
↓
3. 网关串口发送(RS485 半双工,发完切接收)
↓
4. 等从站回执
↓
5. 回执校验:
- 原样回显 → 写成功
- 返回 8X + 功能码 → 异常(01不支持/02地址错/03数据非法)
↓
6. 回读确认:再用 03 读一次运行模式/状态字
↓
7. 平台状态机更新:running / stopped / fault关键:写完后必须回读。很多一体机“写成功但没动作”——值超范围、本地锁键、湿度已达设定、消毒互锁,都不会真动。
# hvac_start_stop.py
import time
from pymodbus.client import ModbusSerialClient
class PurifierController:
def __init__(self, port, slave=1, baudrate=9600, parity="N", timeout=1.5):
self.slave = slave
self.client = ModbusSerialClient(
port=port, baudrate=baudrate, parity=parity,
stopbits=1, bytesize=8, timeout=timeout
)
# 点表:不同厂家改这里
self.REG = {
"run_mode": 0, # 40001
"remote_enable": 14, # 40015
"power_ctrl": 1, # 40002(若厂家用保持寄存器做启停)
}
self.COIL = {
"power_coil": 0, # 线圈 00001
}
def connect(self):
return self.client.connect()
# ---- 线圈启停 ----
def start_by_coil(self):
rr = self.client.write_coil(self.COIL["power_coil"], True, slave=self.slave)
if rr.is_error():
raise RuntimeError(f"coil start error: {rr}")
return self._confirm_running()
def stop_by_coil(self):
rr = self.client.write_coil(self.COIL["power_coil"], False, slave=self.slave)
if rr.is_error():
raise RuntimeError(f"coil stop error: {rr}")
return self._confirm_stopped()
# ---- 保持寄存器启停 ----
def start_by_register(self):
# 先开远程权限
self.client.write_register(self.REG["remote_enable"], 1, slave=self.slave)
# 写运行模式=自动
rr = self.client.write_register(self.REG["run_mode"], 1, slave=self.slave)
if rr.is_error():
raise RuntimeError(f"register start error: {rr}")
return self._confirm_running()
def stop_by_register(self):
rr = self.client.write_register(self.REG["run_mode"], 0, slave=self.slave)
if rr.is_error():
raise RuntimeError(f"register stop error: {rr}")
return self._confirm_stopped()
# ---- 回读确认 ----
def _confirm_running(self, retry=3):
for _ in range(retry):
rr = self.client.read_holding_registers(self.REG["run_mode"], 1, slave=self.slave)
if not rr.is_error():
mode = rr.registers[0]
status = self.read_status_word()
return {
"mode": mode,
"running": mode != 0 and "running" in status,
"status": status,
}
time.sleep(0.5)
return {"running": False, "status": ["read_back_failed"]}
def _confirm_stopped(self, retry=3):
for _ in range(retry):
rr = self.client.read_holding_registers(self.REG["run_mode"], 1, slave=self.slave)
if not rr.is_error():
mode = rr.registers[0]
return {"mode": mode, "stopped": mode == 0}
time.sleep(0.5)
return {"stopped": False, "status": ["read_back_failed"]}
def read_status_word(self):
rr = self.client.read_holding_registers(8, 1, slave=self.slave) # 40009 状态字
if rr.is_error():
return ["read_error"]
w = rr.registers[0]
bits = {0:"running",1:"fault",2:"humidifying",3:"dehumidifying",
4:"purifying",5:"disinfecting"}
return [v for k,v in bits.items() if w & (1<<k)]单纯“湿度>60% 启动除湿”会出事:湿度在 59/61 之间晃,设备一分钟启停七八次。
正确联动三件套:
湿度 > 60%RH → 启动除湿
湿度 < 52%RH → 停止除湿
52~60 之间:保持现状湿度 > 60%RH 且 持续 5 分钟 → 才下发启动
湿度 < 52%RH 且 持续 10 分钟 → 才下发停止单台最少运行 10 分钟
两次启停间隔 ≥ 3 分钟
多台同时动作 ≤ 3 台,其余按地址错峰 30s伪代码:
if rh > 60 and since_over_high > 300:
if now - last_switch > 180:
controller.start_by_register()
last_switch = now
if rh < 52 and since_under_low > 600:
if now - last_switch > 180:
controller.stop_by_register()
last_switch = now档案库房/配电室真实案例:12 台一体机同时收到平台指令同时启动压缩机,配电柜直接跳闸——错峰和写队列是必做项。
项目 | 规则 |
|---|---|
可写点表 | 只开放 run_mode / target_rh / remote_enable / disinfect_mode 等白名单 |
只读点 | 温湿度、故障码、累计时长、滤网剩余——平台禁止写 |
本地优先 | 屏上“本地/远程”开关在“本地”时,平台写指令被忽略或回异常 |
权限分级 | 操作员可启停,访客只读,平台账号分角色 |
二次确认 | Web 点“停机”弹窗:“确认停止恒湿机?库房将失去湿控” |
通信中断 | 平台 3 次轮询无响应 → 标通信丢失,但不自动下发任何指令,设备按本地设定继续跑 |
消毒互锁 | 门磁/烟感/有人态为真时,平台禁止启动 UV/臭氧 |
01 05 00 00 FF 00 或 01 06 00 01 00 01,看设备屏是否变“运行” 81 05 / 81 06 = 异常 01 03 00 00 00 01 看运行模式寄存器 现象 | 根因 | 处理 |
|---|---|---|
平台显示“启动成功”但机器不动 | 没回读,实际本地锁键/模式冲突 | 写后必须 03 回读状态字 |
写 05 发 00 01 不开机 | 05 开=FF00,不是 0001 | 改报文 |
12 台同时启动跳闸 | 无错峰 | 写队列+按地址延迟 |
湿度 59↔61 设备狂启停 | 无死区 | 加回差+最小运行时长 |
通信断了平台还下发停机 | 缺通信互锁 | 丢联时机型进入“本地自治” |
消毒时人在库房 | 没接门磁互锁 | 平台联动规则加“有人=禁消毒” |
RS485 下发启停不是“平台点一下”,而是:白名单校验 → 05/06 发帧 → 原样回显判断 → 03 回读确认 → 状态机更新 → 联动规则带死区/错峰/互锁。
少一步,现场就多一次半夜跳闸或库房湿度失控。
关键词:恒湿一体机,RS485,Modbus RTU,启停指令,05写线圈,06写寄存器,平台联动,回读确认,死区控制,错峰启动
标签:#恒湿一体机 #RS485 #ModbusRTU #启停控制 #05功能码 #06功能码 #平台联动 #回读确认 #死区控制 #动环监控
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。