作者: ken

在 Arduino 平台上使用 ESP8266

No Comments

ESP8266 有官方的軟體開發環境套件及應用函式庫等套件,其包含使用手冊(還是中文的)提供得相當的完整,並且都是免費的。然而對於初學者而言不易上手且需閱讀不少使用文件,有興趣者可逕自至官網下載。

說到這裏我又想到了,絕大部份的各家的微控器開發平台/環境,官方所提供的,也都是試用或必須付費才能使用的。當然也會有第三方免費開發環境,不過真的不多。這也再次顯現 Arduino/ESP 受歡迎的程度。

想直接從應用層面著手的人別擔心,我們還有其他的選擇。
首先我們需在 Arduino IDE 上安裝 ESP8266 的 BSP 套件,已知有不止一個社群有開發提供這樣的套件。首推 ESP8266 Community ForumGitHub 上的 BSP 套件
很簡易的操作如下,

  • 開啟 Arduino IDE
  • 將這段文字
  • https://arduino.esp8266.com/stable/package_esp8266com_index.json
  • 貼至
  • 檔案 -> 偏好設定 -> 額外的開發板管理員網址。可使用逗號分隔多個網址。所加入的網址,Arduino 就會自動去探尋是否有可更新的開發板 BSP 套件。
  • 按確定之後,再到開發板管理員中,我們直接鍵入 esp 來搜尋。可看到可安裝的 ESP8266 套件,點選並安裝即成。
  • 接著,我們切換開發板成 ESP8266 的板子,依據您的板子的名稱來選取。若選單中並沒有列出您的板子,則選通用的即可。直接看圖。
  • 接著插入開發板,記得要選取開發板所使用的序列埠 USB-COM port。其同時提供輸出入及燒錄的通道。
  • 最後不免俗地,我們開啟範例程式 blink 編譯及燒錄,即可看到板子的 LED 在閃爍了,是不是 Arduino 得輕鬆愉快。

讀者如果眼尖或許會發覺,ESP8266 的 Blink 範例程式碼,與 Arduino UNO 板的 Blink 範例程式碼,可說是幾無差異,它是有非常關鍵非常重要的背後意義的!即概述,兩顆迥異的晶片,AVR,ESP,在底層 GPIO 及功能腳位做了同名同質異義的定義後,再加上一些硬體設定函式,例如假設,設定 CPU 時脈,各自要填不同的暫存器不同值,便包裝成同名函式而各自引用。如此,將使得底層之外的其他層的函式庫將可最大限度地共用,即原則上,所有 Arduino 的應用函式庫,都可不經修改地被 ESP 所正常使用。

震撼教育

阿。。。買張 ESP8266 開發板來閃燈就滿足了是嗎。。。有沒有搞湊阿。。。未免也太小兒科了吧。。。


嗯,那就來點。。。。非不一樣。。。這是在這張板子上隨手拈來,稀鬆平常的。。。讓我們看下去。。。

開啟 檔案 -> 範例 -> ESP8266HTTPClient -> BasicHttpsClient
開啟後如下圖,我們稍微看一下程式碼內容,

  • ESP8266 的 WIFI 連接,區分成 AP 模式,Station,或 AP+Station(Wifi direct)三種模式,AP 是類似 Server,Station 則是類似 Client。
  • 程式碼中那兩行表示我們將把板子設定成 station 模式(即用戶端),並且下一行提供無線 AP 的帳密,因此 “SSID”必須改成您所擁有的 AP 的名稱,及它的 PASSWORD,其密碼。以讓 ESP8266 登入該 AP 使用網路資源。例如我的 AP 叫 KENAP,密碼 1234,則更改那行成
    WiFiMulti.addAP(“KENAP”, “1234”);
  • 接著我們點選選單,如圖,是要選取清除 flash 的方式,預設是 Sketch,其指的是我們的程式碼內容。即,要規劃出新的程式碼及功能,舊的程式碼必須先被清除才行。即,只能先清再寫,沒有所謂直接覆寫。
  • 然而要是我們程式碼中,曾經有去設定 WIFI AP/Station 相關的設定值,則這些設定值會被 BSP 放置到 Flash 中特別的區塊,其有別於 Sketch。也因此,若延用預設值只清除 Sketch 且我們已設定過 WIFI 設定值,則,例如下次我將開發板重新規劃成只有閃燈功能,該 WIFI 設定仍將被啟用並連線至 AP 上或當成 AP 讓終端連過來開發板;將讓事情複雜化。故建議改為如圖選項。
  • 接著,編譯及上傳。可直接單按上傳其仍會從編譯做起。
  • 上傳完畢後,板子就立即開始跑程式了,我們將序列埠監控視窗開啟,如圖。
  • 如果順利的話(以上循筆者的意思沒做錯)我們會看到有一些輸出,表示著,這張板子以 HTTPS 連線至 https://jigsaw.w3.org/HTTP/connection.html 這個網頁,並將其 html 內容輸出出來,如下圖。
  • 需注意一下,我們從程式碼內容中將目的網址改成我們自己主機的網址,其實是行不通的,因為 HTTPS 連線需要 fingerprint 在程式中可找到,要改成該網站所對應的 fingerprint 才行,目前筆者還不知道怎麼對應著改。
  • 好了,夠震撼了吧,這小小的東西,這麼地輕鬆愉快。
  • 至此,Arduino 與架站,筆者並沒有偏離主題吧,並且往後,筆者偏離主題很遠亦是眾所樂見的對吧!

進階補充

