本次範例是之前在instructables中看到有人DIY做了一個太陽能板WiFi氣象站,一開始我也仿照它的架構做了一個,不過我們這裏要將它改版成自己的版本。我們要開發的架構是氣象站的訊息是傳送到自己架設的網站中的MySQL資料庫,並即時在自架的網站中顯示及用Line bot工具傳送到Line聊天室。這裏我們是用ESP8266的晶片來製作,我們會將訊息透過 MQTT 傳送到Node-RED中,再經由Node-RED上的MySQL元件,將資訊新增到MySQL資料庫中。 氣象站具備以下功能: 氣象站可以測量:溫度、溼度、氣壓、海拔您可以從智能手機、Line或自架網站瞭解天氣參數整個電路以及電源都放在3D列印的外殼中若是WeMos D1 pro版本,則可以通過使用3dBi外部天線可以擴大設備的範圍約100米左右。 所需的零件和工具 Wemos D1 Mini ProTP 4056充電板BME280感測器太陽能板單面纖維板鋰離子充電電池及電池座22 AWG電線熱溶膠3D列印PLA線材使用工具:3D列印機烙鐵熱溶膠槍剪線鉗/剝線鉗 供電系統 本計劃是使用在戶外或偏遠地方,要持續運作氣象站,必須有連續的電源,否則系統將無法工作。可以向電路提供連續電源的最佳方法是使用電池,只是一般電池放電幾天之後,電池電量將耗盡。因此,該範例提出了一種太陽能充電電路,讓使用者利用從太陽中得到電能,為電池充電並為Wemos板供電。本案例是使用18650電池。電池通過TP4056充電模組從太陽能面板充電。TP4056模組帶有電池保護晶片及不帶保護晶片。建議購買包含電池保護晶片的模組。 關於TP4056電池充電器 TP4056模塊非常適合為3.7V 1 Ah或更高的LiPo單體電池充電。基於TP4056充電器IC和DW01電池保護IC,該模組將提供1000 mA充電電流,然後在充電完成時切斷。另外,當電池電壓降至2.4V以下時,保護IC會切斷負載,以保護電池免受欠壓。它還可以防止過電壓和反極性連接。 測量天氣數據 早期,天氣參數(如環境溫度、濕度和氣壓)是通過單獨的模擬儀器測量:溫度計,濕度計和氣壓計。但如今,市場上充斥著可用於測量各種環境參數的價位低且高效的數位感測器。最好的例子是DHT11,DHT 22,BMP180,BMP280等感測器。在此項目中,我們將使用BMP 280感測器。BME 280:BME280是一種複雜的感測器,可以非常準確地測量氣壓和溫度。BME280是Bosch的下一代感測器,是BMP085 / BMP180 / BMP183的升級產品,具有0.25m的低海拔噪聲和相同的快速轉換時間。該感測器的優勢在於它可以使用I2C或SPI與微控制器進行通信。為了簡單易接線,建議購買I2C版本。 使用外部天線(3dBi) Wemos D1 mini Pro開發板內建陶瓷天線,並可以連接外部天線以擴大範圍。在使用外部天線之前,必須將天線信號從內置陶瓷天線重新路由到外部插座,這可以通過旋轉(0603)零歐姆電阻來完成。可以看Alex Eames製作的影片來旋轉零歐姆電阻。然後將天線SMA連接器卡入Wemos Pro迷你天線插槽。 焊接針腳、電路圖架構 本範例太陽能大氣氣象站的電路圖架構圖如上圖所示,各位可以依上圖電路圖焊接。Wemos-> BME 2803.3 V–> VCCGND->GNDD1-> SCLD2-> SDATP4056連接太陽能電池板端子-> +和-靠近微型USB端口電池端子-> B +和B-Wemos的5V和GND-> Out +和Out-焊接在纖維板上 參考上述電路圖,將引腳母接頭、電路線焊接在纖維板上,再將WeMos、TP4056、BME280、太陽能板及電池盒安裝上。 氣象站外殼 這裏從作者已經設定好的stl檔直接下載印出來。我使用的3D列印規格如下:3D印表機:Creality Ender 3 Pro材料:PLA 1.75mm主體印12小時、封面蓋子3.5小時層高設定:0.2射出頭溫度:預設200度床溫:預設60度印出速度:40 mm/s 程式碼編寫 這邊我是自己編寫程式碼,主要架構為WeMos D1 mini pro + Line Notify服務 + MQTT服務。太陽能大氣氣象站定即將偵測到的相關數據傳送給Line Notify服務,通知Line設定的聊天室群組。Line Notify相關設定請參考我之前的文章,另外也將偵測到的相關數據同步傳給MQTT Server。程式碼如下所示: /* 範例名稱:無線氣象台 版本:wifi-line notify */ #include #include #include #include #include #include // 修改成上述寄到登入郵箱的 Token號碼 #define LINE_TOKEN "申請LINE Notify產生的Token號碼" #include // 設定無線基地台SSID跟密碼 const char* ssid = "您的SSID"; const char* password = "SSID密碼"; // 將變數值更改為HomeAssistant IP地址,以便連接到MQTT Broker const char* mqtt_server = "ip"; // 若MQTT Broker有設定認證請輸入自己設定的帳密 const char* mqtt_user = "mqtt username"; const char* mqtt_password = "mqtt password"; // 初始化espClient。如果您在家庭自動化系統中運行多個ESP,則應更改每個espClient變數名稱 WiFiClient espClient; PubSubClient client(espClient); Adafruit_BME280 bme; // I2C // 輔助計時器變數 long now = millis(); long lastMeasure = 0; //設定wifi初始化 void setup_start(){ WiFi.mode(WIFI_STA); // 連接無線基地台 WiFi.begin(ssid, password); Serial.print("nr nrWorking to connect"); // 等待連線,並從 Console顯示 IP while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); bool status; Serial.println(F("BMP280 test")); status = bme.begin(0x76); if (!status) { Serial.println("Could not find a valid BMP280 sensor, check wiring!"); while (1); } client.setServer(mqtt_server, 1883); } // 此功能將您的ESP8266重新連接到MQTT broker // 如果要與ESP8266訂閱更多主題,請更改下面的功能 void reconnect() { // 循環直到我們重新聯繫 while (!client.connected()) { Serial.print("Attempting MQTT connection..."); String clientId = "ESP8266Client-"; clientId += String(random(0xffff), HEX); if (client.connect(clientId.c_str(),mqtt_user,mqtt_password)) { Serial.println("connected"); // 訂閱或重新訂閱主題 // 您可以訂閱更多主題 (可以控制更多燈泡等等) client.subscribe("hotwater/control"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // 重試前等待5秒鐘 delay(5000); } } } void setup() { Serial.begin(115200); Serial.setTimeout(2000); // 等待序列初始化。 while(!Serial) { } // 深度睡眠模式設定60秒,ESP8266自身喚醒,當GPIO 16(在Nodemcu板D0)連接到復位引腳時 setup_start(); sendlineval(); ESP.deepSleep(18e8);//每30分鐘傳送一次訊息 } void loop() { } //發送訊息到Line聊天室 void sendlineval(){ if (!client.connected()) { reconnect(); } float Temp = bme.readTemperature(); Serial.print("T="); Serial.print(Temp); Serial.print(" *C"); float Humidity = bme.readHumidity(); Serial.print(" Humidity = "); Serial.print(Humidity); Serial.print(" %"); float Pressure = bme.readPressure() / 100.0F ; Serial.print(" P="); Serial.print(Pressure); Serial.print(" hPa"); float Altitude = bme.readAltitude(1013.25); Serial.print(" A= "); Serial.print(Altitude); // this should be adjusted to your local forcase Serial.println(" m"); /*這裏將四個值整合變成一個字串,再一起傳送給MQTT Server*/ String weatherStr = String(Temp) + "," + String(Humidity) + "," + String(Pressure) + "," + String(Altitude); byte arrSize = weatherStr.length() + 1; char message[arrSize]; weatherStr.toCharArray(message,arrSize); Serial.println(message); client.publish("mysql/weather", message); String line_notify_result = ""; line_notify_result = "現在溫度:" + String(Temp) + " *Cn" + "濕度:" + String(Humidity) + " %n" + "大氣壓力:" + String(Pressure) + " hPan" + "海拔:" + String(Altitude) + " m"; LINE.setToken(LINE_TOKEN); // 先換行再顯示 LINE.notify("n" + line_notify_result); } Node-RED的MySQL設定 要先到右上角部署旁的功能鍵下的設置地方。我們可以看到使用者設置這邊,到Palette的安裝搜尋處,填入關鍵字"node-red-node-mysql",按下安裝按鍵。安裝完成後,我們可以在儲存的地方看到mysql元件。 接下來我們拉出四個節點,分別是mqtt in、function、mysql及debug。 節點設定如下: mqtt in:接收ESP8266端發送MQTT訊息 function:判斷MQTT訊息,並將訊息折分為需要的值;將值填入INSERT INTO 語法中 mysql:連線MySQL資料庫,將收到INSERT INTO語法及值送出,寫入到雲端資料庫中 debug:檢測每一筆從收到MQTT傳送來的值到寫入mysql資料庫中的作業是否成功或失敗 四個節點的設定及語法如下: mqtt in 節點最重要的地方就是主題設定要跟ESP8266傳送的主題相同,這樣才可以收到它傳送來的值。 mysql function 節點功能是收到mqtt的主題的訊息,該訊息包含溫度、溼度、氣壓及海拔四個值,所以這裡就是將它折分為四個參數值,並填入INSERT INTO語法中,再傳給mysql節點。 msyql節點就是設定它跟雲端的mysql資料庫主機連線,讓從function傳過來的INSERT INOT語法可以寫入參數值。 最後測試,各位可以參考instructables這位作者提供的APP及上傳到ThingSpeak網站來測試結果,而我這邊則是以測試Line聊天室收到的訊息及雲端資料庫來做測試。 天氣氣象站網站建置 當我們建置好從天氣氣象站的感測器讀取數據上傳到Node-RED及發送Line訊息到聊天室後,我也想將寫到資料庫中的數據,用網站網頁的方式呈現出來,這樣不管是用電腦或手機都可以隨時查詢氣象站的即時數據。最後,我們就來講解如何用WordPress製作這樣的網站內容。 首先,你可以找一台樹莓派或是用Oracle VM VirtualGBox新增一個虛擬主機或是在NAS中新增一台虛擬主機或是直接在Windows電腦上安裝XAMPP....等,反正就是用自己的方式,建置一個網站伺服器的環境,我自己則是自己下載TrueNas灌一台主機,並在該台設備上切出VM,然後在上面架設Nginx Server及安裝Docker及Portainer,這樣就可以在Docker上隨時配置建構多台WordPress網站。若各位學員有興趣,我們之後也可以開設建置這樣的課程。 假設我們已經配置並建構好一個WordPress網站,我這裏以weather.omia.site這個網站來說。 我是如何寫出天氣氣象站這樣的網頁的,下面我就一步步的說明。 我這裡有安裝三個外掛,Elementor、Insert PHP Code Snippet及Head,Footer and Post Injections這三個外掛。 Elementor是文章編輯器這我就不用講解了,因為只要有玩WordPress的人應該都知道它的存在。 Insert PHP Code Snippet則是想要在文章、頁面或自訂面板中放入PHP程式碼運作,我們就會需要安裝這個外掛來執行。 Head,Footer and Post Injections則是我想放置一段JavaScript程式碼,所以安裝這個外掛工具。 新增PHP程式碼到PHP Code Snippet中 下面是顯示最新的環境溫度、溼度、氣壓及海拔訊息的php程式碼 <?phprequire_once(dirname(dirname(dirname(dirname(__FILE__)))) . '/wp-config.php');$con = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD,DB_NAME);//查詢$sql = "SELECT * FROM IoT_Weather_Station_ESP8266 ORDER BY wid DESC LIMIT 1";$result = mysqli_query($con,$sql); $colums = mysqli_num_fields($result); //列 echo "";for($i=1; $i < $colums-1; $i++){$field_name=mysqli_fetch_field_direct($result,$i);if($field_name->name == 'temperature'){echo "溫度";}else if($field_name->name == 'humidity'){echo "溼度";}else if($field_name->name == 'pressure'){echo "氣壓";}else if($field_name->name == 'altitude'){echo "海拔";}}echo "";while($row=mysqli_fetch_row($result)){echo "";for($i=1; $i<$colums-1; $i++){echo "$row[$i]";}echo ""; }echo "";?> 新增該php程式碼後,我們可以看到它的短代碼如下: 然後,我們到首頁的頁面中,將該短碼放到短碼工具中。如下設定: 最後再按下發佈,並將該頁面設定為首頁,這樣我們就可以到網址中看到我們抓取的氣象站數據呈現。 但是我們不希望每30秒或是每5分鐘去按下網頁的Refresh(F5)按鍵來更新網頁的內容,所以這時我們的另一個外掛Head,Footer and Post Injections就發揮作用。安裝完該外掛後,我們可以在設定下找到該外掛的設定。 開啟Header and Footer後,我們只要在插入及標籤之間下面填入下面程式碼,這樣我們可以達到每5分鐘refresh頁面的效果。content="300"代表300秒也就是5分鐘的意思。 總結 本篇文章分享了如何從零到建置天氣氣象站的步驟,希望各位學員喜歡。 之後,我會再新增ESP32版本及NBIoT版本的天氣氣象站網站實作課程,敬請期待!