註釋還算挺多的
#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