ESP8266 最初面市其實與 Arduino 是無任何關聯性的。
ESP8266 有它自己的官方 SDK,甚至於是第三方的 SDK。並且也陸續開發了 RTOS 及 non-RTOS 的作業系統層級的軟體開發工具與套件,函式庫,驅動庫等等。簡單講 ESP8266 有它一脈相承自成一格的開發工具與套件及函式庫。
然而就有 Arduino 的愛好者,同樣地開發這些所謂的中介層函式庫與工具或套件,使得 ESP8266 得以在 Arduino 環境下,以與 Arduino 幾近完全相同的方式使用 Arduino 的函式庫,功能套件或驅動套件,以及開發編程方式等等,使得 ESP8266 與 Arduino-based 的純正血統單晶片(AVR)得以平起平坐甚至於更勝於藍。

重點在哪?
官方是一套,Arduino-based 第三方是另一套。
我們並不知道在相容於 Arduino 環境下所做的編程,所使用的下層函式庫是否使用了及使用了哪些官方的 SDK。這意謂著,如果我們混用了這兩套的函式庫,就可能發生硬體資源衝突而難以除錯。因此,官方有很多詳盡的軟體與技術參考文件可供參考,但要引用在程式下就須特別留意了,基本上是該避免引用的。
當前筆者都是基於 Arduino-based 的環境下這一套來使用的。其它的筆者所知有三套:官方 AT 指令套件,SDK 及 RTOS,SDK 及 non-RTOS。有興趣者可自行學習。

而使用 Arduino-based 的開發環境的缺點是,我們比較不容易直接取用到底層硬體資源,故實作下會有綁手綁腳或可實現卻無法實現某功能的窘境。

參考資料


Claude-code 補充 / 20260901

延續您在「震撼教育」段落提到的疑問——把範例中的目的網址改成自己主機的網址會連不上,因為 HTTPS 需要對應的 fingerprint,當時還不知道怎麼改。這題目前已有清楚答案,一併附上可直接用在這台主機(waterfalls.ddns.net)的作法。

為什麼 fingerprint 寫死行不通、不好維護

BasicHttpsClient 範例用的 setFingerprint() 是把「憑證本身」的 SHA1 指紋寫死在程式碼裡。這支憑證每次換發(Let’s Encrypt 每 90 天到期一次,目前這台主機的憑證有效期是 2026-08-10~2026-11-08)指紋就會整個換掉,程式碼要跟著改,不然連線會失敗。這正是您當時卡住的原因所在。

正確作法:釘根憑證(Root CA)而非葉憑證

BearSSL(ESP8266 Arduino core 內建的 TLS 函式庫)提供 setTrustAnchors(),可以只信任「簽發者的根憑證」而非某一張特定憑證。根憑證效期通常是十年、二十年起跳,且同一個憑證機構換發的所有憑證都共用同一張根憑證,因此不會因為網站憑證每 90 天換發就要跟著改程式碼。

waterfalls.ddns.net 目前用的是 Let’s Encrypt,根憑證是 ISRG Root X1(有效期到 2035-06-04,SHA256 指紋 96:BC:EC:06:26:49:76:F3:74:60:77:9A:CF:28:C5:A7:CF:E8:A3:C0:AA:E1:1A:8F:FC:EE:05:C0:BD:DF:08:C6,本次已實際核對主機上 /etc/ssl/certs/ISRG_Root_X1.pem 內容無誤)。範例:

#include <ESP8266WiFi.h>
#include <WiFiClientSecureBearSSL.h>

// ISRG Root X1,Let's Encrypt 的根憑證,有效期到 2035 年
// waterfalls.ddns.net 的憑證每 90 天換發一次,但都是
// 這張根憑證簽出來的,所以這裡不用跟著改
static const char ISRG_ROOT_X1[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----
)EOF";

BearSSL::X509List rootCert(ISRG_ROOT_X1);

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFiMulti.addAP("KENAP", "1234");
  while (WiFiMulti.run() != WL_CONNECTED) delay(500);

  BearSSL::WiFiClientSecure client;
  client.setTrustAnchors(&rootCert);

  if (client.connect("waterfalls.ddns.net", 443)) {
    client.println("GET / HTTP/1.1");
    client.println("Host: waterfalls.ddns.net");
    client.println("Connection: close");
    client.println();
    while (client.connected() || client.available()) {
      if (client.available()) Serial.write(client.read());
    }
  } else {
    Serial.println("連線失敗");
  }
}

void loop() {}

額外提醒

  • 若只是想先跑通、還沒空處理憑證驗證,BearSSL 也提供 client.setInsecure(),直接跳過憑證驗證——開發階段快速測試可以用,正式使用不建議(會失去 HTTPS 防中間人竄改的保護,等同白工)。
  • ESP8266 RAM 有限,X509List 存放的憑證不宜太多;一般網站多半只需這一張根憑證即可涵蓋其簽出的所有子憑證,不需要整包瀏覽器等級的信任清單。
  • 憑證換發不影響根憑證,但如果哪天網站改用不同的憑證機構(例如自架 CA),這裡的根憑證內容就要跟著換。

以上作法已用主機端指令核對 waterfalls.ddns.net:443 目前簽發鏈確實是 Let’s Encrypt(issuer commonName: YE1,屬 Let’s Encrypt 的中繼憑證),根憑證鏈可回溯至 ISRG Root X1,故此範例對本站可直接適用。

Categories: Arduino

Tags: ,

PHP Code Snippets Powered By : XYZScripts.com