HackLab平臺示例代碼解析——@NodeMCU篇-(四)連接阿里雲物聯網平臺

註釋還算挺多的

#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <aliyun_mqtt.h>

#define WIFI_SSID "Tenda_12E9E0"
#define WIFI_PASSWD "88889999"
//          阿里雲三元組
#define PRODUCT_KEY "a1ZJp7eq1cW"
#define DEVICE_NAME "my_flowerpot"
#define DEVICE_SECRET "FKoFPqwLjchgWCguYdXt9dYd7OPzlKRN"

#define ALINK_BODY_FORMAT "{\"id\":\"%u\",\"version\":\"1.0\",\"method\":\"%s\",\"params\":%s}"     //  消息體字符串格式
#define ALINK_TOPIC_PROP_POST "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post"  //發佈,設備屬性上報
#define ALINK_TOPIC_PROP_SET "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/service/property/set"  //訂閱,設備屬性設置
#define ALINK_METHOD_PROP_POST "thing.event.property.post"                                      //設備屬性上報,作爲上面發佈訂閱消息體的method參數

const int LED = D2;
const int BUTTON = D6;

int ledState = HIGH; // the current state of the output pin
int previous = LOW; // the previous reading from the input pin  記錄開關的上一次狀態

// the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounce = 2000; // the debounce time, increase if the output flickers

unsigned long lastMqttConnectMs = 0;

unsigned int postMsgId = 0;

WiFiClient espClient;
PubSubClient mqttClient(espClient);
//              連接WiFi不用多說
void initWifi(const char *ssid, const char *password)
{
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.println("WiFi does not connect, try again ...");
    delay(3000);
  }

  Serial.println("Wifi is connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void mqttCheckConnect()
{
  bool connected = connectAliyunMQTT(mqttClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET);
  if (connected) {//    如果連接上mqtt則打印
    Serial.println("MQTT connect succeed!");
    if (mqttClient.subscribe(ALINK_TOPIC_PROP_SET)) {//     如果訂閱成功,注意上面定義的訂閱消息體,則打印
      Serial.println("subscribe done.");
    } else {
      Serial.println("subscribe failed!");
    }
  }
}
//      設備上報函數,裏面定義死了要上傳LED燈的狀態
void mqttPublish()
{
  char param[32];
  char jsonBuf[128];
//      下面sprintf是格式化字符串
  sprintf(param, "{\"LightSwitch\":%d}", ledState);
  postMsgId += 1;
  sprintf(jsonBuf, ALINK_BODY_FORMAT, postMsgId, ALINK_METHOD_PROP_POST, param);

  if (mqttClient.publish(ALINK_TOPIC_PROP_POST, jsonBuf)) {
     Serial.print("Post message to cloud: ");
     Serial.println(jsonBuf);
  } else {
    Serial.println("Publish message to cloud failed!");
  }
}
//              這個函數是用來解析訂閱的topic的
// https://pubsubclient.knolleary.net/api.html#callback
void callback(char* topic, byte* payload, unsigned int length)
{
  if (strstr(topic, ALINK_TOPIC_PROP_SET))
  {
    Serial.print("Set message arrived [");
    Serial.print(topic);
    Serial.print("] ");
    payload[length] = '\0';
    Serial.println((char *)payload);

    // Deserialization break change from 5.x to 6.x of ArduinoJson
    DynamicJsonDocument doc(100);
    DeserializationError error = deserializeJson(doc, payload);
    if (error)
    {
      Serial.println("parse json failed");
      return;
    }
    //          將字符串payload轉換爲json格式的對象
    // {"method":"thing.service.property.set","id":"282860794","params":{"LightSwitch":1},"version":"1.0.0"}
    JsonObject setAlinkMsgObj = doc.as<JsonObject>();
    // LightSwitch
    int desiredLedState = setAlinkMsgObj["params"]["LightSwitch"];

    if (desiredLedState == HIGH || desiredLedState == LOW) {
      ledState = desiredLedState;//     修改燈的狀態,但是這裏沒有digitalWrite

      const char* cmdStr = desiredLedState == HIGH ? "on" : "off";
      Serial.print("網絡命令: Turn ");
      Serial.print(cmdStr);
      Serial.println(" 這個燈.");
    }
  }
}

// the setup routine runs once when you press reset:
void setup() {
  Serial.begin(115200);
  Serial.println("Hacklab MQTT LED demo starts.");

  pinMode(LED, OUTPUT);
  pinMode(BUTTON, INPUT);

  initWifi(WIFI_SSID, WIFI_PASSWD);
  mqttClient.setCallback(callback);

  lastMqttConnectMs = millis();
  mqttCheckConnect();
  mqttPublish();
}

// the loop routine runs over and over again forever:
void loop() {
  int reading = digitalRead(BUTTON);//讀取的開關的高低電平
    //  設置檢查mqtt連接週期是五秒
  if (millis() - lastMqttConnectMs >= 5000) {
    lastMqttConnectMs = millis();
    mqttCheckConnect();
  }
    //      如果客戶端沒有在循環,那麼打印disconnected
  // https://pubsubclient.knolleary.net/api.html#loop
  if (!mqttClient.loop()) {
    Serial.println("The MQTT client is disconnected!");
  }
//   Serial.println(reading);
  // if the input just went from LOW and HIGH and we've waited long enough
  // to ignore any noise on the circuit, toggle the output pin and remember
  // the time
  if (reading == HIGH && previous == LOW && millis() - lastDebounceTime > debounce) {//函數消除抖動,兩個時間間隔必須大於0.5秒才能進行改變
    if (ledState == HIGH) {
      ledState = LOW;
      Serial.println("Turn off light locally.");
    } else {
      ledState = HIGH;
      Serial.println("Turn on light locally.");
    }

    lastDebounceTime = millis();
    //      這裏修改一下,debounce的參數爲2000,讓設備兩秒再上報一次
    mqttPublish();
    Serial.print("LED state: ");
    Serial.print(ledState);
    Serial.print(", Time: ");
    Serial.println(lastDebounceTime);
  }
  digitalWrite(LED, ledState);
}
//  reading是設備讀取本地開關,previous也是讀取開關,但是你不按就是低電平,不用管,由低到高便是開關合上的過程,即LED改變的信號,但是必須消除抖動,或許我寫的消除抖動不好,但是我的項目不用開關哈哈

在這裏插入圖片描述

每過兩秒上報一次

在這裏插入圖片描述

在運行狀態界面也可以看出,實時更新的,(^-^)V

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章