做網(wǎng)站跟app的區(qū)別營銷策劃公司排行榜
最終效果
基于NodeMCU的物聯(lián)網(wǎng)電燈控制系統(tǒng)設(shè)計

上圖展現(xiàn)了小程序關(guān)燈過程的數(shù)據(jù)傳輸過程:用戶下達(dá)關(guān)燈指令→小程序下發(fā)關(guān)燈指令→MQTT服務(wù)器接收關(guān)燈指令→下位機接收與處理關(guān)燈指令。
項目介紹
該項目是“物聯(lián)網(wǎng)實驗室監(jiān)測控制系統(tǒng)設(shè)計(仿智能家居)”項目中的“家電控制設(shè)計”中的“電燈控制”子項目,最前者還包括“物聯(lián)網(wǎng)設(shè)計”、“環(huán)境監(jiān)測設(shè)計”、“門禁系統(tǒng)設(shè)計計”和“小程序設(shè)計”等內(nèi)容。本文只介紹“電燈控制”部分。
項目功能實現(xiàn)的大致思路為:單片機先識別出當(dāng)前處在的控制模式:為自動模式時,單片機采集光照傳感器傳來的光照強度數(shù)據(jù),以此來控制燈的開閉;為手動模式時,用戶的語音指令和小程序上的開關(guān)是一對雙開關(guān)。單片機會識別這對雙開關(guān)的最后一次命令,以此來控制燈的開閉。為自動模式或語音控制時,單片機會將燈的狀態(tài)實時更新到MQTT服務(wù)器上,使小程序上的開關(guān)狀態(tài)得到及時更新。控制模式通過語音指令切換。
硬件設(shè)計
接線
ESP-12F | GY-302 | LU_ASR01 | LED |
3v3 | VCC | 5V | |
GND | GND | G | |
D1 | SCL | ||
D2 | SDA | ||
D7 | + | ||
D8 | - | ||
RX | TX |
PCB設(shè)計
此電路板僅是為了代替杜邦線而已,上面只有引腳排座,而沒有任何電子元件。
工程 - 立創(chuàng)開源硬件平臺
成本
ESP-12F | GY-302 | LU_ASR01 | LED |
27.9 | 7.4 | 47.5 | 2.5 |
其中共需85元左右來購買該項目所需的模塊。此外還需1根數(shù)據(jù)線、焊接工具(電烙鐵、錫絲、引腳排座)、PCB打板或若干杜邦線。
軟件設(shè)計
LU-ASR01
該功能實現(xiàn)的原理及流程可參考:Arduino中借助LU-ASR01實現(xiàn)語音識別-CSDN博客
使用LU-ASR01語音識別開發(fā)板的語音識別功能。當(dāng)語音識別模塊識別到特定語音時,通過串口輸出特定字符。此時,NodeMCU的串口會接收到這個特定字符,從而得知用戶說出的特定語音。待識別語音、輸出字符和輸出語音之間的對應(yīng)關(guān)系如下表所示:
待識別語音 | 輸出字符 | 輸出語音 |
自動模式 | a | 已進入自動模式 |
手動模式 | m | 已進入手動模式 |
開燈 | 1 | 已開燈 |
關(guān)燈 | 0 | 已關(guān)燈 |
代碼
天問Block IDE中的程序如下:
ESP-12F
本次的開發(fā)環(huán)境為Arduino IDE,開發(fā)板型號為NodeMCU 0.9 (ESP-12 Module)。
本系統(tǒng)軟件部分的流程如下圖所示。初始化完成之后,系統(tǒng)默認(rèn)進入自動模式(60LX為實驗室環(huán)境昏暗與明亮的分界值)。之后會根據(jù)語音、小程序或光照值數(shù)據(jù)控制燈狀態(tài)。
連接WiFi以及與MQTT服務(wù)器雙向通信,可參考:利用ESP-01S中繼實現(xiàn)STM32F103C8T6與MQTT服務(wù)器的串口雙向通信_stm32串口接收esp01s數(shù)據(jù)-CSDN博客
獲取光照強度,可參考:Arduino中使用GY-302測量環(huán)境中的光照強度-CSDN博客
解析JSON數(shù)據(jù),可參考:Arduino中解析JSON數(shù)據(jù)-CSDN博客
控制LED,可參考:未完待續(xù)
代碼
Arduino IDE中的程序如下:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <Arduino.h>
#include <Wire.h> //IIC
#include <math.h>// 設(shè)置wifi接入信息和MQTT服務(wù)器
const char* wifiname = "DOILMSBOIOT";
const char* password = "doilmsboiot";
const char* mqttServer = "broker.emqx.io";bool receive_MQTT_message_flag = false; //1表示收到來自MQTT的信息但還未處理,0表示未收到來自MQTT的信息或已處理WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);// 待解析的json文件
String json = "{\"lamp\":0}";// 創(chuàng)建DynamicJsonDocument對象
const size_t capacity = JSON_OBJECT_SIZE(1) + 24 ; //1表示待解析的JSON對象中有1對數(shù)據(jù),24為解析過程中需要的額外空間,可在此網(wǎng)站計算 https://arduinojson.org/v6/assistant/#/step1
DynamicJsonDocument doc(capacity);bool lamp_Bool_MQTT = false ; // 解析出的來自MQTT的燈的開關(guān)狀態(tài)int BH1750address = 0x23; //GY-302-BH1750的iic通訊地址
byte buff[2]; //用來儲存GY-302-BH1750的iic傳來的原始數(shù)據(jù)
long int light = 0; //光照值char serial_information = '\0'; //從串口獲得的信息bool auto_flag = true; //是否為自動模式,即用光照傳感器的值來決定燈的開關(guān)狀態(tài)。它的反面為手動模式,可通過串口(語音)和MQTT(小程序)控制void setup()
{Serial.begin(9600); WiFi.mode(WIFI_STA); //設(shè)置ESP8266工作模式為無線終端模式connectWifi(); // 連接WiFimqttClient.setServer(mqttServer, 1883); // 設(shè)置MQTT服務(wù)器和端口號mqttClient.setCallback(receiveCallback); // 設(shè)置MQTT訂閱回調(diào)函數(shù)connectMQTTserver(); // 連接MQTT服務(wù)器Wire.begin(); //iic啟動led_initial();
}void loop()
{ if (mqttClient.connected()) // 如果開發(fā)板成功連接服務(wù)器{ mqttClient.loop(); // 處理信息(收到信息后的回調(diào)函數(shù))以及心跳} else // 如果開發(fā)板未能成功連接服務(wù)器{ connectMQTTserver(); // 則嘗試連接服務(wù)器并訂閱主題}if (receive_MQTT_message_flag == 1) //收到來自MQTT的信息但還未處理{ deserializeJson(doc, json); // 反序列化數(shù)據(jù)// 解析收到的數(shù)據(jù)信息lamp_Bool_MQTT = doc["lamp"].as<bool>();}BH1750_Init(BH1750address);if (BH1750_Read(BH1750address) == 2) //如果光照模塊有數(shù)據(jù)傳來{light = ((buff[0] << 8) | buff[1]) / 1.2;Serial.print(light,DEC);Serial.println(" lx");}if (Serial.available() > 0) //如果串口有數(shù)據(jù)傳來{serial_information = Serial.read();Serial.print("接收到的串口數(shù)據(jù)為:");Serial.println(serial_information);} if(serial_information == 'm') //manual手動模式{auto_flag = false;serial_information = '\0';}if(serial_information == 'a') //auto自動模式{auto_flag = true;serial_information = '\0';}if(auto_flag == true) //如果為自動模式{if(light < 60) //光線弱{turn_on_light(); //開燈pubMQTTmsg(true);}else //光線強{turn_off_light(); //關(guān)燈pubMQTTmsg(false);}}else //如果為手動模式,即可通過串口(語音)和MQTT(小程序)控制{if(serial_information == '1') //收到的串口(語音)指令為開燈,且尚未處理此信息{turn_on_light();pubMQTTmsg(true);serial_information = '\0';}if(serial_information == '0') //收到的串口(語音)指令為關(guān)燈,且尚未處理此信息{turn_off_light();pubMQTTmsg(false);serial_information = '\0';}if(receive_MQTT_message_flag == true && lamp_Bool_MQTT == true) //收到的MQTT(小程序)指令為開燈,且尚未處理此信息{turn_on_light();receive_MQTT_message_flag = false;}if(receive_MQTT_message_flag == true && lamp_Bool_MQTT == false) //收到的MQTT(小程序)指令為關(guān)燈,且尚未處理此信息{turn_off_light();receive_MQTT_message_flag = false;}}delay(200);
}int BH1750_Read(int address)
{int i = 0;Wire.beginTransmission(address);Wire.requestFrom(address, 2);while (Wire.available()) {buff[i] = Wire.read(); // receive one bytei++;}Wire.endTransmission();return i;
}void BH1750_Init(int address)
{Wire.beginTransmission(address);Wire.write(0x10); Wire.endTransmission();
}// 連接MQTT服務(wù)器并訂閱主題
void connectMQTTserver()
{// 根據(jù)ESP8266的MAC地址生成客戶端ID(避免與其它ESP8266的客戶端ID重名)String clientId = "esp8266-" + WiFi.macAddress();if (mqttClient.connect(clientId.c_str())) //如果成功連接MQTT服務(wù)器{ Serial.print("MQTT Server Has Connected. ");Serial.print("Server Address: ");Serial.println(mqttServer);Serial.print("ClientId: ");Serial.println(clientId);subscribeTopic(); // 訂閱指定主題} else {Serial.print("MQTT Server Connect Failed. Client State:");Serial.println(mqttClient.state());delay(3000);}
}// 收到信息后的回調(diào)函數(shù)
void receiveCallback(char* topic, byte* payload, unsigned int length)
{Serial.print("Message with the topic of [ ");Serial.print(topic);Serial.println(" ] has been received.");Serial.print("Content: ");for (int i = 0; i < length; i++) {Serial.print((char)payload[i]);json[i] = (char)payload[i]; //將收到的信息賦給json,以便后續(xù)解析和發(fā)射信號}Serial.println("");receive_MQTT_message_flag = 1; //表示收到來自MQTT的信息但還未處理Serial.print("Message Length (Bytes) : ");Serial.println(length);Serial.println(" ");
}void pubMQTTmsg(bool led_status) //向MQTT發(fā)布消息
{String topicString = "deviceControl2"; //發(fā)布信息的主題char publishTopic[topicString.length() + 1]; strcpy(publishTopic, topicString.c_str());String messageString = led_status ? "{\"lamp\":true}" : "{\"lamp\":false}"; //發(fā)布信息的內(nèi)容char publishMsg[messageString.length() + 1]; strcpy(publishMsg, messageString.c_str());if(mqttClient.publish(publishTopic, publishMsg, true)) //如果成功發(fā)布信息;publish函數(shù)第三個參數(shù)用于設(shè)置保留信息{Serial.print("Publish Topic: ");Serial.println(publishTopic);Serial.print("Publish Retained message: ");Serial.println(publishMsg); Serial.println(""); } else //如果未能成功發(fā)布信息{Serial.println("Message Publish Failed."); }
}// 訂閱指定主題
void subscribeTopic()
{String topicString = "deviceControl3/lamp"; // 訂閱的主題名稱char subTopic[topicString.length() + 1]; strcpy(subTopic, topicString.c_str());if(mqttClient.subscribe(subTopic)) //如果成功訂閱主題{Serial.print("Subscrib Topic: ");Serial.println(subTopic);Serial.println("");} else {Serial.print("訂閱主題失敗");}
}// ESP8266連接wifi
void connectWifi()
{WiFi.begin(wifiname, password);Serial.println("Connecting to WiFi");while (WiFi.status() != WL_CONNECTED) //等待WiFi連接,當(dāng)wifi未連接時,持續(xù)輸出".";成功連接后輸出連接成功信息{delay(1000);Serial.print(".");}Serial.println("");Serial.println("WiFi Connected!"); Serial.println("");
}void led_initial() //燈初始化
{pinMode(D7, OUTPUT);pinMode(D8, OUTPUT);
}void turn_on_light() //開燈
{digitalWrite(D7, HIGH);digitalWrite(D8, LOW);
}void turn_off_light() //關(guān)燈
{digitalWrite(D7, LOW);digitalWrite(D8, HIGH);
}