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

玩转OneNET物联网平台之MQTT服务③ —— 远程控制LED(设备自注册)_第1张图片
image

1.理论基础

    参考博主线上博文:

  • 玩转PubSubClient MQTT库
  • 玩转OneNET物联网平台之简介
  • 玩转OneNET物联网平台之MQTT服务①
  • 玩转OneNET物联网平台之MQTT服务②

    在前面的博文中,博主主要通过手动方式去创建设备。这种方式的缺点明显:

  • 人为手动控制,对于开发者来说极度不友好;
  • 如果设备数量很多,岂不是要手动操作非常多次;

    那么,如何实现设备自注册呢?所谓自注册就是设备连入网络后自动往OneNet云平台注册设备信息并获取设备Id。

  • 为了区分唯一性,我们采用ESP-Mac地址的组合形式

2.远程控制LED,实现设备自注册

2.1 实验材料

  • ESP8266 NodeMcu
  • OneNet Mqtt调试工具
  • OneNet平台

2.2 实验步骤

2.2.1 创建 ESP8266智能灯系统 产品(MQTT协议)

玩转OneNET物联网平台之MQTT服务③ —— 远程控制LED(设备自注册)_第2张图片
image

注意点

  • 务必选择MQTT协议

    创建完毕后,我们点击查看具体的产品信息:

玩转OneNET物联网平台之MQTT服务③ —— 远程控制LED(设备自注册)_第3张图片
image

注意点

  • 需要记录产品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 
#include 
#include 
#include 
#include 
#include 
#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);
    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();

  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";//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    "aat9ivuJls3gcAFWnLoxfbwW8bI="
#define DEFAULT_ID "123456"
#define TOPIC     "esp8266led"

unsigned long lastWiFiCheckTick = 0;
bool ledState = 0;

onenet_config config;

#endif

    全部工程代码,博哥放在个人QQ群里。

玩转OneNET物联网平台之MQTT服务③ —— 远程控制LED(设备自注册)_第4张图片
image

注意点

  • 这里用到了JSON,请参考博哥上线博文 玩转ArduinoJson库 V5版本
  • 我们这里使用到了ESP8266 HttpClient来封装Http请求;

    将工程分别烧进多个NodeMcu(博哥这里烧录了两个),然后可以看到串口打印内容,如下:

玩转OneNET物联网平台之MQTT服务③ —— 远程控制LED(设备自注册)_第5张图片
image
玩转OneNET物联网平台之MQTT服务③ —— 远程控制LED(设备自注册)_第6张图片
image
玩转OneNET物联网平台之MQTT服务③ —— 远程控制LED(设备自注册)_第7张图片
image

    同时,也可以在OneNet平台看到设备情况,如下:

玩转OneNET物联网平台之MQTT服务③ —— 远程控制LED(设备自注册)_第8张图片
image

    接下来就可以通过mqtt调试工具进行远程控制led了。

3.总结

在理解MQTT协议的基础上,本篇是非常容易操作的,但是也需要注意几点:

  • 创建自己的OneNet产品,不要用博哥创建的
  • 理解订阅主题含义,尝试去使用onenet提供的api接口。

你可能感兴趣的:(玩转OneNET物联网平台之MQTT服务③ —— 远程控制LED(设备自注册))