天猫精灵控制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设备相关推荐

  1. 毕业设计--20200228--内网搭建domoticz系统 frp内网穿透实现天猫精灵控制内网设备

    记录一下三天的成果. 花费了3天的时间 我在树莓派上面搭建了一个domoticz 的智能家居系统 然后利用frp 去实现将本地的内网地址 穿透到 公网上面的 阿里云的个人服务器的8080 端口, 最终 ...

  2. php与硬件通过wifi对接,基于ESP8266的WiFi排插接入贝壳互联实现天猫精灵控制

    认识众多玩家高手/拆客/DIYer,查阅更多资源,一起学习技术知识 您需要 登录 才可以下载或查看,没有帐号?立即注册 x 本帖最后由 hzy3774 于 2020-1-8 00:45 编辑 * 实验 ...

  3. 开源项目搭建私有物联网智能家居接入天猫精灵控制

    开源项目搭建私有物联网智能家居接入天猫精灵控制 最近几年随着物联网的高速发展,众多智能硬件厂商都开发出自己的智能家居产品,都想在物联网智能家居市场上占有自己的一席之地,而随着众多智能音箱的问世,智能家 ...

  4. 使用ESP8266通过Blinker平台接入天猫精灵控制电视/空调

    目录 `演示视频` 1.准备工作 1.1 `原理` 1.2 `使用的硬件以及硬件连接图` 1.3 `开发环境准备` 2.解码空调红外键值 2.1 `把ESP8266红外接收的实例,上传到NodeMCU ...

  5. (开源)ESP8266改装小风扇,手机app远程控制+天猫精灵控制

    ESP8266改装小风扇,app远程控制+天猫精灵控制 材料准备 拆解风扇 第一 下载ESP8266示例(arduino ide 编程开发) 第二 修改demo例程 关于主题topic 第三 app ...

  6. 使用ESP8266接入“天猫精灵”控制七彩灯(WS2812)的颜色/亮度-开源

    目录 `演示视频` 1.准备工作 1.1 `原理` 1.2 `使用的硬件以及硬件连接图` 1.3 `开发环境准备` `Arduino开发环境` `安装ESP8266的扩展` `安装blinker Ar ...

  7. ESP8266开发、ESP8266连接阿里云物联网、天猫精灵控制esp8266、esp8266一键配网、智能家居

    ESP8266开发.ESP8266连接阿里云物联网.天猫精灵控制esp8266.esp8266一键配网.智能家居 项目介绍 最近会 将arduino IDE开发ESP8266中一些值得记录得部分写下来 ...

  8. 天猫精灵 python_利用天猫精灵控制ESP8266(NodeMCU开发板)arduino ide开发

    第一 下载demo例程 下载地址: 点击下载 本demo 是利用arduino IDE开发,关于arduino IDE 的ESP8266环境配置可参考:环境配置: 点击跳转 第二 修改demo例程 需 ...

  9. android系统wifi控制风扇,(开源)ESP8266改装小风扇,app远程控制+天猫精灵控制...

    本帖最后由 bemfa 于 2020-6-16 10:07 编辑 教程 =教程 =教程 =两个ESP8266通过云端实现远程数据交互 教程 =利用天猫精灵控制NodeMCU(ESP8266) f.pn ...

最新文章

  1. pandas使用groupby函数计算dataframe数据中每个分组的N个数值的滚动最大值(rolling max)、例如,计算某公司的多个店铺每N天(5天)的滚动销售额最大值
  2. 一般关于大宗商品的供需关系相关的数据网址有哪些?
  3. jquery标签选择器应用示例
  4. 在Java语言里 ==和equals的区别
  5. 定义快捷代码_nodepad++代码编辑器替代工具整理
  6. 无心剑中译狄金森诗36首
  7. java调用打印机打印excel linux_手把手教你嵌入式Linux系统驱动hp1020打印机
  8. 如何设置cout的输出格式(转)
  9. DataSet/DataFrame性能比RDD高?
  10. wordpress配置邮箱发送功能
  11. Flutter业务开发常用小技巧(样式布局篇)
  12. 网络贷款系统完整版源码,thinkphp内核开发,安全可靠,定制网贷分销平台系统
  13. c语言窗口炸弹代码,C语言实现宾果消消乐
  14. 【STM32学习笔记——WIFI模块】
  15. 架构师之路 — 分布式系统 — 分布式网络分区难题
  16. 速读《现代软件工程——构建之法》有感
  17. 《未来世界的幸存者》:你会是未来世界的幸存者吗?
  18. 百度云大文件高速下载方法、软件
  19. java 快递打印_基于java的快递打印系统
  20. 木瓜移动再求上市:毛利率走低、盈利能力弱,沈思“迷恋”相亲

热门文章

  1. Linux常用命令——who命令
  2. Python3中pass语句介绍
  3. Docker 从入门到实践系列一 - 什么是Docker
  4. Poading Analysis
  5. 3、Kubernetes的基本使用
  6. require(‘inquirer‘)报错
  7. (FortiGate)飞塔防火墙IPMAC绑定设置步骤
  8. 博客园申请js权限方式
  9. python计算机语言基础_PYTHON之计算机语言基础知识 —— 编程语言的分类
  10. 食物链顶端的人类被这种“飞蚊”折磨得很痛苦?