Když NSPanel po aktualizaci nenaběhne: rozbor jednoho výpadku
Tenhle článek je jiný než ostatní na tomhle webu. Není to návod „udělejte tohle a bude to fungovat", ale rozbor jedné konkrétní závady — od černého displeje až k funkčnímu panelu, včetně všech slepých uliček, do kterých jsem cestou zabočil.
Píšu ho proto, že samotné řešení je nakonec banální. Cenné je to, jak se k němu člověk dostane — a hlavně jak pozná, že hypotéza, na které si zakládá, je špatná. Techniky z téhle diagnostiky se dají použít na jakékoli ESP32 zařízení s ESPHome, ne jen na NSPanel.
Panel je černý, není na Wi-Fi a přeflashování nepomohlo? S velkou pravděpodobností je zamčený v safe mode a factory.bin to nespraví - počítadlo neúspěšných startů leží v NVS oddílu, kterého se factory image vůbec nedotkne.
esptool --port /dev/cu.usbserial-0001 erase-flash
esptool --port /dev/cu.usbserial-0001 --baud 460800 write-flash 0x0 vas-firmware.factory.bin
Celý příkaz s vysvětlením je v sekci Oprava, prevence v Prevenci. Zbytek článku je o tom, jak se k té diagnóze dojde.
Předpokládám, že vám nejsou cizí sériová linka, esptool a čtení logů. Pokud chcete NSPanel jen rozchodit, začněte článkem Sonoff NSPanel v Home Assistantu: eWeLink, ESPHome a NSPanel Easy. Praktické návody bez téhle omáčky najdete v jeho sekci Řešení problémů.
Prostředí
- Sonoff NSPanel EU, ESP32-D0WD-V3 rev 3.1, 4 MB flash
- NSPanel_HA_Blueprint verze
2026041, tažený z větvemainsrefresh: 300s - ESPHome 2026.7.2, ESP-IDF v5.5.5
- V konfiguraci zapnutý
bluetooth_proxy:— půl roku bez potíží - Skrytá SSID na oddělené IoT síti

