找回密碼
 立即註冊
    查看: 155|回覆: 0

    【MQTT 實作 2】進階實體:可控開關、離線偵測,與兩種自己寫的裝置端

    [複製鏈接]

    !lvup!   100%

    386

    主題

    27

    回帖

    2200萬

    積分

    管理員

    積分
    22006063
    發表於 2026-9-21 13:58:30 | 顯示全部樓層 |閱讀模式
    只會發一個唯讀的溫度數字,MQTT 的價值只用到一成。

    這篇要做四件在那之後才有意思的事:做出 HA 能「控制」的實體、讓 HA 知道你的裝置掛了、一則 JSON 餵好幾個實體,以及把上面全部寫進兩種真的會跑的裝置端程式 —— 一支 Python 服務,和一台你自己接線的 ESP8266。

    從零件清單、接線、電阻怎麼算,到完整的程式碼與燒錄後該看到的日誌,全部在這一篇裡。

    把上面全部寫進兩種真的會跑的裝置端程式

    做完這篇你會有什麼


    • 一支跑在 NAS 或小主機上的 Python 服務,把系統狀態變成 HA 的實體,而且斷掉時 HA 會顯示「不可用」
    • 一台 ESP8266,能回報溫度、能被 HA 遠端開關繼電器
    • 用「裝置層探索」一則訊息宣告整台裝置的所有實體,而不是一個實體發一則
    • 看得懂 availability、遺囑訊息、value_template 各自在解決什麼問題


    需要準備的東西


    • 一個能連的 MQTT broker。還沒有的話第一步會從頭建一個
    • 已經能用的 Home Assistant
    • 電腦上裝好 mosquitto 的命令列工具(sudo apt install -y mosquitto-clients,macOS 是 brew install mosquitto)


    下面全部用 192.168.1.20 當 broker 的 IP,記得換成你自己的。

    ---

    第一步:先確定有一個能連的 broker

    已經有了的話,用這行確認它真的通,然後跳到第二步:
    1. mosquitto_sub -h 192.168.1.20 -p 1883 -u 你的帳號 -P 你的密碼 -t '#' -v
    複製代碼

    游標停住不動就是成功(現在還沒人發訊息)。跳回提示字元並印出錯誤的話,往下把 broker 建起來。

    1-1. 建立目錄與設定檔
    1. sudo mkdir -p /opt/mosquitto/{config,data,log}
    複製代碼

    存成 /opt/mosquitto/config/mosquitto.conf(整份):
    1. # Mosquitto 2.0 起,沒有 listener 這一行的話它只綁 127.0.0.1,
    2. # 別台機器完全連不進來,而且啟動日誌看起來一切正常。
    3. listener 1883
    4. protocol mqtt
    5. # 2.0 起只要寫了 listener,這個預設就是 false。明寫出來比較不會忘。
    6. allow_anonymous false
    7. password_file /mosquitto/config/passwd
    8. # retain 訊息要能撐過重開機,不然 HA 裡的 MQTT 裝置會全部消失。
    9. persistence true
    10. persistence_location /mosquitto/data/
    11. autosave_interval 1800
    12. log_dest stdout
    13. log_type error
    14. log_type warning
    15. log_type notice
    16. log_type information
    17. connection_messages true
    18. log_timestamp true
    複製代碼

    1-2. docker-compose.yml(整份)

    存成 /opt/mosquitto/docker-compose.yml:
    1. services:
    2.   mosquitto:
    3.     image: eclipse-mosquitto:2.0.22
    4.     container_name: mosquitto
    5.     restart: unless-stopped
    6.     ports:
    7.       - "1883:1883"
    8.     volumes:
    9.       - ./config:/mosquitto/config
    10.       - ./data:/mosquitto/data
    11.       - ./log:/mosquitto/log
    12.     environment:
    13.       - TZ=Asia/Taipei
    複製代碼

    1-3. 建帳號(這篇會用到三個)
    1. # 第一個用 -c(建立新檔)。⚠ 之後絕對不要再用 -c,它會把前面的帳號全部清掉。
    2. sudo docker run --rm -it -v /opt/mosquitto/config:/mosquitto/config   eclipse-mosquitto:2.0.22   mosquitto_passwd -c /mosquitto/config/passwd homeassistant
    3. sudo docker run --rm -v /opt/mosquitto/config:/mosquitto/config   eclipse-mosquitto:2.0.22   mosquitto_passwd -b /mosquitto/config/passwd pyagent 換成你的密碼
    4. sudo docker run --rm -v /opt/mosquitto/config:/mosquitto/config   eclipse-mosquitto:2.0.22   mosquitto_passwd -b /mosquitto/config/passwd espdev 換成你的密碼
    5. sudo chmod 0700 /opt/mosquitto/config/passwd
    複製代碼

    1-4. 啟動
    1. cd /opt/mosquitto && docker compose up -d && docker compose logs -f
    複製代碼

    你會看到什麼(正常)
    1. 1790276210: mosquitto version 2.0.22 starting
    2. 1790276210: Config loaded from /mosquitto/config/mosquitto.conf.
    3. 1790276210: Opening ipv4 listen socket on port 1883.
    4. 1790276210: Opening ipv6 listen socket on port 1883.
    5. 1790276210: mosquitto version 2.0.22 running
    複製代碼

    1-5. 接上 HA

    設定 → 裝置與服務 → 新增整合,搜尋 MQTT,填 192.168.1.20 / 1883 / homeassistant / 密碼。

    你會看到什麼:整合清單多出 MQTT 卡片。同時開著訂閱視窗的話,會立刻跑出一行 homeassistant/status online。

    接下來全程保持一個訂閱視窗開著,這是後面每一步的驗證管道:
    1. mosquitto_sub -h 192.168.1.20 -p 1883 -u homeassistant -P 密碼 -t '#' -v
    複製代碼

    ---

    接下來全程保持一個訂閱視窗開著

    第二步:做出一個 HA 可以「控制」的開關

    唯讀的感測器只有 state_topic(HA 讀)。可控的實體要多一個 command_topic(HA 寫)。

    整個資料流是這樣:


    • 你在 HA 按下開關 → HA 往 command_topic 發 ON
    • 你的裝置訂閱了 command_topic,收到 ON → 真的去把電器打開
    • 裝置做完之後,往 state_topic 回報 ON
    • HA 收到 state_topic 的 ON,才把介面上的開關畫成「開」


    ⚠ 第四步不是多餘的。HA 不會因為「我發了指令」就假設成功。裝置沒回報,介面上的開關會彈回原來的位置 —— 這是正確的設計,代表你看到的狀態一定是裝置真的回報過的。

    發一個 switch 出來(在另一個視窗執行):
    1. mosquitto_pub -h 192.168.1.20 -p 1883 -u homeassistant -P 密碼   -t 'homeassistant/switch/bath_fan/config' -r   -m '{
    2.   "name": null,
    3.   "unique_id": "bath_fan_001",
    4.   "state_topic": "home/bath/fan/state",
    5.   "command_topic": "home/bath/fan/set",
    6.   "payload_on": "ON",
    7.   "payload_off": "OFF",
    8.   "state_on": "ON",
    9.   "state_off": "OFF",
    10.   "optimistic": false,
    11.   "device": {
    12.     "identifiers": ["bath_controller"],
    13.     "name": "浴室抽風機",
    14.     "manufacturer": "DIY",
    15.     "model": "esp8266-relay-v1"
    16.   },
    17.   "origin": {"name": "manual-test", "sw": "1.0"}
    18. }'
    複製代碼

    三個新欄位


    • name 寫 null —— 代表「這個實體直接沿用裝置的名字」。不寫 null 而寫「開關」的話,實體會變成「浴室抽風機 開關」,一台裝置只有一個主要實體時很囉嗦
    • payload_on / payload_off —— HA 發出去的指令內容。state_on / state_off 則是 HA 讀狀態時要認什麼字。兩組預設都是 ON/OFF,裝置回報的是 1/0 或 true/false 的話要在這裡寫清楚
    • optimistic: false —— 「不要樂觀」。設成 true 的話 HA 發完指令就自己把介面切過去,不等裝置回報。有 state_topic 的時候一律設 false,不然你會看到一個顯示「開」但其實沒開的開關


    你會看到什麼

    設定 → 裝置與服務 → MQTT 底下多一台「浴室抽風機」,裡面一個開關實體,狀態是「不可用」或空白 —— 因為還沒有人往 state_topic 回報過。

    手動扮演裝置。開第三個視窗,訂閱指令主題:
    1. mosquitto_sub -h 192.168.1.20 -p 1883 -u homeassistant -P 密碼   -t 'home/bath/fan/set' -v
    複製代碼

    現在到 HA 按那個開關。

    你會看到什麼
    1. home/bath/fan/set ON
    複製代碼

    而 HA 介面上的開關會彈回「關」。這是對的 —— 沒有人回報狀態。

    手動回報一次:
    1. mosquitto_pub -h 192.168.1.20 -p 1883 -u homeassistant -P 密碼   -t 'home/bath/fan/state' -m 'ON'
    複製代碼

    你會看到什麼:HA 的開關立刻變成「開」並停在那裡。

    這個往返你親手跑過一次,後面寫裝置端程式時就不會搞不清楚誰該發什麼。

    ---

    第三步:讓 HA 知道裝置掛了(availability + 遺囑)

    這是最常被略過、但最值得做的一項。

    沒有它的時候:裝置斷電了,HA 裡的溫度停在最後一個數字不動。你看到「26.4 度」,以為一切正常,其實那是三天前的數字。自動化照樣會拿它去做判斷。

    3-1. 在設定裡加 availability
    1. mosquitto_pub -h 192.168.1.20 -p 1883 -u homeassistant -P 密碼   -t 'homeassistant/switch/bath_fan/config' -r   -m '{
    2.   "name": null,
    3.   "unique_id": "bath_fan_001",
    4.   "state_topic": "home/bath/fan/state",
    5.   "command_topic": "home/bath/fan/set",
    6.   "payload_on": "ON",
    7.   "payload_off": "OFF",
    8.   "optimistic": false,
    9.   "availability_topic": "home/bath/fan/status",
    10.   "payload_available": "online",
    11.   "payload_not_available": "offline",
    12.   "device": {
    13.     "identifiers": ["bath_controller"],
    14.     "name": "浴室抽風機",
    15.     "manufacturer": "DIY",
    16.     "model": "esp8266-relay-v1"
    17.   },
    18.   "origin": {"name": "manual-test", "sw": "1.0"}
    19. }'
    複製代碼

    payload_available 和 payload_not_available 的預設值就是 online 和 offline,寫出來只是讓人看設定檔時不用去查。

    3-2. 自己發一次 online
    1. mosquitto_pub -h 192.168.1.20 -p 1883 -u homeassistant -P 密碼   -t 'home/bath/fan/status' -m 'online' -r
    複製代碼

    你會看到什麼:HA 裡那個開關從「不可用」恢復成可以操作。

    3-3. 發一次 offline 看看
    1. mosquitto_pub -h 192.168.1.20 -p 1883 -u homeassistant -P 密碼   -t 'home/bath/fan/status' -m 'offline' -r
    複製代碼

    以下還有約 80% 的內容
    登入後即可閱讀完整教學

    登入繼續閱讀使用 Google 登入
    您需要登入後纔可以回帖 登入 | 立即註冊

    本版積分規則

    延伸閱讀

    加入惟家 LINE 群 QR Code加入惟家 LINE 群

    Archiver|手機版|惟家的智能論壇

    GMT+8, 2026-11-10 00:36 , Processed in 0.145340 second(s), 25 queries .

    快速回覆 返回頂部 返回列表