Wokwi模擬器支援ESP32的Wi-Fi無線網路連線功能,本文將示範在ESP32模擬器中測試:
- 掃描ESP32周遭的Wi-Fi無線網路名稱和訊號強度
- 網站伺服器程式
- 在OLED螢幕顯示即時氣象資料
掃描周遭的Wi-Fi網路
ESP32的WiFi.h程式庫的scanNetworks()可掃描周遭的Wi-Fi網路,並傳回找到的無線網路分享器數量。如果有找到無線網路分享器,可進一步透過下列函式讀取該分享器的資料:
- WiFi.SSID():無線網路名稱
- WiFi.RSSI():無線網路訊號強度,數值越接近0,代表訊號越強。
- WiFi.encryptionType():通訊加密形式,WIFI_AUTH_OPEN代表無需連線密碼。
底下是掃描周遭Wi-Fi網路的ESP32 Arduino程式碼,改自WiFi.h程式庫內建的WiFiScan.ino範例。
#include <WiFi.h> void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); // 設置成STA(無線終端)模式 WiFi.disconnect(); // 切斷現有的Wi-Fi連線 delay(100); // 先等一下 } void loop() { Serial.println("掃描Wi-Fi熱點…"); int n = WiFi.scanNetworks(); if (n == 0) { Serial.println("找不到Wi-Fi熱點"); } else { Serial.printf("找到 %d 個熱點\n", n); // 列舉熱點的SSID和訊號強度 for (int i = 0; i < n; ++i) { Serial.print(i + 1); Serial.print(": "); Serial.print(WiFi.SSID(i)); Serial.print(" ("); Serial.print(WiFi.RSSI(i)); Serial.print(")"); Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*"); delay(10); } } Serial.println(""); // 暫停5秒再重新掃描 delay(5000); }
把上面的程式碼貼入ESP32模擬環境的sketch.ino程式,再按下三角形「開始模擬」鈕,過一會兒,右下角的「序列埠監控窗格」將顯示找到一個名叫“Wokwi-GUEST”的熱點,不用連線密碼。
以下在ESP32模擬器中執行的網路程式都要連線到“Wokwi-GUEST”。下圖是在ESP32模擬器測試《超圖解ESP32深度實作》動手做6-3「使用WebServer程式庫建立HTTP伺服器」的執行結果,程式雖可正常運作,但是我們連不上那個虛擬的ESP32,因為連線設備必須位在相同網域,也就是10.5.75.xxx。
不知能否在模擬器環境中,透過另一個ESP32前端程式連接到虛擬的ESP32網站伺服器 😛 有興趣的朋友請自行實驗。
下文使用《超圖解ESP32深度實作》7-3節「在OLED螢幕顯示天氣概況」的範例,在模擬器中透過ESP32讀取OpenWeather的台北天氣資料,顯示在OLED螢幕。
新增SSD1306 OLED顯示器元件
首先替ESP32開發板連接一個OLED顯示器。點擊Simulation(模擬)窗格裡的「+」鈕:
輸入“SSD1306”關鍵字,或直接點擊彈出式選單中的SSD1306 OLED顯示器元件。
透過I2C介面連接ESP32:
- 顯示器的CLK(時脈)接ESP32的腳22(SCL)
- 顯示器的Data(資料)接ESP32的腳21(SDA)
新增程式庫
本文採用書本7-3節的範例程式,需要安裝解析JSON格式資料的“ArduinoJSON”程式庫,以及驅動OLED顯示器的“U8g2”程式庫。
切換到Library Manager(程式庫管理員),點擊「+」鈕新增程式庫:
在搜尋欄位輸入程式庫名稱“ArduinoJSON”,不用在乎大小寫,也不必全部輸入,找到之後,點擊名稱即可匯入它。
重複相同的步驟,新增U8g2程式庫。
以上兩個是Wokwi模擬器開發工具內建的程式庫,開發其他專案程式時,假如找不到需要的程式庫,成為付費會員,即可自由上傳程式庫和預先編譯的.bin檔。
新增程式庫之後,開發環境會自動新增一個libraries.txt檔,紀錄此專案採用的程式庫名稱。
上傳Arduino原始檔
OLED顯示器呈現的天氣圖案和文字,定義在weatherFont.h檔,讀者可直接使用“diy7-2-OLED-font”範例資料夾中的檔案,或者按此連結下載OLED天氣情報範例檔。
點擊下圖選單中的Upload file(上傳檔案)選項,上傳weatherFont.h檔。
上傳的檔案會顯示在新的標籤頁,這部份的程式碼不用改。
最後,在sketch.ino主程式的編輯畫面,貼入底下的程式碼並且修改其中的OpenWeather API碼:
#include <map> #include <ArduinoJson.h> #include <HTTPClient.h> #include <U8g2lib.h> #include "weatherFont.h" U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); std::map<String, char> icon_map{ {"01d", 'B'}, {"02d", 'H'}, {"03d", 'N'}, {"04d", 'Y'} , {"09d", 'R'}, {"10d", 'Q'}, {"11d", 'P'}, {"13d", 'W'}, {"50d", 'J'}, {"01n", 'C'} , {"02n", 'I'} , {"03n", '5'}, {"04n", '%'} , {"09n", '8'} , {"10n", '7'}, {"11n", '6'} , {"13n", '#'} , {"50n", 'K'} }; const char* ssid = "Wokwi-GUEST"; // Wokwi提供的Wi-Fi網路名稱 const char* password = ""; String API_KEY = "請輸入你的openWeather API碼"; String city = "Taipei,TW"; HTTPClient http; void connectWiFi() { WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.print("\nIP位址:"); Serial.println(WiFi.localIP()); } String openWeather() { String url = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "&appid=" + API_KEY; String payload = ""; if ((WiFi.status() != WL_CONNECTED)) { connectWiFi(); } else { http.begin(url); int httpCode = http.GET(); if (httpCode > 0) { payload = http.getString(); Serial.printf("回應本體:%s\n", payload.c_str()); } else { Serial.println("HTTP請求出錯了~"); } http.end(); } return payload; } void displayWeather(String json) { DynamicJsonDocument doc(1024); deserializeJson(doc, json); JsonObject weather = doc["weather"][0]; const char* icon = weather["icon"]; const char* city = doc["name"]; JsonObject main = doc["main"]; // 取得絕對溫度,然後轉成攝氏溫度。 float temp = (float)main["temp"] - 273.15; int humid = (int)main["humidity"]; Serial.printf("天氣圖示:%s\n", icon); Serial.printf("攝氏溫度:%.1f\n", temp); // 在OLED螢幕顯示天氣資訊 u8g2.firstPage(); do { u8g2.setFont(u8g2_font_profont12_mr); u8g2.drawUTF8(0, 8, city); u8g2.setFont(u8g2_font_inr16_mf); u8g2.setCursor(60, 36); u8g2.print(String(temp, 1)+ "\xb0"); u8g2.setCursor(60, 62); u8g2.print(String(humid) + "%"); u8g2.setFont(weatherFont); u8g2.setCursor(0, 62); u8g2.print(icon_map[icon]); } while ( u8g2.nextPage() ); } void setup() { Serial.begin(115200); connectWiFi(); u8g2.begin(); } void loop() { String payload = openWeather(); if (payload != "") { displayWeather(payload); } delay(50000); }
按下Simulation(模擬)頁面中的三角形(開始模擬)鈕,過一會兒,將能取得台北的即時天氣情報並呈現在OLED顯示器。
#include
sketch.ino
1 of 1 problem
/libraries/U8g2/src/clib/mui_u8g2.c:560: /libraries/U8g2/src/clib/mui_u8g2.c: In function ‘mui_u8g2_u8_vmm_draw_wm_pi’:
initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]