玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

曾无好事来相访,赖尔高文一起予。这篇文章主要讲述玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制相关的知识,希望能为你提供帮助。

授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力。希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石。。。
QQ技术互动交流群:ESP8266& 32 物联网开发 群号622368884,不喜勿喷
一、你如果想学基于Arduino的ESP8266开发技术一、基础篇
  1. ESP8266开发之旅 基础篇① 走进ESP8266的世界
  2. ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境
  3. ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明
  4. ESP8266开发之旅 基础篇④ ESP8266与EEPROM
  5. ESP8266开发之旅 基础篇⑤ ESP8266 SPI通信和I2C通信
  6. ESP8266开发之旅 基础篇⑥ Ticker——ESP8266定时库
二、网络篇
  1. ESP8266开发之旅 网络篇① 认识一下Arduino Core For ESP8266
  2. ESP8266开发之旅 网络篇② ESP8266 工作模式与ESP8266WiFi库
  3. ESP8266开发之旅 网络篇③ Soft-AP——ESP8266WiFiAP库的使用
  4. ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用
  5. ESP8266开发之旅 网络篇⑤ Scan WiFi——ESP8266WiFiScan库的使用
  6. ESP8266开发之旅 网络篇⑥ ESP8266WiFiGeneric——基础库
  7. ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client
  8. ESP8266开发之旅 网络篇⑧ SmartConfig——一键配网
  9. ESP8266开发之旅 网络篇⑨ HttpClient——ESP8266HTTPClient库的使用
  10. ESP8266开发之旅 网络篇⑩ UDP服务
  11. ESP8266开发之旅 网络篇? WebServer——ESP8266WebServer库的使用
  12. ESP8266开发之旅 网络篇? 域名服务——ESP8266mDNS库
  13. ESP8266开发之旅 网络篇? SPIFFS——ESP8266 Flash文件系统
  14. ESP8266开发之旅 网络篇? web配网
  15. ESP8266开发之旅 网络篇? 真正的域名服务——DNSServer
  16. ESP8266开发之旅 网络篇? 无线更新——OTA固件更新
三、应用篇
  1. ESP8266开发之旅 应用篇① 局域网应用 ——炫酷RGB彩灯
  2. ESP8266开发之旅 应用篇② OLED显示天气屏
  3. ESP8266开发之旅 应用篇③ 简易版WiFi小车
四、高级篇
  1. ESP8266开发之旅 进阶篇① 代码优化 —— ESP8266内存管理
  2. ESP8266开发之旅 进阶篇② 闲聊Arduino IDE For ESP8266配置
  3. ESP8266开发之旅 进阶篇③ 闲聊 ESP8266 Flash
  4. ESP8266开发之旅 进阶篇④ 常见问题 —— 解决困扰
  5. ESP8266开发之旅 进阶篇⑤ 代码规范 —— 像写文章一样优美
  6. ESP8266开发之旅 进阶篇⑥ ESP-specific APIs说明
1.理论基础????参考博主线上博文:
  • 玩转PubSubClient MQTT库
  • 玩转OneNET物联网平台之简介
  • 玩转OneNET物联网平台之MQTT服务①
  • 玩转OneNET物联网平台之MQTT服务②
  • 玩转OneNET物联网平台之MQTT服务③
????在前面的博文中,博主主要通过手动方式去创建设备。这种方式的缺点明显:
  • 人为手动控制,对于开发者来说极度不友好;
  • 如果设备数量很多,岂不是要手动操作非常多次;
????那么,如何实现设备自注册呢?所谓自注册就是设备连入网络后自动往OneNet云平台注册设备信息并获取设备Id。
  • 为了区分唯一性,我们采用ESP-Mac地址的组合形式
  • 同时为了操作方便,博主花了个周末的时间做了一个对应的app,理论上不限制ESP8266接入点的数量
????本篇博文的目的就在于教会大家如何和app通信,完成MQTT协议下的App远程控制LED灯,并且LED灯的数量可以随意接入,用户可以在app端修改设备名字以便方便操作。
  • 博主极度建议大家从第一篇看起,有个大概了解,因为本系列教程都是有相联系的
????先上个概念图:
玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

2.远程控制LED,实现设备自注册 2.1 实验材料
  • ESP8266 NodeMcu
  • android手机
  • OneNet平台
2.2 实验步骤
2.2.1 创建 ESP8266智能灯系统 产品(MQTT协议)
玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

