22961| 18
|
[讨论交流] 阿里云IoT套件测试5:管理多个设备(单个ESP32) |
本帖最后由 szjuliet 于 2019-5-30 10:55 编辑 管理多个设备(单个ESP32) 阿里云IoT套件测试1:开箱、软件安装及示例测试 阿里云IoT套件测试2:IoT平台注册、创建产品及设备 阿里云IoT套件测试3:创建物联网移动应用开发 阿里云IoT套件测试4:智能LED灯 阿里云IoT套件测试5:管理多个设备(单个ESP32) 依据Starter Kit for Aliyun IoT 教程测试:链接地址 感谢@绿水无痕的技术指导!! 演示视频 测试预期目标:
所需元件:
说明:如果将继电器接上插座,就可以实现控制现实生活中的设备。智能插座的项目我在2016年指导学生小课题做过类似的项目,只是通信方式是BLE,使用的是Arduino101,移动端开发使用的是App Inventor。阿里云这个项目的继电器也可以这样来控制,因为时间关系,这一步我就省略了,做法是一样的。下面是Arduino101通过BLE控制电器开关的演示视频。 解决的主要问题 这个项目虽然看上去只是完成了一个简单的功能(实际上我刚开始也觉得这个目标应该很容易实现),但是做了以后才发现不容易。这个项目很是折腾了几天。教程给出的项目都是一个产品一个设备,每次只能控制一个设备。我的设想是控制多个设备。 1. 解决控制多个设备的控制问题: 我采用了一个产品下挂多个设备的方式。在云平台上使用在线模拟虽然可以控制所有设备的开关,但是在手机上却只能控制一个设备,观察串口监视器显示的publish的信息发现虽然控制了不同的设备,但是回调函数返回的topic都是第1个设备(LED)的。向技术人员@绿水无痕 请教后对设置进行了修改,一个产品下只有一个设备,产品自定义功能全部归属到这个设备中,这样就保证subTopic和pubTopic都是唯一的,手机可以控制所有设备。 2. 解决控制的逻辑问题: 虽然可以控制多个设备,但是奇怪的是开启某个设备会把前面开的设备关掉,每次只能有一个设备处于开启的状态,这个和现实是有冲突的。和@绿水无痕多次沟通,在他的帮助下解决了问题。后面会详细说明。 以下是项目测试的详细步骤 一、阿里云IoT设置 实现单ESP32下控制多个设备按下面的流程来进行: 新建项目-->新建产品-->自定义功能(灯,风扇,插座)-->新增设备(一个)-->移动应用开发-->每个控制对应产品的一个自定义功能。 1. 新建项目:
2. 新增(或导入已有)产品:
3. 为产品添加自定义功能:
说明:这里添加了红外,是准备后面做智能防盗用的。 4. 新增设备:
5. 新增可视化应用:
二、线路连接 LED灯接D2,风扇接D4,继电器接D6 三、程序编写 选择样例文件中的任何一个进行改写。 改写的部分代码如下: 1. 定义3个设备的引脚 [mw_shl_code=cpp,true]#define LIGHT D2 #define FAN D4 #define RELAY D6[/mw_shl_code] 2. 定义标识符对应每种物理设备 [mw_shl_code=cpp,true]/*需要操作的产品标识符*/ String Identifier_Light = "LightStatus"; String Identifier_Fan = "FanStatus"; String Identifier_Relay = "RelayStatus";[/mw_shl_code] 3. 三个设备的开关代码 [mw_shl_code=cpp,true]static void openLight(){ digitalWrite(LIGHT, HIGH); } static void closeLight(){ digitalWrite(LIGHT, LOW); } static void openFan(){ digitalWrite(FAN, HIGH); } static void closeFan(){ digitalWrite(FAN, LOW); } static void openRelay(){ digitalWrite(RELAY, HIGH); } static void closeRelay(){ digitalWrite(RELAY, LOW); }[/mw_shl_code] 4. 修改回调函数 [mw_shl_code=cpp,true]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); } Serial.println(); StaticJsonBuffer<300> jsonBuffer; JsonObject& root = jsonBuffer.parseObject((const char *)payload); if(!root.success()){ Serial.println("parseObject() failed"); return; } const uint16_t LightStatus = root["params"][Identifier_Light]; if(LightStatus == 1){ openLight(); }else{ closeLight(); } Serial.println("LightStatus:"); Serial.println(LightStatus); const uint16_t FanStatus = root["params"][Identifier_Fan]; if(FanStatus == 1){ openFan(); }else{ closeFan(); } Serial.println("FanStatus:"); Serial.println(FanStatus); const uint16_t RelayStatus = root["params"][Identifier_Relay]; if(RelayStatus == 1){ openRelay(); }else{ closeRelay(); } Serial.println("RelayStatus:"); Serial.println(RelayStatus); String tempMseg_Light = "{\"id\":"+ClientId+",\"params\":{\""+Identifier_Light+"\":"+(String)LightStatus+"},\"method\":\"thing.event.property.post\"}"; char sendMseg_Light[tempMseg_Light.length()]; strcpy(sendMseg_Light,tempMseg_Light.c_str()); client.publish(pubTopic,sendMseg_Light); String tempMseg_Fan = "{\"id\":"+ClientId+",\"params\":{\""+Identifier_Fan+"\":"+(String)FanStatus+"},\"method\":\"thing.event.property.post\"}"; char sendMseg_Fan[tempMseg_Fan.length()]; strcpy(sendMseg_Fan,tempMseg_Fan.c_str()); client.publish(pubTopic,sendMseg_Fan); String tempMseg_Relay = "{\"id\":"+ClientId+",\"params\":{\""+Identifier_Relay+"\":"+(String)RelayStatus+"},\"method\":\"thing.event.property.post\"}"; char sendMseg_Relay[tempMseg_Relay.length()]; strcpy(sendMseg_Relay,tempMseg_Relay.c_str()); client.publish(pubTopic,sendMseg_Relay);[/mw_shl_code] 5. 定义引脚输出模式 [mw_shl_code=cpp,true] pinMode(LIGHT,OUTPUT); pinMode(FAN,OUTPUT); pinMode(RELAY,OUTPUT); [/mw_shl_code] 四、调试程序 在调试中会遇到很多错误,如编译错误,程序运行错误。编译错误比较好解决,程序运行错误就要仔细分析串口监视器的返回内容,查找错误原因。在DF给的KIT中有许多.h头文件,根据需要打开相应的头文件了解程序运行的机制,还可以根据错误返回信息查找头文件来找出错误原因。 这个错误可以看到是MQTT连接失败,rc=4,返回的错误代码是4,我们找到相应的头文件PubSubClient.h可以查看到返回代码4是凭证错误,也就是三联码:ProductKey,DeviceName和DeviceSecret中的一个或几个有问题,检查后发现确实有一个凭证是错的,修改后问题解决。从下图中可以看到返回代码所代表的含义: MQTT连接超时 -4 MQTT连接丢失 -3 MQTT连接失败 -2 MQTT断开连接 -1 MQTT连接成功 0 MQTT连接协议错误 1 MQTT连接ClientId错误 2 MQTT连接不可用 3 MQTT连接凭证错误 4 MQTT连接未授权 5 进行在线模拟的时候发现虽然在平台上可以控制设备的开关,但是手机上只能控制灯的开关,其他两种设备无法控制,查看串口监视器发现回调函数返回的Topic是有问题的。这是因为我们在一个产品下有多个设备,这样造成Topic不唯一,解决方法是在一个产品下只增加一个设备,产品下面添加自定义功能,每个功能对应设备的一种属性。 按照上面的想法修改程序后,在线模拟以及手机都可以控制所有设备,但是奇怪的是在打开某个设备时也会关闭其他开着的设备,如下面的视频演示: 与@绿水无痕进行探讨,他分析原因应该是“LightStatus是ArduinoJson中的子对象,没法用containSkey判断,只能用root["params"]["LightStatus"]获取,如果没有的话自动返回NULL,会与Bool类型的0冲突,导致无法判断”,即每次发送命令时只有一个设备的状态被发送,另外两个没有发送,而没有发送系统返回null,即0。所以应付对其他两个设备采取关闭的操作,导致上面所演示的错误发生。 解决方法是引入3个变量来读取返回的topic里是否包含了对应的标识符,如果没有包含就不执行任何操作(保持设备原有的状态);如果包含再判断返回来的值是1还是0,1就执行开启操作,0执行关闭操作。 修改回调函数: [mw_shl_code=cpp,true]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); } Serial.println(); StaticJsonBuffer<300> jsonBuffer; JsonObject& root = jsonBuffer.parseObject((const char *)payload); if(!root.success()){ Serial.println("parseObject() failed"); return; } const char* val1=root["params"][Identifier_Light]; const char* val2=root["params"][Identifier_Fan]; const char* val3=root ["params"][Identifier_Relay]; if(val1!=NULL) { Serial.println("++++++++++"); const uint16_t LightStatus = root["params"][Identifier_Light]; if (LightStatus == 1){ openLight(); }else{ closeLight(); } String tempMseg = "{\"id\":"+ClientId+",\"params\":{\""+Identifier_Light+"\":"+(String)LightStatus+"},\"method\":\"thing.event.property.post\"}"; char sendMseg[tempMseg.length()]; strcpy(sendMseg,tempMseg.c_str()); client.publish(pubTopic,sendMseg); } if(val2!=NULL) { Serial. println("----------"); const uint16_t FanStatus = root["params"][Identifier_Fan]; if (FanStatus == 1){ openFan(); }else{ closeFan(); } String tempMseg = "{\"id\":"+ClientId+",\"params\":{\""+Identifier_Fan+"\":"+(String)FanStatus+"},\"method\":\"thing.event.property.post\"}"; char sendMseg[tempMseg.length()]; strcpy(sendMseg,tempMseg.c_str()); client.publish(pubTopic,sendMseg); } if(val3!=NULL) { Serial. println("**********"); const uint16_t RelayStatus = root["params"][Identifier_Relay]; if (RelayStatus == 1){ openRelay(); }else{ closeRelay(); } String tempMseg = "{\"id\":"+ClientId+",\"params\":{\""+Identifier_Relay+"\":"+(String)RelayStatus+"},\"method\":\"thing.event.property.post\"}"; char sendMseg[tempMseg.length()]; strcpy(sendMseg,tempMseg.c_str()); client.publish(pubTopic,sendMseg); } }[/mw_shl_code] 程序修改完后运行,执行开启设备命令后串口监视器如下: 提升 在现实家居生活中有多个设备,单用一个ESP32肯定是不够也不方便,可以用多个ESP32,每个ESP32下可以挂多个设备。每个ESP32程序结构大致一样,不需要做过多的修改。只需要在阿里云的项目中增加产品,每个产品对应一个ESP32即可。手头有FireBeetle,掌控板,Linkit7697,还有Obloq,ArduinoUNO WiFi,等有机会试验一下。 无力吐槽一下阿里云。这个平台目前还是不太稳定,总会有奇奇怪怪的问题出现:删除的设备在组件属性中还是会出现,即使更新并保存,过一会儿又恢复已删除的东西;打包的app运行后点进页面出现“访问发现错误,当前版本没有打包”,重新开发一个新的app才运行正常;23号更坑,打包的app一运行就闪退,换电脑,换手机,换网络,重新构建...试了各种方法仍然不行,24号早上才得知是阿里云本身出了问题,最近更新出了bug,这是得多大的bug,太不应该了啊!另外已经在线模拟或使用的app不能删除也是一个大槽点,太不方便了。 倒是DF的器材性能很稳定,尤其主控板连接很迅速,响应也很快。赞一个!! |
2.09 KB, 下载次数: 26
售价: 10 创造力 [记录]
INO文件
大叔1 发表于 2021-3-3 22:14 我也遇到了和你同样的问题。今天和阿里云IOT的一个工程师沟通了半天,结果发现是,当阿里云平台发送指令(类似于 /sys/hrkchWpcCEv/LED/thing/service/property/set)后,原本我们的esp32应该发送一个且仅有一个reply给云平台的。再DFRobot提供的程序里面,是通过callback()函数的。 但是不知道什么原因,这个callback函数被不停的调用,多次上报给云平台,而因为设备端短时间上报次数过多导致了云平台的限流,所以没有上报成功,从而web项目报错, 为保护设备,自动恢复到开始的状态。 阿里云IoT的工程建议我,修改下设备端上报逻辑。 我自己通过调看串口,的确发现短时间内,callback函数被调用了50多次。 但是我们这边如果需要修改callback()函数的化,工作量不是一般的大。只能请DFRobot的工程师@绿水无痕来修改的。 |
狮山闲人 发表于 2022-4-27 11:35 我也遇到了和你同样的问题。今天和阿里云IOT的一个工程师沟通了半天,结果发现是,当阿里云平台发送指令(类似于 /sys/hrkchWpcCEv/LED/thing/service/property/set)后,原本我们的esp32应该发送一个且仅有一个reply给云平台的。再DFRobot提供的程序里面,是通过callback()函数的。 但是不知道什么原因,这个callback函数被不停的调用,多次上报给云平台,而因为设备端短时间上报次数过多导致了云平台的限流,所以没有上报成功,从而web项目报错, 为保护设备,自动恢复到开始的状态。 阿里云IoT的工程建议我,修改下设备端上报逻辑。 我自己通过调看串口,的确发现短时间内,callback函数被调用了50多次。 但是我们这边如果需要修改callback()函数的化,工作量不是一般的大。只能请DFRobot的工程师@绿水无痕来修改的。 |
大叔1 发表于 2021-3-3 22:14 这个是代码callback函数问题的。 |
helloworld_dfro 发表于 2022-10-18 00:07 和DFRobot的工程师沟通了半天,并没有解决。后面找了一个计算机的高手。修改了回调函数,解决了问题。不得不吐槽一下下DFRobot的工程师,这么大的bug放在那里几年了,还没有解决,一直说是他们的套件没有问题,验证了无数次。 |
© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed