2026年11月9日 星期一

【ESP32 物聯網實戰 05】聯網:Wi-Fi 自動連線與 NTP 時間同步機制

在上一篇中,我們成功在 OLED 螢幕上顯示了本地的溫濕度數據,讓 ESP32 具備了獨立運作的「視覺」。不過,這依然只能算是一個「單機設備」。要成為真正意義上的「物聯網(IoT)」節點,裝置必須能夠上網,且數據必須伴隨精確的時間標記。

今天,我們要來解鎖 ESP32 最強大的天賦——無線聯網 (Wi-Fi)!我們將實作如何讓 ESP32 在開機時自動連上當地的無線網路,並透過 NTP (網路時間協定) 向世界級的標準時間伺服器「對時」。這樣一來,我們採集到的每一筆數據,都能打上精準的「時間戳記 (Timestamp)」,這是日後大數據分析與異常追溯必備的基礎!

1. 觀念解析:什麼是 NTP 網路時間協定?

ESP32 內部雖然有定時器,但它沒有像電腦或手機那樣有「水銀電池(RTC 模組)」來保存時間。每次只要斷電重開,它的時間就會歸零(回到 2000 年 1 月 1 日)。這在大數據採集中是非常致命的,因為我們無法得知「這筆異常高溫是在何時發生的」。

為了解決這個問題,只要讓 ESP32 聯網,就能使用 NTP (Network Time Protocol)。這是一種用來在網路中同步電腦時間的協定。透過向公開的 NTP 伺服器發送請求,我們的 ESP32 就能獲取誤差在幾毫秒內的 UTC 標準時間,並轉換為台灣當地的標準時間(UTC+8)!

ESP32 Wi-Fi 自動連線與 NTP 時間同步架構 ESP32 (Client) 📶 Wi-Fi 連線中 ⏰ 2026-10-25 16:29 📟 Wi-Fi AP DHCP / IP ☁️ 網際網路 ⏱️ NTP Server pool.ntp.org 提供標準時間 ▲ 網路對時:ESP32 連上 Wi-Fi 路由器後,向外網 NTP 伺服器校時,獲取精準 Timestamp
▲ ESP32 Wi-Fi 自動連線與 NTP 時間同步示意圖

2. 實作一:讓 ESP32 連上 Wi-Fi

import network
import time

def connect_wifi(ssid, password):
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    
    if wlan.isconnected():
        print("已經處於連線狀態:", wlan.ifconfig())
        return True
        
    print(f"正在連線到 Wi-Fi: {ssid}...")
    wlan.connect(ssid, password)
    
    timeout = 10
    # 注意:這裡使用 > 代表大於符號
    while not wlan.isconnected() and timeout > 0:
        print(".", end="")
        time.sleep(1)
        timeout -= 1
        
    if wlan.isconnected():
        print("\n連線成功!獲得 IP 配置:")
        print(wlan.ifconfig())
        return True
    else:
        print("\n連線失敗,請檢查帳號密碼或網路訊號!")
        return False

connect_wifi("Your_WiFi_SSID", "Your_WiFi_Password")

3. 實作二:NTP 網路時間校準與台灣時區轉換

import ntptime
import time

print("嘗試向 NTP 伺服器對時中...")
try:
    ntptime.settime()
    print("對時成功!")
except Exception as e:
    print("對時失敗,請確認是否已聯網。錯誤原因:", e)

def get_taiwan_time():
    taiwan_seconds = time.time() + (8 * 3600)
    local_t = time.localtime(taiwan_seconds)
    formatted_time = "{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(
        local_t[0], local_t[1], local_t[2], local_t[3], local_t[4], local_t[5]
    )
    return formatted_time

for _ in range(5):
    print("台灣時間:", get_taiwan_time())
    time.sleep(1)

4. 進階實作:聯網、對時與環境採集(整合 main.py)

from machine import Pin, I2C
import ssd1306
import dht
import time
import network
import ntptime

i2c = I2C(0, scl=Pin(22), sda=Pin(21))
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
sensor = dht.DHT11(Pin(4))

SSID = "Your_WiFi_SSID"
PASSWORD = "Your_WiFi_Password"

oled.fill(0)
oled.text("Connecting...", 10, 20)
oled.show()

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, PASSWORD)

timeout = 10
while not wlan.isconnected() and timeout > 0:
    time.sleep(1)
    timeout -= 1

if wlan.isconnected():
    oled.fill(0)
    oled.text("Connected!", 10, 20)
    oled.text(wlan.ifconfig()[0], 10, 40)
    oled.show()
    time.sleep(2)
    try:
        ntptime.settime()
    except:
        pass
else:
    oled.fill(0)
    oled.text("WiFi Failed", 10, 20)
    oled.show()
    time.sleep(2)

def get_tw_time():
    t_sec = time.time() + (8 * 3600)
    t = time.localtime(t_sec)
    return "{:02d}:{:02d}:{:02d}".format(t[3], t[4], t[5])

while True:
    try:
        sensor.measure()
        temp = sensor.temperature()
        humi = sensor.humidity()
        
        oled.fill(0)
        oled.text("ESP32 IoT Node", 5, 0)
        oled.text("----------------", 0, 10)
        oled.text(f"Time: {get_tw_time()}", 0, 25)
        oled.text(f"Temp: {temp} C", 0, 40)
        oled.text(f"Humi: {humi} %", 0, 52)
        oled.show()
    except Exception as e:
        oled.fill(0)
        oled.text("Error!", 10, 25)
        oled.show()
    time.sleep(2)

沒有留言:

張貼留言

熱門文章