天猫精灵控制Zigbee设备
天猫精灵控制Zigbee设备
1. 介绍
我们在天猫精灵控制ESP32设备的文章中已经知道如何利用阿里巴巴的Link Kit SDK跑在ESP32平台,连接到阿里云的智能生活开放平台,从而使得天猫精灵能够控制WiFi设备的灯的开关。理论上我们可以添加各种协议的方案通过串口和WiFi设备交换信息和命令,从而实现天猫精灵控制终端设备。 例如Zigbee, Bluetooth Mesh, Z-Wave, Proprietary等。天猫精灵本身就支持Bluetooth Mesh设备的直接控制,就没有必要通过这种云对云的方式来控制。那么我们今天要讨论的是如何基于以上技术来实现天猫精灵控制Zigbee的设备。
为了实现控制Zigbee的终端设备,我们需要一个Coordinator来组建Zigbee的Mesh网络,实现终端设备的加网,退网,控制,状态获取等,并通过自定义的协议和WiFi设备通讯,作为一个网络桥接器,和阿里云进行交互,进而实现天猫精灵对Zigbee终端设备的语音控制。
在这个文章中我们选择Silicon Laboratories公司的WSTK板,Radio Board型号是BRD4162A,板上芯片为EFR32MG12来做Zigbee的Coordinator。
2. 生成Zigbee的Coordinator
Zigbee协议中Coordinator作为控制中心可以创建Mesh网络,管理子设备入网,退网,命令和信息传输。
在官网下载并安装好Simplicity Studio (SS), 然后在SS里面下载好Zigbee SDK.
2.1. 生成一个blank project
A) 在SS里点击"New Project", 选择"ZCL Application Framework V2",再选"EmberZNet 6.5.5.0 GA SoC 6.5.5.0",然后勾选"Start with a blank application",按Next
项目名起为Coordinator,按Next再Finish就生成了一个空的项目工程。
我们会看到项目里只有一个Coordinator.isc的文件,这个是用来配置Zigbee相关的参数,并根据配置自动生成源代码。
如图可以看到许多Tab用来配置不同的参数。
B) 选ZCL global tab,在Manufacturer code输入Ember [0x1002]
C) 选ZCL Clusters, 选择 ZCL device type为"ZigBee Custom->HA Home Gateway / Energy Management"。
选General->Basic->On/off, 使能Client
D) 选Plugins tab,使能
Network Creator
Network Creator Security
Device Table
NVM3 Library
Simulated EEPROM version2 to NVM3 Upgrade Stub
禁止Simulated EEPROM version 1 Libray, 这个和NVM3功能重叠了
E) 配置串口
在Plugins tab,选择Serial plugin,使能USART3。
选择HAL configuration tab, 点击"Open Hardware Configurator"打开硬件配置,enable"Virtual COM Port". 选择USART3,关掉Flow control mode, 存盘触发自动生成硬件配置文件,退出Hardware Configurator
F) 选Callbacks tab, 使能如下Callback函数
Non-cluster related
- Main Init, Main Tick, Hal Button Isr, Message Sent
Plugins-specific callbacks
- Device Left, New Device, State Change - Device Table plugin specific
- Complete - Network Creator plugin specific
在下面的章节我们会介绍这些callback函数的用法。
G) 选Includes tab,在Custom Event列表中添加commisioning, led, subdevState event controls
H) 打开项目属性, 将C Library中Print float和Scanf float勾选上,这样处理以后的JSON浮点数就没有问题了
I) 在Coordinator.isc右上角点击Generate按钮生成源代码
J) 去除编译错误
由于Device Table是默认在Linux下Gateway工程下工作,有些配置在Soc下编译是不能通过的,需要修改。
device-table-discovery.c
添加头文件的包含
#include "app/util/zigbee-framework/zigbee-device-common.h"
去除ezsp的调用,改为ember的调用函数。
static void setCurrentSourceRoute(uint16_t nodeId)
{emberAppendSourceRouteHandler(nodeId, EMBER_NULL_MESSAGE_BUFFER);
}
device-table.c
添加include的路径, 以及NVM3的头文件和KEY的定义
#include "app/framework/util/af-main.h"
#include "app/framework/util/attribute-storage.h"
#include "app/framework/util/common.h"#if defined (USE_NVM3)
#include "nvm3.h"
#include "nvm3_hal_flash.h"
// Device table counter key and data key
#define NVM3_DT_CNT_KEY 0x1000
#define NVM3_DT_KEY 0x2000
#endif
Device Table的存取默认是在Linux下用文件形式操作,但是在Soc上我们要把接口替换为NVM3的方式来操作
void emAfDeviceTableSave(void)
{EmberAfPluginDeviceTableEntry *deviceTable = emberAfDeviceTablePointer();uint8_t i;uint32_t counter = 0;for (i = 0; i < EMBER_AF_PLUGIN_DEVICE_TABLE_DEVICE_TABLE_SIZE; i++) {if (deviceTable[i].nodeId != EMBER_AF_PLUGIN_DEVICE_TABLE_NULL_NODE_ID) {nvm3_writeData(nvm3_defaultHandle,NVM3_DT_KEY + counter, &deviceTable[i], sizeof(deviceTable[i]));counter++;}}// Write counternvm3_writeCounter(nvm3_defaultHandle, NVM3_DT_CNT_KEY, counter);
}void emAfDeviceTableLoad(void)
{EmberAfPluginDeviceTableEntry *deviceTable = emberAfDeviceTablePointer();uint8_t i;uint32_t counter = 0;// Read number of object of device tablenvm3_readCounter(nvm3_defaultHandle, NVM3_DT_CNT_KEY, &counter);for (i = 0; i < counter; i++) {nvm3_readData(nvm3_defaultHandle,NVM3_DT_KEY + i, &deviceTable[i], sizeof(deviceTable[i]));deviceTable[i].state = EMBER_AF_PLUGIN_DEVICE_TABLE_STATE_JOINED;deviceTable[i].lastMsgTimestamp = halCommonGetInt32uMillisecondTick();}
}
处理完毕编译通过。
2.2 增添文件和功能函数
A) device-table-tracking.c
getCurrentState()函数需要被外部调用,去除其static的定义。另外添加一个getLastDeviceId()函数同样为外部调用。
B) cJSON.c, 用来处理JSON格式的信息
将本Repo的network\utility\cjson\下的cJSON.c和cJSON.h拷贝到和Coordinator_callbacks.c的同目录下。
把其中的动态内存分配的宏改为标准函数名字
#define internal_malloc malloc
#define internal_free free
#define internal_realloc realloc
由于Zigbee的SDK没有考虑动态内存分配的事情,需要我们在Coordinator_callbacks.c定义一个64KB的数组,section为".heap",这样动态内存分配函数就可以在heap区工作。
C) hal-config\hal-config.h, 将此头文件里的HAL_SERIAL_USART3_ENABLE 设置为1,否则USART3不能工作,每次isc重新生成文件后,此文件都会被覆盖,需要人工把它改过来。
D) Coordinator_callbacks.c
在这个文件里集中了我们生成的所有callback函数,我们把协议处理和WiFi处理器通讯部分都在此函数实现. 详情可以看本Repo的coordinator\coordinator_callbacks.c. 下面我们简要的介绍些流程和功能函数。
emberAfMainInitCallback()
此函数初始化时被调用,我们在这里初始化串口,LED,并启动一个延时子设备状态查询的Event,每30秒查询一次。
void emberAfMainInitCallback(void)
{halInternalInitLed();emberSerialInit(APP_COM, 115200, PARITY_NONE, 1);emberEventControlSetDelayMS(subdevStateEventControl, SUBDEV_STATE_PERIOD_MS);
}
emberAfHalButtonIsrCallback()
在有按键的情况下激活commissioningEventControl
commissioningEventHandler()
建立一个centralized network。 在网络建好后,button0触发开放网络允许子设备加入, button1关闭网络禁止设备加入。
subdevStateEventHandler()
从device table里依次找出子设备的device index, 发送Identify命令给子设备。子设备由于断电和加电会使得命令发送失败或者成功,我们就可以知道子设备在线与否。
emberAfMessageSentCallback()
每条对子设备发送的命令都会回调此函数,通过判断通讯成功和失败,来改变子设备的登记状态。
emberAfPluginDeviceTableNewDeviceCallback()
当有子设备加网成功,此函数会被调用,我们会在这里通知WiFi控制器新设备加入的信息,进而更新阿里云服务器上的设备拓扑关系。
emberAfPluginDeviceTableDeviceLeftCallback()
子设备退网触发此函数,同样通知阿里云改变设备拓扑关系。
emberAfPluginDeviceTableStateChangeCallback()
当子设备的device table的状态发生变化, 如在线,离线,未知等,发送response packet到WiFi控制器,进而改变设备在阿里云服务器上的在线和离线状态。
cmdHandler() and sendResponsePacket()
用来处理和WiFi控制器之间的通讯。
emberAfMainTickCallback()
在每个系统tick结尾处调用,用来查看串口是否有命令数据进来。超过4个字节就调用cmdHandler()来处理命令。
3. 生成WiFi的网桥
我们需要在network\app\example\linkkit_gateway\linkkit_example_gateway.c中做适当的修改来适应我们的完整功能需求。另外添加comm.c和comm.h来处理和Coordinator之间的通讯。
阿里巴巴在三月份更新了设备管理的API,原来旧有的接口例程放在了本目录的deprecated子目录下。 新的API接口还有些地方没有完善或者功能欠缺,给后期的开发带来不少麻烦,通过其他方式来做了补充。
下面我们按照执行顺序和功能模块来进行介绍。
3.1. 网桥设备注册登录阿里云
网桥设备是一机一密的方式,没有采用动态登录方式。
创建主设备,选择上海的云服务器,选择非动态登录方式,连接到阿里云
/* Register Callback */
IOT_RegisterCallback(ITE_TOPOLIST_REPLY, user_topolist_reply_event_handler);
IOT_RegisterCallback(ITE_INITIALIZE_COMPLETED, user_initialized);/* Create Master Device Resources */
user_example_ctx->master_devid = IOT_Linkkit_Open(IOTX_LINKKIT_DEV_TYPE_MASTER, &master_meta_info);/* Choose Login Server */
int domain_type = IOTX_CLOUD_REGION_SHANGHAI;
IOT_Ioctl(IOTX_IOCTL_SET_DOMAIN, (void *)&domain_type);/* Choose Login Method */
int dynamic_register = 0;
IOT_Ioctl(IOTX_IOCTL_SET_DYNAMIC_REGISTER, (void *)&dynamic_register);/* Start Connect Aliyun Server */
res = IOT_Linkkit_Connect(user_example_ctx->master_devid);
3.2. 获取网桥子设备拓扑关系
在网桥设备连云初始化完成后,会调用ITE_INITIALIZE_COMPLETED对应的回调函数user_initialized()。然后可以用ITM_MSG_QUERY_TOPOLIST选项来调用IOT_Linkkit_Query以获取与其存在拓扑关系的所有子设备信息. 列表信息将在ITE_TOPOLIST_REPLY事件回调中返回。
res = IOT_Linkkit_Query(user_example_ctx->master_devid, ITM_MSG_QUERY_TOPOLIST,NULL, 0);
数据为JSON格式,如下两个设备范例
{"id":2,"code":200,"devid":0,
"topo":[{"deviceSecret":"ZI0OtnNGd4fFExOerguZRH0huyiUcDrW","productKey":"a1dOIDDEMGM","deviceName":"000b57fffe648d84"},
{"deviceSecret":"OODoAak2RWyHHxftQWbMhDEuQvtvzdJk","productKey":"a1dOIDDEMGM","deviceName":"000b57fffe648dc2"}]}
将接收到的子设备信息进行解析,调用device_table_add_subdev()添加到本地设备列表方面以后操作管理。
3.3. 子设备的登入和登出
在创建完本地的设备列表后,通过device_get_property()和Zigbee的Coordinator进行通讯查看相应的子设备是否在线。
命令格式 为 packet_len, ~packet_len, {“cmd”:CMD_GET_PROPERTY,“dn”:“000b57fffe648dc2”}
Coordinator收到命令后会汇报子设备的状态。响应包格式,packet_len, ~packet_len, {“dn”:“000b57fffe648dc2”,“cmd”:RSP_DEV_PROPERTY, “online”:online}. 根据返回的online的值来向阿里云汇报子设备的登入和登场状态。
if (online) {res = IOT_Linkkit_Report(devid, ITM_MSG_LOGIN, NULL, 0);
} else {res = IOT_Linkkit_Report(devid, ITM_MSG_LOGOUT, NULL, 0);
}
3.4. 子设备的添加与删除
当有新的子设备加入,Coordinator会向网桥汇报RSP_DEV_ADDED。命令中包含"model",表示是什么设备。 目前我们只支持两种设备, DEVICE_ID_DIMMABLE_LIGHT和DEVICE_ID_COLOR_DIMMABLE_LIGHT。其他的model我们会不处理。
准备好子设备的meta三元组数据,创建子设备,连接阿里云,更新本地设备列表,子设备登入。
devid = IOT_Linkkit_Open(IOTX_LINKKIT_DEV_TYPE_SLAVE, meta_info);
res = IOT_Linkkit_Connect(devid);
device_table_add_subdev(meta_info, devid);
res = IOT_Linkkit_Report(devid, ITM_MSG_LOGIN, NULL, 0);
删除子设备时,Coordinator向网桥汇报RSP_DEV_REMOVED。
登出子设备,汇报阿里云删除拓扑关系,关闭子设备,更新本地设备列表
res = IOT_Linkkit_Report(devid, ITM_MSG_LOGOUT, NULL, 0);
res = IOT_Linkkit_Report(devid, ITM_MSG_DELETE_TOPO, NULL, 0);
res = IOT_Linkkit_Close(devid);
res = device_table_del_subdev(devid);
3.5. 子设备灯的开关控制
云端发送过来设备控制命令会触发ITE_PROPERTY_SET注册的回调函数。命令以JSON形式,如{“LightSwitch”:1}。 我们对云端发送过来的命令不做任何修改,跟随设备信息直接发送给coordinator。格式如下{“cmd”:67,“dn”:“000b57fffe648dc2”,“pk”:“a1dOIDDEMGM”,“payload”:{“LightSwitch”:1}}。这样做有利于以后支持新设备,不用修改网桥控制部分代码。
然后向阿里云汇报子设备开关状态,这里直接假设控制成功,如果子设备因为离线没能控制,会在RSP_DEV_PROPERTY中处理正确的状态。
res = IOT_Linkkit_Report(devid, ITM_MSG_POST_PROPERTY, (uint8_t *)request, request_len);
4. 天猫精灵控制设备灯的开关
在云智能App选择第三方服务,选中天猫精灵,设置好用户名和密码。在天猫精灵App里发现新添加的设备,起好名字。
对天猫精灵说"打开书房的灯", 灯开; “关闭书房的灯”, 灯灭; “现在灯是开的么?”, 回答"现在灯处于关闭状态"。
至此我们实现了天猫精灵以云对云的方式来控制Zigbee设备。
天猫精灵控制Zigbee设备相关推荐
- 毕业设计--20200228--内网搭建domoticz系统 frp内网穿透实现天猫精灵控制内网设备
记录一下三天的成果. 花费了3天的时间 我在树莓派上面搭建了一个domoticz 的智能家居系统 然后利用frp 去实现将本地的内网地址 穿透到 公网上面的 阿里云的个人服务器的8080 端口, 最终 ...
- php与硬件通过wifi对接,基于ESP8266的WiFi排插接入贝壳互联实现天猫精灵控制
认识众多玩家高手/拆客/DIYer,查阅更多资源,一起学习技术知识 您需要 登录 才可以下载或查看,没有帐号?立即注册 x 本帖最后由 hzy3774 于 2020-1-8 00:45 编辑 * 实验 ...
- 开源项目搭建私有物联网智能家居接入天猫精灵控制
开源项目搭建私有物联网智能家居接入天猫精灵控制 最近几年随着物联网的高速发展,众多智能硬件厂商都开发出自己的智能家居产品,都想在物联网智能家居市场上占有自己的一席之地,而随着众多智能音箱的问世,智能家 ...
- 使用ESP8266通过Blinker平台接入天猫精灵控制电视/空调
目录 `演示视频` 1.准备工作 1.1 `原理` 1.2 `使用的硬件以及硬件连接图` 1.3 `开发环境准备` 2.解码空调红外键值 2.1 `把ESP8266红外接收的实例,上传到NodeMCU ...
- (开源)ESP8266改装小风扇,手机app远程控制+天猫精灵控制
ESP8266改装小风扇,app远程控制+天猫精灵控制 材料准备 拆解风扇 第一 下载ESP8266示例(arduino ide 编程开发) 第二 修改demo例程 关于主题topic 第三 app ...
- 使用ESP8266接入“天猫精灵”控制七彩灯(WS2812)的颜色/亮度-开源
目录 `演示视频` 1.准备工作 1.1 `原理` 1.2 `使用的硬件以及硬件连接图` 1.3 `开发环境准备` `Arduino开发环境` `安装ESP8266的扩展` `安装blinker Ar ...
- ESP8266开发、ESP8266连接阿里云物联网、天猫精灵控制esp8266、esp8266一键配网、智能家居
ESP8266开发.ESP8266连接阿里云物联网.天猫精灵控制esp8266.esp8266一键配网.智能家居 项目介绍 最近会 将arduino IDE开发ESP8266中一些值得记录得部分写下来 ...
- 天猫精灵 python_利用天猫精灵控制ESP8266(NodeMCU开发板)arduino ide开发
第一 下载demo例程 下载地址: 点击下载 本demo 是利用arduino IDE开发,关于arduino IDE 的ESP8266环境配置可参考:环境配置: 点击跳转 第二 修改demo例程 需 ...
- android系统wifi控制风扇,(开源)ESP8266改装小风扇,app远程控制+天猫精灵控制...
本帖最后由 bemfa 于 2020-6-16 10:07 编辑 教程 =教程 =教程 =两个ESP8266通过云端实现远程数据交互 教程 =利用天猫精灵控制NodeMCU(ESP8266) f.pn ...
最新文章
- pandas使用groupby函数计算dataframe数据中每个分组的N个数值的滚动最大值(rolling max)、例如,计算某公司的多个店铺每N天(5天)的滚动销售额最大值
- 一般关于大宗商品的供需关系相关的数据网址有哪些?
- jquery标签选择器应用示例
- 在Java语言里 ==和equals的区别
- 定义快捷代码_nodepad++代码编辑器替代工具整理
- 无心剑中译狄金森诗36首
- java调用打印机打印excel linux_手把手教你嵌入式Linux系统驱动hp1020打印机
- 如何设置cout的输出格式(转)
- DataSet/DataFrame性能比RDD高?
- wordpress配置邮箱发送功能
- Flutter业务开发常用小技巧(样式布局篇)
- 网络贷款系统完整版源码,thinkphp内核开发,安全可靠,定制网贷分销平台系统
- c语言窗口炸弹代码,C语言实现宾果消消乐
- 【STM32学习笔记——WIFI模块】
- 架构师之路 — 分布式系统 — 分布式网络分区难题
- 速读《现代软件工程——构建之法》有感
- 《未来世界的幸存者》:你会是未来世界的幸存者吗?
- 百度云大文件高速下载方法、软件
- java 快递打印_基于java的快递打印系统
- 木瓜移动再求上市:毛利率走低、盈利能力弱,沈思“迷恋”相亲