目錄
1.1? 通信協(xié)議的選擇
1.1.1? MQTT的簡(jiǎn)介
1.1.2? MQTT的通信模型
?1.2? 物聯(lián)網(wǎng)服務(wù)平臺(tái)的選擇
1.2.1? 注冊(cè)物聯(lián)網(wǎng)平臺(tái)
1.3??Web端或手機(jī)端遠(yuǎn)程控制和監(jiān)測(cè)跟蹤裝置
1.3.1? Node-RED設(shè)計(jì)??????
1.3.2??移動(dòng)端設(shè)計(jì)?????
1.3.3??遠(yuǎn)程監(jiān)視設(shè)計(jì)
1.3.4? 代碼實(shí)現(xiàn)
1.4? 自適應(yīng)天氣運(yùn)行控制策略
1.4.1? 自適應(yīng)天氣運(yùn)行的需求
1.4.2? 自適應(yīng)天氣運(yùn)行的設(shè)計(jì)原理
1.4.3? 天氣信息平臺(tái)的選擇
1.3.4? 自適應(yīng)天氣運(yùn)行的設(shè)計(jì)方案
1.4.5? 代碼實(shí)現(xiàn)
? ? ? ? 1、使用心知天氣數(shù)據(jù)服務(wù)的準(zhǔn)備工作
? ? ? ? 2、ESP8266獲取并解析心知天氣數(shù)據(jù)
? ? ? ? 3、自適應(yīng)天氣運(yùn)行+遠(yuǎn)程監(jiān)控代碼
物聯(lián)網(wǎng)是通過(guò)ESP8266 nodeMCU來(lái)實(shí)現(xiàn)WiFi聯(lián)網(wǎng)的,本系統(tǒng)是采用Arduino IDE來(lái)對(duì)ESP8266進(jìn)行開(kāi)發(fā),因此本章的代碼僅適用于Arduino IDE上。
1.1? 通信協(xié)議的選擇
????????在物聯(lián)網(wǎng)協(xié)議中,一般分為兩大類(lèi),一類(lèi)是傳輸協(xié)議,一類(lèi)是通信協(xié)議。傳輸協(xié)議一般負(fù)責(zé)子網(wǎng)內(nèi)設(shè)備間的組網(wǎng)及通信;通信協(xié)議則主要是運(yùn)行在傳統(tǒng)互聯(lián)網(wǎng)TCP/IP協(xié)議之上的設(shè)備通訊協(xié)議,負(fù)責(zé)設(shè)備通過(guò)互聯(lián)網(wǎng)進(jìn)行數(shù)據(jù)交換及通信。MQTT是一種輕量級(jí)消息傳輸協(xié)議,它為物聯(lián)網(wǎng)設(shè)備提供了一種簡(jiǎn)單的方法來(lái)傳輸數(shù)據(jù)信息。由于MQTT占用網(wǎng)絡(luò)資源小,且適用于遠(yuǎn)程信息傳輸,MQTT在物聯(lián)網(wǎng)(IoT)領(lǐng)域起著重要作用。
1.1.1? MQTT的簡(jiǎn)介
????????MQTT(Message Queuing Telemetry Transport, 消息隊(duì)列遙測(cè)傳輸協(xié)議),是一種基于發(fā)布/訂閱(publish/subscribe)模式的"輕量級(jí)"通訊協(xié)議,該協(xié)議構(gòu)建于TCP/IP協(xié)議上,屬于應(yīng)用層協(xié)議,因此只要是支持TCP/IP協(xié)議棧的地方,都可以使用MQTT。
????????MQTT協(xié)議最大的特點(diǎn)就是,兩個(gè)設(shè)備端(Client)之間不及進(jìn)行直接通訊,而是將數(shù)據(jù)發(fā)送到服務(wù)端(Server),由服務(wù)器將設(shè)備端發(fā)送的數(shù)據(jù)傳遞給對(duì)應(yīng)的設(shè)備端。
1.1.2? MQTT的通信模型
????????MQTT協(xié)議提供一對(duì)多的消息發(fā)布,可以降低應(yīng)用程序的耦合性,用戶(hù)只需要編寫(xiě)極少量的應(yīng)用代碼就能完成一對(duì)多的消息發(fā)布與訂閱,該協(xié)議是基于<客戶(hù)端-服務(wù)器>模型,在協(xié)議中主要有三種身份:發(fā)布者(Publisher)、服務(wù)器(Broker)以及訂閱者(Subscriber)。其中,MQTT消息的發(fā)布者和訂閱者都是客戶(hù)端,服務(wù)器只是作為一個(gè)中轉(zhuǎn)的存在,將發(fā)布者發(fā)布的消息進(jìn)行轉(zhuǎn)發(fā)給所有訂閱該主題的訂閱者;發(fā)布者可以發(fā)布在其權(quán)限之內(nèi)的所有主題,并且消息發(fā)布者可以同時(shí)是訂閱者,實(shí)現(xiàn)了生產(chǎn)者與消費(fèi)者的脫耦,發(fā)布的消息可以同時(shí)被多個(gè)訂閱者訂閱。MQTT通信模型如圖1所示。

?1.2? 物聯(lián)網(wǎng)服務(wù)平臺(tái)的選擇
????????本系統(tǒng)著重對(duì)個(gè)人開(kāi)發(fā)者相對(duì)友好以及對(duì)Arduino的支持情況兩個(gè)方面考慮,最終選擇然也物聯(lián)作為物聯(lián)網(wǎng)服務(wù)平臺(tái)。然也物聯(lián)平臺(tái)可提供社區(qū)版MQTT服務(wù),其為面向個(gè)人用戶(hù)的免費(fèi)MQTT服務(wù)。社區(qū)版MQTT服務(wù)中的用戶(hù)個(gè)人主題和信息傳輸受到用戶(hù)名和密碼保護(hù)。即,A用戶(hù)的個(gè)人主題只有A用戶(hù)可以發(fā)布和訂閱,其他人不能對(duì)該主題進(jìn)行訂閱和發(fā)布,為個(gè)人開(kāi)發(fā)者提供了很好的安全保護(hù)。
????????然也物聯(lián)平臺(tái)還提供相應(yīng)的手機(jī)APP的接入方式,使得用戶(hù)可以更多元化的管理自己的設(shè)備和傳感器,隨時(shí)了解設(shè)備動(dòng)態(tài)。
1.2.1? 注冊(cè)物聯(lián)網(wǎng)平臺(tái)
? ? ? ? 進(jìn)入然也物聯(lián)的官網(wǎng):http://www.ranye-iot.net
? ? ? ? 在首頁(yè)點(diǎn)擊物聯(lián)平臺(tái)后會(huì)進(jìn)行頁(yè)面跳轉(zhuǎn),然后往下滑就可以找到?社區(qū)版MQTT服務(wù)
? ? ? ? 最近好像沒(méi)得注冊(cè)用戶(hù)了... 進(jìn)而無(wú)法進(jìn)行平臺(tái)申請(qǐng)...也無(wú)法使用社區(qū)版MQTT服務(wù)了...
? ? ? ? ?服務(wù)端連接基本信息
? ? ? ? ?客戶(hù)端連接信息(共有8組)
? ? ? ? ?專(zhuān)屬個(gè)人主題
? ? ? ? ?社區(qū)版服務(wù)有效期為一年,屆時(shí)會(huì)有工作人員聯(lián)系。
1.3??Web端或手機(jī)端遠(yuǎn)程控制和監(jiān)測(cè)跟蹤裝置
????????光伏跟蹤裝置的遠(yuǎn)程監(jiān)測(cè)控制系統(tǒng)可由感知層、網(wǎng)絡(luò)層以及應(yīng)用層組成。
????????第一層為感知層,由單片機(jī)、傳感器模塊和ESP8266 WiFi模塊所組成,對(duì)環(huán)境進(jìn)行數(shù)據(jù)采集和對(duì)執(zhí)行機(jī)構(gòu)的控制,通過(guò)WiFi模塊將數(shù)據(jù)傳輸?shù)骄W(wǎng)絡(luò)層。
????????第二層為網(wǎng)絡(luò)層,主要包括路由器和服務(wù)器,網(wǎng)絡(luò)層主要用于處理不同層之間的數(shù)據(jù)交互,感知層的數(shù)據(jù)通過(guò)網(wǎng)絡(luò)層可以傳遞到應(yīng)用層,應(yīng)用層的下行命令可以通過(guò)網(wǎng)絡(luò)層傳遞到感知層。感知層中監(jiān)測(cè)到的數(shù)據(jù)經(jīng)過(guò)ESP8266 WiFi模塊,通過(guò)路由器接入互聯(lián)網(wǎng),將數(shù)據(jù)發(fā)送到然也物聯(lián)平臺(tái)搭建的MQTT服務(wù)器上。
????????感知層的數(shù)據(jù)通過(guò)基于TCP的MQTT協(xié)議上傳到1個(gè)PubTopic,并通過(guò)訂閱SubTopic以接收下行命令,進(jìn)行執(zhí)行器的控制。
????????第三層為應(yīng)用層,主要包括Web端和移動(dòng)端的數(shù)據(jù)顯示、管理和控制,在Web端通過(guò)Node-Red進(jìn)行數(shù)據(jù)的遠(yuǎn)程監(jiān)控和對(duì)裝置的控制,在移動(dòng)端也可以通過(guò)APP進(jìn)行實(shí)時(shí)監(jiān)測(cè)環(huán)境數(shù)據(jù)和向感知層下發(fā)下行命令以控制裝置的執(zhí)行機(jī)構(gòu)運(yùn)動(dòng)。
1.3.1? Node-RED設(shè)計(jì)??????
? ? ? ? 通過(guò)mqtt in節(jié)點(diǎn)配置連接的服務(wù)器 IP 地址,確定 mqtt 連接的 Topic 主題和Qos方式后,便可以連接到傳輸層,得到感知層的環(huán)境數(shù)據(jù)和執(zhí)行器的狀態(tài),然后通過(guò)文本顯示節(jié)點(diǎn),便可以將上述數(shù)據(jù)顯示文本窗口。
? ? ? ? 要完成以上步驟,首先需要下載node.js才可進(jìn)入node-red,接下來(lái)如何使用node-red可觀看以下視頻,重點(diǎn)學(xué)習(xí)如何使用MQTT進(jìn)行通信。
【太極創(chuàng)客】零基礎(chǔ)入門(mén)學(xué)用物聯(lián)網(wǎng) - MQTT應(yīng)用篇 3-1-5 用電腦搭建物聯(lián)網(wǎng)控制臺(tái)(上)https://www.bilibili.com/video/BV1VR4y1n7nj/?spm_id_from=333.999.0.0&vd_source=b4d125df2ebf1ab26fbed06ba725ac39
?????????Web端監(jiān)控頁(yè)面如下圖所示。
1.3.2??移動(dòng)端設(shè)計(jì)?????
????????本系統(tǒng)在移動(dòng)端的監(jiān)測(cè)控制是通過(guò)然也物聯(lián)提供的移動(dòng)應(yīng)用平臺(tái)所設(shè)計(jì)而成。首先,配置所要連接的服務(wù)器的客戶(hù)端ID、 IP 地址、端口號(hào)、網(wǎng)絡(luò)協(xié)議、用戶(hù)名和密碼,然后確定 mqtt 連接的 Topic 主題和Qos方式后進(jìn)入到功能設(shè)計(jì)頁(yè)面;可設(shè)置文本顯示框架,便可以將服務(wù)器數(shù)據(jù)顯示到文本窗口,還可設(shè)置控制按鈕,配置下行命令;這樣便可以連接到傳輸層,得到感知層的環(huán)境數(shù)據(jù)和執(zhí)行器的狀態(tài),或?qū)⑾滦忻钔ㄟ^(guò)傳輸層下達(dá)到感知層,控制執(zhí)行機(jī)構(gòu)運(yùn)動(dòng)。
???????? 要完成以上步驟,需先下載然也物聯(lián)的APP,可觀看以下視頻進(jìn)行學(xué)習(xí),重點(diǎn)學(xué)習(xí)如何使用MQTT進(jìn)行通信,視頻里也會(huì)教如何下載APP。
【太極創(chuàng)客】零基礎(chǔ)入門(mén)學(xué)用物聯(lián)網(wǎng) - MQTT應(yīng)用篇 3-1-4 手機(jī)應(yīng)用控制ESP8266(下)https://www.bilibili.com/video/BV1QT4y1R7uf/?spm_id_from=333.999.0.0&vd_source=b4d125df2ebf1ab26fbed06ba725ac39
????????移動(dòng)端監(jiān)控頁(yè)面如下圖所示。
1.3.3??遠(yuǎn)程監(jiān)視設(shè)計(jì)
????????設(shè)置ESP32-CAM為STA模式,即可通過(guò)路由器接入互聯(lián)網(wǎng)。在瀏覽器中輸入其生成的IP地址,即可在Web端或移動(dòng)端看到由ESP32-CAM拍攝所上傳的畫(huà)面,這樣便可實(shí)現(xiàn)遠(yuǎn)程監(jiān)視效果。
? ? ? ? 這部分在CSDN搜索都有很多教程。
????????視頻監(jiān)視效果如下圖所示。
1.3.4? 代碼實(shí)現(xiàn)
? ? ? ? 代碼后的注釋能解釋清楚每一句代碼的作用。
? ? ? ? 初始化設(shè)置
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <string.h>
// 設(shè)置wifi接入信息(請(qǐng)根據(jù)您的WiFi信息進(jìn)行修改)
const char* ssid = "SunFlower"; // 請(qǐng)將您需要連接的WiFi名填入引號(hào)中
const char* password = "88888888"; // 請(qǐng)將您需要連接的WiFi密碼填入引號(hào)中
const char* mqttServer = "iot.ranye-iot.net"; //連接MQTT服務(wù)器,iot開(kāi)頭代表是社區(qū)版服務(wù)端的地址
//建立兩對(duì)象
WiFiClient wifiClient; // 連接網(wǎng)絡(luò)
PubSubClient mqttClient(wifiClient); // MQTT通信用的
// ****************************************************
// 注意!以下需要用戶(hù)根據(jù)然也物聯(lián)平臺(tái)信息進(jìn)行修改!否則無(wú)法工作!
// ****************************************************
const char* mqttUserName = "UserName"; // 服務(wù)端連接用戶(hù)名(需要修改)
const char* mqttPassword = "password"; // 服務(wù)端連接密碼(需要修改)
const char* clientId = "UserName_1_id"; // 客戶(hù)端id (需要修改)
const char* subTopic1 = "UserName/phone"; // 訂閱主題(需要修改)
const char* subTopic2 = "UserName/web"; // 訂閱主題(需要修改)
const char* pubTopic1 = "UserName/esp8266_1"; // 發(fā)布主題(需要修改)
const char* pubTopic2 = "UserName/esp8266_2"; // 發(fā)布主題(需要修改)
const char* pubTopic3 = "UserName/esp8266_3"; // 發(fā)布主題(需要修改)
const char* pubTopic4 = "UserName/esp8266_4"; // 發(fā)布主題(需要修改)
const char* willTopic = "UserName/led_yz"; // 遺囑主題名稱(chēng)(需要修改)
// ****************************************************
//遺囑相關(guān)信息
const char* willMsg = "esp8266 offline"; // 遺囑主題信息
const int willQos = 0; // 遺囑QoS
const int willRetain = false; // 遺囑保留
const int subQoS = 1; // 客戶(hù)端訂閱主題時(shí)使用的QoS級(jí)別(截止2020-10-07,僅支持QoS = 1,不支持QoS = 2)
const bool cleanSession = false; // 清除會(huì)話(如QoS>0必須要設(shè)為false)
//*****************************************************
const char* host = "api.seniverse.com"; // 將要連接的服務(wù)器地址
const int httpPort = 80; // 將要連接的服務(wù)器端口
// 心知天氣HTTP請(qǐng)求所需信息
String reqUserKey = "************"; // 私鑰
String reqLocation = "你的城市所在地"; // 城市
String reqUnit = "c"; // 攝氏/華氏
//*****************************************************
void setup(){
Serial.begin(115200);
//設(shè)置ESP8266工作模式為無(wú)線終端模式
WiFi.mode(WIFI_STA);
// 連接WiFi
connectWiFi();
// 設(shè)置MQTT服務(wù)器和端口號(hào)
mqttClient.setServer(mqttServer, 1883);
mqttClient.setCallback(receiveCallback);
// 連接MQTT服務(wù)器
connectMQTTserver();
}
? ? ? ? 由于主函數(shù)中涵蓋了自適應(yīng)天氣運(yùn)行部分的代碼,因此具體代碼放在文末與自適應(yīng)天氣部分一起放上。
1.4? 自適應(yīng)天氣運(yùn)行控制策略
1.4.1? 自適應(yīng)天氣運(yùn)行的需求
????????為實(shí)現(xiàn)系統(tǒng)避風(fēng)、避雪,保護(hù)支架、組件,減少裝置的受損概率,延長(zhǎng)支架、組件的使用壽命,延長(zhǎng)發(fā)電壽命,增加發(fā)電收益。本系統(tǒng)針對(duì)天氣對(duì)光伏發(fā)電的影響為跟蹤裝置設(shè)計(jì)了自適應(yīng)天氣運(yùn)行,即適應(yīng)天氣的變化使跟蹤裝置作出相應(yīng)的調(diào)整,以最大化地提高發(fā)電效益,力求將天氣對(duì)光伏發(fā)電所帶來(lái)的影響降到最低。
1.4.2? 自適應(yīng)天氣運(yùn)行的設(shè)計(jì)原理
????????①本系統(tǒng)采用的是混合跟蹤方式,光電跟蹤方式在尤其是在陰雨或者多云天氣時(shí),很難與太陽(yáng)光線對(duì)正,有些情況下還會(huì)出現(xiàn)誤跟蹤、丟跟蹤和往反跟蹤等現(xiàn)象,沒(méi)辦法保證跟蹤精度;而視日軌跡跟蹤方式的主要缺點(diǎn)在于運(yùn)行時(shí)會(huì)產(chǎn)生累積誤差,該誤差不能自行消除,往往需要人為定期調(diào)整跟蹤累積誤差。
????????綜合分析考慮決定,在晴朗天氣下,系統(tǒng)將采用光電跟蹤方式;而在陰天或多云天氣時(shí),系統(tǒng)將采用視日軌跡跟蹤方式。
????????②本系統(tǒng)中配置風(fēng)速風(fēng)向監(jiān)測(cè)儀用于監(jiān)測(cè)光伏支架安裝環(huán)境中風(fēng)速的大小、風(fēng)的方向(當(dāng)接收到與風(fēng)相關(guān)的天氣信息方啟動(dòng)風(fēng)速風(fēng)向檢測(cè)儀,以降低系統(tǒng)整體能耗);如果測(cè)量的風(fēng)速大于設(shè)定值時(shí),MCU即驅(qū)動(dòng)執(zhí)行機(jī)構(gòu),使太陽(yáng)能電池板的側(cè)面迎風(fēng),正面避開(kāi)風(fēng)的正面,減少迎風(fēng)面積,從而減少受風(fēng)力,降低受損概率;同時(shí)可以驅(qū)動(dòng)俯仰角轉(zhuǎn)動(dòng),使得俯仰角變小,張力變小,機(jī)械受外力不易損壞。
????????③本系統(tǒng)配置雨滴傳感器用于檢測(cè)雨雪量(當(dāng)接收到與雨雪相關(guān)的天氣信息方啟動(dòng)雨滴傳感器,以降低系統(tǒng)整體能耗);如果雨雪量大于設(shè)定值時(shí),容易造成組件或支架受雨雪壓力受損,MCU即可驅(qū)動(dòng)執(zhí)行機(jī)構(gòu)轉(zhuǎn)動(dòng),使得太陽(yáng)能電池板正面和地面垂直或接近垂直,雨雪就不容易積壓到太陽(yáng)能電池板表面上,嚴(yán)寒地區(qū)安裝的組件表面也不易結(jié)冰,減少雨雪對(duì)組件的腐蝕和壓力;當(dāng)雨量小于設(shè)定值時(shí),系統(tǒng)將采用視日軌跡跟蹤方式,此時(shí)較小的雨量并不容易對(duì)組件造成損害,相反,還可利用雨水沖刷掉光伏組件表面的污垢和灰塵,從而增加光照強(qiáng)度,提高光伏發(fā)電系統(tǒng)的輸出功率。
1.4.3? 天氣信息平臺(tái)的選擇
? ? ? ? 互聯(lián)網(wǎng)上有很多天氣信息平臺(tái),心知天氣是信息最準(zhǔn)確,服務(wù)最穩(wěn)定的平臺(tái)。更重要的是,心知天氣所提供的基礎(chǔ)服務(wù)是完全免費(fèi)的,其免費(fèi)的天氣信息就包含3天的天氣預(yù)報(bào)信息,實(shí)時(shí)天氣以及生活指數(shù)。
1.3.4? 自適應(yīng)天氣運(yùn)行的設(shè)計(jì)方案
? ? ? ? ①對(duì)WiFi模塊進(jìn)行初始化設(shè)置,設(shè)置成STA模式,WiFi模塊通過(guò)路由器/手機(jī)熱點(diǎn)可連接互聯(lián)網(wǎng);建立“心知天氣”API當(dāng)前天氣請(qǐng)求資源地址,通過(guò)互聯(lián)網(wǎng)向“心知天氣”服務(wù)器發(fā)送HTTP請(qǐng)求,并獲取服務(wù)器返回的天氣信息,從服務(wù)器響應(yīng)中解析出天氣代碼(如圖2所示)。
? ? ? ? ②設(shè)定特殊天氣的轉(zhuǎn)換程序,即將所需響應(yīng)的天氣情況所對(duì)應(yīng)的天氣代碼轉(zhuǎn)換為控制系統(tǒng)可識(shí)別的字符。此時(shí)WiFi模塊同時(shí)作為上位機(jī),與單片機(jī)進(jìn)行串行通信,將可識(shí)別的天氣字符傳送給單片機(jī)。

