
Web 按鈕已能控制實體 LED,今天要讓網頁等 MCU 回報後再更新狀態。
Day 16 已建立 {"status": label},今天直接沿用這個格式,不重新定義欄位,也不在 JavaScript 自行推算 ON/OFF。
將 on_led_status() 修改如下。
def on_led_status(state: bool):
label = "ON" if state else "OFF"
message = {"status": label}
print("LED 狀態:", message["status"])
ui.send_message("led_update", message) # 本日新增
ui.send_message() 的第一個參數是事件名稱 "led_update",第二個參數是要送給瀏覽器的字典,Web 端收到後會以 data.status 取得內容。
事件名稱負責選擇哪一個 JavaScript listener,資料欄位則負責提供 listener 需要的內容,兩者功能不同,led_update 必須與 socket.on() 一致,status 則必須與 data.status 一致。
這個函式只在 MCU 回報後執行,因此送出的 ON/OFF 代表硬體已完成的真正結果,而不是瀏覽器剛才提出的要求。
在 assets/app.js 中加入以下接收程式。
// 本日新增
socket.on("led_update", (data) => {
statusEl.textContent = data.status;
statusEl.className = data.status === "ON" ? "on" : "off";
});
socket.on() 會持續等待 "led_update",事件到達後執行箭頭函式,data 就是 Python 傳來的資料物件。
textContent 修改狀態區的文字,className 則依 ON/OFF 選擇 on 或 off,CSS 會自動套用對應顏色。
更新文字與 class 要在同一個 callback 中完成,避免畫面出現文字已是 ON、顏色卻仍使用 off 的短暫不一致,收到一筆 MCU 結果後,前端應一次完成整組顯示更新。
data.status === "ON" ? "on" : "off" 是 JavaScript 條件運算式,若狀態文字完全等於 "ON",就將 class 設成 "on",否則設成 "off"。
三個等號 === 代表嚴格比較,這裡比較的是字串內容,不使用單一等號,因為單一等號是指定值,不是判斷是否相等。
這項判斷只決定顯示樣式,不會產生新的硬體狀態,真正資料仍來自 data.status。
重新執行 App,開啟頁面後點擊切換按鈕,D2 LED 應切換,Python Console 顯示 ON 或 OFF,瀏覽器文字與顏色接著同步更新。
完整路徑是 Web 發出 toggle_led、Python 呼叫 MCU、MCU 更新 ledState、回報 led_status、Python 推送 led_update,最後 JavaScript 更新畫面。
若 LED 有變化但頁面沒有更新,先確認 Python 是否執行 ui.send_message(),再檢查兩端事件名稱 "led_update" 與欄位 status 是否一致。
也可在 JavaScript listener 內暫時加入 console.log(data),確認瀏覽器是否收到物件,若已收到卻沒有更新,問題就在 DOM 或條件式,若完全沒收到,則回到 Python 推送與 Socket.IO 連線。
按下 D9 實體按鈕時,MCU 同樣使用 toggle_led(),完成後會回報 led_status,Python 再推送 led_update,因此頁面也應同步變化。
這表示遠端與現場雖有不同入口,最後都使用同一條狀態回報路徑,瀏覽器不需要分辨切換來源,只要接收 MCU 的真正結果。
多個瀏覽器使用同一事件
ui.send_message() 會把狀態事件推送給連線中的管理頁面,因此不同裝置若同時開啟介面,都能收到相同的 ON/OFF。
本篇不建立每個瀏覽器自己的狀態資料,所有畫面都只是顯示同一份 MCU 回報,這能避免不同裝置各自猜測燈號。
測試時可先用 Web 切換一次,再用 D9 切換一次,兩次都應觸發完全相同的 led_update listener,若只有 Web 操作會更新,代表回報可能被錯放在遠端專用路徑,應回到 MCU 的共同 toggle_led() 檢查。
最終畫面必須同時更新文字與顏色,不能只改 ON/OFF 而保留上一個 class,文字與顏色必須同時一致。
Web 顯示、Python 輸出與實體 LED 三者一致,才代表狀態回程真正完成。
ui.send_message() 推送狀態。socket.on() 接收 led_update。現在網頁已能依 MCU 回報更新文字與顏色,遠端控制需要的兩條路徑都已建立,下一篇要從 Web 按鈕開始完整驗收整條遠端控制流程。
下一篇|從 Web 串起遠端控制完整路徑