workerman不能直接支持zigbee协议,必须通过mqtt等标准协议桥接zigbee2mqtt网关;其核心角色是上层调度中枢,而非硬件驱动层,需避免阻塞式串口操作,依赖zigbee2mqtt封装的设备状态与主题通信机制。

Workerman 本身不直接支持 Zigbee 协议,它只是个 PHP 网络通信框架;想让它接入智能家居中控,关键不是“让 Workerman 认识 Zigbee”,而是把它作为上层控制逻辑的调度中枢,通过标准协议桥接真实 Zigbee 网关。硬连串口或 USB 设备会破坏其多进程稳定性,也违背边缘计算分层设计原则。
Workerman 不能直接读取 /dev/ttyACM0 的原因
Workerman 的 onMessage 回调运行在事件循环中,而串口读写是阻塞式 I/O。若在回调里直接调用 fopen('/dev/ttyACM0', 'r+') ,会导致整个进程卡死——一个设备响应慢,所有连接都会被拖住。更严重的是,Workerman 多进程模型下,多个 worker 同时打开同一串口会触发资源竞争,轻则数据错乱,重则内核报 Device or resource busy 错误。
- 必须将 Zigbee 物理层交互(如 Z-Stack 或 zigbee2mqtt)剥离为独立服务,暴露 HTTP / MQTT / WebSocket 接口
- Workerman 只负责消费这些接口返回的数据,或向其下发指令,不碰硬件层
- 若强行用
stream_select()做非阻塞串口轮询,会极大增加 CPU 占用,且无法处理 Zigbee 的重传、确认、路由发现等状态机逻辑
推荐对接路径:Workerman ←→ MQTT ←→ zigbee2mqtt ←→ Zigbee 协调器
这是目前最稳定、可扩展性最强的组合。zigbee2mqtt 已经封装了 Z-Stack Linux 的全部复杂性,把 Zigbee 设备映射成标准 MQTT 主题(如 zigbee2mqtt/living_room_light),Workerman 只需用 php-mqtt/client 库订阅/发布即可。
- zigbee2mqtt 必须启用
experimental: true并配置homeassistant: false(避免与 Home Assistant 冲突) - Workerman 进程启动时,用
MQTTClient::connect()建立长连接,不要每次请求都重连 - 设备上报数据走
onMessage回调解析 JSON payload,再转发给 WebSocket 客户端或存入 Redis 缓存 - 用户语音指令(如“客厅灯打开”)由 Workerman 解析后,向
zigbee2mqtt/living_room_light/set发送{"state": "ON"}
Zigbee 设备上线后,Workerman 如何实时感知?
Zigbee 设备本身不会主动向 Workerman 注册,它只和 zigbee2mqtt 通信。所以“感知上线”本质是监听 zigbee2mqtt 的系统主题。该网关默认发布设备加入事件到 zigbee2mqtt/bridge/event,payload 类似:{"type":"device_joined","data":{"friendly_name":"0x123456789abcdef0","ieee_address":"0x123456789abcdef0"}}。
- Workerman 必须提前订阅
zigbee2mqtt/bridge/event和zigbee2mqtt/bridge/log两个主题 - 收到
device_joined后,立即向zigbee2mqtt/0x123456789abcdef0/get发送空消息,触发一次状态同步 - 别依赖
device_announce——很多低功耗传感器(如纽扣电池温湿度计)根本不会发这个帧,它们只在被轮询时才响应 - 若需设备在线状态,应以 zigbee2mqtt 的
availability字段为准,而非 TCP 连接是否存活
真正难的从来不是“连上”,而是 Zigbee 设备行为的不可预测性:有的上报间隔固定,有的靠唤醒,有的掉线后根本不重连。Workerman 做再多心跳检测也没用——它得信任 zigbee2mqtt 的设备状态管理能力,自己只管好协议转换和业务路由这一层。











