Tmall Genie control the Zigbee devices via cloud with Micrium OS - markding/iot-developer-boot-camp GitHub Wiki
本项目的主要目的开发一个Zigbee的bridge,通过这个bridge将Zigbee设备连接到阿里云,从而实现使用天猫精灵来控制Zigbee网络中的设备。项目的示意图如下:
此外,在本项目中,使用Amazon的Echo Plus作为Zigbee的coordinator,首先将Zigbee设备加入由echo plus创建的Zigbee网络中,通过echo plus可以直接控制。另外一方面,本项目开发的router bridge也是加入到echo plus的网络中,然后通过这个bridge将zigbee网络中的设备加入阿里云。最终可以实现同时使用天猫精灵和echo plus来控制。
-
项目中涉及的平台和组件包括:
-
天猫精灵平台,只需购买一台天猫精灵智能音箱,使用淘宝账号登录即可。
-
阿里物联生活平台,需要注册帐号,并创建相关产品。
-
Zigbee router bridge, 即本项目开发的目标。由WiFi和Zigbee两部分组成,用UART接口连接二者。
- Zigbee部分,基于Silicon Labs公司的EFR32MG12以及EmberZnet SDK开发;
- WiFi部分,基于Silicon Labs公司的WGM110模组开发;
-
Amazon Echo Plus,用户需要在手机端下载Alexa APP来控制echo plus
-
-
涉及的资源和资料链接:
Silicon Labs公司的Simplicity Studio可以从官网下载,建议安装到默认的路径(C盘预留20GB以上的空间)。由于需要下载Zigbee协议SDK, 需要购买Zigbee开发套件才能拥有下载权限。本项目基于EmberZnet SDK 6.7.6版本开发。此外,此项目中还是用到了Micrium OS操作系统,也需要从Simplicity Studio中下载安装。最后由于EmberZnet中支持Micrium OS的插件现在只支持使用IAR来编译,因此需要安装IAR。对于没有IAR的用户,可以通过如下的方式来支持Micrium OS,但是Silicon Labs官方不提供技术支持。
- 下载Micrium RTOS plugin的配置文件, 替代
protocol\zigbee\app\framework\plugin-soc\micrium-rtos\plugin.properties
. (请提前做好备份) - 下载BLE plugin的配置文件, 替代
protocol\zigbee\app\framework\plugin-soc\ble\plugin.properties
. (请提前做好备份)
推荐使用GCC来编译,因为使用IAR来编译阿里云的SDK的时候,会出现很多编译错误,需要逐条修改,这些编译错误大部分都是一些类型不严格匹配的问题。
主要步骤如下:
- 启动Simplicity Studio, 打开菜单
File
-->New
-->Project
; - 选择
Silicon Labs AppBuilder Project
, 然后点击Next
继续; - 选择
Silicon Labs Zigbee
, 然后点击Next
继续; - 选择
EmberZnet 6.7.6.0 GA Soc 6.7.6.0
, 然后点击Next
继续; - 选择
ZigbeeMinimal
, 然后点击Next
继续; - 输入工程名称
Z3Aliyun
, 然后点击Next
继续; - 在
Boards
列表框, 选择BRD4162A
, 然后Part
框会自动更新成对应的芯片型号。在编译器中选择GCC,最后点击Finish
完成。 上述步骤完成后,Simplicity Studio会自动打开锁创建的工程对应的isc文件。
- 选择
ZCL Clusters
tab, 选中Endpoint 1, 然后在下面的ZCL device type
一栏选择Zigbee Custom
->HA Devices
->HA Color Dimmer Switch
。然后选择如下的Cluster:- On/Off Cluster client side
- Level Control Cluster client side
- Shade Configuration Cluster client side
- Color Control Cluster client side
- 选择
Zigbee Stack
tab, 修改设备类型为Coordinator or Router
。 - 选择
Plugins
tab, 勾选或取消如下plugins:- Counters
- Device Table
- Ember Minimal Printf
- Standard Printf Support
- Idle/Sleep
- Micrium-RTOS
- CPU Usage Tracking
- Application Task 1,
Stack Size
set to2048
- Network Creator
- Network Creator Security
- Network Steering
- Optimize scans
-
Radio output power
set to10dbm
- RAIL Library
- RAIL Library Multiprotocol
- Simple main
- Source Route Library
-
Source Route Table Size
set to32
-
- Stack Diagnostics
- NVM3 Library
-
Cache Size
set to254
-
- Zigbee PRO Stack Library
-
Child Table Size
set to32
-
Packet Buffer Count
set to32
-
Broadcast Table Size
set to32
-
- 选择
Printing and CLI
tab, 勾选Add Custom CLI sub-menu
- 选择
Callbacks
tab, 勾选/取消如下callbacks函数:- emberAfPluginNetworkSteeringCompleteCallback
- emberAfStackStatusCallback
- emberAfHalButtonIsrCallback
- emberAfMainInitCallback
- emberAfMainTickCallback
- emberAfReadAttributesResponseCallback
- emberAfPluginMicriumRtosAppTask1InitCallback
- emberAfPluginMicriumRtosAppTask1MainLoopCallback
- 选择
Includes
tab, 添加如下自定义宏:-
NO_LED
值为1
-
MBEDTLS_CIPHER_MODE_CBC
值为1
-
MBEDTLS_CIPHER_MODE_CFB
值为1
-
- 选择
Includes
tab, 添加如下自定义Event:- Event
pollAttrEventControl
, HandlerpollAttrEventHandler
- Event
clearWiFiEventControl
, HandlerclearWiFiEventHandler
- Event
commissionEventControl
, HandlercommissionEventHandler
- Event
softWdgEventControl
, HandlersoftWdgEventHandler
- Event
wifiCheckEventControl
, HandlerwifiCheckEventHandler
- Event
- 选择
Includes
tab, 添加如下自定义token:这里主要增加了3个token:/***************************************************************************//** * @file * @brief Tokens for Z3Aliyun301. ******************************************************************************* * # License * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b> ******************************************************************************* * * The licensor of this software is Silicon Laboratories Inc. Your use of this * software is governed by the terms of Silicon Labs Master Software License * Agreement (MSLA) available at * www.silabs.com/about-us/legal/master-software-license-agreement. This * software is distributed to you in Source Code format and is governed by the * sections of the MSLA applicable to Source Code. * ******************************************************************************/ #define CREATOR_KV_PAIRS (0x6801) #define NVM3KEY_KV_PAIRS (NVM3KEY_DOMAIN_USER | 0x6801) #define CREATOR_DEV_TABLE (0x6901) #define NVM3KEY_DEV_TABLE (NVM3KEY_DOMAIN_USER | 0x6901) #define CREATOR_WIFI_INFO (0x6931) #define NVM3KEY_WIFI_INFO (NVM3KEY_DOMAIN_USER | 0x6931) #ifdef DEFINETYPES // Include or define any typedef for tokens here typedef struct { char kv_key[63]; uint8_t value_len; uint8_t value[64]; } tokTypeKvs; typedef struct { uint8_t endpoint; uint16_t deviceId; EmberNodeId nodeId; EmberEUI64 eui64; } tokTypeDevTable; typedef struct { char ssid[64]; char passwd[64]; } tokTypeWiFiInfo; #endif //DEFINETYPES #ifdef DEFINETOKENS // Define the actual token storage information here #define MAX_KV_NUMBER 16 DEFINE_INDEXED_TOKEN(KV_PAIRS, tokTypeKvs, MAX_KV_NUMBER, { {0, }, 0, {0, } }) #define MAX_DEV_TABLE_NUMBER 32 DEFINE_INDEXED_TOKEN(DEV_TABLE, tokTypeDevTable, MAX_DEV_TABLE_NUMBER, { 0xFF, 0xFFFF, 0xFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} }) DEFINE_BASIC_TOKEN(WIFI_INFO, tokTypeWiFiInfo, {0}) #endif //DEFINETOKENS
- Key-value pair, 这里主要是用于存储阿里云SDK所需的一些数据,是以key-value配对的形式保存的
- Device table
- WiFi的用户名密码
参考阿里物联生活平台的开发指南,首先下载最新版本的SDK(V3.01), 参考SDK的用户手册进行配置和移植。
https://code.aliyun.com/linkkit/c-sdk/repository/archive.zip?ref=tag-v3.0.1
以windows为例,运行config.bat脚本,会弹出如下配置窗口:
用方向键进行控制,空格键或者Enter进行选择或者取消,ESC键返回。 在默认配置的基础上,需要配置的选项有:
- PLATFORM_HAS_OS
- FEATURE_DYNAMIC_REGISTER
- Device Model Configurations
- FEATURE_DEVICE_MODEL_GATEWAY
- FEATURE_ALCS_ENABLED
- FEATURE_DEV_RESET
- FEATURE_WIFI_PROVISION_ENABLED
- FEATURE_AWSS_SUPPORT_SMARTCONFIG
- FEATURE_AWSS_SUPPORT_DEV_AP
保存配置退出。
配置完成后,用户的配置保存在make.settings文件中。运行extract.bat脚本,自动提取相应的SDK源码,放置在output/eng文件夹下面。将eng文件夹拷贝到前面创建的Zigbee工程中,将eng文件夹名称修改为iotkit-embeded-sdk。
编译Zigbee工程,会有一些编译错误。主要原因是提取的SDK的头文件路径没有包含到工程中。 选择工程,右键,"Properties",将SDK各个部分的路径添加到Include中,如下图:
反复检查修改,直至编译通过。
wrapper.c中有一些接口是需要根据各自平台的具体情况来实现。这里我们使用的是运行在EFR32(ARM Cortex-M4)上的Micrium OS, IP通信依赖WGM110模组来实现。 wrapper.c中的接口主要分成几类:
- IP 通信相关接口,包括:
- TCP 连接以及读写
- UDP 读写
- TLS 连接以及读写
- 读取本地IP以及MAC
- 操作系统相关接口:
- 定时器Timer
- 内存分配Memory (malloc/free)
- 信号量Semaphore
- 互斥量Mutex
- 任务管理Task
- AES加密解密
- WiFi配网相关接口
- 其他平台接口,包括:
- 打印和格式化
- 获取运行tick
- 随机数生成
- 对接阿里物联网平台所需的接口,包括:
- 读取设备名称和产品key
- 读取和保存设备secret
- 读取和保存平台特有的key-value对
其中OS相关的接口可以参考Micrium OS的文档和手册来逐步实现。wrapper.c 的实现可以参考iotkit-embedded-sdk/wrappers/wrapper.c
.
主要参考linkkit_example_gateway.c,将其修改为动态注册,以便支持一型一密。 设备名称采用Eui64+Endpoint的方式来格式化,例如Eui64为000D6F00056AE60A的设备,有两个endpoint,1和2,因此需要要云端添加两个子设备,子设备名称分别是000D6F00056AE60A_1和000D6F00056AE60A_2。这样做的好处是解析云端的命令时,可以直接根据云端的devid提取设备名称,进而知道要操作的Zigbee设备的Eui64和endpoint。
详细实现可以参考iotkit-embedded-sdk/wrappers/aliyun_main.c
.
开发WGM110的驱动软件,主要参考API手册。需要注意的是,EFR32与WGM110是通过UART连接的,速率115200,因此报文收发速度有限。另外,发送比较大的包时,需要分割成128字节的片来发送,否则容易出错。 WGM110驱动实现主要包括以下几个部分,详细的情况直接参考wifi/wgm110.c
- 串口初始化和读写
- WiFi 消息接收任务
- 所有WiFi相关的接口都用的是同步方式实现,即发送命令给WiFi模组后,同步等待回应直至超时
- 分别实现TCP/UDP的数据接收队列
当前Device Table是保存在文件系统里面的一个txt文件,这个不适用于SoC的模式。针对这里,需要做一些修改:
- 修改函数
emAfDeviceTableSave
andemAfDeviceTableLoad
, 改成从token来保存和恢复device table - 修改函数
emberAfDeviceTableCommandIndexSendWithEndpoint
, 在发送失败的情况下重试一次. - 修改文件
device-table-discovery.c
里面的函数newEndpointDiscovered
, 以便我们可以在一个新的endpoint发现的时候,获取到Endpoint ID, Eui64和Device ID。
详细的修改可以参考工程中的代码。
- 修改rtos_cfg.h中的assert宏:
从修改为#define RTOS_CFG_ASSERT_DBG_ARG_CHK_EXT_MASK (RTOS_CFG_MODULE_ALL) #define RTOS_CFG_RTOS_ASSERT_DBG_FAILED_END_CALL(ret_val) while (1) {; } #define RTOS_CFG_RTOS_ASSERT_CRITICAL_FAILED_END_CALL(ret_val) CPU_SW_EXCEPTION(ret_val)
目的是方便调试定位。void halInternalAssertFailed(const char *filename, int linenumber); #define RTOS_CFG_ASSERT_DBG_ARG_CHK_EXT_MASK (RTOS_CFG_MODULE_ALL) #define RTOS_CFG_RTOS_ASSERT_DBG_FAILED_END_CALL(ret_val) halInternalAssertFailed(__FILE__, __LINE__ );//while (1) {; } #define RTOS_CFG_RTOS_ASSERT_CRITICAL_FAILED_END_CALL(ret_val) halInternalAssertFailed(__FILE__, __LINE__ );//CPU_SW_EXCEPTION(ret_val)
- 修改os_cfg_app.h,将其中的消息数
OS_CFG_MSG_POOL_SIZE
修改为256
修改函数halInternalEnableWatchDog
, 将init.perSel = wdogPeriod_64k
修改为init.perSel = wdogPeriod_128k
,从而将门限从1.5s修改为3s
在这个项目中,有多个task同时运行。入口部分主要是3个task:
- Zigbee Application, 是Zigbee 任务运行的task
- Application Task 1, 是Aliyun SDK启动的第一个task
- WiFi task,是负责WiFi模组的task
项目中,创建了两个消息队列:
- ZBMsgQueue, 用于其它task跟Zigbee task通信的时候用;
- AliyunMsgQueue,用于其它task跟Aliyun的task通信时使用;
相关代码在msgQue.c
和ipc.c
中。
在实际调试过程中,发现网络不稳定的时候,即使WiFi能够重连,但linkkit SDK内部仍然不能恢复的情况。此外,WGM110模组概率性出现不响应复位命令的情况。为了规避问题增加了软件看门狗。其实现如下:
- 在Zigbee task中增加计数。阿里云的task中定时查询云端的时间戳,如果查询成功,表明云端连接OK,这种情况下发送消息给Zigbee task来清除计数。如果计数长时间未清除,120s后复位恢复。
- 在Zigbee task中定时检测与WiFi模组的通信是否正常。如果长时间通信不成功,复位恢复。