????????③對(duì)單片機(jī)進(jìn)行初始化設(shè)置,設(shè)計(jì)接收到不同的天氣字符即運(yùn)行不同的舵機(jī)驅(qū)動(dòng)代碼。當(dāng)單片機(jī)接收到實(shí)時(shí)的天氣信息后,配合雨滴傳感器、風(fēng)速風(fēng)向傳感器來(lái)確認(rèn)天氣信息屬實(shí)后,才會(huì)驅(qū)動(dòng)跟蹤裝置執(zhí)行相應(yīng)的動(dòng)作。
????????目前僅對(duì)四種天氣情況進(jìn)行了設(shè)置:
????????晴天時(shí),單片機(jī)將運(yùn)行光電跟蹤模式;
????????陰天或多云時(shí),單片機(jī)將運(yùn)行視日軌跡跟蹤模式,確保光伏板始終朝向太陽(yáng),以提供最佳的能量收集效果,最大限度地提高能量輸出效率;
????????雨天時(shí),單片機(jī)將中斷當(dāng)前所執(zhí)行的模式,轉(zhuǎn)而驅(qū)動(dòng)控制俯仰角的舵機(jī)將光伏電池板置于傾斜45°的狀態(tài),令雨水沖刷板面,以清理塵土、落葉等遮擋物, 從而減弱熱斑效應(yīng),延長(zhǎng)系統(tǒng)壽命。
????????雪天時(shí),單片機(jī)將中斷當(dāng)前所執(zhí)行的模式,轉(zhuǎn)而驅(qū)動(dòng)控制俯仰角的舵機(jī)將光伏電池板置于垂直地面的狀態(tài),系統(tǒng)能夠自動(dòng)調(diào)整光伏板角度,使其正面和地面垂直或接近垂直,減少積雪對(duì) 組件的腐蝕和壓力。
????????自適應(yīng)天氣運(yùn)行控制策略的流程圖如圖3所示。

