# 14. 云框架 Edge101WE 主板支持使用多个云框架。以下是各种支持的云框架示例。 ## 14.1 阿里云物联网 ### 14.1.1 Aliyun IoT #### 认识阿里云AIoT 阿里云IoT致力于实现万物互联的美好世界,为生态合作伙伴提供基于云端一体化、安全物联网基础平台等,在通过该平台高效连接,管理设备的同时,其开放能力使合作伙伴更高效、低成本地构建各种创新的物联网应用场景。阿里云物联网平台为设备提供安全可靠的连接通信能力,向下连接海量设备,支撑设备数据采集上云;向上提供云端API,指令数据通过API调用下发至设备端,实现远程控制。此外阿里云物联网平台还提供了丰富的开发服务,用户可以直接在该平台上搭建Web可视化、移动应用、服务开发等开发服务,这降低了物联网项目开发的难度,有了它,用户无需任何专业的开发技巧也可开发自己的项目。 #### 阿里云物联网的开发框架 ![AliyunIoT](./pictures/AliyunIoT-1621666597418.png) #### 什么是物联网平台 阿里云物联网平台为设备提供安全可靠的连接通信能力,向下连接海量设备,支撑设备数据采集上云;向上提供云端API,服务端通过调用云端API将指令下发至设备端,实现远程控制。 物联网平台消息通信流程图如下。 [![企业基于物联网平台的业务链路](./pictures/p132750.png)](https://static-aliyun-doc.oss-accelerate.aliyuncs.com/assets/img/zh-CN/3199158061/p132750.png) 实现设备消息的完整通信流程,需要您完成设备端的设备开发、云端服务器的开发(云端SDK的配置)、数据库的创建、手机App的开发。 下文介绍物联网平台消息通信链路。 **上行数据链路** - 设备通过MQTT协议与物联网平台建立长连接,上报数据(通过Publish发布Topic和Payload)到物联网平台。 - 您可配置规则引擎,编写SQL对上报数据进行处理,并配置转发规则,将处理后的数据转发到RDS、表格存储、函数计算、TSDB、企业版实例内的时序数据存储、DataHub、消息队列RocketMQ等云产品中,或通过AMQP消费组流转到您的ECS服务器上。 **下行指令链路** - ECS业务服务器调用基于HTTPS协议的API接口Pub,给Topic发送指令,将数据发送到物联网平台。 - 物联网平台通过MQTT协议,使用Publish发送数据(指定Topic和Payload)到设备端。 #### 产品架构 设备连接物联网平台,与物联网平台进行数据通信。物联网平台可将设备数据流转到其他阿里云产品中进行存储和处理。这是构建物联网应用的基础。 [![物联网平台架构](./pictures/p202711.png)](https://static-aliyun-doc.oss-accelerate.aliyuncs.com/assets/img/zh-CN/7769728061/p202711.png) **IoT SDK** 物联网平台提供IoT SDK,设备集成SDK后,即可安全接入物联网平台,使用设备管理、数据流转等功能。 只有支持TCP/IP协议的设备可以集成IoT SDK。 **边缘计算** 边缘计算能力允许您在最靠近设备的地方构建边缘计算节点,过滤清洗设备数据,并将处理后的数据上传至云平台。更多信息,请参见[物联网边缘计算](https://help.aliyun.com/document_detail/85155.htm?spm=a2c4g.11186623.2.12.6df3bebeNDP1wk#concept-egf-t13-d2b)。 **设备接入** 物联网平台提供各类[设备端SDK](https://help.aliyun.com/document_detail/42648.htm?spm=a2c4g.11186623.2.13.6df3bebeNDP1wk#concept-jlk-mjl-vdb)、[设备认证方式](https://help.aliyun.com/document_detail/42649.htm?spm=a2c4g.11186623.2.14.6df3bebeNDP1wk#concept-fqy-pjl-vdb),支持[MQTT](https://help.aliyun.com/document_detail/30540.htm?spm=a2c4g.11186623.2.15.6df3bebeNDP1wk#concept-jfq-vjw-vdb)、[CoAP](https://help.aliyun.com/document_detail/57699.htm?spm=a2c4g.11186623.2.16.6df3bebeNDP1wk#concept-tcf-yq5-wdb)、[HTTP](https://help.aliyun.com/document_detail/58036.htm?spm=a2c4g.11186623.2.17.6df3bebeNDP1wk#concept-l14-nt5-wdb)等多种协议,实现设备快速上云。 设备上云后与云端通过IoT Hub进行稳定可靠地双向通信。 **消息通信** 物联网平台支持通过[服务端订阅](https://help.aliyun.com/document_detail/89226.htm?spm=a2c4g.11186623.2.18.6df3bebeNDP1wk#concept-d2m-g2v-y2b)、[云产品流转](https://help.aliyun.com/document_detail/68677.htm?spm=a2c4g.11186623.2.19.6df3bebeNDP1wk#concept-g11-dcl-vdb)、[场景联动](https://help.aliyun.com/document_detail/102240.htm?spm=a2c4g.11186623.2.20.6df3bebeNDP1wk#concept-mkd-k44-f2b)、[广播通信](https://help.aliyun.com/document_detail/155755.htm?spm=a2c4g.11186623.2.21.6df3bebeNDP1wk#task-2433926)、[RRPC通信](https://help.aliyun.com/document_detail/90567.htm?spm=a2c4g.11186623.2.22.6df3bebeNDP1wk#concept-zlp-gsl-cfb)等方式,通过配置规则,实现设备、服务器、物联网平台之间通信消息的同步、转化、过滤、存储等功能。 **设备管理** 物联网平台为您提供功能丰富的设备管理服务,包括:生命周期、[设备分发](https://help.aliyun.com/document_detail/143450.htm?spm=a2c4g.11186623.2.23.6df3bebeNDP1wk#task-2340090)、[设备分组](https://help.aliyun.com/document_detail/90386.htm?spm=a2c4g.11186623.2.24.6df3bebeNDP1wk#task-ejm-qp2-cfb)、[设备影子](https://help.aliyun.com/document_detail/53930.htm?spm=a2c4g.11186623.2.25.6df3bebeNDP1wk#concept-r4r-b1v-wdb)、[设备拓扑](https://help.aliyun.com/document_detail/89082.htm?spm=a2c4g.11186623.2.26.6df3bebeNDP1wk#task-z1r-q1p-y2b)、[物模型](https://help.aliyun.com/document_detail/73727.htm?spm=a2c4g.11186623.2.27.6df3bebeNDP1wk#concept-okp-zlv-tdb)、[数据解析](https://help.aliyun.com/document_detail/68702.htm?spm=a2c4g.11186623.2.28.6df3bebeNDP1wk#concept-rhj-535-42b)、[数据存储](https://help.aliyun.com/document_detail/96443.htm?spm=a2c4g.11186623.2.29.6df3bebeNDP1wk#task-j31-lmt-sfb)等。 **监控运维** 物联网平台支持[OTA升级](https://help.aliyun.com/document_detail/58328.htm?spm=a2c4g.11186623.2.30.6df3bebeNDP1wk#task-prw-fzz-xdb)、[在线调试](https://help.aliyun.com/document_detail/99981.htm?spm=a2c4g.11186623.2.31.6df3bebeNDP1wk#task-wpk-dtg-cgb)、[日志服务](https://help.aliyun.com/document_detail/44542.htm?spm=a2c4g.11186623.2.32.6df3bebeNDP1wk#concept-a32-x4w-f2b)、[远程配置](https://help.aliyun.com/document_detail/84891.htm?spm=a2c4g.11186623.2.33.6df3bebeNDP1wk#concept-om1-tgs-c2b)、[实时监控](https://help.aliyun.com/document_detail/141582.htm?spm=a2c4g.11186623.2.34.6df3bebeNDP1wk#concept-2321153)、远程维护等功能。 **数据分析** 数据分析是阿里云为物联网开发者提供的数据智能分析服务,针对物联网数据特点,提供海量数据的存储备份、资产管理、报表分析和数据服务等能力,帮助企业用户更容易地挖掘物联网数据中的价值。 更多信息,请参见[物联网数据分析](https://help.aliyun.com/document_detail/188646.htm?spm=a2c4g.11186623.2.35.6df3bebeNDP1wk#topic-1961048)。 **安全认证和权限策略** 安全是IoT的重要话题。阿里云物联网平台提供多重防护,保障设备和云端数据的安全。 #### 产品名词解释 | 名词 | 描述 | | :------------ | :----------------------------------------------------------- | | 产品 | 设备的集合,通常指一组具有相同功能的设备。物联网平台为每个产品颁发全局唯一的ProductKey。 | | 设备 | 归属于某个产品下的具体设备。物联网平台为设备颁发产品内唯一的证书DeviceName。设备可以直接连接物联网平台,也可以作为子设备通过网关连接物联网平台。 | | 分组 | 物联网平台支持建立设备分组,分组中可包含不同产品下的设备。通过设备组来进行跨产品管理设备。 | | 网关 | 能够直接连接物联网平台的设备,且具有子设备管理功能,能够代理子设备连接云端。 | | 子设备 | 本质上也是设备。子设备不能直接连接物联网平台,只能通过网关连接。 | | 设备证书 | 设备证书指**ProductKey**、**DeviceName**、**DeviceSecret**的组合。**ProductKey**:是物联网平台为产品颁发的全局唯一标识。该参数很重要,在设备认证以及通信中都会用到,因此需要您保管好。**DeviceName**:在注册设备时,自定义的或系统生成的设备名称,具备产品维度内的唯一性。该参数很重要,在设备认证以及通信中都会用到,因此需要您保管好。**DeviceSecret**:物联网平台为设备颁发的设备密钥,和DeviceName成对出现。该参数很重要,在设备认证时会用到,因此需要您保管好并且不能泄露。 | | ProductSecret | 由物联网平台颁发的产品密钥,通常与ProductKey成对出现,可用于一型一密的认证方案。该参数很重要,需要您保管好,不能泄露。 | | 设备X.509证书 | 物联网平台支持设备使用X.509数字证书进行身份验证。您创建认证方式为X.509证书的设备后,物联网平台为设备颁发对应的X.509证书,证书信息包括:X.509数字证书(**Certificate**)、X.509证书ID(**CertSN**)和X.509证书密钥(**PrivateKey**)。 | | Topic | Topic是UTF-8字符串,是发布(Pub)/订阅(Sub)消息的传输中介。可以向Topic发布或者订阅消息。 | | Topic类 | 同一产品下不同设备的Topic集合,用${productkey}和${deviceName}通配一个唯一的设备,一个Topic类对一个ProductKey下所有设备通用。 | | 发布 | 操作Topic的权限类型,对应的英文名称为Pub。可以往此类Topic中发布消息。 | | 订阅 | 操作Topic的权限类型,对应的英文名称为Sub。可以从此类Topic中订阅消息。 | | RRPC | 全称:Revert-RPC。RPC(Remote Procedure Call)采用客户机/服务器模式,用户不需要了解底层技术协议,即可远程请求服务。RRPC则可以实现由服务端请求设备端,并能够使设备端响应的功能。 | | 标签 | 标签分为产品标签、设备标签和分组标签。产品标签:描述同一个产品下,所有设备所具有的共性信息。设备标签:通常根据设备的特性为设备添加的特有标记,您可以自定义标签内容。分组标签:描述同一个分组下,所有设备所具有的共性信息。 | | Alink协议 | 阿里云定义的设备与云端之间的通信协议。 | | 物模型 | 是对设备在云端的功能描述,包括设备的属性、服务和事件。物联网平台通过定义一种物的描述语言来描述物模型,称之为TSL(即 Thing Specification Language),采用JSON格式,您可以根据TSL组装上报设备的数据。 | | 属性 | 设备的功能模型之一,一般用于描述设备运行时的状态,如环境监测设备所读取的当前环境温度等。属性支持GET和SET请求方式。应用系统可发起对属性的读取和设置请求。 | | 期望属性值 | 通过期望属性值功能,设置您希望的设备属性值。若设备在线,将实时更新属性值;若设备离线,期望属性值将缓存在云端。设备上线后,获取期望属性值,并更新属性值。 | | 服务 | 设备的功能模型之一,设备可被外部调用的能力或方法,可设置输入参数和输出参数。相比于属性,服务可通过一条指令实现更复杂的业务逻辑,如执行某项特定的任务。 | | 事件 | 设备的功能模型之一,设备运行时的事件。事件一般包含需要被外部感知和处理的通知信息,可包含多个输出参数。例如,某项任务完成的信息,或者设备发生故障或告警时的温度等,事件可以被订阅和推送。 | | 数据解析脚本 | 针对采用透传格式/自定义数据格式的设备,需要在云端编写数据解析脚本,将设备上报的二进制数据或自定义的JSON数据,转换为物联网平台支持的Alink JSON数据格式;将平台下发的Alink JSON格式数据,转换为设备支持的格式。 | | 设备影子 | 是一个JSON文档,用于存储设备或者应用的当前状态信息。每个设备都会在云端有唯一的设备影子。无论该设备是否连接到Internet,您都可以使用设备影子通过MQTT协议或HTTP协议获取和设置设备的状态。 | | 规则引擎 | 通过创建、配置规则,以实现服务端订阅、数据流转和场景联动。 | | 服务端订阅 | 服务端订阅产品下所有类型的消息:设备上报消息、设备状态变化通知、网关发现子设备上报消息、设备生命周期变更消息和设备拓扑关系变更消息。目前支持两种方式实现服务端订阅:AMQP:Advanced Message Queuing Protocol,高级消息队列协议。服务端通过AMQP协议接入云端,接收云端推送的消息。MNS:将消息流转到指定阿里云消息服务(MNS)队列中,您的服务端从MNS队列中接收消息。 | | 数据流转 | 物联网平台规则引擎的数据流转功能,可将Topic中的数据转发至其他Topic或其他阿里云服务进行存储或处理。 | | 场景联动 | 场景联动是一种开发自动化业务逻辑的可视化编程方式。您可以通过可视化的方式定义设备之间联动规则,并将规则部署至云端或者边缘端。 | | 一机一密 | 每个设备烧录其唯一的设备证书(ProductKey、DeviceName和DeviceSecret)。当设备与物联网平台建立连接时,物联网平台对其携带的设备证书信息进行认证。 | | 一型一密 | 同一产品下所有设备可以烧录相同产品证书(即ProductKey和ProductSecret)。设备发送激活请求时,物联网平台其携带的产品证书信息进行认证,认证通过,下发该设备接入所需信息。设备再携带这些信息与物联网平台建立连接。 | | 公共实例 | 产品、设备、规则等资源均在实例中进行操作管理。默认开通的物联网平台服务为公共实例。公共实例部署于阿里云经典网络。多账号共用一个公共实例,账号之间逻辑隔离。 | | 企业版实例 | 您购买的实例为企业版实例。部署于阿里云VPC网络的物联网平台。一个账号可购买多个企业版实例,且独享每个实例资源。 | #### 应用场景 **智能家居** 物联网平台广泛应用于智能家居电器,以智能插座为例,用户可远程查看插座使用情况,并控制其开关,避免因大功率电器过热,发生危险。 您可使用一机一密的方式稳定接入海量设备,防止黑客批量攻击。 [![智能插座](./pictures/p203531.png)](https://static-aliyun-doc.oss-accelerate.aliyuncs.com/assets/img/zh-CN/3987358061/p203531.png) **农业设备** 使用各种传感器设备和通信网络,实时监控采集农业大棚中数据。传感器设备可通过RS485总线连接网关,再通过网关将其连接到物联网平台,实现在云端展示和管理数据。 [![农业设备](./pictures/p203564.png)](https://static-aliyun-doc.oss-accelerate.aliyuncs.com/assets/img/zh-CN/1016458061/p203564.png) 阿里云物联网详细手册请点击: https://help.aliyun.com/product/30520.html?spm=a2c4g.11174283.6.540.371c166845oVZh #### 示例功能 本示例,在阿里云物联网平台创建一个名字为LED的产品,在产品中新建一个LED设备。在物联网应用开发 IoT Studio 平台新建一个Web UI,通过操作UI上的按钮控制 Edge101WE 主板上 LED的亮灭,同时将 LED的状态显示到UI界面。如果主板用户按钮按下,将发送命令给阿里云,通过在 IoT Studio 建立逻辑,如果有按钮按下,将状态发送到钉钉群中。另外还实现了OTA无线远程升级的功能。 ##### 注册并登陆阿里云账号 浏览器访问网址 https://www.aliyun.com 进入阿里云主界面,点击登陆,在密码登陆栏点击免费注册,进入阿里云账号注册界面(若已有账号可直接登陆),按要求完成注册即可。 注册完成后,点击 产品 -> 物联网IoT -> 物联网云服务 -> 企业物联网平台 ![image-20210521183243037](./pictures/image-20210521183243037.png) 进入企业物联网平台后,点击 进入控制台。 ![image-20210521183538442](./pictures/image-20210521183538442.png) 点击 公共实例。目前开通的服务只有公共实例,便于原型调试或个人用户使用。企业实例需要额外付费。 ![image-20210521183730379](./pictures/image-20210521183730379.png) 跳转到新页面后,在左侧菜单栏点击产品,点击 创建产品,弹出 新建产品 页面。产品名称命名为 “FireBeetle_LED_Button”,自定义品类,直连设备,联网方式 Wi-Fi,数据格式Json。点击确认。 ![image-20210522164944056](./pictures/image-20210522164944056.png) ##### 定义产品功能 点击 查看 新建的“FireBeetle_LED_Button”产品,点击 功能定义 -> 编辑草稿。 ![image-20210522165922568](./pictures/image-20210522165922568.png) 添加自定义功能,为产品定义一个LED灯工作状态的属性,灯有两种工作状态:开和关,可用布尔型表示,其中0代表灯关,1代表灯开。点击确认。 ![image-20210522170717729](./pictures/image-20210522170717729.png) 再自定义按钮功能 ![image-20210522172511408](./pictures/image-20210522172511408.png) 点击发布上线,发布物模型。可看到自定义LED和按钮功能定义。 ![image-20210522172711297](./pictures/image-20210522172711297.png) 为 FireBeetle_LED_Button 产品添加设备 ![image-20210522173048535](./pictures/image-20210522173048535.png) ![image-20210522173254303](./pictures/image-20210522173254303.png) 复制设备证书的 ProductKey,DeviceName,DeviceSecret,保存到记事本,用于 Edge101WE 主板固件开发。 ![image-20210522174317272](./pictures/image-20210522174317272.png) 设备证书包含ProductKey、DeviceName和DeviceSecret,是设备与物联网平台进行通信的重要身份认证。后续设备接入,需设置此信息,请复制后妥善保管。 | 参数 | 说明 | | :----------- | :----------------------------------------------------------- | | ProductKey | 设备所属产品的ProductKey,即物联网平台为产品颁发的全局唯一标识符。 | | DeviceName | 设备在产品内的唯一标识符。DeviceName与设备所属产品的ProductKey组合,作为设备标识,用来与物联网平台进行连接认证和通信。 | | DeviceSecret | 物联网平台为设备颁发的设备密钥,用于认证加密。需与DeviceName成对使用。 | 点击启用这个设备 ![image-20210522180113016](./pictures/image-20210522180113016.png) ##### 设备开发 DFRobot_Aliyun库依赖ArduinoJson库,在使用之前需要在Arduino IDE库管理器中安装该库。 只需转到**Sketch** > **Include Library** > **Manage Libraries** ,搜索库的名字 ArduinoJson,点击安装 ![image-20210506170659912](./pictures/image-20210506170659912.png) ArduinoJson 库详细教程:https://arduinojson.org/v6/example/parser/ 参考[DFRobot_Aliyun](https://github.com/wxzed/DFRobot_Aliyun) 例子程序,修改以下参数: 1、连接WiFi的信息 ```c++ /*配置WIFI名和密码*/ const char * WIFI_SSID = "WIFI_SSID"; const char * WIFI_PASSWORD = "WIFI_PASSWORD"; ``` 2、设备证书信息 ![image-20210522192019398](./pictures/image-20210522192019398.png) ```c++ /*配置设备证书信息*/ String ProductKey = "you Product Key"; String ClientId = "12345"; // 自定义ID String DeviceName = "you Device Name"; String DeviceSecret = "you Device Secret"; ``` 3、物模型产品标识符 ![image-20210522191502659](./pictures/image-20210522191502659.png) ```c++ /*需要操作的产品标识符*/ String lightIdentifier = "LightStatus"; String buttonIdentifier = "ButtonStatus"; ``` 4、Topic ![image-20210522191655646](./pictures/image-20210522191655646.png) ```c++ /*需要上报和订阅的两个TOPIC*/ const char * subTopic = "/sys/a1MqGxxxxxx/board1/thing/service/property/set"; //****set const char * pubTopic = "/sys/a1MqGxxxxxx/board1/thing/event/property/post"; //******post ``` board1 是刚才新建的设备名称。 ##### 例程:Aliyun AIoT 将修改好的代码下载到 Edge101WE 主板。 ```c++ #include #include #include #include "DFRobot_Aliyun.h" #define USER_LED 15 #define USER_BUTTON 38 /*配置WIFI名和密码*/ const char * WIFI_SSID = "WIFI_SSID"; const char * WIFI_PASSWORD = "WIFI_PASSWORD"; /*配置设备证书信息*/ String ProductKey = "you Product Key"; String ClientId = "12345"; // 自定义ID String DeviceName = "you Device Name"; String DeviceSecret = "you Device Secret"; /*配置域名和端口号*/ String ALIYUN_SERVER = "iot-as-mqtt.cn-shanghai.aliyuncs.com"; uint16_t PORT = 1883; /*需要操作的产品标识符*/ String lightIdentifier = "LightStatus"; String buttonIdentifier = "ButtonStatus"; /*需要上报和订阅的两个TOPIC*/ const char * subTopic = "/sys/a1MqG******/board1/thing/service/property/set"; //****set const char * pubTopic = "/sys/a1MqG******/board1/thing/event/property/post"; //******post DFRobot_Aliyun myAliyun; WiFiClient espClient; PubSubClient client(espClient); static void openLight() { digitalWrite(USER_LED, LOW); } static void closeLight() { digitalWrite(USER_LED, HIGH); } void connectWiFi() { Serial.print("Connecting to "); Serial.println(WIFI_SSID); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.println("WiFi connected"); Serial.print("IP Adderss: "); Serial.println(WiFi.localIP()); } void callback(char * topic, byte * payload, unsigned int len) { Serial.print("Recevice ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < len; i++) { Serial.print((char)payload[i]); } Serial.println(); StaticJsonDocument<300> jsonBuffer; DeserializationError error = deserializeJson(jsonBuffer, (const char *)payload); if (error) { Serial.print(F("deserializeJson() failed: ")); Serial.println(error.f_str()); return; } const uint16_t LightStatus = jsonBuffer["params"][lightIdentifier]; if (LightStatus == 1) { openLight(); } else { closeLight(); } String tempMseg = "{\"id\":" + ClientId + ",\"params\":{\"" + lightIdentifier + "\":" + (String)LightStatus + "},\"method\":\"thing.event.property.post\"}"; char sendMseg[tempMseg.length()]; strcpy(sendMseg, tempMseg.c_str()); client.publish(pubTopic, sendMseg); } void ConnectAliyun() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); /*根据自动计算的用户名和密码连接到Alinyun的设备,不需要更改*/ if (client.connect(myAliyun.client_id, myAliyun.username, myAliyun.password)) { Serial.println("connected"); client.subscribe(subTopic); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } void setup() { Serial.begin(115200); pinMode(USER_LED, OUTPUT); pinMode(USER_BUTTON, INPUT); /*连接WIFI*/ connectWiFi(); /*初始化Alinyun的配置,可自动计算用户名和密码*/ myAliyun.init(ALIYUN_SERVER, ProductKey, ClientId, DeviceName, DeviceSecret); client.setServer(myAliyun.mqtt_server, PORT); /*设置回调函数,当收到订阅信息时会执行回调函数*/ client.setCallback(callback); /*连接到Aliyun*/ ConnectAliyun(); /*开机先关灯*/ closeLight(); /*上报关灯信息*/ client.publish(pubTopic, ("{\"id\":" + ClientId + ",\"params\":{\"" + lightIdentifier + "\":0},\"method\":\"thing.event.property.post\"}").c_str()); } void loop() { if (!client.connected()) { ConnectAliyun(); } if (digitalRead(USER_BUTTON) == 0) { /*上报按钮的状态*/ client.publish(pubTopic, ("{\"id\":" + ClientId + ",\"params\":{\"" + buttonIdentifier + "\":1},\"method\":\"thing.event.property.post\"}").c_str()); delay(1000); } else { } client.loop(); } ``` 设备上电后,串口显示已经连接到WiFi,并且显示已经连接到阿里云物联网。 ![image-20210522192153937](./pictures/image-20210522192153937.png) 此时在阿里云物联网 设备列表可看到产品已经在线 ![image-20210522192350874](./pictures/image-20210522192350874.png) 进入在线调试界面,选择要操作的设备。LED状态选择 开-1,调试下拉菜单点击设置。此时可看到主板上的灯被点亮。LED状态选择 关-0,点击设置,主板上的LED灯熄灭。 ![image-20210522192724338](./pictures/image-20210522192724338.png) 按下FireBeetle MESH 主板上的用户按钮,可在 阿里云物联网 在线调试界面收到一条信息,包含"Params":"{\"ButtonStatus\":1}",此时点击获取按钮,可看到按钮状态显示按下-1。 ![image-20210522193317978](./pictures/image-20210522193317978.png) #### 物联网应用开发平台 IoT Studio 接下来我们使用 IoT Studio 来开发一个Web应用UI界面来显示 FireBeetle MESH 主板上的用户LED灯状态,并通过UI上的开关来控制主板上的用户LED灯亮灭。可用于指示机床是否为可用状态。 机床在使用过程中如果出现故障,操作人员按下 FireBeetle MESH 主板 的板载用户按钮,将通过钉钉群机器人发送内容 **检修请求:5号机床需要检修**到钉钉群,提醒机床维护人员来检修机器。 我们要用到Web可视化开发,它是物联网应用开发(IoT Studio)中的工具。无需写代码,只需在编辑器中,拖拽组件到画布上,再配置组件的显示样式、数据源及交互动作,以可视化的方式进行Web应用开发。适用于开发状态监控面板、设备管理后台、设备数据分析报表等。 登录 IoT Studio 的网址 https://www.aliyun.com/product/iotstudio,点击立即使用。 ![image-20210521135937648](./pictures/image-20210521135937648.png) ##### 创建Web应用 新建项目,点击左侧的**项目管理**,在**普通项目**中,点击 **新建项目**,新建空白项目。应用名称 ”Call_System“。 ![image-20210610162749598](./pictures/image-20210610162749598.png) 在项目**主页**页面的**项目开发**下,选择**Web应用**,**新建**。创建待开发的Web应用,应用名称 “Call_Button”。 ![image-20210610163610522](./pictures/image-20210610163610522.png) 创建应用完成后,会自动打开Web应用编辑器。拖动一个**指示灯**。 ![image-20210610171753500](./pictures/image-20210610171753500.png) 点击指示灯,数据源配置 ![image-20210610172000255](./pictures/image-20210610172000255.png) 此时关联物联网产品, 注意:在**关联产品同时关联其下所有设备** 处 **打勾**。 ![image-20210610171512781](./pictures/image-20210610171512781.png) 点击**配置数据源**,**选择数据来源、产品、设备**和**属性**。点击 **验证数据格式** ,如果成功,点击**确定**。 ![image-20210610190406555](./pictures/image-20210610190406555.png) ![image-20210610190533563](./pictures/image-20210610190533563.png) 拖动一个开关。 ![image-20210610191530915](./pictures/image-20210610191530915.png) 点击**配置数据源**,**选择数据来源、产品、设备**和**属性**。点击 **验证数据格式** ,如果成功,点击**确定**。 ![image-20210610192348498](./pictures/image-20210610192348498.png) 再次点击**发布** ![image-20210610192641595](./pictures/image-20210610192641595.png) 点击生成的连接可看到控制界面。此时切换开关,可看到 界面的 指示灯由蓝色变成了黄色。同时 Edge101WE 主板上的绿色LED灯被点亮。 ![image-20210610192928347](./pictures/image-20210610192928347.png) ![image-20210610193039164](./pictures/image-20210610193039164.png) ##### 钉钉消息推送 物联网应用开发(IoT Studio)提供了物联网业务逻辑的开发工具,支持通过编排服务节点的方式快速完成简单的物联网业务逻辑的设计。 在项目界面,点击左上角图标,**业务逻辑开发**点击**新建** ![image-20210611101833254](./pictures/image-20210611101833254.png) 新建一个 **空白模板** ![image-20210611102145554](./pictures/image-20210611102145554.png) 分别拖入 **设备触发,条件判断,钉钉机器人**三个节点。 点击**设备触发**节点,设置节点的属性后,点击**部署调试**。 ![image-20210611111400004](./pictures/image-20210611111400004.png) 点击**条件判断**,设置当**设备触发**后 **按钮状态** **等于 数值 1** 时,触发钉钉机器人。 ![image-20210611111711624](./pictures/image-20210611111711624.png) 点击**钉钉机器人**节点,设置钉钉机器人。此时需要到钉钉软件去新建一个群,并添加群机器人。 选择**自定义** ,通过Webhook接入自定义服务。 ![image-20210611112207901](./pictures/image-20210611112207901.png) 设置群机器人,消息推送 **开启**,复制**Webhook**,自定义关键词 **检修** ,点击**完成**。 ![image-20210611112349471](./pictures/image-20210611112349471.png) 返回到业务逻辑的**钉钉机器人**节点属性配置页面,将复制的**Webhook**粘贴进去,配置方式选择**自定义**,消息类型**text**。 配置要发送给群机器人的内容 **检修请求:5号机床需要检修**。内容包括了群机器人要识别的 **检修** 关键词。 填写群里面某个成员的移动电话号码。点击右上角的**保存**图标,对设置进行保存。 ![image-20210611111921745](./pictures/image-20210611111921745.png) 此时按下 FireBeetle MESH 主板上的用户按钮,业务逻辑界面的三个节点 将标注 打勾图标,说明节点业务逻辑已经连通。 ![image-20210611113105352](./pictures/image-20210611113105352.png) 在钉钉群也收到了 **检修请求:5号机床需要检修** 的信息。至此 IoT Studio 的Web应用和业务逻辑已经运行起来。 ### 14.1.2 Aliyun IoT OTA 这里演示阿里云IoT的基本用法,将采用云端UI界面控制 Edge101WE 主板板载的用户LED的亮度,并且固件可通过阿里云进行空中升级。 #### 例程: ```c++ /*! * @file AliyunOTA.ino.ino * * @brief Simulate esp32 as a bedroom light and use Aliyun as a cloud platform. * @n Subscribe to the Light Intensities topic to enable remote control of bedroom lights * @n Aliyun OTA * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) * @licence The MIT License (MIT) * @author [Yangfeng](feng.yang@dfrobot.com) * @version V1.0 * @date 2021-06-24 * @get from https://www.dfrobot.com */ #include #include #include #include "DFRobot_Iot.h" #include "HttpsOTAUpdate.h" #define BEDROOD_LIGHT 15 /*Configure the WiFi name and password*/ const char * WIFI_SSID = "++++++++"; const char * WIFI_PASSWORD = "++++++++"; /*Configure the device certificate information*/ String ProductKey = "++++++"; String ClientId = "1234";/*The custom ID*/ String DeviceName = "++++++"; String DeviceSecret = "++++++"; /*Configure the domain name and port number*/ String ALIYUN_SERVER = "iot-as-mqtt.cn-shanghai.aliyuncs.com"; uint16_t PORT = 1883; /*Topics to be reported and subscribed to*/ const char * subTopic = "/sys/${ProductKey}/${DeviceName}/thing/service/property/set"; const char * subTopic1 = "/ota/device/upgrade/${ProductKey}/${DeviceName}"; const char * pubTopic1 = "/ota/device/inform/${ProductKey}/${DeviceName}"; const char * pubTopic = "/sys/${ProductKey}/${DeviceName}/thing/event/property/post"; static const char *server_certificate = "-----BEGIN CERTIFICATE-----\r\n" "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n" \ "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" \ "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n" \ "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" \ "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n" \ "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n" \ "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n" \ "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n" \ "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n" \ "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n" \ "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n" \ "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n" \ "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n" \ "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n" \ "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n" \ "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n" \ "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n" \ "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n" \ "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n" \ "-----END CERTIFICATE-----"; static HttpsOTAStatus_t otastatus; DFRobot_Iot myIot; WiFiClient espClient; PubSubClient client(espClient); void HttpEvent(HttpEvent_t *event) { switch(event->event_id) { case HTTP_EVENT_ERROR: Serial.println("Http Event Error"); break; case HTTP_EVENT_ON_CONNECTED: Serial.println("Http Event On Connected"); break; case HTTP_EVENT_HEADER_SENT: Serial.println("Http Event Header Sent"); break; case HTTP_EVENT_ON_HEADER: Serial.printf("Http Event On Header, key=%s, value=%s\n", event->header_key, event->header_value); break; case HTTP_EVENT_ON_DATA: break; case HTTP_EVENT_ON_FINISH: Serial.println("Http Event On Finish"); break; case HTTP_EVENT_DISCONNECTED: Serial.println("Http Event Disconnected"); break; } } void connectWiFi(){ Serial.print("Connecting to "); Serial.println(WIFI_SSID); WiFi.begin(WIFI_SSID,WIFI_PASSWORD); while(WiFi.status() != WL_CONNECTED){ delay(500); Serial.print("."); } Serial.println(); Serial.println("WiFi connected"); Serial.print("IP Adderss: "); Serial.println(WiFi.localIP()); } void callback(char * topic, byte * payload, unsigned int len){ Serial.print("Recevice ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < len; i++){ Serial.print((char)payload[i]); } Serial.println(); StaticJsonDocument<300> jsonBuffer; auto error = deserializeJson(jsonBuffer, (char *)payload); if (error){ Serial.println("parseObject() failed:"); Serial.println(error.f_str()); } if( strcmp(topic,subTopic1)==0){ String str = jsonBuffer["data"]["url"]; if(str.compareTo("null")!=0){ String version0 =jsonBuffer["data"]["version"] ; String a = "\""; String version = a+version0+a; Serial.println(version); Serial.println(str); HttpsOTA.onHttpEvent(HttpEvent); Serial.println("Starting OTA"); HttpsOTA.begin(const_cast(str.c_str()) , server_certificate); Serial.println("Please Wait it takes some time ..."); while(1){ otastatus = HttpsOTA.status(); if(otastatus == HTTPS_OTA_SUCCESS) { client.publish(pubTopic1,("{\"id\":"+ClientId+",\"params\":{\"version\":"+version+",\"module\":\"esp32\"}}").c_str()); Serial.printf("Firmware written successfully. Current version information: %s . To reboot device, call API ESP.restart() or PUSH restart button on device",version0); Serial.println("Auto restart after 3 seconds"); for(uint8_t i=0;i<2;i++){ delay(1000); Serial.print("."); } delay(1000); Serial.println("."); ESP.restart(); break; } else if(otastatus == HTTPS_OTA_FAIL) { Serial.println("Firmware Upgrade Fail"); break; } } } }else if( strcmp(topic,subTopic)==0){ const uint16_t LightAdjustLevel = jsonBuffer["params"]["LightAdjustLevel"]; bool LightStatus = jsonBuffer["params"]["LightStatus"]; Serial.print("LightAdjustLevel="); Serial.println(LightAdjustLevel); uint8_t Light = LightAdjustLevel*255/100; /*Adjust the light intensity*/ sigmaDeltaWrite(0, Light); /*Publish the intensity information of the light*/ String tempMseg = "{\"id\":" + ClientId + ",\"params\":{\"LightStatus\":"+LightStatus+",\"LightAdjustLevel\":"+LightAdjustLevel+"},\"method\":\"thing.event.property.post\"}"; char sendMseg[tempMseg.length()]; strcpy(sendMseg, tempMseg.c_str()); client.publish(pubTopic, sendMseg); } } void ConnectAliyun(){ while (!client.connected()){ Serial.print("Attempting MQTT connection..."); /*A device connected to the cloud platform based on an automatically calculated username and password*/ if (client.connect(myIot._clientId, myIot._username, myIot._password)){ Serial.println("connected"); client.subscribe(subTopic); client.subscribe(subTopic1); } else{ Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } void setup(){ Serial.begin(115200); sigmaDeltaSetup(0, 312500); sigmaDeltaAttachPin(BEDROOD_LIGHT, 0); /* connect WIFI */ connectWiFi(); /*Initializes Alinyun's configuration to automatically calculate user name and password*/ myIot.init(ALIYUN,ALIYUN_SERVER,ProductKey,ClientId,DeviceName,DeviceSecret,PORT); client.setServer(myIot._mqttServer,PORT); /*Set the callback function that executes when a subscription is received*/ client.setCallback(callback); /*Connect to the Aliyun*/ ConnectAliyun(); /*Report firmware version information*/ client.publish(pubTopic1,("{\"id\":"+ClientId+",\"params\":{\"version\":\"V1.0\",\"module\":\"esp32\"}}").c_str()); /*Report light brightness information*/ client.publish(pubTopic, ("{\"id\":" + ClientId + ",\"params\":{\"LightStatus\":\"0\",\"LightAdjustLevel\":\"0\"},\"method\":\"thing.event.property.post\"}").c_str()); } void loop(){ if(!client.connected()){ ConnectAliyun(); } client.loop(); } ``` #### 云端相关操作: ##### 1、创建一个产品 ![image-20210622165428300](./pictures/image13_1_2_1.png) - 产品名称可自定义,这里我们可以命名为"ESP32_MESH_LED" - 所属品类可根据功能而定,这里选择路灯照明 - 节点类型选择直连设备 - 后面的选项如图配置 ##### 2、创建一个设备 ![image-20210622170302654](./pictures/image13_1_2_2.png) - 产品选择上面创建的产品,这里选择“ESP_MESH_LED” - 设备名称可自定义,这里选择使用“LED_ONE” - 备注名称可自定义 ##### 3、记录设备信息 ![image-20210622171310822](./pictures/image13_1_2_3.png) 这里**一键复制**设备证书,代码中需要使用到这些信息 ![image-20210622171712809](./pictures/image13_1_2_4.png) ##### 4、云平台控制LED灯亮度 ![image-20210622171922701](./pictures/image13_1_2_5.png) - 选择我们定义的产品以及设备 - 这里我们直接采用平台自带的模块功能——**调光等级**,等级为(0-100)可选配,填入数值后点击"**设置**",即可控制MESH开发板上的用户灯亮度。(前提是设备接入云端) ##### 5、自定义网页界面控制LED灯亮度 - 登录 IoT Studio 的网址 https://www.aliyun.com/product/iotstudio,点击立即使用 ![image-20210622172914538](./pictures/image13_1_2_6.png) - 创建Web应用 新建项目,点击左侧的**项目管理**,在**普通项目**中,点击 **新建项目**,新建空白项目。应用名称可自定义。 ![image-20210622173115310](./pictures/image13_1_2_7.png) - 创建应用完成后,会自动打开Web应用编辑器。如图操作,在第二步时将滑条拖到界面中。 ![image-20210622173450356](./pictures/image13_1_2_8.png) - 在拖动后,点击界面中的滑条图形,屏幕右侧会出现该滑条的一些配置功能,这里主要对**数据源**进行配置 ![image-20210622173842744](./pictures/image13_1_2_9.png) - 这里选择我们上面设置的产品和设备进行关联,将属性选择为“**调光等级**”,然后点击确定 ![image-20210622174145116](./pictures/image13_1_2_10.png) - 而后,点击**发布** ![image-20210622174527080](./pictures/image13_1_2_11.png) - 最后会生成一个网址,进入网页,滑动滑条将可以控制LED的亮度 (这里在设备已接入云平台的前提下操作滑条) ![image-20210622174707308](./pictures/image13_1_2_12.png) ![image-20210622174747041](./pictures/image13_1_2_13.png) ##### 6、OTA设置 - 首先在OTA升级界面添加一个新的模块,可以自定义模块名称,这里我们与代码Json信息包一致,使用“esp32” ![image-20210622175254460](./pictures/image13_1_2_14.png) - 接下来我们添加一个升级包,升级包名称可自定义,选择我们前面配置的产品,版本号要高于本机的固件版本,在是否选择平台验证时,可以选择不验证。当配置完成后点击**确定**。这样一个升级包就已经配制好了。 ![image-20210622175825412](./pictures/image13_1_2_16.png) - 发起一次升级任务。点击**批量升级**,后出现第二张图片的界面,在升级范围我们可以选择全部升级,当设备接入云端后,会自动上报版本信息,所以这里**待升级版本号**在设备连入云端后会出现选项,如果设备固件版本与云端升级包版本一致则不用升级。 ![image-20210622180240006](./pictures/image13_1_2_17.png) ![image-20210622180306631](./pictures/image13_1_2_18.png) - 升级包推送速率必填项,可自定义。**升级失败重试间隔**可自定义,这里我们选择重试,后面默认配置即可 ![image-20210622180955248](./pictures/image13_1_2_19.png) - 升级成功后平台会显示成功信息 ![image-20210622181357175](./pictures/image13_1_2_20.png) ## 14.2 腾讯云 Tencent IoT https://github.com/espressif/esp-welink is an open source repository for ESP32 based on Tencent’s welink SDK. Tencentyun IoT https://github.com/espressif/esp-qcloud is an open source repository for ESP32 based on Tencentyun’s qcloud-iot-sdk-embedded-c SDK. 这里演示腾讯云IOT的基本用法,将采用云端控制MESH开发板板载的用户LED的开关,并且固件可通过腾讯云进行空中升级。 ### 例程:TencentYun OTA ```c++ /*! * @file Bedroom_Light.ino * * @brief Simulate esp32 as a bedroom light and use TencentYun as a cloud platform. * @n Subscribe to the switch status theme to enable remote switch control bedroom lights * @n TencentYun OTA * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com) * @licence The MIT License (MIT) * @author [Yangfeng](feng.yang@dfrobot.com) * @version V1.0 * @date 2021-06-24 * @get from https://www.dfrobot.com */ #include #include #include #include "DFRobot_Iot.h" #include "HttpsOTAUpdate.h" #define BEDROOD_LIGHT 15 /*Set WIFI name and password*/ const char *WIFI_SSID = "----------------"; const char *WIFI_PASSWORD = "----------------"; /*Configure device certificate information*/ String ProductID = "-----------------------"; String DeviceName = "-------------------"; String DeviceSecret = "---------------------------"; String clientToken = "1234"; /*Configure the domain name and port number*/ String TENCENT_SERVER = "iotcloud.tencentdevices.com"; uint16_t PORT = 1883; /*TOPIC that need to be published and subscribed*/ const char *subTopic ="$thing/down/property/${ProductID}/${DeviceName}"; const char *pubTopic = "$thing/up/property/${ProductID}/${DeviceName}"; const char *subTopic1 ="$ota/update/${ProductID}/${DeviceName}"; const char *pubTopic1 = "$ota/report/${ProductID}/${DeviceName}"; DFRobot_Iot myIot; WiFiClient espClient; PubSubClient client(espClient); uint8_t flagUpdate; static const char *server_certificate = "-----BEGIN CERTIFICATE-----\r\n" "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n" \ "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" \ "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n" \ "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" \ "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n" \ "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n" \ "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n" \ "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n" \ "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n" \ "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n" \ "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n" \ "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n" \ "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n" \ "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n" \ "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n" \ "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n" \ "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n" \ "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n" \ "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n" \ "-----END CERTIFICATE-----"; static HttpsOTAStatus_t otastatus; void HttpEvent(HttpEvent_t *event) { switch(event->event_id) { case HTTP_EVENT_ERROR: Serial.println("Http Event Error"); break; case HTTP_EVENT_ON_CONNECTED: Serial.println("Http Event On Connected"); break; case HTTP_EVENT_HEADER_SENT: Serial.println("Http Event Header Sent"); break; case HTTP_EVENT_ON_HEADER: Serial.printf("Http Event On Header, key=%s, value=%s\n", event->header_key, event->header_value); break; case HTTP_EVENT_ON_DATA: break; case HTTP_EVENT_ON_FINISH: Serial.println("Http Event On Finish"); break; case HTTP_EVENT_DISCONNECTED: Serial.println("Http Event Disconnected"); break; } } static void openLight() { digitalWrite(BEDROOD_LIGHT, HIGH); } static void closeLight() { digitalWrite(BEDROOD_LIGHT, LOW); } void connectWiFi() { Serial.print("Connecting to "); Serial.println(WIFI_SSID); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); while (WiFi.status() != WL_CONNECTED){ delay(500); Serial.print("."); } Serial.println(); Serial.println("WiFi connected"); Serial.print("IP Adderss: "); Serial.println(WiFi.localIP()); } void callback(char *topic, byte *payload, unsigned int len) { Serial.print("Recevice ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < len; i++){ Serial.print((char)payload[i]); } Serial.println(); StaticJsonDocument<1024> jsonBuffer; deserializeJson(jsonBuffer, (const char *)payload); auto error = deserializeJson(jsonBuffer, (const char *)payload); if (error){ Serial.println("parseObject() failed"); return; } /*Determine whether it is the firmware update topic*/ if(strcmp(topic,subTopic1) == 0){ String str = jsonBuffer["url"]; if(str.compareTo("null")!=0){ flagUpdate = 0; String version0 =jsonBuffer["data"]["version"] ; String a = "\""; String version = a+version0+a; Serial.println(version); Serial.println(str); HttpsOTA.onHttpEvent(HttpEvent); Serial.println("Starting OTA"); HttpsOTA.begin(const_cast(str.c_str()) , server_certificate); Serial.println("Please Wait it takes some time ..."); while(1){ otastatus = HttpsOTA.status(); if(otastatus == HTTPS_OTA_SUCCESS) { client.publish(pubTopic1,("{\"type\":\"report_progress\",\"report\":{\"progress\":{\"state\":\"burning\",\"result_code\":\"0\",\"result_msg\":\"\"},\"version\":"+version+"}}").c_str()); Serial.printf("Firmware written successfully. Current version information: %s . To reboot device, call API ESP.restart() or PUSH restart button on device",version0); client.publish(pubTopic1,("{\"type\":\"report_progress\",\"report\":{\"progress\":{\"state\":\"done\",\"result_code\":\"0\",\"result_msg\":\"\"},\"version\":"+version+"}}").c_str()); Serial.println("Auto restart after 3 seconds"); for(uint8_t i=0;i<2;i++){ delay(1000); Serial.print("."); } delay(1000); Serial.println("."); ESP.restart(); break; } else if(otastatus == HTTPS_OTA_FAIL) { Serial.println("Firmware Upgrade Fail"); break; }else if(otastatus == HTTPS_OTA_UPDATING){ if(flagUpdate ==0){ Serial.println("downloading..."); flagUpdate = 1; } } } } }else{ const uint16_t LightStatus = jsonBuffer["params"]["power_switch"]; if (LightStatus == 1){ openLight(); } else{ closeLight(); } String tempMseg = "{\"method\":\"control_reply\",\"clientToken\":\""+clientToken+"\",\"code\":\"0\",\"status\":\"success\"}"; char sendMseg[tempMseg.length()]; strcpy(sendMseg, tempMseg.c_str()); client.publish(pubTopic, sendMseg); } } void ConnectCloud() { while (!client.connected()){ Serial.print("Attempting MQTT connection..."); /*A device connected to the cloud platform based on an automatically calculated username and password*/ if (client.connect(myIot._clientId, myIot._username, myIot._password)){ Serial.println("connected"); client.subscribe(subTopic); client.subscribe(subTopic1); }else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } void setup() { Serial.begin(115200); pinMode(BEDROOD_LIGHT, OUTPUT); /*Connect to WIFI*/ connectWiFi(); /*Initialize the configuration of Aliyun*/ myIot.init(TENCENTYUN,TENCENT_SERVER, ProductID, clientToken, DeviceName, DeviceSecret); client.setServer(myIot._mqttServer, PORT); /*Set the callback function to execute the callback function when receiving the subscription information*/ client.setCallback(callback); /*Connect to the cloud platform*/ ConnectCloud(); /*Turn off the lights first*/ closeLight(); String ver = "{\"type\":\"report_version\",\"report\":{\"version\":\"0.1\"}}"; /*Publish information about turning off the lights*/ client.publish(pubTopic1,ver.c_str()); client.publish(pubTopic, ("{\"method\":\"report\",\"clientToken\":\""+clientToken+"\",\"timestamp\":1212121221,\"params\":{\"power_switch\":0}}").c_str()); } void loop() { if (!client.connected()){ ConnectCloud(); } client.loop(); } ``` ### 云端相关操作 #### 1、首先登录腾讯云,在物联网开发平台的公共实例创建一个项目,在项目里创建本次的产品以及设备。 ![image-20210624093726264](./pictures/image13_2_1.png) ![image-20210624093908127](./pictures/image13_2_2.png) ![image-20210624094043190](./pictures/image13_2_3.png) ![image-20210624094301523](./pictures/image13_2_4.png) ![image-20210624094714760](./pictures/image13_2_5.png) ![image-20210624095540129](./pictures/image13_2_7.png) ![image-20210624095723908](./pictures/image13_2_8.png) ![image-20210624100229563](./pictures/image13_2_9.png) ![image-20210624100318503](./pictures/image13_2_10.png) ![image-20210624101953655](./pictures/image13_2_17.png) ![image-20210624101845608](./pictures/image13_2_16.png) 代码填入上图信息 ![image-20210624102254308](./pictures/image13_2_18.png) #### 2、调试设备——微信小程序控制 ![image-20210624100749072](./pictures/image13_2_11.png) ![image-20210624101118742](./pictures/image13_2_12.png) ![image-20210624101318101](./pictures/image13_2_13.png) ![image-20210624101413837](./pictures/image13_2_14.png) #### 3、调试设备——云平台控制 ![image-20210624101509943](./pictures/image13_2_15.png) ![image-20210624102744952](./pictures/image13_2_19.png) #### 4、OTA 远程升级 OTA详情请参考腾讯云提供的开发文档https://cloud.tencent.com/document/product/634/14674 ![image-20210624103310766](./pictures/image13_2_20.png) 具体操作如下: ![image-20210624103931012](./pictures/image13_2_21.png) ![image-20210624104251415](./pictures/image13_2_22.png) ![image-20210624105051662](./pictures/image13_2_24.png) ![image-20210624104725590](./pictures/image13_2_23.png) ## 14.3 亚马逊AWS IoT ### 14.3.1 AWS IoT #### 14.3.1.1 AWS IOT 控制台的搭建 访问https://signin.aws.amazon.com根据官方提示创建一个AWS账号,已拥有账号的请直接登录; ![](./pictures/one.png) 登录成功后在 ”All services“ 中找到 ”IoT Core“ 进入IOT控制台; ![image-20210914164041751](./pictures/two-16413730535472.png) ![image-20210914164151090](./pictures/three-16413731630603.png) ![image-20210914164251253](./pictures/four-16413731855314.png) 接下来我们的操作就是来进行AWS IOT 控制台的搭建,第一步,创建一个”Things“; ![image-20210914164558803](./pictures/five.png) 在这里,我们创建一个物品 ![image-20210914165038874](./pictures/six.png) 我们直接设置名称后进入下一步 ![image-20210914173023958](./pictures/seven.png) 这里选择自动生成证书,并进入下一步 ![image-20210914173727400](./pictures/eight.png) 这里我们先直接创建,不设置policies。 ![image-20210914174121952](./pictures/nine.png) 这一步很重要,上一步完成后,会直接跳转到这里的界面,按照图中的顺序下载保存备用。 ![image-20210914174433128](./pictures/ten.png) 上一步完成后,自动跳转到”things“界面,然后我们进入刚刚创建的thing——test. ![image-20210914174727673](./pictures/eleven.png) 进入test界面,我们先来设置它的Device Shadows ![image-20210914175338373](./pictures/twelve.png) 在这里我们创建一个Named Shadow。 ![image-20210914175627799](./pictures/thirteen.png) 进入Shadow界面,记录URL ![image-20210914180028852](./pictures/fourteen.png) ![image-20210914180631953](./pictures/fifteen.png) 接下来,我们来制定policies。 ![image-20210914181957055](./pictures/sixteen.png) ![image-20210914182207211](./pictures/seventeen.png) ![image-20210914182752534](./pictures/eighteen.png) 图上添加的语句如下: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:Publish", "iot:Subscribe", "iot:Connect", "iot:Receive" ], "Resource": [ "*" ] } ] } ``` ​ 接下来,我们将本policy添加到创建thing时生成的证书中 ![image-20210914183719108](./pictures/nineteen.png) ![image-20210914183940082](./pictures/twenty.png) ![image-20210914184106297](./pictures/twenty-one.png) 到这里,简单的AWS IOT 控制台就设置完成,接下来,我们来做一个监测LED状态的小示例 #### 14.3.1.2 LED状态检测应用 首先我们来更改Shadow 里面的**Device Shadow document** ![image-20210914185304384](./pictures/twenty-two.png) ![image-20210914185447248](./pictures/twenty-three.png) 【图上添加的语句如下: { "state": { "desired": { "welcome": "aws-iot" }, "reported": { "welcome": { "timestamp": 1631519032 }, "LED": { "LED_STATUS": "on state" } } } } 】 接下来我们去监测mqtt topic ![image-20210914190104786](./pictures/twenty-four.png) 在此界面我们可以监测到topic信息 ![image-20210914190302289](./pictures/twenty-five.png) 下面。我们进入本地——代码与设备阶段 首先在代码中更改证书信息,证书信息就是创建thing是生成的证书,当时我们保存到了本地,现在将它复制到代码中,我们需要的证书信息有:certificate_pem_crt、private_pem_key、rootCA,既图中框起来的三个。 ![image-20210915083228352](./pictures/twenty-six.png) 将自己的证书信息以图中的格式更改代码。 ![image-20210915083716462](./pictures/twenty-seven.png) 接下来,我们更改代码中topic为自己shadow的topic并且更改自己的AWS端点。这里我们订阅”update/rejected“、“update/accepted"这两个topic用来确认我们每次向平台推送的消息是否被接收。 ![image-20210915085343741](./pictures/twenty-eight.png) 接下来,更改自己的wifi信息,之后我们就可以开始烧录代码到开发板中进行测试了! ![image-20210915085719227](./pictures/twenty-nine.png) (烧录代码中)...... 本次编写的代码主要实现的功能是:用户按下用户按键,用户LED状态改变一次并且上报LED状态到云端。接下来,我们直接上图看一下设备上报的LED状态。 ![image-20210915090407160](./pictures/thirty.png) ![image-20210915090650211](./pictures/thirty-one.png) 本地设备通过串口打印云端返回的信息 ![image-20210915091023651](./pictures/thirty-two.png) 到这里测试就完成啦。附上代码位置:(SDK->libraries->DFRobot_Iot->example->AWSIot->AWSIot.ino) ### 14.3.2 AWS_S3_OTA_Update #### 14.3..2.1 创建 S3 Buckets 访问AWS 官方提供网站(https://signin.aws.amazon.com )并进入AWS Management Console界面,从AWS Management Console界面进入S3控制台。 ![image-20210915095414699](./pictures/thirty-three.png) 话不多说,直接创建一个Buckets 。 ![image-20210915095903131](./pictures/thirty-four.png) 这里我们如图配置 ![image-20210915100602234](./pictures/thirty-five.png) 接下来我们上传更新固件 ![image-20210915100722039](./pictures/thiry-six.png) ![image-20210915100945162](./pictures/thirty-seven.png) ![image-20210915101419645](./pictures/thirty-eight.png) ![image-20210915102156473](./pictures/thirty-nine.png) 到这里我们就完成了对固件的上传,接下来我们来进行设备端的准备工作 #### 14.3.2.2 设备端 首先保存云端固件的URL ![image-20210915102455603](./pictures/forty.png) ![image-20210915103013810](./pictures/forty-one.png) 根据URL修改代码。 ![](./pictures/forty-two.png) 然后修改自己的wifi信息 ![forty-three](./pictures/forty-three.png) 接下来就可以烧入程序进行测试啦。 (烧入程序)...... 现在我们来看看程序运行的结果 ![image-20210915110013167](./pictures/forty-four.png) 到这里就成功啦。附上代码位置:(SDK->libraries->example->AWS_S3_OTA_Update->AWS_S3_OTA_Update.ino)