原理简介
这个智能控制系统采用 ZigBee 作为无线通信协议。
在支持 OpenWRT 系统的路由器上刷入 Ruff,利用 ZigBee-USB dongle 模块,和其他 ZigBee 终端设备通信,实现遥控功能。
物件清单
主控平台
极路由3 ,已刷入 Ruff。
传感器和执行元件
ZigBee-USB dongle 模块
ZigBee 灯
小米 ZigBee 开关
开发步骤
初始化 APP
$ rap init
添加 zigbee 驱动,id 为 zigbee ,型号选择
jn5168a
$ rap device add zigbee (jn5168a)
-
编写
src/index.js
代码'use strict'; var zigbee; $.ready(function (error) { if (error) { console.log(error); return; } zigbee = $('#zigbee'); zigbee.startup(); zigbee.setTurnLightOn(); zigbee.setTurnLightOff(); zigbee.setToggleLight(); }); $.end(function () { });
改写板卡描述
board.json
由于路由器上没有 GPIO 之类的接口,所以我们要改写板卡描述文件 ruff_modules/ruff-mbd-v1/board.json
。
{
"version": "2.0",
"id": "ruff-mbd-v1",
"model": "ruff-mbd-v1",
"preloads": {
"uart-0": "uart-0/uart"
},
"outputs": {
"uart-0": "uart-0/uart",
"gnd-0": "ground/gnd-0",
"vdd-0": "power/vdd-0"
},
"devices": [
{
"id": "ground",
"outputs": {
"gnd-0": {
"type": "ground"
}
}
},
{
"id": "power",
"outputs": {
"vdd-0": {
"type": "power",
"args": {
"voltage": "3.3v"
}
}
}
},
{
"id": "uart-0",
"model": "ruff-sys-uart",
"driver": "sys-uart",
"inputs": {
"device": {
"type": "string",
"args": {
"path": "/dev/ttyUSB0"
}
}
},
"outputs": {
"uart" : {
"type":"uart"
}
}
}
]
}
5.部署代码
`$ rap deploy your-router-ip -s`
ZigBee 驱动解析
以下三个部分分别从
ZigBee 网络包的组成
ZigBee 网络的组建
开关灯控制
三个方面,来介绍 ZigBee 驱动模块。
ZigBee 组包、解包和解析
以开关灯的控制协议来看 ZigBee 的组包过程:
start = 0x1
end = 0x3
data = [0x2, 0x44, 0xa6, 0x1, 0x1, 0x1]
msgType = 146 = 0x92 (OnOff)
msgLen = 0x6
crc = 0x92 ^ 0x6 ^ 0x2 ^ 0x44 ^ 0xa6 ^ 0x1 ^ 0x1 ^ 0x1 = 0x75
-----------------------------------------------------------------------------------
| 0x1 | 0x92 | 0x6 | 0x75 | 0x2, 0x44, 0xa6, 0x1, 0x1, 0x1 | 0x3 |
-----------------------------------------------------------------------------------
| start | msgType | msgLen | crc | Data | stop |
-----------------------------------------------------------------------------------
包的首尾是开始和结束标志。前三个字段分别是message type, message length, CRC checksum, 之后就是具体的控制数据。
由于要在包内容里避免使用开头或者结尾的标志字段,所以需要对源包内容进行转义,转义示意如下。
0x00 0x92 -> 0x2 0x10^0x00 0x92
------------------------------------------------------------------------------------------------------------
| 0x1 | 0x2 0x10 0x92 | 0x2 0x10 0x2 0x16 | 0x75 | 0x2 0x12 0x44 0xa6 0x2 0x11 0x2 0x11 0x2 0x11 | 0x3 |
------------------------------------------------------------------------------------------------------------
| start | msgType | msgLen | crc | Data | stop |
------------------------------------------------------------------------------------------------------------
解包是组包的逆过程。
解析而是依据ZigBee协议的数据手册(JN-AN-1194-ZigBee-IoT-Gateway-Control-Bridge pdf),一一对照着解析包的内容。
ZigBee网络组建代码
根据数据手册,ZigBee初始化组建网络需要经过以下几个步骤:
this.getVersion();
this.setExtendedPANID();
this.setChannelMask();
this.setSecurityStateAndKey();
this.setDeviceType();
this.startNetwork();
this.permitJoiningRequest();
在这之后,ZigBee 网络处于开放状态,可以接受连接请求。我们就可以接入上面展示的 ZigBee 灯和开关了。
ZigBee 开关灯代码
ZigBee 协议里有直接控制开关的通信类型,通过查找 ZigBee 数据手册,可以找到如下信息:
利用这个通信类型,我们写的开关灯的代码是这样的。
ZigBee.prototype.turnLightOn = function () {
console.log('turn light on');
var devices = interpreter.getDeviceList();
var msg = new Buffer([0x2, 0xff, 0xff, 0x1, 0x1, 0x1]);
if (devices.length !== 0) {
msg.writeUInt16BE(devices[0].shortAddress, 1);
}
this._writeCmd(0x92, msg);
}
ZigBee.prototype.turnLightOff = function () {
console.log('turn light off');
var devices = interpreter.getDeviceList();
var msg = new Buffer([0x2, 0xff, 0xff, 0x1, 0x1, 0x0]);
if (devices.length !== 0) {
msg.writeUInt16BE(devices[0].shortAddress, 1);
}
this._writeCmd(0x92, msg);
}
ZigBee.prototype.toggleLight = function () {
console.log('toggle light');
var devices = interpreter.getDeviceList();
var msg = new Buffer([0x2, 0xff, 0xff, 0x1, 0x1, 0x2]);
if (devices.length !== 0) {
msg.writeUInt16BE(devices[0].shortAddress, 1);
}
this._writeCmd(0x92, msg);
}
演示视频
演示(腾讯)