Urządzenia ESPHome zwykle współpracują z Home Assistantem, ale nie jest on do niczego niezbędny. Na samym urządzeniu może działać strona WWW, obsługa zapytań HTTP ze skryptów i własny punkt dostępu uruchamiany po utracie połączenia z siecią Wi-Fi. Przydaje się to przy przekaźniku w warsztacie, czujniku na działce albo płytce testowej, która ma działać, zanim w domu pojawi się jakikolwiek serwer.

Poniżej znajdziesz konfigurację takiego urządzenia z trzema komponentami ESPHome: web_server, captive_portal i zapasowym punktem dostępu Wi-Fi. Opisane są też ustawienia bezpieczeństwa, które mają znaczenie, gdy między urządzeniem a siecią nie ma żadnej innej warstwy ochrony. Nazwy opcji i wartości domyślne pochodzą z dokumentacji ESPHome dla wydania 2026.10.

Co otrzymujesz

  • Stronę WWW pod adresem IP urządzenia albo pod nazwą <node_name>.local/ (z ukośnikiem na końcu) dzięki mDNS. Na stronie widać wszystkie encje, można je przełączać, śledzić dziennik na żywo, a po kliknięciu czujnika pojawia się mały wykres.
  • Interfejs REST na tym samym porcie: w odpowiedzi na żądanie GET na adres /<domain>/<entity_name> przychodzi stan w formacie JSON, a żądaniem POST na /<domain>/<entity_name>/<action> można ten stan zmienić.
  • Strumień zdarzeń pod /events (Server-Sent Events) ze zdarzeniami state, log i ping. Ten sam strumień jest używany przez stronę WWW.
  • Zapasowy punkt dostępu: jeśli nie da się połączyć z routerem, na urządzeniu uruchamia się własna sieć Wi-Fi, a w portalu pod adresem http://192.168.4.1/ można wpisać nowe dane sieci albo wgrać oprogramowanie.

Według dokumentacji serwer WWW służy do podglądu i zmiany stanów, a nie do edycji konfiguracji. Każda zmiana w pliku YAML nadal oznacza kompilację i wgranie nowego oprogramowania.

Konfiguracja

Przykład dotyczy ESP32 z jednym wyjściem przekaźnikowym i czujnikiem siły sygnału Wi-Fi. Zamiast GPIO26 wpisz wolny pin na swojej płytce, a przekaźnik podłącz przez gotowy moduł przekaźnika, nie bezpośrednio do pinu.

esphome:
  name: workshop-relay
  friendly_name: Workshop Relay

esp32:
  variant: esp32

logger:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "Workshop-Relay-Fallback"
    password: !secret workshop_relay__ap_password

captive_portal:

web_server:
  port: 80
  version: 3
  local: true
  ota: false
  auth:
    username: admin
    password: !secret workshop_relay__web_password
    type: digest

ota:
  - platform: esphome
    encryption:
      key: !secret workshop_relay__ota_esphome_key

switch:
  - platform: gpio
    pin: GPIO26
    name: "Relay"

sensor:
  - platform: wifi_signal
    name: "WiFi Signal"
    update_interval: 60s

W pliku secrets.yaml trzymasz dane sieci Wi-Fi, hasło do punktu dostępu, hasło do strony WWW i klucz do aktualizacji. Zwróć uwagę, czego brakuje: nie ma bloku api:, bo z natywnego API nikt nie będzie korzystać.

Do czego służy każda opcja

version: 3 oznacza najnowszą wersję strony. Domyślna jest wersja 2. Wersja 1 jest przestarzała i według dokumentacji zniknie w ESPHome 2027.1.0.

Przy local: true skrypty JavaScript i arkusze CSS strony są wbudowane w oprogramowanie. Bez tej opcji są pobierane z oi.esphome.io, więc w sieci bez dostępu do internetu strona by się nie wyświetliła, a urządzenia działające bez Home Assistanta często trafiają właśnie do takich sieci. Kosztem jest większe zajęcie pamięci flash.