? ? ? ? ?補(bǔ)充:圖中在執(zhí)行雨雪天氣時(shí),漏了得先經(jīng)過(guò)雨滴傳感器的數(shù)據(jù)輔助判斷當(dāng)前天氣情況是否屬實(shí)這一步。
1.4.5? 代碼實(shí)現(xiàn)
? ? ? ? 1、使用心知天氣數(shù)據(jù)服務(wù)的準(zhǔn)備工作
? ? ? ? ①注冊(cè)心知天氣賬戶(hù)
????????打開(kāi)心知天氣網(wǎng)頁(yè):www.seniverse.com
? ? ? ? ?②申請(qǐng)免費(fèi)天氣數(shù)據(jù)API服務(wù)
????????完成注冊(cè)后進(jìn)行登錄,然后從首頁(yè)進(jìn)入控制臺(tái)頁(yè)面(如下圖所示)
? ? ? ? ?申請(qǐng)?zhí)鞖鈹?shù)據(jù)API免費(fèi)版
? ? ? ? ?申請(qǐng)成功后可以在控制臺(tái)中看到(如下圖所示)
?????????點(diǎn)擊該服務(wù)鏈接,進(jìn)入天氣數(shù)據(jù)API免費(fèi)服務(wù)頁(yè)面
? ? ? ? ③獲取用戶(hù)私鑰、?
? ? ? ? 點(diǎn)擊私鑰旁邊的 閉合上的眼睛 即可查看自己的私鑰信息?
? ? ? ? 2、ESP8266獲取并解析心知天氣數(shù)據(jù)
? ? ? ? 這里可以先使用“太極創(chuàng)客團(tuán)隊(duì)”的代碼來(lái)實(shí)現(xiàn) 獲取實(shí)時(shí)天氣信息(溫度、天氣)
????????要實(shí)現(xiàn)本系統(tǒng)的自適應(yīng)天氣運(yùn)行功能,照搬太極創(chuàng)客的代碼是行不通的。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-769050.html
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
const char* ssid = "taichimaker"; // 連接WiFi名(此處使用taichi-maker為示例)
// 請(qǐng)將您需要連接的WiFi名填入引號(hào)中
const char* password = "12345678"; // 連接WiFi密碼(此處使用12345678為示例)
// 請(qǐng)將您需要連接的WiFi密碼填入引號(hào)中
const char* host = "api.seniverse.com"; // 將要連接的服務(wù)器地址
const int httpPort = 80; // 將要連接的服務(wù)器端口
// 心知天氣HTTP請(qǐng)求所需信息
String reqUserKey = "XXXXXXXXXXXXXXXXX"; // 私鑰
String reqLocation = "Beijing"; // 城市
String reqUnit = "c"; // 攝氏/華氏
void setup(){
Serial.begin(9600);
Serial.println("");
// 連接WiFi
connectWiFi();
}
void loop(){
// 建立心知天氣API當(dāng)前天氣請(qǐng)求資源地址
String reqRes = "/v3/weather/now.json?key=" + reqUserKey +
+ "&location=" + reqLocation +
"&language=en&unit=" +reqUnit;
// 向心知天氣服務(wù)器服務(wù)器請(qǐng)求信息并對(duì)信息進(jìn)行解析
httpRequest(reqRes);
delay(3000);
}
// 向心知天氣服務(wù)器服務(wù)器請(qǐng)求信息并對(duì)信息進(jìn)行解析
void httpRequest(String reqRes){
WiFiClient client;
// 建立http請(qǐng)求信息
String httpRequest = String("GET ") + reqRes + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n";
Serial.println("");
Serial.print("Connecting to "); Serial.print(host);
// 嘗試連接服務(wù)器
if (client.connect(host, 80)){
Serial.println(" Success!");
// 向服務(wù)器發(fā)送http請(qǐng)求信息
client.print(httpRequest);
Serial.println("Sending request: ");
Serial.println(httpRequest);
// 獲取并顯示服務(wù)器響應(yīng)狀態(tài)行
String status_response = client.readStringUntil('\n');
Serial.print("status_response: ");
Serial.println(status_response);
// 使用find跳過(guò)HTTP響應(yīng)頭
if (client.find("\r\n\r\n")) {
Serial.println("Found Header End. Start Parsing.");
}
// 利用ArduinoJson庫(kù)解析心知天氣響應(yīng)信息
parseInfo(client);
} else {
Serial.println(" connection failed!");
}
//斷開(kāi)客戶(hù)端與服務(wù)器連接工作
client.stop();
}
// 連接WiFi
void connectWiFi(){
WiFi.begin(ssid, password); // 啟動(dòng)網(wǎng)絡(luò)連接
Serial.print("Connecting to "); // 串口監(jiān)視器輸出網(wǎng)絡(luò)連接信息
Serial.print(ssid); Serial.println(" ..."); // 告知用戶(hù)NodeMCU正在嘗試WiFi連接
int i = 0; // 這一段程序語(yǔ)句用于檢查WiFi是否連接成功
while (WiFi.status() != WL_CONNECTED) { // WiFi.status()函數(shù)的返回值是由NodeMCU的WiFi連接狀態(tài)所決定的。
delay(1000); // 如果WiFi連接成功則返回值為WL_CONNECTED
Serial.print(i++); Serial.print(' '); // 此處通過(guò)While循環(huán)讓NodeMCU每隔一秒鐘檢查一次WiFi.status()函數(shù)返回值
} // 同時(shí)NodeMCU將通過(guò)串口監(jiān)視器輸出連接時(shí)長(zhǎng)讀秒。
// 這個(gè)讀秒是通過(guò)變量i每隔一秒自加1來(lái)實(shí)現(xiàn)的。
Serial.println(""); // WiFi連接成功后
Serial.println("Connection established!"); // NodeMCU將通過(guò)串口監(jiān)視器輸出"連接成功"信息。
Serial.print("IP address: "); // 同時(shí)還將輸出NodeMCU的IP地址。這一功能是通過(guò)調(diào)用
Serial.println(WiFi.localIP()); // WiFi.localIP()函數(shù)來(lái)實(shí)現(xiàn)的。該函數(shù)的返回值即NodeMCU的IP地址。
}
// 利用ArduinoJson庫(kù)解析心知天氣響應(yīng)信息
void parseInfo(WiFiClient client){
const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(6) + 230;
DynamicJsonDocument doc(capacity);
deserializeJson(doc, client);
JsonObject results_0 = doc["results"][0];
JsonObject results_0_now = results_0["now"];
const char* results_0_now_text = results_0_now["text"]; // "Sunny"
const char* results_0_now_code = results_0_now["code"]; // "0"
const char* results_0_now_temperature = results_0_now["temperature"]; // "32"
const char* results_0_last_update = results_0["last_update"]; // "2020-06-02T14:40:00+08:00"
// 通過(guò)串口監(jiān)視器顯示以上信息
String results_0_now_text_str = results_0_now["text"].as<String>();
int results_0_now_code_int = results_0_now["code"].as<int>();
int results_0_now_temperature_int = results_0_now["temperature"].as<int>();
String results_0_last_update_str = results_0["last_update"].as<String>();
Serial.println(F("======Weahter Now======="));
Serial.print(F("Weather Now: "));
Serial.print(results_0_now_text_str);
Serial.print(F(" "));
Serial.println(results_0_now_code_int);
Serial.print(F("Temperature: "));
Serial.println(results_0_now_temperature_int);
Serial.print(F("Last Update: "));
Serial.println(results_0_last_update_str);
Serial.println(F("========================"));
}
? ? ? ? 3、自適應(yīng)天氣運(yùn)行+遠(yuǎn)程監(jiān)控代碼
? ? ? ?? 代碼后的注釋能解釋清楚每一句代碼的作用。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-769050.html
void loop(){
//*****************************************************
// 建立心知天氣API當(dāng)前天氣請(qǐng)求資源地址
String reqRes = "/v3/weather/now.json?key=" + reqUserKey +
+ "&location=" + reqLocation +
"&language=en&unit=" +reqUnit;
// 向心知天氣服務(wù)器服務(wù)器請(qǐng)求信息并對(duì)信息進(jìn)行解析
httpRequest(reqRes);
//*****************************************************
//*****************************************************
// 如果開(kāi)發(fā)板未能成功連接服務(wù)器,則嘗試連接服務(wù)器
if (!mqttClient.connected()) {
connectMQTTserver();
}
// 處理信息以及心跳
mqttClient.loop();
//*****************************************************
char a[20] = ""; //定義字符數(shù)組,接受來(lái)自串口的數(shù)據(jù)
char b;
int i = 0;
while (Serial.available()) //當(dāng)發(fā)現(xiàn)緩存中有數(shù)據(jù)時(shí),將數(shù)據(jù)送至字符數(shù)組a中
{
a[i] = Serial.read();
i++;
}
b = a[0];
if (b == '1'){
mqttClient.publish(pubTopic4, "YES"); //向Web端發(fā)送雨滴傳感器的狀態(tài),有雨或無(wú)雨
Serial.print('5');
}else{
mqttClient.publish(pubTopic4, "NO");
}
if(Serial.available() == 0){
mqttClient.publish(pubTopic3, a); //向Web端和移動(dòng)端發(fā)送跟蹤裝置的俯仰角度和水平角度
}
}
// 向心知天氣服務(wù)器服務(wù)器請(qǐng)求信息并對(duì)信息進(jìn)行解析
void httpRequest(String reqRes){
WiFiClient client;
// 建立http請(qǐng)求信息
String httpRequest = String("GET ") + reqRes + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n";
// 嘗試連接服務(wù)器
if (client.connect(host, 80)){
// 向服務(wù)器發(fā)送http請(qǐng)求信息
client.print(httpRequest);
// 獲取并顯示服務(wù)器響應(yīng)狀態(tài)行
String status_response = client.readStringUntil('\n');
// 使用find跳過(guò)HTTP響應(yīng)頭
if (client.find("\r\n\r\n")) {
// Serial.println("Found Header End. Start Parsing.");
}
// 利用ArduinoJson庫(kù)解析心知天氣響應(yīng)信息
parseInfo(client);
delay(1000);
} else {
// Serial.println(" connection failed!");
}
//斷開(kāi)客戶(hù)端與服務(wù)器連接工作
client.stop();
}
// 連接WiFi
void connectWiFi(){
WiFi.begin(ssid, password); // 啟動(dòng)網(wǎng)絡(luò)連接
int i = 0; // 這一段程序語(yǔ)句用于檢查WiFi是否連接成功
while (WiFi.status() != WL_CONNECTED) { // WiFi.status()函數(shù)的返回值是由NodeMCU的WiFi連接狀態(tài)所決定的。
delay(1000);
}
}
// 利用ArduinoJson庫(kù)解析心知天氣響應(yīng)信息
void parseInfo(WiFiClient client){
const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(6) + 230;
DynamicJsonDocument doc(capacity);
deserializeJson(doc, client);
JsonObject results_0 = doc["results"][0];
JsonObject results_0_now = results_0["now"];
const char* results_0_now_text = results_0_now["text"]; // "Sunny"
const char* results_0_now_code = results_0_now["code"]; // "0"
const char* results_0_now_temperature = results_0_now["temperature"]; // "32"
const char* results_0_last_update = results_0["last_update"]; // "2020-06-02T14:40:00+08:00"
String results_0_now_text_str = results_0_now["text"].as<String>();
int results_0_now_code_int = results_0_now["code"].as<int>();
int results_0_now_temperature_int = results_0_now["temperature"].as<int>();
String results_0_last_update_str = results_0["last_update"].as<String>();
mqttClient.publish(pubTopic2, results_0_now_text);//將天氣情況發(fā)送到Web端,使其可顯示當(dāng)前天氣情況
//轉(zhuǎn)換成單片機(jī)可識(shí)別的天氣狀態(tài)字符,然后通過(guò)串口傳給單片機(jī)
if(results_0_now_code_int == 24 || results_0_now_code_int == 25)//雪天
{
Serial.print('3');
}
if(results_0_now_code_int == 13 || results_0_now_code_int == 14 || results_0_now_code_int == 15 || results_0_now_code_int == 16 || results_0_now_code_int == 17 || results_0_now_code_int == 18)//雨天
{
Serial.print('5');
}
if(results_0_now_code_int == 0)//晴天
{
Serial.print('0');
}
if(results_0_now_code_int == 4 || results_0_now_code_int == 5 || results_0_now_code_int == 6 || results_0_now_code_int == 7 || results_0_now_code_int == 8 || results_0_now_code_int == 9)//陰天
{
Serial.print('1');
}
//將天氣情況發(fā)送到移動(dòng)端,使其可顯示當(dāng)前天氣情況
char* pubMessage;
pubMessage = "天氣:";
if(mqttClient.publish(pubTopic1, results_0_now_text)){
mqttClient.publish(pubTopic1, pubMessage);
}
}
// 連接MQTT服務(wù)器并訂閱信息
void connectMQTTserver(){
// 根據(jù)ESP8266的MAC地址生成客戶(hù)端ID(避免與其它ESP8266的客戶(hù)端ID重名)
/* 連接MQTT服務(wù)器
boolean connect(const char* id, const char* user,
const char* pass, const char* willTopic,
uint8_t willQos, boolean willRetain,
const char* willMessage, boolean cleanSession);
若讓設(shè)備在離線時(shí)仍然能夠讓qos1工作,則connect時(shí)的cleanSession需要設(shè)置為false
*/
if (mqttClient.connect(clientId, mqttUserName,
mqttPassword, willTopic,
willQos, willRetain, willMsg, cleanSession)) {
subscribeTopic(); // 訂閱指定主題
} else {
delay(5000);
}
}
// 收到信息后的回調(diào)函數(shù)。
void receiveCallback(char* topic, byte* payload, unsigned int length) {
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]); // 訂閱了Web端和移動(dòng)端發(fā)布的主題,當(dāng)收到這兩端發(fā)布信息后,便會(huì)通過(guò)串口傳給單片機(jī)
}
}
// 訂閱指定主題
void subscribeTopic(){
mqttClient.subscribe(subTopic1, subQoS);
mqttClient.subscribe(subTopic2, subQoS);
}
到了這里,關(guān)于系統(tǒng)物聯(lián)網(wǎng)的方案及功能設(shè)計(jì)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!