引言
在前面我们已经介绍了几种Mind+程序接入MQTT平台的方法:
前面也提到Nanomq桥接的方法有点麻烦,而接入巴法云的方法不适用华为云。今天介绍另外一种方法来接入华为云。
原理
之所以不能用Mind+的MQTT模块接入华为云是因为MQTT模块不能设置clientid,它是随机生成的,而华为云的clientid和用户名、密码构成加密三元组,随便设置clientid是不行的。所以需要找到一种办法能够设置clientid。
在前面的博文(【行空板K10】Mind+生成的代码初探_mind+怎么生成应用程序-CSDN博客)说过Mind+实际上是将Scratch积木转换为C++代码,然后再编译C++代码为可执行文件。我们可以在Mind+编程环境的代码窗口中看到它生成的代码:
而MQTT的参数初始化的Block对应的是DFRobot_Iot::init函数。这个函数有如下两个版本:
/*Use ONENET cloud platform*/
void DFRobot_Iot::init(String OneNetServer,
String OneNetProductID, String OneNetDeviceID,
String OneNetApiKey, const String iotTopics[],
uint16_t OneNetPort)
{
if(OneNetServer == "183.230.40.96"){
this->_MQTTSERVER = OneNetServer;
this->_ProductID = OneNetProductID;
this->_DeviceID = OneNetDeviceID;
this->_ApiKey = OneNetApiKey;
this->_port = OneNetPort;
this->_UseServer = ONENET_NEW;
}else{
this->_MQTTSERVER = OneNetServer;
this->_ProductID = OneNetProductID;
this->_DeviceID = OneNetDeviceID;
this->_ApiKey = OneNetApiKey;
this->_port = OneNetPort;
this->_UseServer = ONENET;
}
for(int i = 0; i < MAXTOPICNUMBER; i++){
if(iotTopics[i] != ""){
this->mqtt_topicArray.push_back(iotTopics[i]);
}
}
setConfig();
}
/*Use Aliyun cloud platform*/
void DFRobot_Iot::init(String AliyunServer, String AliProductKey,
String AliClientId, String AliDeviceName,
String AliDeviceSecret, const String iotTopics[],
uint16_t AliPort)
{
this->_MQTTSERVER = AliyunServer;
this->_ProductKey = AliProductKey;
this->_ClientId = AliClientId;
this->_DeviceName = AliDeviceName;
this->_DeviceSecret = AliDeviceSecret;
this->_port = AliPort;
this->_UseServer = ALIYUN;
for(int i = 0; i < MAXTOPICNUMBER; i++){
if(iotTopics[i] != ""){
this->mqtt_topicArray.push_back(iotTopics[i]);
}
}
setConfig();
}
7个参数的版本是阿里云平台专用的,而6个参数的版本是其他三种MQTT平台使用的。我们只关心后一个,它的6个参数是:服务器地址、用户名、clientid、密码、初试订阅的主题数组和端口号。
所以,我的思路就很简单了:手工修改生成的代码,把其中随机生成的clientid改为华为云规定的clientid。
Mind+代码编写
Mind+的代码是在前面博文基础上添加,主要是读取温湿度信息,然后按照华为云要求的物模型格式发送到平台上。
从代码窗口可以看到其生成的代码:
/*!
* MindPlus
* esp32s3bit
*
*/
#include <DFRobot_Iot.h>
#include "unihiker_k10.h"
// 动态变量
String mind_s_my_string_variable, mind_s_data;
volatile float mind_n_temp, mind_n_hum;
// 静态常量
const String topics[5] = {"","","","",""};
// 创建对象
UNIHIKER_K10 k10;
AHT20 aht20;
uint8_t screen_dir=2;
DFRobot_Iot myIot;
// 主程序开始
void setup() {
k10.begin();
k10.initScreen(screen_dir);
k10.creatCanvas();
mind_n_temp = aht20.getData(AHT20::eAHT20TempC);
mind_n_temp = (mind_n_temp - 8);
mind_n_hum = aht20.getData(AHT20::eAHT20HumiRH);
k10.setScreenBackground(0x000000);
mind_s_my_string_variable = (String("温度:") + String(mind_n_temp));
k10.canvas->canvasText(mind_s_my_string_variable, 3, 0xFFFFFF);
k10.canvas->canvasText((String("湿度:") + String(mind_n_hum)), 4, 0xFFFFFF);
k10.canvas->updateCanvas();
myIot.wifiConnect("CU_fjGX", "12345678");
while (!myIot.wifiStatus()) {}
k10.rgb->write(0, 0x0000FF);
k10.canvas->canvasText(myIot.getWiFiSoftIP(), 5, 0xFFFF00);
k10.canvas->updateCanvas();
myIot.init("bde4cbe7aa.st1.iotda-device.cn-north-4.myhuaweicloud.com","XXXXXX_test","6397496829442821","XXXXXXXXX", topics, 1883);
myIot.connect();
while (!myIot.connected()) {}
k10.rgb->write(1, 0x0000FF);
}
void loop() {
mind_s_data = "{\"services\": [{\"serviceId\": \"温湿度\",\"properties\": {\"温度\": ";
mind_s_data = (String(mind_s_data) + String(mind_n_temp));
mind_s_data = (String(mind_s_data) + String(", \"湿度\":"));
mind_s_data = (String(mind_s_data) + String(mind_n_hum));
mind_s_data = (String(mind_s_data) + String(" } } ] }"));
myIot.publish(" $oc/devices/XXXXXXX_test/sys/properties/report", mind_s_data);
delay(5000);
}
核心问题就是修改myIot.init中的"6397496829442821"为华为IoT平台的clientid。
手工代码修改
在生成代码的窗口上右键,选择全选和复制,然后切换到“手工编辑”窗口粘贴代码。
然后找到myIot.init一句,修改"6397496829442821"为华为IoT平台的clientid。此时再编译程序就是手工修改的这个版本了。
测试
对华为云平台不熟悉的朋友可以看我以前的博文,例如:
- 【HZHY-AI300G智能盒试用连载体验】在华为IoTDA平台上建立设备_hzhy-ai300g智盒-CSDN博客
- 使用Python连接华为IoTDA并发布数据_python 华为云iot-CSDN博客
设备烧录成功后,可以顺利地接入华为云平台,可以看到有一个设备在线:
设备详情里面可以看到上报的数据:
至此验证了我想法。
调试中遇到的一个小错误
刚开始测试的时候,发现平台可以收到消息,但是无法解析成物模型。查看日志,发现显示如下信息:
IoTDA has received the message reported by the device.data: {"services": [{"serviceId": "温湿度","properties": {"温度": 24.07, "湿度":15.88 } } ] },
而正常的信息应该是:
IoTDA has received the properties reported from the device.data: {"services": [{"serviceId": "温湿度","properties": {"温度": 24.07, "湿度":15.88 } } ] } ,
看来几遍也没有找到问题,后来检查生成的代码,才发现publish的主题前面多了空格:
myIot.publish(" $oc/devices/XXXXXXX_test/sys/properties/report", mind_s_data);
因此,华为云不认识这条消息了。检查了Mind+的代码,确实是自己多敲了:
结语
至此,解决了所有MQTT平台的接入问题。但是手工修改代码有个缺点就是每次生成之后都要改,比较麻烦。另外,修改代码需要对C++非常熟悉,对Mind+平台的代码工作原理有了解。所以比较理想的方法是编写第三方库,这个问题留给下周解决。