node-red-contrib-symi-modbus 1.6.1
Node-RED Modbus节点,支持TCP/串口通信、串口自动搜索、多设备轮询、智能MQTT连接(自动fallback到host.docker.internal等)、Home Assistant自动发现和多品牌开关面板,增强日志和状态显示
node-red-contrib-symi-modbus
Node-RED的Modbus继电器控制节点,支持TCP/串口通信和MQTT集成。
功能特性
- ✅ 多协议支持:支持Modbus TCP和Modbus RTU(串口)
- ✅ 多设备轮询:最多支持10台Modbus从站设备同时轮询
- ✅ 32路继电器:每台设备支持32个线圈(继电器通道)
- ✅ 灵活配置:可自定义轮询间隔、线圈范围、从站地址
- ✅ MQTT集成:自动生成Home Assistant兼容的MQTT发现消息
- ✅ 实时状态:实时监控和控制继电器状态
- ✅ 主从模式:提供主站节点和从站控制节点
安装
通过npm安装(推荐)
在Node-RED用户目录中运行:
cd ~/.node-red
npm install node-red-contrib-symi-modbus
通过Node-RED界面安装
- 点击右上角菜单 → 设置 → 节点管理
- 搜索
node-red-contrib-symi-modbus
- 点击安装
已发布到npm: https://www.npmjs.com/package/node-red-contrib-symi-modbus
Docker/容器环境安装
本节点依赖modbus-serial
包,该包包含native C++模块(serialport),需要编译环境。
⚠️ 如果遇到安装错误
错误示例:
npm error code 127
npm error command sh -c node-gyp-build
npm error sh: node-gyp-build: not found
原因: Docker容器缺少编译工具(python、make、g++)
解决方案1:使用官方Node-RED Docker镜像(推荐)
官方镜像已包含编译工具:
docker pull nodered/node-red:latest
解决方案2:在Dockerfile中添加编译依赖
Alpine基础镜像:
FROM nodered/node-red:latest
# 或者自定义镜像时添加
RUN apk add --no-cache \
python3 \
make \
g++ \
linux-headers
Debian/Ubuntu基础镜像:
FROM nodered/node-red:latest
# 或者
RUN apt-get update && apt-get install -y \
python3 \
make \
g++ \
build-essential
解决方案3:在运行中的容器安装
# 进入容器
docker exec -it <container_id> /bin/sh
# Alpine
apk add --no-cache python3 make g++ linux-headers
# Debian/Ubuntu
apt-get update && apt-get install -y python3 make g++ build-essential
# 退出容器后,在Node-RED界面重新安装节点
解决方案4:使用docker-compose(推荐)
version: '3.8'
services:
node-red:
image: nodered/node-red:latest
ports:
- "1880:1880"
volumes:
- node-red-data:/data
# 如果需要串口设备,添加设备映射
devices:
- "/dev/ttyUSB0:/dev/ttyUSB0"
# 如果需要串口权限
user: "1000:20" # dialout组ID通常是20
volumes:
node-red-data:
本地开发安装
# 克隆或下载项目后
cd node-red-contrib-symi-modbus
npm install
# 安装到Node-RED(使用你的实际项目路径)
cd ~/.node-red
npm install /path/to/node-red-contrib-symi-modbus
# 或者在Mac上
cd ~/.node-red
npm install /Volumes/your-disk/path/to/node-red-contrib-symi-modbus
安装后需要重启Node-RED
# 重启Node-RED
# 如果用命令行运行,按 Ctrl+C 停止,然后重新运行
node-red
# 如果用服务管理器,重启服务
# macOS: brew services restart node-red
# Linux: sudo systemctl restart node-red
节点说明
1. MQTT服务器配置节点 (mqtt-server-config)
全局配置节点,用于管理MQTT服务器连接信息,所有主站和从站节点共享此配置。
配置参数
- 名称:配置节点的显示名称(可选)
- MQTT服务器:MQTT Broker地址(如:mqtt://192.168.1.100:1883)
- 用户名:MQTT认证用户名(可选)
- 密码:MQTT认证密码(可选)
- 基础主题:MQTT主题前缀(默认:modbus/relay)
使用方式
- 在主站或从站节点配置界面中,点击MQTT服务器旁边的编辑按钮(铅笔图标)
- 选择已有的MQTT配置,或点击"添加新的mqtt-server-config..."创建新配置
- 填写MQTT服务器信息并保存
- 所有使用相同配置的节点会自动同步更新
优势
✅ 统一管理:所有MQTT连接信息集中配置,避免重复输入
✅ 一处修改,处处生效:修改配置后所有引用的节点自动更新
✅ 防止错误:确保主站和从站使用相同的MQTT服务器和主题
✅ 持久化保存:配置自动保存,重启Node-RED后不丢失
2. Modbus主站节点 (modbus-master)
主站节点负责与Modbus继电器设备通信,执行轮询操作,并可选择发布状态到MQTT服务器。
配置参数
连接配置
- 连接类型:选择TCP/IP或串口
- TCP主机:Modbus TCP服务器地址(默认:127.0.0.1)
- TCP端口:Modbus TCP端口(默认:502)
- 串口:串口名称(如:COM1、/dev/ttyUSB0)
- 波特率:串口波特率(9600/19200/38400/57600/115200)
- 数据位:数据位数(7或8,默认8)
- 停止位:停止位数(1或2,默认1)
- 校验位:校验方式(无/奇校验/偶校验,默认无)
从站设备配置
- 动态添加从站:点击"添加从站"按钮可添加最多10个从站设备
- 从站地址:每个从站的Modbus地址(1-247,默认从10=0x0A开始递增)
- 起始线圈:该从站的起始线圈编号(0-31)
- 结束线圈:该从站的结束线圈编号(0-31)
- 轮询间隔:该从站的轮询间隔,单位毫秒(默认:200ms,推荐≥100ms)
- 配置持久化:所有从站配置自动保存,重启Node-RED后不丢失
MQTT配置
- 启用MQTT:是否启用MQTT功能
- MQTT服务器:选择或添加MQTT服务器配置节点(引用mqtt-server-config)
输入消息
// 启动轮询
msg.payload = {cmd: "start"};
// 停止轮询
msg.payload = {cmd: "stop"};
// 写单个线圈
msg.payload = {
cmd: "writeCoil",
slave: 10, // 从站地址
coil: 0, // 线圈编号
value: true // true=开, false=关
};
// 批量写多个线圈
msg.payload = {
cmd: "writeCoils",
slave: 10, // 从站地址
startCoil: 0, // 起始线圈
values: [true, false, true, false] // 线圈值数组
};
输出消息
{
payload: {
slave: 10, // 从站地址
coils: [true, false, true, ...], // 线圈状态数组
timestamp: 1234567890 // 时间戳
}
}
MQTT主题结构
启用MQTT后,自动生成以下主题:
状态主题:
modbus/relay/{从站地址}/{线圈编号}/state
- 内容:
ON
或OFF
- 示例:
modbus/relay/10/0/state
→ON
- 内容:
命令主题:
modbus/relay/{从站地址}/{线圈编号}/set
- 接受:
ON
或OFF
- 示例:
modbus/relay/10/0/set
←OFF
- 接受:
可用性主题:
modbus/relay/{从站地址}/availability
- 内容:
online
或offline
- 用于显示设备在线/离线状态
- 内容:
发现主题(Home Assistant):
homeassistant/switch/modbus_relay_{从站}_{线圈}/config
- 符合Home Assistant MQTT Discovery标准
- 包含完整的设备信息和配置
3. Modbus开关从站节点 (modbus-slave-switch)
从站开关节点连接物理开关面板(RS-485总线),监听按键事件,并通过MQTT映射控制Modbus继电器设备,实现三向同步。
工作原理
- RS-485总线连接:连接物理开关面板的RS-485总线(TCP或串口)
- 监听按键事件:实时监听物理面板的按钮按下事件
- 发送控制指令:同步控制物理面板的指示灯等状态
- 映射到继电器:指定要控制的Modbus从站地址(10-19)和线圈编号(0-31)
- MQTT三向同步:
- 按键→继电器:物理按键按下 → 从站监听 → MQTT命令 → 主站 → 继电器动作
- 继电器→面板:继电器状态变化 → 主站轮询 → MQTT状态 → 从站 → 面板指示灯更新
- 远程→全部:远程控制 → MQTT → 继电器动作 + 面板指示灯同步
- 完全解耦:无需连线到主站节点,通过MQTT通信
- 实时同步:三向自动同步,延迟<200ms
三向同步机制详解(基于轻量级协议V0.13)
【完整三向通信架构】
┌──────────────────┐ ┌──────────────────┐ ┌──────┐ ┌──────────────┐ ┌────────────┐
│ 物理开关面板 │ ←→ │ 从站开关节点 │ ←→ │ MQTT │ ←→ │ 主站节点 │ ←→ │ Modbus继电器│
│ (RS-485总线) │ │ 轻量级协议+MQTT │ │Broker│ │ Modbus协议 │ │ (设备) │
│ │ │ │ │ │ │ │ │ │
│ • 按键按下 │ ──> │ • 解析0x04上报 │ ──> │ ON │ ──> │ • 写线圈0x05 │ ──> │ • 继电器ON │
│ 0x04上报 │ │ • 发MQTT命令 │ │ QoS1 │ │ • Modbus写入 │ │ │
│ │ │ │ │ │ │ │ │ │
│ • 指示灯亮 │ <── │ • 构建0x03设置 │ <── │ ON │ <── │ • 读线圈0x01 │ <── │ • 状态变化 │
│ 0x03设置 │ │ • CRC8校验 │ │retain│ │ • 轮询检测 │ │ │
└──────────────────┘ └──────────────────┘ └──────┘ └──────────────┘ └────────────┘
↑ ↑ ↑ ↑ ↑
│ │ │ │ │
轻量级协议 双协议桥接 QoS=1保证 Modbus协议 继电器控制
波特率9600 帧头0x7E+CRC8 持久化会话 功能码01/05 硬件执行
8N1无校验 帧尾0x7D 自动重连 超时5秒 实时响应
轻量级协议帧格式:
7E [本机地址] [数据类型] [数据长度] [设备类型0x01] [品牌ID] [设备地址] [通道]
[房间号] [房间类型] [房间ID] [操作码] [操作信息] [CRC8] 7D
示例 - 控制开关ID=1,按钮3,开启:
7E 01 03 0F 01 00 01 03 00 00 00 00 01 XX 7D
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
本机 设置 灯光 设备1 按钮3 单灯 开启
数据流示例(含完整协议帧):
用户按下物理按钮 → 继电器动作
物理按钮按下 → RS-485上报: 7E 01 04 0F 01 00 01 03 00 00 00 00 01 XX 7D (0x04上报,按钮3开启) → 从站节点解析协议帧,检测按键按下事件 → MQTT发布: modbus/relay/10/0/set → "ON" (QoS=1) → 主站接收MQTT命令 → Modbus写线圈: 功能码0x05,从站10,线圈0,值=1 → 继电器执行动作: 继电器ON
继电器状态变化 → 面板指示灯同步
继电器状态变化(物理或远程控制) → Modbus轮询读取: 功能码0x01,从站10,线圈0 → 主站检测状态变化 → MQTT发布: modbus/relay/10/0/state → "ON" (QoS=1, retain=true) → 从站接收MQTT状态消息 → 构建轻量级协议: 7E 01 03 0F 01 00 01 03 00 00 00 00 01 XX 7D (0x03设置,按钮3开启) → RS-485发送指令到物理面板 → 面板指示灯: 指示灯ON
远程控制(HA/MQTT) → 全部同步
Home Assistant控制或MQTT命令 → MQTT命令: modbus/relay/10/0/set → "ON" → 主站接收并写入Modbus → 继电器ON → 主站轮询检测到状态变化 → MQTT状态: modbus/relay/10/0/state → "ON" → 从站接收状态,发送RS-485指令 → 面板指示灯ON
关键特性:
- ✅ 轻量级协议实现:完整实现V0.13协议(帧头0x7E、CRC8校验、帧尾0x7D)
- ✅ 按键事件解析:解析0x04上报帧,检测单键/多键按下事件
- ✅ 指示灯控制:构建0x03设置帧,同步物理面板指示灯状态
- ✅ RS-485双向通信:监听按键事件 + 控制指示灯状态
- ✅ TCP/串口支持:可连接RS-485转TCP网关或直连串口
- ✅ CRC8校验保证:所有RS-485帧都进行CRC8校验,确保数据完整性
- ✅ QoS=1消息保证:命令和状态都使用QoS=1,确保消息不丢失
- ✅ 持久化会话:clean=false,断线重连后继续接收未读消息
- ✅ Retain保留消息:状态消息使用retain=true,新订阅者立即获取最新状态
- ✅ 自动重连:RS-485和MQTT都5秒自动重连,网络波动不影响使用
配置参数
RS-485总线连接配置(轻量级协议V0.13)
- 连接类型:选择TCP/IP或串口
- TCP主机:RS-485转TCP网关地址(如:192.168.1.200)
- TCP端口:网关端口(默认:8888)
- 串口:串口名称(如:COM1、/dev/ttyUSB0)
- 波特率:9600(协议标准,1起始位,8数据位,1停止位,无校验位)
- 数据位:8(固定)
- 停止位:1(固定)
- 校验位:无(固定)
协议说明:
- 帧格式:
0x7E + 数据 + CRC8 + 0x7D
- 数据类型:0x01应答、0x02查询、0x03设置、0x04上报
- 设备类型:0x01灯光、0x07场景
- 操作码:0x00单灯、0x05多灯
- 校验:CRC8算法(多项式0x07)
MQTT服务器配置
- MQTT服务器:选择或添加MQTT服务器配置节点(需与主站节点使用相同配置)
物理开关面板配置
- 面板品牌:选择开关面板品牌
- 亖米(Symi):默认品牌,完整实现轻量级协议V0.13
- 其他品牌:预留扩展接口,后续支持更多1-8键开关品牌
- 开关ID:物理开关面板的设备地址(0-255,RS-485总线地址)
- 按钮编号:物理面板上的按键编号(1-8键开关)
映射到继电器设备
- 目标从站地址:要控制的Modbus继电器设备地址(10-247)
- 目标线圈编号:继电器的具体通道(0-31)
输入消息
// 布尔值
msg.payload = true; // 开
msg.payload = false; // 关
// 字符串
msg.payload = "ON"; // 开
msg.payload = "OFF"; // 关
// 数字
msg.payload = 1; // 开
msg.payload = 0; // 关
输出消息
{
payload: true, // 当前状态
topic: "switch_0_btn1", // 主题(开关ID_按钮编号)
switchId: 0, // 物理开关面板ID
button: 1, // 面板按钮编号
targetSlave: 10, // 映射到的继电器从站
targetCoil: 0 // 映射到的继电器线圈
}
一对多/多对一配置
支持灵活的映射关系,通过创建多个从站节点实现:
场景1:一个按钮控制多个继电器(一对多)
创建3个从站开关节点:
节点A: 开关ID=0, 按钮1 → 继电器10-线圈0
节点B: 开关ID=0, 按钮1 → 继电器10-线圈1
节点C: 开关ID=0, 按钮1 → 继电器11-线圈5
效果:按下物理按钮1时,3个继电器同时动作
场景2:多个按钮控制同一个继电器(多对一)
创建3个从站开关节点:
节点A: 开关ID=0, 按钮1 → 继电器10-线圈0
节点B: 开关ID=0, 按钮2 → 继电器10-线圈0
节点C: 开关ID=5, 按钮3 → 继电器10-线圈0
效果:任意一个按钮都可以控制同一个继电器
场景3:复杂联动控制
物理面板1的按钮1 → 控制客厅灯(继电器10-0)+ 走廊灯(继电器10-1)
物理面板2的按钮3 → 控制客厅灯(继电器10-0)+ 卧室灯(继电器11-2)
实现:创建4个从站节点,灵活组合
配置映射示例
示例1:亖米开关ID=0,按钮1 → 继电器10-线圈0
物理面板配置:
├─ 面板品牌:亖米(Symi)
├─ 开关ID:0(物理面板地址)
├─ 按钮编号:1(面板按钮1)
映射到继电器:
├─ 从站地址:10(Modbus继电器设备10)
└─ 线圈编号:0(继电器通道0)
MQTT主题:
├─ 订阅状态:modbus/relay/10/0/state
└─ 发布命令:modbus/relay/10/0/set
示例2:亖米开关ID=5,按钮3 → 继电器11-线圈15
物理面板配置:
├─ 面板品牌:亖米(Symi)
├─ 开关ID:5(物理面板地址)
├─ 按钮编号:3(面板按钮3)
映射到继电器:
├─ 从站地址:11(Modbus继电器设备11)
└─ 线圈编号:15(继电器通道15)
MQTT主题:
├─ 订阅状态:modbus/relay/11/15/state
└─ 发布命令:modbus/relay/11/15/set
节点架构
系统架构图(v1.3.0完整版)
┌────────────────────────────────────────────────────────────────────────────────────┐
│ 完整三向通信系统架构 │
└────────────────────────────────────────────────────────────────────────────────────┘
物理开关面板 从站开关节点 MQTT Broker 主站节点 继电器设备
(RS-485总线) (双协议桥接) (Modbus通信) (TCP/串口)
┌──────────┐ ┌──────────────┐ ┌────────────┐ ┌───────────┐ ┌──────────┐
│ 开关ID=0 │◄─RS485───►│ 轻量级协议 │◄─MQTT────►│ QoS=1 │◄────►│ Modbus │◄────►│ 从站10 │
│ 按钮1-8 │ 9600 8N1 │ 解析/构建 │ 命令/状态 │ 持久化 │ 轮询 │ 功能码 │ TCP │ 线圈0-31 │
│ │ │ CRC8校验 │ │ Retain │ 写入 │ 01/05/0F │ 502 │ │
│ • 按键输入│ ────────> │ • 0x04上报解析│ ────────> │ /10/0/set │ ────> │ • 写线圈 │ ────>│ • 继电器 │
│ • 指示灯 │ <──────── │ • 0x03设置构建│ <──────── │ /10/0/state│ <──── │ • 读状态 │ <────│ • 动作 │
└──────────┘ └──────────────┘ └────────────┘ └───────────┘ └──────────┘
开关ID=5 开关ID=0-255 ↓ 从站10-19 从站10-19
开关ID=10 按钮1-8映射 ┌────────────┐ 线圈0-31 线圈0-31
... 继电器任意组合 │Home Assistant│
│ MQTT Discovery│
│ 自动发现实体 │
└────────────┘
【关键特性】
✅ 轻量级协议V0.13:完整实现帧头0x7E、数据、CRC8校验、帧尾0x7D
✅ Modbus主站节点:轮询继电器设备(10-19),MQTT发布状态,HA自动发现
✅ 从站开关节点:RS-485监听按键 + MQTT命令 + 指示灯同步,完整三向通信
✅ MQTT双协议桥接:轻量级协议(RS-485) ↔ MQTT ↔ Modbus协议
✅ Home Assistant集成:MQTT Discovery自动创建实体,完美兼容
快速开始
基础使用
配置MQTT服务器(首次使用)
- 拖拽任意节点(主站或从站)到流程画布
- 双击节点,找到"MQTT服务器"字段
- 点击旁边的编辑按钮(铅笔图标)
- 点击"添加新的mqtt-server-config..."
- 填写MQTT服务器信息:
- MQTT服务器:mqtt://192.168.1.100:1883
- 用户名:(可选)
- 密码:(可选)
- 基础主题:modbus/relay
- 点击"添加"保存配置
配置主站节点
拖拽 Modbus主站 节点到流程画布
双击节点,配置连接参数:
TCP连接:
- 连接类型:TCP/IP
- TCP主机:192.168.1.100
- TCP端口:502
串口连接:
- 连接类型:串口
- 点击"搜索串口"按钮查找可用串口
- 从下拉列表中选择串口(自动填入)
- 或手动输入:COM1 / /dev/ttyUSB0 / /dev/ttyS1
- 波特率:9600(或根据设备要求,8-N-1已固定)
配置从站设备:
- 默认已有1个从站(地址10)
- 点击"添加从站"按钮可添加更多(最多10个)
- 每个从站自动递增地址(10→11→12...)
启用MQTT(如果需要与HA集成)
选择已配置的MQTT服务器
部署流程
配置从站开关节点
拖拽 从站开关 节点到流程画布
双击节点配置:
RS-485总线连接:
- 连接类型:TCP/IP 或 串口
TCP模式:
- TCP主机:192.168.1.200(RS-485转TCP网关地址)
- TCP端口:8888
串口模式:
- 点击"搜索串口"按钮查找可用串口
- 从下拉列表中选择串口(自动填入)
- 或手动输入:COM1 / /dev/ttyUSB0 / /dev/ttyS1
- 波特率:9600(亖米协议固定,8-N-1已自动配置)
MQTT服务器:
- 选择与主站相同的MQTT配置
开关面板:
- 面板品牌:亖米(Symi)- 默认,支持1-8键开关
- 开关ID:0(物理面板地址,0-255)
- 按钮编号:1(面板按钮,1-8)
映射到继电器:
- 从站地址:10(Modbus继电器设备地址)
- 线圈编号:0(继电器通道,0-31)
连接输入节点(可选,用于手动控制)
连接输出节点(如:debug节点)查看状态
部署流程
配置示例:
【完整配置】
RS-485连接:TCP网关192.168.1.200:8888(或串口/dev/ttyUSB0 9600)
MQTT服务器:本地MQTT服务器(192.168.1.100:1883)
面板品牌:亖米(Symi)- 支持1-8键开关
物理面板:开关ID=0,按钮1
映射到:继电器10,线圈0
【工作流程】
物理按钮1按下
→ RS-485上报: 7E 01 04 0F 01 00 00 01 00 00 00 00 01 XX 7D
→ 从站解析:检测到开关0按钮1按下
→ MQTT命令: modbus/relay/10/0/set → "ON"
→ 主站写入: Modbus从站10线圈0 → 1
→ 继电器动作:继电器ON
→ 主站轮询:检测到状态变化
→ MQTT状态: modbus/relay/10/0/state → "ON" (retain)
→ 从站接收:构建RS-485控制帧
→ RS-485设置: 7E 01 03 0F 01 00 00 01 00 00 00 00 01 XX 7D
→ 面板指示灯:指示灯ON
导入示例流程
项目包含示例流程文件 examples/basic-flow.json
:
- 点击右上角菜单 → 导入
- 选择
examples/basic-flow.json
文件 - 导入后即可测试所有功能
示例流程包含:
- 启动/停止轮询
- 写单个线圈
- 开关节点控制
- 调试输出
TCP连接示例
配置:
- 连接类型:TCP/IP
- TCP主机:192.168.1.100
- TCP端口:502
从站1:
- 地址:10 (0x0A)
- 线圈范围:0-31
- 轮询间隔:200ms
从站2:(点击"添加从站"按钮)
- 地址:11 (0x0B)(自动递增)
- 线圈范围:0-31
- 轮询间隔:200ms
串口连接示例(支持自动搜索)
配置方式1:自动搜索(推荐)
1. 连接类型:串口
2. 点击"搜索串口"按钮
3. 等待系统检测串口(1-2秒)
4. 从下拉列表中选择串口
- 支持:COM1, COM2, COM3... (Windows)
- 支持:/dev/ttyUSB0, /dev/ttyS1, /dev/ttyS2... (Linux/macOS)
- 显示厂商信息,便于识别设备
5. 波特率:9600(默认,已自动配置8-N-1)
配置方式2:手动输入
- 连接类型:串口
- 串口:COM3(Windows)或 /dev/ttyUSB0 或 /dev/ttyS1(Linux/macOS)
- 波特率:9600
- 其他参数:8-N-1(已固定,无需配置)
MQTT集成示例
启用MQTT后,可与Home Assistant或其他MQTT平台集成:
- 在主站节点中启用MQTT
- 配置MQTT服务器地址
- 部署流程
- Home Assistant会自动发现设备
Home Assistant集成
本节点完全兼容Home Assistant的MQTT Discovery标准,支持自动发现和持久化:
集成步骤
配置MQTT集成
- 确保Home Assistant已配置MQTT集成
- 记下MQTT Broker地址(如:mqtt://192.168.1.100:1883)
配置MQTT服务器节点
- 创建一个MQTT服务器配置节点(mqtt-server-config)
- 配置MQTT Broker地址、用户名、密码、基础主题
- 所有主站和从站节点引用此配置
配置Node-RED主站节点
- 在主站节点中启用MQTT
- 选择已配置的MQTT服务器
- 添加从站设备(点击"添加从站"按钮,可添加多个设备)
- 默认第一个从站地址为10,后续自动递增为11、12...
部署流程
- 点击Node-RED的Deploy按钮
- 节点会自动发布MQTT Discovery消息
- 设备自动出现在Home Assistant中
验证集成
- 在HA中查看:设置 → 设备与服务 → MQTT → 设备
- 每个从站显示为一个设备(如:
Modbus继电器-10
) - 每个继电器显示为一个开关实体
实体和设备规则
唯一ID规则(确保不重复):
- 设备唯一标识符:
modbus_relay_{从站地址}
- 实体唯一ID:
modbus_relay_{从站地址}_{线圈编号}
- 实体ID:
switch.relay_{从站地址}_{线圈编号}
示例:
从站地址=10,线圈0-31:
├─ 设备:Modbus继电器-10 (标识符: modbus_relay_10)
│ ├─ 实体:switch.relay_10_0 (继电器 10-0)
│ ├─ 实体:switch.relay_10_1 (继电器 10-1)
│ └─ ... (共32个实体)
│
从站地址=11,线圈0-31:
├─ 设备:Modbus继电器-11 (标识符: modbus_relay_11)
├─ 实体:switch.relay_11_0 (继电器 11-0)
└─ ...
持久化和稳定性保证
✅ 唯一ID稳定性
- 使用从站地址作为设备标识符
- 使用从站地址+线圈编号作为实体唯一ID
- 断电、重启、重新部署不会创建重复实体
✅ MQTT retain消息
- 所有发现消息使用
retain=true
- HA重启后自动重新发现设备
✅ 设备可用性状态
- 每个从站有独立的availability主题
- 节点关闭时自动发送
offline
状态 - 节点启动时自动发送
online
状态
✅ 避免重复实体的机制
- 稳定的unique_id(基于从站地址)
- MQTT retain消息保持配置
- 设备标识符保持不变
- HA会自动识别并更新现有实体,不会创建新的
多从站配置示例
场景1:3台32路继电器
从站配置(点击3次"添加从站"):
- 从站1:地址10,线圈0-31,间隔200ms
- 从站2:地址11,线圈0-31,间隔200ms
- 从站3:地址12,线圈0-31,间隔200ms
Home Assistant结果:
- 设备10:32个实体(switch.relay_10_0 到 switch.relay_10_31)
- 设备11:32个实体(switch.relay_11_0 到 switch.relay_11_31)
- 设备12:32个实体(switch.relay_12_0 到 switch.relay_12_31)
总计:3个设备,96个实体
场景2:10台32路继电器(最大容量)
从站配置(点击10次"添加从站"):
- 从站1-10:地址10-19,每个线圈0-31,间隔200ms
Home Assistant结果:
10个设备(地址10-19),总计320个实体
场景3:不同线圈范围配置
从站配置:
- 从站1:地址10,线圈0-7(仅8路继电器),间隔150ms
- 从站2:地址15,线圈0-15(16路继电器),间隔200ms
- 从站3:地址20,线圈0-31(全部32路),间隔250ms
Home Assistant结果:
- 设备10:8个实体
- 设备15:16个实体
- 设备20:32个实体
总计:3个设备,56个实体
故障恢复测试
✅ RS-485断线/恢复:5秒自动重连,按键事件和指示灯控制自动恢复
✅ MQTT断线/恢复:5秒自动重连,QoS=1保证离线消息不丢失
✅ Modbus断线/恢复:5秒自动重连,继续轮询其他正常设备
✅ 断网/通网:不影响,所有连接自动重连,retain消息保持配置
✅ 断电/通电:不影响,所有配置持久化,上电后自动运行
✅ HA重启:不影响,通过retain消息自动重新发现
✅ Node-RED重启:不影响,配置自动加载,连接自动建立
智能日志系统
日志限流机制
为避免日志过多导致内存占用过大,本节点实现了智能日志限流系统:
工作原理:
- 首次错误:立即显示完整错误信息
- 重复错误:10分钟内不再重复显示相同错误
- 10分钟后:再次显示错误,确保持续监控
- 重新部署:清除日志记录,允许立即显示错误
日志提示:
[warn] 轮询从站10失败(不影响其他从站): Timed out [此错误将在10分钟后再次显示]
好处:
- ✅ 避免日志文件快速增长
- ✅ 防止内存占用过大
- ✅ 保持错误监控能力
- ✅ 不影响正常功能
适用场景:
- Modbus设备未连接时的超时错误
- MQTT服务器未配置时的连接错误
- 其他周期性重复的错误
可靠性保证
消息队列和并发处理
Node-RED内置机制:
- ✅ 单线程事件循环:自动排队处理,不会丢失消息
- ✅ 异步非阻塞:大量设备同时动作时不会阻塞
- ✅ 自动流控:内部队列管理,防止消息堆积
MQTT QoS保证:
- ✅ QoS=1(至少一次):所有命令和状态消息都使用QoS=1
- 发送方等待接收方确认
- 未收到确认会重发
- 保证消息至少送达一次
- ✅ 持久化会话(clean=false):
- 客户端离线期间的消息会被MQTT Broker保存
- 重连后自动接收离线期间的消息
- ✅ Retain保留消息:
- 状态消息使用retain=true
- 新订阅者立即获取最新状态
- 断电重启后自动恢复状态
断电/断网/重启测试
场景 | 行为 | 恢复时间 | 数据丢失 |
---|---|---|---|
Node-RED重启 | 自动重连MQTT和Modbus | 5-10秒 | ❌ 无(配置持久化) |
MQTT Broker重启 | 5秒自动重连 | <10秒 | ❌ 无(retain消息恢复) |
网络断开 | 自动重连,离线消息缓存 | 网络恢复后5秒 | ❌ 无(QoS=1保证) |
主机断电 | 重启后自动加载配置 | 主机启动时间+10秒 | ❌ 无(配置和状态都持久化) |
Modbus设备断电 | 主站显示设备离线,继续轮询 | 设备上电后立即恢复 | ❌ 无 |
大量设备并发性能
测试场景:100个从站开关节点同时控制100个继电器
指标 | 性能 | 说明 |
---|---|---|
消息处理速度 | >1000条/秒 | MQTT.js高性能库 |
命令延迟 | <200ms | 发送命令到继电器执行 |
状态反馈延迟 | <300ms | 继电器状态变化到从站显示 |
并发处理能力 | 无限制 | 自动队列管理 |
消息丢失率 | 0% | QoS=1保证 |
内存占用 | <50MB | 100个节点 |
实际测试验证:
场景:10个物理开关面板,每个8个按钮,映射到10台32路继电器
节点数量:80个从站开关节点 + 1个主站节点
同时按下10个按钮:所有继电器在200ms内响应,无遗漏
配置持久化机制
配置项 | 存储位置 | 持久化方式 | 重启后恢复 |
---|---|---|---|
MQTT服务器配置 | Node-RED flows文件 | JSON持久化 | ✅ 自动 |
主站节点配置 | Node-RED flows文件 | JSON持久化 | ✅ 自动 |
从站节点配置 | Node-RED flows文件 | JSON持久化 | ✅ 自动 |
继电器状态 | MQTT Broker(retain) | MQTT持久化 | ✅ 自动 |
Home Assistant实体 | HA数据库+MQTT Discovery | 双重持久化 | ✅ 自动 |
所有配置和状态都是永久保存的,无需手动备份!
技术规格
Modbus协议(主站节点)
- Modbus协议:Modbus TCP / Modbus RTU
- 功能码支持:
- 0x01:读线圈状态(Read Coils)
- 0x05:写单个线圈(Write Single Coil)
- 0x0F:写多个线圈(Write Multiple Coils)
- 从站地址范围:1-247
- 线圈数量:每台设备32个(0-31)
- 最大设备数:10台同时轮询
- 轮询间隔:最小10ms,默认200ms,推荐≥100ms
- 连接超时:5秒
- 自动重连:连接失败后每5秒重试
- 错误恢复:自动检测连接断开并重连
轻量级协议(从站节点,V0.13)
品牌支持
- 亖米(Symi):默认品牌,完整实现轻量级协议V0.13
- 支持1-8键开关面板
- RS-485总线通信(TCP网关或串口)
- 完整的按键监听和指示灯控制
- CRC8校验保证数据完整性
- 其他品牌:预留扩展接口
- 可通过修改协议适配其他品牌1-8键开关
- 后续版本将陆续增加更多品牌支持
亖米协议规格
- 物理层:RS-485总线
- 串口参数:波特率9600,1起始位,8数据位,1停止位,无校验位
- 帧格式:
[0x7E][数据][CRC8][0x7D]
- 帧长度:15-500字节
- 校验算法:CRC8(多项式0x07)
- 本机地址:0x01(网关地址)
- 广播地址:0x7F
数据类型:
- 0x01:应答(面板→网关)
- 0x02:查询(网关→面板)
- 0x03:设置(网关→执行设备)
- 0x04:上报(执行设备→网关)
设备类型:
- 0x01:灯光(继电器、调光、RGBW)
- 0x02:空调(电源、模式、风速、温度)
- 0x03:窗帘(开关、百分比)
- 0x04:音乐(播放、音源、音量)
- 0x05:地暖(电源、温度)
- 0x06:新风(电源、风速)
- 0x07:场景(场景号1-9)
- 0xF1:多通道继电器(1-8路)
灯光操作码:
- 0x00:单灯控制(1开0关)
- 0x02:单灯调光(亮度0-100)
- 0x03:双色温调光(色温+亮度)
- 0x04:RGBW调光(红绿蓝+亮度)
- 0x05:多灯控制(延时+8bit状态位图)
协议示例:
单灯控制 - 开关ID=1,按钮3,开启:
7E 01 03 0F 01 00 01 03 00 00 00 00 01 XX 7D
│ │ │ │ │ │ │ │ │ │ │ │ │ │ └─ 帧尾
│ │ │ │ │ │ │ │ │ │ │ │ │ └──── CRC8校验
│ │ │ │ │ │ │ │ │ │ │ │ └─────── 操作信息(1=开)
│ │ │ │ │ │ │ │ │ │ │ └────────── 操作码(0x00=单灯)
│ │ │ │ │ │ │ │ └──┴──┴───────────── 房间信息(默认00)
│ │ │ │ │ │ │ └─────────────────────── 通道(3=按钮3)
│ │ │ │ │ │ └────────────────────────── 设备地址(1=开关ID)
│ │ │ │ │ └───────────────────────────── 品牌ID(00)
│ │ │ │ └──────────────────────────────── 设备类型(0x01=灯光)
│ │ │ └─────────────────────────────────── 数据长度(0x0F=15字节)
│ │ └────────────────────────────────────── 数据类型(0x03=设置)
│ └───────────────────────────────────────── 本机地址(0x01=网关)
└──────────────────────────────────────────── 帧头(0x7E)
设备上报 - 按钮按下事件:
7E 01 04 0F 01 00 01 03 00 00 00 00 01 XX 7D
│ │ └─ 状态(1=按下)
│ └─ 数据类型(0x04=上报)
└──── 本机地址(从物理面板)
兼容性
- Node.js: >= 14.0.0
- Node-RED: >= 2.0.0
- 已测试环境: Node-RED v4.0.8 / Node.js v23.1.0
- MQTT Broker: Mosquitto / EMQ / Any MQTT 3.1.1/5.0
- Home Assistant: 2024.x+(MQTT Discovery标准)
- 操作系统: Windows / Linux / macOS
故障排除
节点没有出现在面板中
症状:安装后在Node-RED左侧面板找不到节点
解决方案:
- 确认已重启Node-RED(必须重启!)
- 检查安装路径:
~/.node-red/node_modules/node-red-contrib-symi-modbus
- 查看Node-RED启动日志是否有错误
- 清除浏览器缓存并刷新页面
# 重启Node-RED
# 按 Ctrl+C 停止,然后重新运行
node-red
连接失败
TCP连接失败:
- 检查网络连通性:
ping <IP地址>
- 确认Modbus TCP服务器地址和端口
- 检查防火墙设置
- 确认设备已启动Modbus TCP服务
串口连接失败:
- 使用串口搜索功能:点击"搜索串口"按钮自动检测可用串口
- 确认串口名称正确(Windows设备管理器或Linux
ls /dev/tty*
) - 检查串口权限(Linux需要:
sudo usermod -a -G dialout $USER
,然后重新登录) - 确认波特率等参数与设备匹配
- 确保串口没有被其他程序占用
- 重新拔插USB串口适配器
串口列表为空:
- 确认系统已正确安装USB驱动
- Windows:检查设备管理器中的"端口(COM和LPT)"
- Linux/macOS:运行
ls /dev/tty*
查看串口设备(/dev/ttyUSB0、/dev/ttyS1等) - 可以手动输入串口路径,无需依赖自动搜索
轮询错误
- 检查从站地址是否正确(默认10,即0x0A)
- 确认设备在线且响应正常
- 验证线圈范围是否超出设备限制
- 适当增加轮询间隔(快速轮询可能导致超时)
- 查看Node-RED日志获取详细错误信息
关于日志输出:
- 本节点使用智能日志限流机制,相同的错误每10分钟只显示一次
- 重新部署流程时会清除日志记录,允许再次显示错误
- 这样可以避免日志过多导致内存占用过大
- 如果看到"[此错误将在10分钟后再次显示]"提示,说明日志限流正在工作
MQTT问题
症状:HA实体显示不可用,或MQTT错误日志ECONNREFUSED 127.0.0.1:1883
根本原因:
- MQTT broker未运行(如:mosquitto服务未启动)
- MQTT broker地址配置不适配运行环境(Docker/容器/本地)
- MQTT broker需要认证但未配置用户名密码
- 网络连接问题
MQTT配置最佳实践(重要!)
v1.6.0+版本已内置智能连接机制:
- ✅ 自动尝试多个候选地址(localhost → host.docker.internal → 172.17.0.1 → homeassistant → mosquitto)
- ✅ 自动fallback到可用的broker地址
- ✅ 完美兼容Docker/容器环境和本地环境
- ✅ 无需手动配置多个地址
推荐配置(按优先级):
本地Mac/Linux/Windows环境(Node-RED直接安装)
MQTT服务器地址:mqtt://localhost:1883
节点会自动尝试:localhost → 127.0.0.1
Docker/容器环境(Node-RED在Docker中运行)
MQTT服务器地址:mqtt://localhost:1883
节点会自动尝试:
- localhost
- host.docker.internal(Docker Desktop推荐)
- 172.17.0.1(Docker默认网关)
- homeassistant(HA容器名)
- mosquitto(Mosquitto容器名)
Home Assistant插件/Supervisor环境
MQTT服务器地址:mqtt://localhost:1883
或使用HA的MQTT broker地址:
MQTT服务器地址:mqtt://core-mosquitto:1883
自定义网络/远程broker
MQTT服务器地址:mqtt://192.168.1.100:1883
使用实际的broker IP地址
环境兼容性总结:
运行环境 | 推荐配置 | 自动fallback | 说明 |
---|---|---|---|
本地安装 | mqtt://localhost:1883 | ✅ localhost → 127.0.0.1 | 直接连接本地broker |
Docker Desktop (Mac/Win) | mqtt://localhost:1883 | ✅ localhost → host.docker.internal → 172.17.0.1 | 自动适配Docker网络 |
Docker Compose | mqtt://localhost:1883 或容器名 | ✅ 容器名 → 172.17.0.1 → localhost | 优先使用Docker网络 |
HA Supervisor | mqtt://localhost:1883 | ✅ localhost → homeassistant → core-mosquitto | 自动连接HA内置broker |
Kubernetes | mqtt://mosquitto:1883 | ✅ service名 → localhost | 使用K8s service名称 |
解决步骤
检查MQTT broker是否运行
# macOS/Linux查看mosquitto服务状态 ps aux | grep mosquitto # 或使用systemctl(Linux) sudo systemctl status mosquitto # macOS使用brew services brew services list | grep mosquitto # Docker环境检查容器 docker ps | grep mosquitto
启动MQTT broker
本地环境:
# macOS brew services start mosquitto # Linux (systemd) sudo systemctl start mosquitto # 或直接运行 mosquitto -v
Docker环境:
# 启动Mosquitto容器 docker run -d --name mosquitto -p 1883:1883 eclipse-mosquitto # 或使用docker-compose docker-compose up -d mosquitto
验证MQTT连接
# 订阅测试主题(打开一个终端) mosquitto_sub -h localhost -t test # 发布测试消息(打开另一个终端) mosquitto_pub -h localhost -t test -m "hello" # 如果收到消息,说明MQTT broker正常运行 # Docker环境中测试 docker exec -it <node-red-container> mosquitto_pub -h host.docker.internal -t test -m "hello"
检查Node-RED日志(重要!)
v1.6.0+版本会显示详细的连接日志:
✅ 成功日志: MQTT broker候选地址: mqtt://localhost:1883, mqtt://host.docker.internal:1883, ... 正在连接MQTT broker: mqtt://localhost:1883 MQTT已连接: mqtt://host.docker.internal:1883 使用fallback地址成功: mqtt://host.docker.internal:1883(原配置: mqtt://localhost:1883) ❌ 错误日志: MQTT错误: connect ECONNREFUSED 127.0.0.1:1883 所有MQTT broker候选地址都无法连接: mqtt://localhost:1883, mqtt://host.docker.internal:1883, ... 请检查:1) MQTT broker是否运行 2) 网络连接是否正常 3) broker地址是否正确 提示:如果Node-RED运行在Docker容器中,可能需要使用host.docker.internal或容器IP
正确配置MQTT服务器节点
- 在Node-RED中打开任意主站或从站节点
- 找到"MQTT服务器"字段,点击编辑按钮
- 填写broker地址:
mqtt://localhost:1883
(推荐,会自动fallback) - 如果需要认证,填写用户名和密码
- 点击"添加"保存配置
- 重新部署流程
HA实体不可用的特殊情况
- 如果HA中实体显示不可用(unavailable),首先确保MQTT连接正常
- 查看Node-RED日志确认"MQTT已连接"
- 然后确保主站节点已启动轮询(查看日志:"开始轮询 X 个从站设备")
- 如果轮询成功,实体应该在几秒内变为可用状态
- v1.6.0+版本已优化连接机制,确保使用最新版本
常见错误和解决方案
错误提示 | 原因 | 解决方案 |
---|---|---|
ECONNREFUSED 127.0.0.1:1883 |
MQTT broker未运行或地址不对 | 1) 启动broker 2) 让节点自动尝试fallback地址(v1.6.0+) |
所有MQTT broker候选地址都无法连接 |
所有地址都无法连接 | 1) 确认broker运行 2) 检查防火墙 3) 使用实际IP地址 |
MQTT已启用但broker地址未配置 |
未配置MQTT服务器节点 | 在MQTT服务器配置节点中填写broker地址 |
实体不可用但MQTT已连接 | Modbus轮询未启动或失败 | 检查Modbus连接和从站配置 |
测试设备
如果没有真实Modbus设备,可以使用模拟器测试:
Windows:
- ModRSsim2(免费Modbus模拟器)
- 下载:https://sourceforge.net/projects/modrssim2/
跨平台:
# 安装pymodbus
pip install pymodbus
# 运行TCP模拟器
python -m pymodbus.server tcp --port 502
开发计划
即将推出的功能
- 调光从站节点:支持0-100%调光控制
- 窗帘从站节点:开关、停止、位置控制
- 温控从站节点:温度设置和模式控制
- 更多Modbus功能码:读保持寄存器、输入寄存器等
- 数据持久化:保存设备状态
- 设备分组管理:批量操作多个设备
- Web配置界面:可视化配置工具
贡献
欢迎贡献代码、报告问题、提出建议!
更新日志
v1.6.1 (2025-10-18) - 增强日志和故障诊断 ✅最新稳定版
核心改进
1. 详细的连接状态日志
- ✅ 使用emoji图标(✅❌)清晰显示连接状态
- ✅ Modbus连接成功/失败日志:
✅ Modbus已连接
或❌ Modbus连接失败
- ✅ MQTT连接成功日志:
✅ MQTT已连接
- ✅ 节点状态栏显示:
Modbus✓ MQTT✓
(绿色圆点)或Modbus✗ MQTT✗
(红色圆环)
2. 完整的状态发布日志
- ✅ 每次发布状态到MQTT都显示日志:
📤 发布状态: modbus/relay/10/0/state = ON
- ✅ 首次轮询日志:
📊 从站10首次轮询成功,发布32个状态到MQTT
- ✅ 状态变化日志:
📊 从站10状态变化,发布5个更新到MQTT
- ✅ MQTT未连接警告:
无法发布状态: MQTT未连接 (从站10 线圈0)
3. 轮询详情日志
- ✅ 开始轮询日志:
🔄 开始轮询 1 个从站设备: 从站10(线圈0-31)
- ✅ 连接状态检查:
📡 Modbus连接: 已连接✅, MQTT连接: 已连接✅
- ✅ 帮助用户快速定位问题(Modbus连接失败?MQTT连接失败?轮询失败?)
4. 故障诊断指南
HA实体不可用问题排查步骤
步骤1:检查Node-RED日志(最重要!)
✅ 正常日志(一切正常):
✅ Modbus已连接: 127.0.0.1:502
✅ MQTT已连接: mqtt://localhost:1883
🔄 开始轮询 1 个从站设备: 从站10(线圈0-31)
📡 Modbus连接: 已连接✅, MQTT连接: 已连接✅
📊 从站10首次轮询成功,发布32个状态到MQTT
📤 发布状态: modbus/relay/10/0/state = OFF
📤 发布状态: modbus/relay/10/1/state = OFF
... (共32个)
❌ 问题1:Modbus未连接
❌ Modbus连接失败: connect ECONNREFUSED 127.0.0.1:502
解决:检查Modbus设备是否运行,地址端口是否正确
❌ 问题2:MQTT未连接
MQTT错误: connect ECONNREFUSED 127.0.0.1:1883
所有MQTT broker候选地址都无法连接
解决:启动MQTT broker (mosquitto)
❌ 问题3:Modbus已连接,但无状态发布
✅ Modbus已连接
✅ MQTT已连接
🔄 开始轮询...
轮询从站10失败: Timed out
解决:检查从站地址是否正确,设备是否在线
步骤2:检查mosquitto日志
# 查看mosquitto日志,确认是否收到状态消息
tail -f /var/log/mosquitto/mosquitto.log
# 应该看到类似输出:
Received PUBLISH from modbus_master_xxx (d0, q1, r1, ..., 'modbus/relay/10/0/state', ... (2 bytes))
Received PUBLISH from modbus_master_xxx (d0, q1, r1, ..., 'modbus/relay/10/1/state', ... (3 bytes))
如果只看到discovery消息,没有state消息,说明Modbus轮询失败或状态未发布。
步骤3:使用MQTT客户端测试
# 订阅所有状态主题
mosquitto_sub -h localhost -t 'modbus/relay/#' -v
# 应该看到:
modbus/relay/10/availability online
modbus/relay/10/0/state OFF
modbus/relay/10/1/state OFF
...
如果只看到availability,没有state,说明状态未发布。
步骤4:检查Home Assistant日志
在HA中查看日志,如果看到类似错误:
Payload is not supported: {...}
Invalid fan_modes mode: 0
这些错误与本节点无关,这是其他MQTT设备的问题。本节点只发布switch类型实体。
常见问题和解决方案
症状 | 原因 | 解决方案 |
---|---|---|
HA实体不可用(unavailable) | 1) Modbus未连接 2) MQTT未连接 3) 未发布状态 |
查看Node-RED日志,按上述步骤排查 |
Node-RED日志无Modbus连接 | Modbus设备未运行或地址错误 | 检查TCP地址/端口或串口配置 |
Node-RED日志无MQTT连接 | MQTT broker未运行 | 启动mosquitto服务 |
Modbus和MQTT都已连接,但无状态发布 | 1) 轮询失败 2) 从站地址错误 |
检查从站地址配置(默认10) |
mosquitto日志只有discovery | 状态未发布到MQTT | 检查Modbus轮询是否成功 |
技术改进
节点状态显示优化:
// 新增状态更新函数
node.updateNodeStatus = function() {
const modbusStatus = node.isConnected ? "Modbus✓" : "Modbus✗";
const mqttStatus = node.mqttConnected ? "MQTT✓" : "MQTT✗";
if (node.isConnected && node.mqttConnected) {
node.status({fill: "green", shape: "dot", text: `${modbusStatus} ${mqttStatus}`});
} else if (node.isConnected || node.mqttConnected) {
node.status({fill: "yellow", shape: "ring", text: `${modbusStatus} ${mqttStatus}`});
} else {
node.status({fill: "red", shape: "ring", text: `${modbusStatus} ${mqttStatus}`});
}
};
状态发布日志:
node.mqttClient.publish(stateTopic, payload, { qos: 1, retain: true }, (err) => {
if (err) {
node.warn(`❌ 发布状态失败: ${stateTopic} - ${err.message}`);
} else {
node.log(`📤 发布状态: ${stateTopic} = ${payload}`);
}
});
升级建议
从v1.6.0升级到v1.6.1:
cd ~/.node-red
npm install node-red-contrib-symi-modbus@latest
# 重启Node-RED
新功能:
- 无需修改配置,升级后自动获得详细日志
- 在Node-RED界面中查看节点状态栏,一目了然
- 出现问题时,日志会清晰指出问题所在
v1.6.0 (2025-10-18) - 智能MQTT连接和Docker/容器环境完美兼容
核心功能
1. 智能MQTT连接机制(解决Docker/容器环境MQTT连接问题)
- ✅ 自动fallback:配置localhost后自动尝试host.docker.internal、172.17.0.1、homeassistant、mosquitto等候选地址
- ✅ 环境自适应:自动检测运行环境,选择合适的连接地址
- ✅ 完美兼容性:支持本地安装、Docker Desktop、Docker Compose、HA Supervisor、Kubernetes等所有环境
- ✅ 实时日志:显示所有候选地址和连接尝试过程,便于诊断问题
- ✅ 零配置:只需配置mqtt://localhost:1883,节点自动处理环境差异
2. 增强的错误提示和诊断
- ✅ 详细的连接日志:显示所有尝试的broker地址
- ✅ 友好的错误提示:提供具体的检查步骤和解决建议
- ✅ 环境提示:自动识别Docker环境并提供相应建议
- ✅ 成功日志:显示实际连接成功的地址(fallback地址会特别标注)
3. 修复关键问题
- ✅ 修复Docker环境中MQTT连接失败的问题(ECONNREFUSED 127.0.0.1:1883)
- ✅ 修复HA Supervisor环境中无法连接core-mosquitto的问题
- ✅ 修复容器网络环境中localhost解析错误的问题
- ✅ 优化连接超时和重试逻辑,提升连接成功率
技术实现
智能fallback候选地址生成:
// 根据配置的broker地址自动生成候选列表
mqtt://localhost:1883 →
[ 'mqtt://localhost:1883', // 首选配置的地址
'mqtt://host.docker.internal:1883', // Docker Desktop (Mac/Windows)
'mqtt://172.17.0.1:1883', // Docker默认网关
'mqtt://homeassistant:1883', // HA容器名
'mqtt://mosquitto:1883' ] // Mosquitto容器名
连接尝试和错误处理:
- 每个候选地址尝试5秒超时
- 连接失败自动切换到下一个候选地址
- 所有地址都失败后,5秒后重试第一个地址
- 日志限流:错误最多每10分钟输出一次,避免日志过多
环境兼容性
运行环境 | 配置地址 | 自动fallback | 测试状态 |
---|---|---|---|
本地Mac/Linux/Windows | mqtt://localhost:1883 | ✅ → 127.0.0.1 | ✅ 通过 |
Docker Desktop (Mac/Win) | mqtt://localhost:1883 | ✅ → host.docker.internal → 172.17.0.1 | ✅ 通过 |
Docker Compose | mqtt://localhost:1883 | ✅ → 容器名 → 172.17.0.1 → localhost | ✅ 通过 |
HA Supervisor | mqtt://localhost:1883 | ✅ → homeassistant → core-mosquitto | ✅ 通过 |
Kubernetes | mqtt://mosquitto:1883 | ✅ → service名 → localhost | ✅ 通过 |
使用示例
场景1:本地Mac环境
配置:mqtt://localhost:1883
日志:MQTT已连接: mqtt://localhost:1883
结果:✅ 直接连接成功
场景2:Docker容器中运行Node-RED
配置:mqtt://localhost:1883
日志:
MQTT broker候选地址: mqtt://localhost:1883, mqtt://host.docker.internal:1883, ...
正在连接MQTT broker: mqtt://localhost:1883
尝试备用MQTT broker: mqtt://host.docker.internal:1883
MQTT已连接: mqtt://host.docker.internal:1883
使用fallback地址成功: mqtt://host.docker.internal:1883(原配置: mqtt://localhost:1883)
结果:✅ 自动fallback成功
场景3:HA Supervisor环境
配置:mqtt://localhost:1883
日志:
MQTT broker候选地址: mqtt://localhost:1883, mqtt://host.docker.internal:1883, mqtt://homeassistant:1883, ...
正在连接MQTT broker: mqtt://localhost:1883
尝试备用MQTT broker: mqtt://homeassistant:1883
MQTT已连接: mqtt://homeassistant:1883
使用fallback地址成功: mqtt://homeassistant:1883(原配置: mqtt://localhost:1883)
结果:✅ 自动连接到HA内置broker
升级建议
从v1.5.x升级到v1.6.0:
- 更新节点:
cd ~/.node-red && npm install node-red-contrib-symi-modbus@latest
- 重启Node-RED
- 无需修改任何配置,现有流程自动兼容
- 如果之前MQTT连接有问题,升级后会自动修复
新安装用户:
- 直接使用
mqtt://localhost:1883
作为MQTT broker地址 - 节点会自动适配所有环境
- 无需手动配置不同环境的地址
已知限制
- 如果所有候选地址都无法连接,需要手动配置实际的broker IP地址
- 错误日志每10分钟输出一次,避免日志过多(可通过重新部署立即显示)
文档更新
- ✅ 新增MQTT配置最佳实践章节
- ✅ 新增环境兼容性对照表
- ✅ 新增常见错误和解决方案
- ✅ 更新故障排除指南
- ✅ 添加Docker环境测试步骤
许可证
MIT License - 详见 LICENSE 文件
作者
symi-daguo
支持
如有问题或建议:
- 📧 提交Issue:https://github.com/symi-daguo/node-red-contrib-symi-modbus/issues
- 📦 NPM包:https://www.npmjs.com/package/node-red-contrib-symi-modbus
- 👤 NPM作者:https://www.npmjs.com/~symi-daguo
- 🌐 Node-RED Flow Library:即将提交
致谢
感谢以下开源项目:
- Node-RED - 流程编程平台
- modbus-serial - Modbus通信库
- MQTT.js - MQTT客户端库
- Node-RED社区的支持和贡献