Klient MQTT w ESPHome może wysłać wiadomość shutdown_message, gdy urządzenie się restartuje, wyłącza albo przechodzi w głęboki sen (deep_sleep). Każdy, kto subskrybuje dany temat, wie wtedy, że urządzenie zniknęło celowo. W praktyce ta wiadomość często w ogóle nie docierała. Poprawka autorstwa bdraco, scalona z gałęzią rozwojową 25 października 2026, każe klientowi czekać, aż broker potwierdzi jej odbiór. Powinna trafić do ESPHome 2026.11 i nie wymaga żadnych zmian w konfiguracji, takiej jak ta z opisu zmiany:
mqtt:
broker: 192.168.1.10
shutdown_message:
topic: livingroom/status
payload: offline
Dlaczego wiadomość ginęła
Stary kod wysyłał wiadomość i od razu zrywał połączenie, a między jednym a drugim było tylko wywołanie yield(). Klient MQTT nie miał etapu zamykania, więc restart następował po kilku mikrosekundach i pakiet często nie zdążył opuścić urządzenia. Przycisk i przełącznik shutdown w ogóle nie uruchamiały etapu zamykania.
Pomiary bdraco pokazują skalę problemu. Na obecnym kodzie z gałęzi rozwojowej wiadomość dotarła przy 0 z 10 restartów ESP32, 3 z 10 restartów ESP8266 i 0 z 3 przejść ESP32 w głęboki sen. Z poprawką te same próby dały 10 na 10 restartów na obu układach i 3 na 3 przejścia w głęboki sen.
Czemu nie wystarczy chwilę poczekać
Pierwsza wersja poprawki wstrzymywała rozłączenie na stałe 100 ms. Wiadomość przechodziła wtedy tylko przy 3 z 10 restartów ESP32. Zapis ruchu sieciowego pokazał, że przy nieudanych próbach ESP32 przez około 465 ms po poleceniu restartu nie wysyłał niczego, bo Wi-Fi się przycinało, a TCP ponawiał transmisję. Okno 900 ms zadziałało 8 razy na 8, ale wydłużałoby tak każdy restart.
Co się zmieniło
Wiadomość o wyłączeniu idzie teraz z ustawionym dla niej poziomem QoS, ale nie niższym niż 1, więc broker musi potwierdzić odbiór. Rozłączenie przeniesiono do etapu zamykania komponentu, który czeka na to potwierdzenie. Zwykle trwa to kilka milisekund. Przy słabym łączu czas oczekiwania ogranicza limit z rdzenia ESPHome: 1 sekunda przy restarcie i 5 sekund przed głębokim snem.
Nowa funkcja App.safe_shutdown() uruchamia po kolei procedury wyłączania, zamykanie z limitem czasu i procedury odcięcia zasilania. Korzystają z niej teraz safe_reboot(), deep_sleep oraz przycisk i przełącznik shutdown, więc platformy wyłączania też porządnie zamykają komponenty, zanim układ zaśnie. Akcja mqtt.disable nadal rozłącza od razu.
Zmiana obejmuje klienta MQTT z ESP-IDF i bibliotekę AsyncMqttClient, której ESPHome używa na ESP8266 i układach z LibreTiny. Kosztuje 8 bajtów RAM na ESP-IDF i LibreTiny oraz 4 bajty na ESP8266. Jeśli Home Assistant albo inny subskrybent oznacza urządzenia jako niedostępne na podstawie tego tematu, stan po zaplanowanym restarcie lub przejściu w głęboki sen powinien być teraz zgłaszany pewnie, a nie zależeć od szczęścia.