1. 理论基础
???? 参考博主线上博文:
玩转 PubSubClient MQTT 库
玩转 OneNET 物联网平台之简介
玩转 OneNET 物联网平台之 MQTT 服务1
玩转 OneNET 物联网平台之 MQTT 服务2
???? 在前面的博文中, 博主主要通过手动方式去创建设备. 这种方式的缺点明显:
人为手动控制, 对于开发者来说极度不友好;
如果设备数量很多, 岂不是要手动操作非常多次;
???? 那么, 如何实现设备自注册呢? 所谓自注册就是设备连入网络后自动往 OneNet 云平台注册设备信息并获取设备 Id.
为了区分唯一性, 我们采用 ESP-Mac 地址的组合形式
2. 远程控制 LED, 实现设备自注册
2.1 实验材料
ESP8266 NodeMcu
OneNet Mqtt 调试工具
OneNet 平台
2.2 实验步骤
2.2.1 创建 ESP8266 智能灯系统 产品 (MQTT 协议)
注意点:
务必选择 MQTT 协议
???? 创建完毕后, 我们点击查看具体的产品信息:
注意点:
需要记录产品 ID, 其用来区分产品唯一标识符
Master-APIkey, 网络请求鉴权信息, 接口调用需要带入
2.2.2 NodeMcu 烧录代码 -- MQTT 设备端
???? 为了明确区分代码功能, 博哥命名工程名为 P_OneNet_Exam04:
P_OneNet_Exam04.ino 文件:
- /**
- * 功能: ESP8266 Mqtt 客户端自注冊功能, 订阅 OneNet Mqtt 工具发过来的控制 Led 消息
- * 作者: 单片机菜鸟
- * 时间: 2019-06-30
- * 描述:
- * 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 0xAA
- int state;
- WiFiClient espClient;
- // 声明方法
- void initSystem();
- void initOneNetMqtt();
- void callback(char* topic, byte* payload, unsigned int length);
- void saveConfig();
- void loadConfig();
- bool parseRegisterResponse();
- /**
- * 初始化
- */
- 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("\r\n\r\nStart 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);
- Wi-Fi.disconnect();
- delay(100);
- Wi-Fi.begin(ssid, password);
- while (Wi-Fi.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();
- if ((char)payload[0] == '1') {
- digitalWrite(LED_BUILTIN, LOW);
- } else {
- digitalWrite(LED_BUILTIN, HIGH);
- }
- }
- /*
- * 保存参数到 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("-------------------");
- }
- /**
- * 解析注册返回结果
- */
- bool parseRegisterResponse(){
- Serial.println("start parseRegisterResponse");
- StaticJsonBuffer<200> jsonBuffer;
- // StaticJsonBuffer 在栈区分配内存 它也可以被 DynamicJsonBuffer(内存在堆区分配) 代替
- // DynamicJsonBuffer jsonBuffer;
- 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";//Wi-Fi 账号
- const char* password = "xxxxxxx";//Wi-Fi 秘密
- //OneNet 相关
- PubSubClient mqttClient;
- const char* mqttServer = "183.230.40.39";//mqtt 服务器
- const uint16_t mqttPort = 6002;
- #define PRODUCT_ID "253190" // 此为博哥自己的产品 id 请新建自己的
- #define API_KEY "aat9ivuJls3gcAFWnLoxfbwW8bI="
- #define DEFAULT_ID "123456"
- #define TOPIC "esp8266led"
- unsigned long lastWiFiCheckTick = 0;
- bool ledState = 0;
- onenet_config config;
- #endif
???? 全部工程代码, 博哥放在个人 QQ 群里.
注意点:
这里用到了 JSON, 请参考博哥上线博文 玩转 ArduinoJson 库 V5 版本;
我们这里使用到了 ESP8266 HttpClient 来封装 Http 请求;
???? 将工程分别烧进多个 NodeMcu(博哥这里烧录了两个), 然后可以看到串口打印内容, 如下:
???? 同时, 也可以在 OneNet 平台看到设备情况, 如下:
???? 接下来就可以通过 mqtt 调试工具进行远程控制 led 了.
3. 总结
在理解 MQTT 协议的基础上, 本篇是非常容易操作的, 但是也需要注意几点:
创建自己的 OneNet 产品, 不要用博哥创建的
理解订阅主题含义, 尝试去使用 onenet 提供的 API 接口.
来源: http://www.bubuko.com/infodetail-3109623.html