auth z type: digest. Serwer WWW obsługuje dwa tryby uwierzytelniania: basic i digest. W trybie basic hasło przy każdym żądaniu trafia do sieci w łatwo odwracalnej postaci Base64, a w trybie digest przesyłane są tylko skróty. W dokumentacji zalecany jest digest. Obecnie domyślny jest basic, a od ESPHome 2027.1.0 domyślny będzie digest. W przewodniku bezpieczeństwa ESPHome sprawa jest postawiona jasno: bez uwierzytelniania każdy w sieci lokalnej może odczytać stan urządzenia i przełączać jego wyjścia.

ota: false w bloku web_server wyłącza wgrywanie oprogramowania przez zwykłą stronę WWW. Wraz z komponentem captive_portal automatycznie dołączany jest mechanizm aktualizacji serwera WWW, a dzięki tej opcji strona wgrywania jest dostępna tylko w portalu, czyli w czasie, gdy działa zapasowy punkt dostępu. W dokumentacji serwera WWW jest ostrzeżenie: aktualizacja przez stronę bez uwierzytelniania oznacza, że oprogramowanie może wgrać każdy, kto ma dostęp do urządzenia przez sieć.

ota z platform: esphome i encryption zapewnia szyfrowane aktualizacje przez sieć z narzędzia wiersza poleceń esphome. Zwykle w bloku aktualizacji używany jest klucz natywnego API, ale tu nie ma bloku api:, więc potrzebny jest osobny klucz key. Według dokumentacji jest to 32-bajtowy ciąg zakodowany w base64. Można go wygenerować na przykład tak:

openssl rand -base64 32

W dokumentacji ESPHome jest też wyjaśnienie, dlaczego szyfrowanie jest lepsze od starszej opcji password: obraz oprogramowania zawiera dane logowania do sieci Wi-Fi, a hasło służy tylko do potwierdzenia tożsamości osoby wgrywającej, bez ukrywania zawartości obrazu. Obu opcji nie da się łączyć. Jeśli na urządzeniu działa już oprogramowanie bez szyfrowania, przed dodaniem tego bloku przeczytaj w dokumentacji aktualizacji część „Enabling Encryption on an Existing Device”. Po dodaniu encryption: nieszyfrowanego obrazu nie da się już wysłać z narzędzia wiersza poleceń.

ap z hasłem. Zapasowy punkt dostępu bez hasła to otwarte drzwi: gdy router nie działa, każdy w pobliżu może się połączyć i dostać do urządzenia. W przewodniku bezpieczeństwa jest zalecenie, by zawsze ustawiać hasło albo całkiem usunąć ap: z urządzeń, które tej funkcji nie potrzebują.

Pierwsze wgranie i kolejne aktualizacje

Pierwsze wgranie odbywa się przez USB, po zainstalowaniu narzędzia esphome:

esphome run workshop-relay.yaml

Gdy pojawi się pytanie, wybierz port szeregowy. Przy kolejnych uruchomieniach tego samego polecenia na liście jest też adres sieciowy i wtedy aktualizacja przebiega bezprzewodowo, z szyfrowaniem. Dziennik przez sieć można śledzić poleceniem:

esphome logs workshop-relay.yaml

Działa to bez natywnego API, bo dziennik jest przesyłany przez serwer WWW pod adresem /events, dopóki opcja log jest włączona, a domyślnie jest.

Korzystanie z interfejsu REST

Przy type: digest każdy klient musi używać uwierzytelniania digest. W curl służy do tego przełącznik --digest. Żądania z samym uwierzytelnianiem basic są odrzucane.

Odczyt siły sygnału Wi-Fi (spacja w nazwie encji to w adresie %20):

curl --digest -u admin:HASLO "http://workshop-relay.local/sensor/WiFi%20Signal"

W odpowiedzi przychodzi obiekt JSON z polami id, tekstowym state i liczbowym value. Od ESPHome 2026.8.0 pole id ma postać domain/entity_name, tutaj sensor/WiFi Signal. W skryptach pisanych pod starsze oprogramowanie może być używany poprzedni format.

Przełączanie przekaźnika:

curl --digest -u admin:HASLO -X POST "http://workshop-relay.local/switch/Relay/turn_on"
curl --digest -u admin:HASLO -X POST "http://workshop-relay.local/switch/Relay/toggle"

