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]