Příznaky
Panel nejdřív po aktualizaci zůstal viset na modré obrazovce s nápisem Initializing a prázdnými poli. Restart to jen zopakoval. Po odpojení od 230 V už nenaskočilo vůbec nic — černý displej, žádná odezva, panel se neobjevil na Wi-Fi.
Přeflashování firmwaru přes sériovou linku nepomohlo.
Časová osa
Tohle jsem zrekonstruoval až nakonec, z historie Home Assistanta. Uvádím to na začátku, ale během diagnostiky jsem to nevěděl:
| Čas | Co se stalo |
|---|---|
| 21. 7., 18:54 | Poslední úspěšný start, panel běží |
| 23. 7., 19:06 | Panel se odmlčel a už nenaběhl |
| 25. 7., 10:45 | Začátek diagnostiky, první sériový log |
| 25. 7., 13:01 | První použitelný log - z pořádného napájení |
| 25. 7., 13:20 | Smazání flash a přehrání firmwaru |
| 25. 7., 13:31 | Panel opět plně funkční |
Výpadek trval 42 hodin, samotná diagnostika necelé tři.
Slepá ulička č. 1: slabé napájení z pinu 3V3
První sériový log vypadal takhle (zkráceno):
[C][safe_mode:189]: Unsuccessful boot attempts: 2
[I][app:060]: Running through setup()
[C][wifi:649]: Starting
ets Jul 29 2019 12:21:46
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
Panel se restartoval každou sekundu a vždycky přesně po wifi: Starting.
Co znamená rst:0x1 (POWERON_RESET) a rst:0xc (SW_CPU_RESET)
Tady je první přenositelná dovednost. Ten řádek rst: je nejrychlejší způsob, jak rozdělit svět na dvě poloviny:
| Kód | Význam | Kde hledat |
|---|---|---|
rst:0x1 (POWERON_RESET) | Čip ztratil napájení, nebo byl resetován pinem EN | Napájení, hardware |
rst:0xc (SW_CPU_RESET) | Software spadl a restartoval se | Firmware, konfigurace |
rst:0x8 (TG1WDT_SYS_RESET) | Zasáhl watchdog — něco se zaseklo | Blokující kód |
rst:0xf (RTCWDT_BROWNOUT_RESET) | Detektor podpětí | Napájení |
POWERON_RESET v cyklu, vždy v okamžiku startu Wi-Fi, tedy ve chvíli největšího odběru — to je učebnicový příznak slabého zdroje. Uzavřel jsem to jako problém s napájením.
A byla to slepá ulička. Ne proto, že bych ten log četl špatně, ale proto, že měřicí sestava byla vadná.
Proč byl ten log bezcenný
Panel byl v tu chvíli napájený z pinu 3V3 na USB-TTL převodníku. Ten pin jde z drobného stabilizátoru na desce převodníku, který dá 50–100 mA. Na samotné flashování to stačí a právě to je zrádné - firmware se nahraje bez problémů. Jenže při startu si Wi-Fi řekne o násobky a napájení se složí. Ten log tedy věrně dokumentoval limity mého adaptéru, ne závadu panelu.
Než začnete věřit datům, ověřte sestavu, na které jste je naměřil. Stačí přepojit napájení z 3V3 na pin +5V téhož převodníku - ten jde prakticky z USB VBUS a panel si ho převede vlastním stabilizátorem. Žádný externí zdroj k tomu není potřeba.
Zajímavý detail: pád nastal i v safe mode, kde neběží nic z Blueprintu. To jsem tehdy bral jako důkaz hardwarové příčiny — a u téhle vadné sestavy to i platilo.
Slepá ulička č. 2: vyčerpaná paměť
Druhá hypotéza stála na dokumentaci samotného Blueprintu, která popisuje příznak doslova:
During Startup: If your device runs out of memory at startup, it may not load the firmware, resulting in a black screen and an unresponsive device.
- Be cautious when adding memory-intensive components like
bluetooth_proxy.
Černý displej, nereagující zařízení. Přesná shoda. A bluetooth_proxy jsem v konfiguraci měl.
Měření místo dohadů: kolik paměti sebere bluetooth_proxy
Místo spekulací jsem zkompiloval tutéž konfiguraci dvakrát, jediný rozdíl byl bluetooth_proxy:. ESPHome na konci kompilace vypíše skutečné využití, a stačí k tomu Download firmware binary — do panelu se nic nenahrává.
s bluetooth_proxy | bez | rozdíl | |
|---|---|---|---|
| Flash | 1 529 391 B (83,3 %) | 1 110 539 B (60,5 %) | −409 kB |
| DRAM využito | 69 352 B | 57 384 B | −12 kB |
| DRAM celkový pool | 124 580 B | 180 736 B | −56 kB |
| DRAM volno | 55 228 B | 123 352 B | +66 kB |
Tady je něco, co jsem nečekal. Celkový pool DRAM není v obou případech stejný. BLE controller si svoji paměť vyřízne z poolu už při linkování — není to tedy jen otázka spotřeby. Volná vnitřní DRAM padá ze 123 kB na 55 kB, tedy na méně než polovinu.
A PSRAM to nezachrání, i když jí panel má 2 MB a využívá z ní jednotky procent. Pufry pro Wi-Fi musí být DMA-schopné a na ESP32 v PSRAM být nemohou. Souběh Wi-Fi a Bluetooth je proto na interní DRAM nejcitlivější místo celého systému.
sram1_as_iram a +40 kB IRAMCelý tenhle článek je o tom, že panel běžel bez rezervy. Tak co s tím vlastně jde udělat? Jednu věc dostanete zdarma a ESPHome si o ni na tomhle panelu samo řekne - v logu je řádek, kterého jsem si během diagnostiky nevšímal:
[W][app:198]: Bootloader supports SRAM1 as IRAM (+40KB). Set sram1_as_iram: true under esp32 > framework > advanced
Nabízí se tu paměť, kterou si rezervoval bootloader jako DRAM a která se dá místo toho dát aplikaci jako IRAM: +40 kB. Zapíná se takhle:
esp32:
framework:
advanced:
sram1_as_iram: true
Volnou heap ani DRAM to nic nestojí, protože ta paměť v heapu nikdy nebyla. Vedle toho se rozšíří okno flash cache pro XIP, takže je méně cache miss a všechen kód běžící z flash - Wi-Fi, BLE i API server - jede lépe. Pomáhá to i proti chybě „IRAM overflow" při kompilaci. Jestli tuhle druhou věc vůbec potřebujete, si ověřte v souhrnu na konci buildu - najděte si v něm řádek IRAM. Tenhle panel hlásí IRAM 84 263 B (48,98 %), zbývá 87 769 B z 172 032 B, tedy do stropu ještě půlku místa, takže z celého přínosu mu zůstává jen to širší okno flash cache. Platí to jen pro původní ESP32 a jen s frameworkem ESP-IDF; tenhle panel (ESP32-D0WD-V3, esp-idf) obojí splňuje a výchozí hodnota je false.
Ať je v tom pořádek: tenhle výpadek by to nevyřešilo. Rozdává se tu IRAM, kdežto tíseň, kterou jsem naměřil výš, byla ve DRAM. Těch 55 kB volné DRAM by zůstalo 55 kB.
A hlavně to nezapínejte naslepo. Vyžaduje to bootloader z ESP-IDF v5.1 nebo novějšího a OTA aktualizace bootloader nemění - ten přepíše jedině flash přes USB nebo sériovou linku. Se starým bootloaderem zařízení vůbec nenaběhne a dostane ho zpátky jen sériové přeflashování. Po tom, co je v tomhle článku, asi tušíte, jak nerad bych panel zase sundával ze zdi.
Pravidlo, které se ověří samo, je proto tohle: zapněte to jen tehdy, když ten řádek [W][app:198] máte ve svém vlastním logu. ESPHome ho vypisuje právě tehdy, když detekuje, že bootloader to podporuje. Když ho tam nemáte, nechte to být.
Dodatek: OTA rollback to potvrdil
Po opravě jsem bluetooth_proxy zkusil vrátit zpátky a nahrát přes OTA. V logu pak stálo:
[W][safe_mode:094]: OTA rollback detected! Rolled back from partition 'app1'
[W][safe_mode:094]: The device reset before the boot was marked successful
Build s Bluetooth se nahrál, nenaběhl, a bootloader se sám vrátil na předchozí firmware. Panel jsem pak našel v pořádku — ale běžel na starém buildu bez proxy, ne na tom novém.
Tohle je zpětně nejsilnější důkaz pro paměťovou hypotézu, jaký mám. A zároveň čtvrtá záchranná síť, o které jsem během diagnostiky nevěděl: ESP-IDF nově nahraný firmware sleduje, a když se resetuje dřív, než ho ESPHome označí za funkční, vrátí předchozí verzi. Proto se OTA aktualizací nedá panel zabít tak snadno jako sériovým flashem.
Pokud po OTA vidíte OTA rollback detected, vaše nová verze neběží. Zkontrolujte si compiled on v logu — když je starší než vaše poslední kompilace, díváte se na starý firmware a nová verze se nikdy nechytila. Druhý test: v dump_config musí být [C][esp32_ble_tracker:...] a [C][bluetooth_proxy:...]. Když tam nejsou, proxy neběží.
Na druhý pokus, tentokrát už s safe_mode: storage: rtc v konfiguraci, se ten build udržel dost dlouho, aby se stihl přihlásit — a ESPHome zachytil pády:
*** CRASH DETECTED ON PREVIOUS BOOT ***
Reason: Fault - Unknown
Crashed core: 1
PC: 0x4011A490 ← první pád
PC: 0x4000BFF0 ← druhý pád, tato adresa leží v ROM
Dvě po sobě jdoucí spuštění spadla na jiné adrese, přičemž druhá je uvnitř ROM čipu. A zároveň oba pády procházejí stejnou funkcí — 0x4011A4AB z druhého backtrace leží 27 bajtů za místem prvního pádu.
To je diagnosticky cenné samo o sobě: deterministická chyba v kódu padá pokaždé na stejné adrese. Různá místa pádu, z toho jedno v ROM, ukazují spíš na poškozenou paměť nebo selhávající alokaci, která si najde náhodnou oběť. Sedí to i s prvním pádem, kde LBEG/LEND mířily do oblasti paměťových rutin v ROM.
Chtěl jsem ty adresy přeložit na názvy funkcí, ale nešlo to — a ta příčina je poučná. Kompiloval jsem přes remote build, takže lokálně nebyl žádný ESP-IDF toolchain (CMAKE_ADDR2LINE not found) a firmware.elf se navíc přepsal hned dalším buildem. Když jsem se pokusil adresy přeložit proti tomu ELF, který na disku zbyl, vyšel mi nesouvisející mix funkcí z NVS, lwipu a API — protože to byl ELF jiného buildu. Poznal jsem to podle toho, že v jeho symbolech nebyl ani jeden výskyt bluetooth_proxy.
A teď to, co jsem se naučil až z dalšího crash logu z tohohle panelu — protože chybějící bluetooth_proxy v symbolech je vodítko, které se dá mít i lepší.
ESPHome dekódované názvy funkcí vypíše i ve chvíli, kdy zároveň varuje, že dekódovat neumí. V tom logu stálo:
WARNING Crash trace decoding unavailable: ESP-IDF toolchain not available:
CMAKE_ADDR2LINE not found in CMake output.
a hned pod tím byly hezky čitelné názvy funkcí. To jim dává falešnou autoritu a je snadné vzít je za hotovou věc.
Silnější test je proto tenhle: porovnejte dekódovaný symbol s tím, co váš build vůbec obsahuje. Rámec v tom logu nesl UserServiceBase<StringRef, StringRef, bool>, tedy API akci se třemi argumenty typu (string, string, bool). Připnutý balíček ale definuje sedm API akcí a ani jedna tuhle signaturu nemá — nejblíž je components_visibility s (string, string[], bool), kde je prostřední argument pole, tedy v C++ std::vector, ne StringRef. Berte to prosím jako indicii, ne důkaz: jistotu, jak přesně ESPHome string[] v té šabloně reprezentuje, nemám.
A třetí vodítko je časové: pád byl označený ON PREVIOUS BOOT, ale firmware se kompiloval dvě minuty před tím logem. Mohl tedy patřit staršímu buildu, než je ELF, proti kterému se dekódovalo.
Lekce: backtrace má cenu jen s ELF přesně toho buildu, který spadl. Chcete-li ho dekódovat, kompilujte lokálně a ten ELF si odložte, ještě než pád zreprodukujete.
Takže co je a co není prokázané: build s bluetooth_proxy na tomhle panelu opakovaně nenaběhne — to je doloženo rollbackem i dvěma zachycenými pády. Že právě tohle shodilo panel 23. července, prokázané není a zůstává hypotézou.
Potvrzení z druhé strany: jak paměť u bootu řeší NSPanel Easy
Nezávislé potvrzení téhle diagnózy přišlo mezitím ze strany samotného projektu. Vývoj NSPanel_HA_Blueprintu se přesunul do NSPanel Easy (postup přechodu mám v článku Z NSPanel_HA_Blueprint na NSPanel Easy) a ten paměť u bootu adresuje i na své straně. V dokumentaci to v sekci Reducing Registered API Actions stojí takhle:
Each API action registered by ESPHome consumes heap memory at boot. On memory-constrained configurations — such as those running Bluetooth Proxy — this can cause boot instability or crashes.
Akce upload_tft a wake_up jsou proto defaultně vypnuté a zapínají se substitucemi include_action_upload_tft: true a include_action_wake_up: true. Neberte to jako popření toho, co jsem naměřil — je to potvrzení z druhé strany, a od lidí, kteří ten firmware píšou. Hlavní zjištění to ale nezmenšuje: BLE controller si svých 56 kB vyřízne z poolu už při linkování, takže úspora na registrovaných API akcích je proti tomu řádově menší (dokumentace ji nečísluje a sám jsem ji neměřil). Doporučení dát Bluetooth proxy na samostatnou ESP32, která má celou paměť pro sebe, platí dál.
Proč je to jen poloviční odpověď
Odstranil jsem bluetooth_proxy, naflashoval, zapnul — a panel pořád nenaběhl. Ta paměťová tíseň byla reálná a změřená, ale nebyla to ta věc, která panel držela mrtvý.
Změřený faktor a prokázaná příčina jsou dvě různé věci. Že jsem našel něco, co je objektivně na hraně, neznamenalo, že jsem našel viníka.
Konečně použitelný log
Teprve s napájením z pinu +5V a se sériovkou zapojenou jen na TX, RX a GND jsem dostal log, který za něco stál:
[C][safe_mode:189]: Unsuccessful boot attempts: 10
[E][safe_mode:201]: Boot loop detected
[I][app:060]: Running through setup()
[C][wifi:649]: Starting
[D][wifi:1325]: Starting scan
[C][component:209]: Setup wifi took 98ms
[I][app:117]: setup() finished successfully!
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x400e111b PS : 0x00060530 A0 : 0x8018ac74 A1 : 0x3ffb8520
...
EXCVADDR: 0x00000000 LBEG : 0x4000c349 LEND : 0x4000c36b
...
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
Všechno se změnilo. rst:0xc (SW_CPU_RESET) místo POWERON_RESET — je to pád softwaru, ne napájení.
Co znamená Guru Meditation LoadProhibited a EXCVADDR: 0x00000000
Druhá přenositelná dovednost. Ty dva řádky stačí:
LoadProhibited/EXCCAUSE: 0x1c— program se pokusil číst z adresy, ze které čtení není dovolenoEXCVADDR: 0x00000000— a ta adresa byla nula
Dohromady to znamená dereferenci null pointeru. Někde v kódu je ukazatel, o kterém se předpokládá, že je platný, a on není.
Užitečné jsou i další registry: A8: 0x00000000 ukazuje, který registr tu nulu nesl, a PC: 0x400e111b je adresa instrukce, na které to spadlo.
Co to zúžilo
Pád nastal v safe mode, kde ESPHome spustí jen logger, wifi, ota a safe_mode. Nic z Blueprintu, žádný displej, žádné skripty. Takže:
- není to chyba konfigurace panelu
- není to chybějící TFT firmware
- je to pád ve vlastním kódu ESPHome
Slepá ulička č. 3: verze ESPHome
Pád po Starting scan a čerstvá aktualizace ESPHome — nasnadě byla regrese. Tuhle hypotézu jsem se rozhodl ověřit ve zdrojácích, ne odhadem.
Mapování logu na zdrojový kód
Třetí přenositelná dovednost, a možná nejužitečnější. Všimněte si čísel v hranatých závorkách:
[C][wifi:649]: Starting
[D][wifi:1325]: Starting scan
To nejsou náhodná čísla — je to řádek ve zdrojovém souboru, který ten log vypsal. Stáhnete si zdrojáky přesně své verze a podíváte se:
gh api "repos/esphome/esphome/contents/esphome/components/wifi/wifi_component.cpp?ref=2026.7.2" \
--jq '.content' | base64 -d > wifi_component.cpp
sed -n '649p;1325p' wifi_component.cpp
A vyjde:
649: ESP_LOGCONFIG(TAG, "Starting");
1325: ESP_LOGD(TAG, "Starting scan");
Sedí to. Tím mám potvrzeno, že se dívám do správné verze i do správného souboru — což není samozřejmost, protože tag wifi používá i wifi_component_esp_idf.cpp. Ten má ale jen 1288 řádků, takže řádek 1325 v něm být nemůže.
Časování zabilo hypotézu
Podezíral jsem řazení výsledků scanu, které v tom souboru začíná hned pod řádkem 1325. Ale podívejte se na časové značky:
[13:01:51][D][wifi:1325]: Starting scan
[13:01:51][C][component:209]: Setup wifi took 98ms
[13:01:51][I][app:117]: setup() finished successfully!
[13:01:51]Guru Meditation Error
Všechno ve stejné sekundě. A v logu chybí Found networks: i No networks found. Scan přitom trvá běžně dvě sekundy — takže se nestihl dokončit a k obsluze jeho výsledků se to vůbec nedostalo.
Časové značky v logu jsou důkaz. Když hypotéza tvrdí, že se něco stalo ve funkci, která se ještě nespustila, hypotéza padá — bez ohledu na to, jak dobře znělo její vysvětlení.
Srovnání verzí
Zbývalo ověřit, jestli se ta část kódu vůbec měnila:
diff -u 2026.6.5_wifi_component.cpp 2026.7.0_wifi_component.cpp | grep -c "^[+-]"
# 34
diff -u 2026.7.0_wifi_component.cpp 2026.7.2_wifi_component.cpp | grep -c "^[+-]"
# 0
Wi-Fi komponenta je bajtově identická ve verzích 2026.7.0, 7.1 i 7.2. Uvnitř řady 7.x tedy rozdílem být nemůže. A celý přechod z 6.5 na 7.0 je 34 řádků, ve kterých není žádná nechráněná dereference — nová podmínka pro roaming, přejmenování USE_RP2040 na USE_RP2, potlačení rebootu při provisioningu (a to je hlídané na != nullptr) a změna v ukládání fast_connect preference.
Zdrojáky hypotézu nepotvrdily. To je legitimní výsledek, i když nepříjemný — vyloučil jsem podezřelého, ne našel viníka.
Past, ze které nebylo cesty: tři zámky safe mode
Tady je jádro celé věci. Zpětně nebyla nejdůležitější otázka „co panel shodilo", ale „proč se z toho nedostal". Jednorázový pád se změnil ve 42hodinový výpadek, protože do sebe zapadly tři zámky.
Zámek 1: počítadlo doletělo na deset za patnáct sekund
ESPHome má ochranu proti boot loopu: po deseti neúspěšných startech přepne do safe mode. Jenže restarty šly po sobě v odstupu 1,5 sekundy, takže deset pokusů bylo otázkou chvilky. Než jsem si vůbec všiml, že je něco špatně, panel byl zamčený.
Zámek 2: počítadlo je ve flash a přežije odpojení od proudu
Výchozí nastavení safe_mode na ESP32 je storage: flash. Dokumentace to říká na rovinu:
Flash storage: persists through power loss
Takže každé vypnutí a zapnutí, kterým jsem se snažil panel oživit, bylo k ničemu. Počítadlo zůstávalo na desítce a panel šel rovnou do safe mode — kde se displej nespouští, odtud ta černá obrazovka.
Zámek 3: factory.bin nepřepíše NVS, smaže ji jen erase-flash
A tenhle je nejzákeřnější. Podívejte se na tabulku oddílů z bootovacího logu:
0 otadata OTA data 01 00 00009000 00002000
1 phy_init RF data 01 01 0000b000 00001000
2 app0 OTA app 00 10 00010000 001c0000
3 app1 OTA app 00 11 001d0000 001c0000
4 nvs WiFi data 01 02 00390000 00070000
Počítadlo je v oddílu nvs na adrese 0x390000. Factory image se zapisuje od 0x0 a pokrývá bootloader, tabulku oddílů a app0. NVS se ho vůbec netkne.
Proto jsem mohl panel přeflashovat, kolikrát jsem chtěl. Počítadlo tam sedělo dál, panel dál naskakoval do safe mode — a safe mode dál padal na tom null pointeru.
Kterýkoli z těch tří zámků samostatně by se dal obejít. Všechny tři dohromady znamenaly, že nic, co jsem zkoušel, fungovat nemohlo.
Oprava
Když je diagnóza hotová, oprava je na tři příkazy:
# volitelne: precist verzi predchoziho firmwaru z druheho OTA oddilu
esptool --port /dev/cu.usbserial-0001 read-flash 0x1d0000 0x200 app1.bin
# smazat CELY flash vcetne NVS - tohle je ten podstatny krok
esptool --port /dev/cu.usbserial-0001 erase-flash
esptool --port /dev/cu.usbserial-0001 --baud 460800 \
write-flash 0x0 nspanel01-firmware.factory.bin
Wi-Fi údaje jsou zakompilované ve firmwaru, takže smazáním NVS o nic nepřijdete.
A první start po tom:
[C][safe_mode:189]: Unsuccessful boot attempts: 0
[I][app:060]: Running through setup()
...
[I][nspanel.core:189]: Blueprint progress: 100.0%
[I][nspanel.boot:165]: Progress: Completed
[C][wifi:1259]: IP Address: 192.168.1.50
Počítadlo na nule, plný setup místo safe mode, Blueprint na sto procentech.
Prevence
Tři změny v konfiguraci, každá řeší jednu věc z tohohle příběhu:
Pozn.: tohle je konfigurace ve stavu, v jakém byla v době incidentu — tedy ještě s původním repozitářem Blackymas/NSPanel_HA_Blueprint. Aktuální doporučená podoba je v Kroku 2 hlavního návodu a přejít na ni jde obyčejnou OTA aktualizací, bez sundání panelu ze stěny.
# 1) Pocitadlo do RTC pameti - odpojeni od proudu ho vymaze
safe_mode:
storage: rtc
# 2) Skryta SSID: pripojit se rovnou, bez scanovani
wifi:
fast_connect: true
# 3) Pripnuta verze Blueprintu misto 'main' + refresh
packages:
remote_package:
url: https://github.com/Blackymas/NSPanel_HA_Blueprint
ref: 05ecefde2bac5db8bc96c02148058518d78a06fb
refresh: never
safe_mode: storage: rtc je z těch tří nejcennější. RTC paměť přežije softwarový reset, ale odpojení od proudu ji smaže. Rozdíl je zásadní:
storage: flash (výchozí) | storage: rtc | |
|---|---|---|
| Přechodný pád | počítadlo doleze na 10 a zamkne se natrvalo | každé vypnutí dá firmwaru čistý pokus |
| Trvalý pád | mrtvé, jen přes sériovku | pořád padá, ale nezamkne se |
Safe mode vám zůstane jako záchranná síť, ale panel se v něm už nikdy nezasekne tak, že by ho zachránila jen sériová linka.
Celou konfiguraci v kontextu instalace — dnes už s balíčkem NSPanel Easy, jiným url a jiným formátem ref — najdete v Kroku 2 hlavního návodu.
Připnutý ref znamená, že vám verze Blueprintu nepoteče pod rukama při každé rekompilaci. Přestanete tím dostávat opravy — to je záměr. Aktualizace budete dělat vědomě, zkontrolujete čísla paměti a teprve pak nahrajete.
Co jako záchrana nefunguje
Zvažoval jsem, jestli by nešlo namapovat záchrannou akci na fyzické tlačítko. Nešlo — a stojí za to vysvětlit proč.
Tlačítko je bez šance. V boot loopu se firmware k obsluze tlačítek nedostane a v safe mode neběží binary sensory z Blueprintu vůbec. Jakákoli záchrana ve firmwaru vyžaduje, aby firmware běžel; a on je právě to, co padá.
Komponenta factory_reset s resets_required vypadá jako přesná odpověď — pětkrát vypnout a zapnout a zařízení si smaže preference. Jenže když se člověk podívá do implementace:
static bool was_power_cycled() {
return esp_reset_reason() == ESP_RST_POWERON;
}
...
if (was_power_cycled()) { count++; ... }
else { this->save_(0); } // jakykoli JINY reset pocitadlo vynuluje
Počítá jen skutečná zapnutí. Reset po pádu je SW_CPU_RESET, který spadne do else a počítadlo vynuluje. V boot loopu to tedy vypadá takhle: zapnu → 1 → panel spadne → 0 → zapnu → 1 → spadne → 0. Na pětku se nedostanete nikdy.
Užitečná je ta komponenta na jinou situaci: zařízení normálně běží, ale je špatně nakonfigurované a nedosáhnete na něj po síti.
Home Assistant jako forenzní nástroj
Časovou osu na začátku článku jsem zrekonstruoval z HA přes REST API. Je to podceňovaný nástroj — a hlavně jím jde hypotézy vyvracet.
Kdy přesně zařízení odešlo vytáhnete z historie kterékoli jeho entity. Pozor na to, že bez end_time vrací endpoint jen jeden den:
curl -H "Authorization: Bearer $TOKEN" \
"$HA/api/history/period/$START?end_time=$END&filter_entity_id=sensor.nspanel01_temperature&minimal_response"
Tímhle jsem našel přesnou sekundu, ve které panel zmlkl.
Vyvrácení hypotézy o výpadku elektřiny bylo elegantnější. Kdyby šla elektrika, restartovala by se i ostatní zařízení. Stačilo se podívat na uptime jiné ESP32 ve stejné síti:
sensor.esp32_bluetooth_proxy_uptime = 407702 s ≈ 4,7 dne
Ta hodnota přesahuje celý incident, takže elektrika nešla. Jedno číslo, hypotéza vyřízená.
Podobně padla domněnka o restartu hostitele, na kterém běží HA — sensor.node_pve_last_boot ukazoval na datum čtyři měsíce staré.
A logbook ukázal, co se ve chvíli výpadku dělo doopravdy: restartoval se Home Assistant a vrátilo se z něj všechno kromě panelu.
Co jsem nezjistil
Poctivě: prvotní spouštěč se zjistit nepodařilo a už se nepodaří.
Panel na tom firmwaru dva dny normálně běžel, takže nabootovat umí. Něco ho 23. července v 19:06 shodilo, ale co, už nezjistím — všechny důkazy jsou přepsané:
app0jsem přeflashovalapp1, druhý OTA oddíl, byl prázdný (0xffffffff)- NVS jsem smazal, což bylo nutné k opravě
- ELF soubor pro dekódování backtrace přepsaly nové kompilace
sw_versionv registru zařízení HA se aktualizoval, jakmile se panel připojil
Zůstává tedy hypotéza: paměťová tíseň z bluetooth_proxy s 55 kB volné DRAM byla přesně ten druh rezervy, který jedna aktualizace spolkne. Prokázané to ale není a nechci to vydávat za víc, než to je.
Pád ESPHome v safe mode na null pointeru je věc sama pro sebe. V esphome/issues k tomu není žádné hlášení, takže buď je to vzácná kombinace, nebo tu cestu málokdo prošlape. Bez ELF souboru z původního buildu se ale nedá nahlásit tak, aby to bylo k něčemu.
Co si z toho vzít
Dvanáct věcí, které se dají použít jinde:
- Čtěte
rst:kód jako první. Rozdělí problém na napájení versus software rychleji než cokoli jiného. EXCVADDR: 0x00000000u Guru Meditation znamená dereferenci null pointeru.- Ověřte měřicí sestavu, než uvěříte datům. Napájení z
3V3pinu převodníku mi vyrobilo falešnou závadu. - Čísla v logu jsou řádky ve zdrojáku.
[D][wifi:1325]se dá dohledat ve své verzi ESPHome a přestanete hádat. - Časové značky vyvracejí hypotézy. Chybějící log ze scanu dokázal, že pád je jinde.
- Měřte, nehádejte. Dvě kompilace daly rozdíl 66 kB DRAM. Odhad by nedal nic.
- Rozlišujte pool a spotřebu. BLE ubere 56 kB z celkového poolu už při linkování, nejen ze spotřeby.
- Vědět, který oddíl váš flash nástroj přepisuje. Factory image nechává NVS na pokoji, a v NVS byl zámek.
- HA je forenzní nástroj. Uptime jiného zařízení vyvrátí teorii o výpadku elektřiny jedním číslem.
- Různá místa pádu znamenají paměť, ne chybu v kódu. Deterministická chyba padá pokaždé na stejné adrese. Když se fault PC mezi restarty mění, hledejte vyčerpanou nebo poškozenou paměť.
- Backtrace je bezcenný bez ELF přesně toho buildu, který spadl. Dekódování proti jinému buildu vyrobí věrohodně vypadající nesmysl - a zrádné je, že ESPHome ty dekódované názvy funkcí vypíše i tehdy, když zároveň hlásí, že dekódovat neumí (
Crash trace decoding unavailable ... CMAKE_ADDR2LINE not found), takže vypadají důvěryhodněji, než jsou. Tři vodítka na neshodu: v symbolech ELF hledejte komponentu, kterou ten build měl obsahovat; porovnejte dekódovaný symbol s tím, co váš build vůbec definuje (rámecUserServiceBase<StringRef, StringRef, bool>proti balíčku, kde žádná ze sedmi API akcí signaturu(string, string, bool)nemá); a u pádu označenéhoON PREVIOUS BOOTsi ověřte, že nepatří staršímu buildu, než je váš ELF. Podrobně to rozebírám ve Slepé uličce č. 2. - OTA je bezpečnější než sériový flash. ESP-IDF novou verzi sleduje a při pádu se vrátí na předchozí. Cenou je, že se pak koukáte na starý firmware a musíte si všimnout
OTA rollback detected.
A nakonec to nejméně technické: nechte si rezervu. Panel běžel na 55 kB volné paměti půl roku a fungoval. Chyba nebyla v tom, že by konfigurace byla špatná — chyba byla, že neměla rezervu, a jedna rutinní aktualizace ji spolkla.
Související články
- Sonoff NSPanel v Home Assistantu: eWeLink, ESPHome a NSPanel Easy — hlavní návod, hardware a pinout
- Z NSPanel_HA_Blueprint na NSPanel Easy — migrace krok za krokem, když panel běží na původním projektu
- ESPHome - Úvod a instalace
- Bluetooth Proxy v Home Assistant
Zdroje
- Safe Mode - ESPHome — chování počítadla a volba
storage - NSPanel_HA_Blueprint - Customization — správa paměti a varování o
bluetooth_proxy - NSPanel Easy - Installation — snižování počtu registrovaných API akcí kvůli paměti u bootu
- Issue #2669 — odstranění Bluetooth Proxy add-onu
- NSPanel teardown na blakadder.com — rozbor hardwaru
Pomohl vám tenhle návod?
Návody tu píšu ve volném čase a udržuju je aktuální. Když vám některý ušetřil čas, můžete přispět.
Jednorázově, kartou nebo Apple Pay. Částku lze na další stránce změnit.
Nechcete posílat peníze? Kupujte podle návodů přes moje odkazy na produkty. Cena je pro vás stejná a pomůže to taky.