Dla przełączników dostępne są akcje turn_on, turn_off i toggle, a odpowiedzią na udane wywołanie jest kod 200 OK. Dla świateł można podać dodatkowe parametry w adresie, na przykład /light/Desk/turn_on?brightness=128&transition=2. Dopisanie ?detail=all do żądania GET daje bardziej szczegółową odpowiedź.

Zmiany na żywo można śledzić w terminalu, utrzymując otwarte połączenie ze strumieniem zdarzeń:

curl --digest -u admin:HASLO -N "http://workshop-relay.local/events"

Przeglądarki, inne strony i żądania z innych źródeł

Od ESPHome 2026.7.0 żądania przeglądarki do adresów stanu i sterowania są odrzucane, jeśli pochodzą z innej strony (innego źródła), chyba że to źródło jest na liście allowed_origins. Dzięki temu z przypadkowej strony internetowej nie da się sterować urządzeniem przez przeglądarkę użytkownika. Żądania bez nagłówka Origin, na przykład z curl i skryptów, są zawsze przyjmowane. W dokumentacji ten mechanizm jest opisany jako dodatkowa warstwa ochrony, a nie granica bezpieczeństwa. Mechanizm nie dotyczy też adresu /update służącego do aktualizacji przez stronę. Właściwą ochroną są nadal uwierzytelnianie i zaufana, wydzielona sieć. Jeśli budujesz własny panel umieszczony na innym serwerze, dopisz jego dokładne źródło do allowed_origins, zamiast używać "*".

Jak działa zapasowy punkt dostępu

  • Punkt dostępu jest uruchamiany dopiero wtedy, gdy urządzenie nie może połączyć się ze skonfigurowaną siecią. W dokumentacji Wi-Fi domyślny czas ap_timeout to 90 sekund, a na stronie portalu jest mowa o „1 minucie”. Licz się z czasem w tym przedziale.
  • Połącz się z punktem dostępu z telefonu albo laptopa i otwórz http://192.168.4.1/, jeśli strona portalu nie otworzy się sama.
  • Dane sieci wpisane w portalu są używane zamiast zapisanych w oprogramowaniu. Według dokumentacji portalu przy każdym późniejszym wgraniu przez USB są one nadpisywane, więc popraw też plik YAML. Jeśli w pliku YAML w ogóle nie ma danych sieci Wi-Fi, zapisane dane są zachowywane także przy aktualizacjach bezprzewodowych, co opisano w dokumentacji Wi-Fi.
  • Przy opcji reboot_timeout (domyślnie 15 minut) urządzenie bez połączenia jest uruchamiane ponownie, ale nie w trybie punktu dostępu.

Stały adres zamiast mDNS

Nazwy .local działają tylko na klientach z obsługą mDNS, a mDNS nie działa przez routery ani między sieciami VLAN. Jeśli na telefonie albo w skrypcie nazwa workshop-relay.local nie jest rozpoznawana, zarezerwuj dla urządzenia adres w ustawieniach DHCP routera albo ustaw go w ESPHome:

wifi:
  manual_ip:
    static_ip: 192.168.1.50
    gateway: 192.168.1.1
    subnet: 255.255.255.0

Te klucze wpisz w istniejącym bloku wifi: i dopasuj adresy do swojej sieci.

Lista kontrolna bezpieczeństwa

W modelu zagrożeń ESPHome jest założenie, że urządzenia pracują w zaufanej sieci domowej albo firmowej, za zaporą i bez dostępu z internetu. W przypadku urządzenia działającego samodzielnie oznacza to:

  • Nigdy nie przekierowuj portu 80 urządzenia na routerze.
  • Ustaw uwierzytelnianie strony z type: digest i hasło do zapasowego punktu dostępu.
  • Używaj szyfrowanych aktualizacji i zostaw ota: false w bloku web_server, chyba że naprawdę potrzebujesz wgrywania z przeglądarki.
  • Dla każdego urządzenia używaj osobnego klucza i hasła, trzymaj je w secrets.yaml i nie publikuj tego pliku w publicznych repozytoriach.
  • Jeśli router ma taką funkcję, przenieś urządzenia IoT do osobnego segmentu sieci.