注意点:
  • 务必选择MQTT协议
????创建完毕后,我们点击查看具体的产品信息:
玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

注意点:
  • 需要记录产品ID,其用来区分产品唯一标识符,这个ID待会需要填入App
  • Master-APIkey,网络请求鉴权信息,接口调用需要带入,这个ID待会需要填入App
2.2.2 NodeMcu烧录代码 —— MQTT设备端????为了明确区分代码功能,博哥命名工程名为P_OneNet_Exam05:
  • P_OneNet_Exam05.ino文件:
/** *功能:ESP8266 Mqtt客户端自注冊功能,通过配套App控制Led消息,理论上可以接入无数个esp8266 *作者:单片机菜鸟 *时间:2019-10-27 *描述: *1.初始化工作:初始化网络配置,Mqtt客户端自注冊,连接鉴权,订阅主题 *2.订阅消息:获取发送过来的消息(json格式),解析消息,实现控制亮灭灯 */#include < ESP8266WiFi.h> #include < PubSubClient.h> #include < ESP8266HTTPClient.h> #include < ArduinoJson.h> #include < EEPROM.h> #include < Ticker.h> #include " H_project.h" #define MAGIC_NUMBER 0xAAint state; WiFiClient espClient; //声明方法 void initSystem(); void initOneNetMqtt(); void callback(char* topic, byte* payload, unsigned int length); void saveConfig(); void loadConfig(); bool parseRegisterResponse(); void parseOneNetMqttResponse(char* payload); /** * 初始化 */ void setup() { initSystem(); initOneNetMqtt(); }void loop() { ESP.wdtFeed(); state = connectToOneNetMqtt(); if(state == ONENET_RECONNECT){ //重连成功 需要重新注册 mqttClient.subscribe(TOPIC,1); mqttClient.loop(); }else if(state == ONENET_CONNECTED){ mqttClient.loop(); } delay(2000); }void initSystem(){ int cnt = 0; Serial.begin (115200); Serial.println(" Start ESP8266 MQTT" ); Serial.print(" Firmware Version:" ); Serial.println(VER); Serial.print(" SDK Version:" ); Serial.println(ESP.getSdkVersion()); wifi_station_set_auto_connect(0); //关闭自动连接 ESP.wdtEnable(5000); WiFi.disconnect(); delay(100); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); cnt++; Serial.print(" ." ); if(cnt> =40){ cnt = 0; //重启系统 delayRestart(1); } } pinMode(LED_BUILTIN, OUTPUT); loadConfig(); //还没有注册 if(strcmp(config.deviceid,DEFAULT_ID) == 0){ int tryAgain = 0; while(!registerDeviceToOneNet()){ Serial.print(" ." ); delay(500); tryAgain++; if(tryAgain == 5){ //尝试5次 tryAgain = 0; //重启系统 delayRestart(1); } } if(!parseRegisterResponse()){ //重启系统 delayRestart(1); while(1); } } }void initOneNetMqtt(){ mqttClient.setServer(mqttServer,mqttPort); mqttClient.setClient(espClient); mqttClient.setCallback(callback); initOneNet(PRODUCT_ID,API_KEY,config.deviceid); }void callback(char* topic, byte* payload, unsigned int length) { Serial.print(" Message arrived [" ); Serial.print(topic); Serial.print(" ] " ); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); parseOneNetMqttResponse((char *)payload); }/* * 保存参数到EEPROM */ void saveConfig() { Serial.println(" Save OneNet config!" ); Serial.print(" deviceId:" ); Serial.println(config.deviceid); EEPROM.begin(150); uint8_t *p = (uint8_t*)(& config); for (int i = 0; i < sizeof(config); i++) { EEPROM.write(i, *(p + i)); } EEPROM.commit(); }/* * 从EEPROM加载参数 */ void loadConfig() { EEPROM.begin(150); uint8_t *p = (uint8_t*)(& config); for (int i = 0; i < sizeof(config); i++) { *(p + i) = EEPROM.read(i); } EEPROM.commit(); if (config.magic != MAGIC_NUMBER) { strcpy(config.deviceid, DEFAULT_ID); config.magic = MAGIC_NUMBER; saveConfig(); Serial.println(" Restore config!" ); } Serial.println(" -----Read config-----" ); Serial.print(" deviceId:" ); Serial.println(config.deviceid); Serial.println(" -------------------" ); }/** * 解析mqtt数据 */ void parseOneNetMqttResponse(char* payload){ Serial.println(" start parseOneNetMqttResponse" ); StaticJsonBuffer< 100> jsonBuffer; // StaticJsonBuffer 在栈区分配内存它也可以被 DynamicJsonBuffer(内存在堆区分配) 代替 // DynamicJsonBufferjsonBuffer; JsonObject& root = jsonBuffer.parseObject(payload); // Test if parsing succeeds. if (!root.success()) { Serial.println(" parseObject() failed" ); return ; }String deviceId = root[" Did" ]; int status = root[" sta" ]; if(strcmp(config.deviceid,deviceId.c_str()) == 0){ if (status == 1) { digitalWrite(LED_BUILTIN, LOW); } else { digitalWrite(LED_BUILTIN, HIGH); } } }/** * 解析注册返回结果 */ bool parseRegisterResponse(){ Serial.println(" start parseRegisterResponse" ); StaticJsonBuffer< 200> jsonBuffer; // StaticJsonBuffer 在栈区分配内存它也可以被 DynamicJsonBuffer(内存在堆区分配) 代替 // DynamicJsonBufferjsonBuffer; JsonObject& root = jsonBuffer.parseObject(response); // Test if parsing succeeds. if (!root.success()) { Serial.println(" parseObject() failed" ); return false; }int errno = root[" errno" ]; if(errno !=0){ Serial.println(" register failed!" ); return false; }else{ Serial.println(" register sucess!" ); strcpy(config.deviceid, root[" data" ][" device_id" ]); saveConfig(); return true; } }

  • H_project.h 代码:
#ifndef _MAIN_H__ #define _MAIN_H__extern " C" { #include " user_interface.h" #include " smartconfig.h" }struct onenet_config { char deviceid[15]; uint8_t magic; }; /************** ESP8266相关操作 **************************/ void delayRestart(float t); void delayNs(uint8_t m); /*********************************************************//*************** OneNet MQTT相关操作 ****************************/ void initOneNet(uint8_t *productId,uint8_t *apiKey,uint8_t *deviceId); int connectToOneNetMqtt(); /*********************************************************//**************** OneNet Http相关操作 ***************************/ HTTPClient http; String response; const char* host = " api.heclouds.com" ; bool registerDeviceToOneNet(); /****************************************************************/#define ONENET_DISCONNECTED 1 //已经断开 #define ONENET_CONNECTED 2//已经连接上 #define ONENET_RECONNECT 3//重连成功//常量 #define VER" MQTT_LED_V1.0" const char* ssid = " xxxxxxxx" ; //wifi账号 const char* password = " xxxxxxx" ; //wifi秘密//OneNet相关 PubSubClient mqttClient; const char* mqttServer = " 183.230.40.39" ; //mqtt服务器 const uint16_t mqttPort = 6002; #define PRODUCT_ID" 253190" //此为博哥自己的产品id 请新建自己的 #define API_KEY" xxxxxx" #define DEFAULT_ID " 123456" #define TOPIC" esp8266led" unsigned long lastWiFiCheckTick = 0; bool ledState = 0; onenet_config config; #endif

????全部工程代码,博哥放在个人QQ群里或者 代码下载地址。
玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

注意点:
  • 这里用到了JSON,请参考博哥上线博文 玩转ArduinoJson库 V5版本;
  • 我们这里使用到了ESP8266 HttpClient来封装Http请求;
????将工程分别烧进多个NodeMcu(博哥这里烧录了两个),然后可以看到串口打印内容,如下:
玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

【玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制】????同时,也可以在OneNet平台看到设备情况,如下:
玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

????接下来就可以通过App进行远程控制led了。
3.配套android App 3.1 下载App
  • 博主把App放在了个人交流群上以及Github
  • App源码暂不开源,博主也上传到了个人交流群
3.2 配置App
玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

  • 手机App作为一个特殊的设备,需要自行注册一个新的设备,然后填入deviceId,至于如何注册设备,请参考 之前的博文。
3.3 操作App
玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

  • 主页面可以看到当前所有的设备列表(也就是你自注册的所有智能灯),并且标明了设备状态,然后我们就可以远程控制开关灯。
3.4 实验效果
玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制

文章图片

4.总结需要注意几点:
  • 创建自己的OneNet产品,不要用博哥创建的,不然很容易发生MQTT重连的现象
  • 理论上设备接入数是无限制的,基本上能满足普通需求。

    推荐阅读