Webhook

Jak si poslat webhook při krádeži telefonu

Webhook je jediná funkce v celém Pubbym, která posílá data ven. Jakmile někdo vytáhne kabel, pošle POST požadavek přesně tam, kam mu řekneš. Až poplach ukončíš, pošle druhý. Co se s tím stane dál, je celé na tobě.

Zapíná se v Nastavení, v kartě Webhook, a je to VIP funkce. Vedle pole na adresu najdeš tlačítko „Poslat test“, které pošle nanečisto to samé tělo požadavku jako ostrý poplach.

Co přesně přijde

  • Metoda. POST, s hlavičkou content-type: application/json; charset=utf-8.
  • Adresa. Pouze https://. Android nezašifrovaný HTTP provoz aplikacím blokuje už od verze 9. Požadavek na HTTP by selhal hluboko v systému na socketu a na obrazovce bys neviděl žádnou kloudnou chybu. Adresa se vejde do dvou tisíc znaků, aby se do ní bez problémů vešel podepsaný odkaz s tokenem.
  • Autorizace. Žádná. Oba konce téhle roury jsou tvoje, takže si ověřovací token dej přímo do adresy (jako parametr nebo do cesty).
  • Přesměrování. Nenásledujeme je. Odpověď 3xx by požadavek poslala na server, který jsi nikam nezadal, a POST se navíc při přesměrování často mění na GET, takže by tělo tiše zmizelo. Přesměrování bereme jako chybnou adresu a rovnou ti to řekneme.
  • Opakování (Retries). Tři pokusy v rozmezí zhruba čtyř sekund. Ale jen tehdy, když tvůj server vůbec neodpoví. Vytažení kabelu a ztráta místní Wi-Fi jdou často ruku v ruce, takže jeden pokus by nestačil. Čtvrtý pokus za dvě minuty by už ale telefonu, který za chvíli vůbec nemusí být na síti, nijak nepomohl.
  • Timeout. Čtyři sekundy na spojení, osm sekund na celé volání.

Tělo požadavku

unplugged

{
  "app": "pubby",
  "v": 1,
  "event": "unplugged",
  "id": "9f2c4a1b0d3e",
  "at": "2026-09-03T19:33:20Z",
  "grace": 10,
  "shared": true
}

Došlo k vytažení kabelu. Tento webhook odchází okamžitě, ještě před vypršením nastavené prodlevy sirény.

stopped

{
  "app": "pubby",
  "v": 1,
  "event": "stopped",
  "id": "9f2c4a1b0d3e",
  "at": "2026-09-03T19:34:02Z"
}

Poplach jsi manuálně ukončil. Chodí jedině tehdy, pokud se předtím úspěšně odeslal unplugged.

test

{
  "app": "pubby",
  "v": 1,
  "event": "test",
  "id": "41d0c8b7a562",
  "at": "2026-09-03T19:20:05Z"
}

Pošle ho výhradně tlačítko „Poslat test“ v nastavení aplikace.

Význam polí

  • app – řetězec, vždycky pubby. Užitečné pro společný endpoint, do kterého posíláš víc různých věcí.
  • v – číslo, verze formátu těla. Přidání dalšího pole do JSONu ji nezvedne; číslo se zvedne jedině tehdy, pokud nějaké existující pole změní svůj význam.
  • event – řetězec, jedna ze tří hodnot: unplugged, stopped, test.
  • id – řetězec, dvanáct hexadecimálních znaků. Události unplugged i stopped z jednoho konkrétního poplachu nesou stejné ID, takže si je v logu snadno spáruješ. Pokud ti stejné id přijde dvakrát u stejného eventu, jde o opakovaný pokus (telefon si myslel, že tvůj server požadavek nezpracoval).
  • at – řetězec, čas události v UTC (podle ISO 8601) oříznutý na celé sekundy. Jde o přesný okamžik vytažení kabelu, nikoliv o okamžik odeslání do sítě.
  • grace – číslo, dostupné jen u unplugged. Říká, kolik sekund zbývá, než se z telefonu ozve skutečná siréna. Nula znamená, že už řve.
  • shared – boolean, jen u unplugged. Říká, jestli v danou chvíli běžela Sdílená hlídka (tedy jestli poplach vidí ještě někdo další). Hodnota false znamená, že tento POST je jediné upozornění, které z telefonu ven odešlo.

Zkus to bez telefonu

Než kolem toho začneš stavět logiku, pošli si to samé tělo z příkazové řádky. Tvůj server nepozná rozdíl:

# Send a test payload exactly like the app does
curl -i -X POST \
  -H 'content-type: application/json' \
  -d '{"app":"pubby","v":1,"event":"unplugged","id":"9f2c4a1b0d3e","at":"2026-09-03T19:33:20Z","grace":10,"shared":true}' \
  https://tvoje-instance/api/webhook/pubby-9f2c4a1b0d3e

Parametr -i je tam proto, abys rovnou viděl, co tvůj server odpovídá. Cokoli jiného než kód 2xx bere Pubby jako odmítnutí a dané číslo ti pak vypíše na obrazovku v nastavení. Druhou polovinu poplachu vyzkoušíš tak, že v JSONu přepíšeš pole event na stopped a pole grace se shared úplně vynecháš.

Co se neposílá

Z principu se nedozvíš, že se hlídání vůbec zapnulo nebo vypnulo. Nedozvíš se stav baterie ani polohu telefonu – tu Pubby nezná. O GPS oprávnění si neřekne a nikam ji tak nemůže odeslat.

Myslet si, že systém ti drží stabilní spojení jen na základě jedné počáteční zprávy (bez heartbeat/tepu), je hloupost. Kdyby proces Pubbyho potichu spadl, tvůj dashboard by svítil „hlídá se“ i dlouho potom. Skutečný „tep“ v Pubbym existuje, ale jmenuje se Sdílená hlídka – ta aktivně drží spojení s prohlížečem tvého kamaráda a naopak nečekané ticho vyhodnotí jako poplach.

Home Assistant

Níže je ukázka automatizace se spouštěčem typu webhook. Vlož ji přímo do automations.yaml a uprav pouze webhook_id a entitu, kterou chceš ovládat:

automation:
  - alias: Pubby – vytažený kabel
    triggers:
      - trigger: webhook
        # IMPORTANT: Keep this ID secret
        webhook_id: pubby-9f2c4a1b0d3e
        allowed_methods: [POST]
        # Must be false so it works outside your home network
        local_only: false
    conditions:
      - "{{ trigger.json.event == 'unplugged' }}"
    actions:
      - action: light.turn_on
        target:
          entity_id: light.obyvak
        data:
          color_name: red

Adresa, kterou následně napíšeš do aplikace, bude: https://tvoje-instance/api/webhook/pubby-9f2c4a1b0d3e. K tomu si pamatuj tři věci:

  • webhook_id je tvoje tajné heslo. Kdo ho zná, dokáže ti na dálku spustit automatizaci. Zvol si ho proto dostatečně dlouhé a náhodné.
  • Parametr local_only: false tam být musí. Ve výchozím stavu přijímá Home Assistant webhooky jen z domácí sítě, takže požadavek z telefonu přes mobilní data by neprošel. A protože Pubby odesílá výhradně přes https://, potřebuješ instanci dostupnou zvenčí (např. přes Nabu Casa nebo vlastní reverzní proxy).
  • Událost stopped vyřešíš zkopírováním stejné automatizace. Stačí změnit podmínku na stopped a akci na light.turn_off. Hodnota webhook_id zůstává pochopitelně stejná, obě události totiž padají na tu samou adresu.

Další recepty

  • ntfy, Pushover, Gotify. Push notifikace přímo do druhého telefonu nebo hodinek. U ntfy stačí zadat adresu tvého tématu a bude to fungovat okamžitě – tělo JSONu se ti jen ukáže v surové formě jako text zprávy.
  • Node-RED nebo n8n. Přidej uzel pro příjem POST požadavků a hned za něj dej výhybku (Switch) podle hodnoty v poli event. Je to nejrychlejší cesta, jak naučit každou událost spouštět jinou komplexní akci.
  • Discord, Slack, Telegram. Sem napřímo posílat nejde. Tyto služby očekávají vlastní specifická pole (např. content nebo text), ale Pubby posílá tvrdě svůj pevný formát. Budeš k tomu potřebovat mezikus (třeba Cloudflare Worker nebo n8n), který ten první JSON prostě přepíše na ten druhý.
  • Vlastní skript. Dva řádky kódu, které si jen zaznamenají časovou stopu do logu, pokud tě zajímá, jak často ti na mobil někdo sahá.

Na co si dát u webhooků pozor

  • Zprávu odesílá přímo hlídaný telefon. Webhook není náhrada za Sdílenou hlídku. Pokud zloděj telefon vypne, nebo se mu rychle vybije baterka, žádný další POST (stopped) nepřijde a automatizace zůstane viset.
  • Vynucené zastavení aplikace stopped nepošle. Pokud systém aplikaci zabije (Force Stop), proces okamžitě zmizí a nemá jak událost odeslat. Kdo si podle události stopped něco automaticky vypíná, ať k tomu má pro jistotu postavený i časovač.
  • unplugged odchází ještě před odkladem. Odklad (grace period) se týká jen reálné sirény v místnosti. Zpráva odchází ihned. Proto je v těle hodnota grace – ať tvůj server ví, jestli je v danou chvíli v kavárně ještě ticho, nebo už tam je řev.
  • Nespárované stopped nechodí. Pokud si na telefonu webhook zapneš až chvíli po vytažení kabelu, ukončovací zpráva už nepřijde, protože neproběhl ten prvotní POST.
  • Klidná hlídka mlčí. Pokud jsi celou dobu poctivě hlídal, ale nikdo s kabelem ani nehnul, z aplikace ti nepřijde do logu vůbec nic.

Když z telefonu nic nechodí

Zmáčkni v nastavení tlačítko „Poslat test“ a hned si přečti, co ti aplikace vypíše. Tyto tři hlášky mají tři různá řešení:

  • „Dorazilo!“ Cílový server v pořádku odpověděl kódem ze série 2xx.
  • „Někdo tam je, ale odpověděl chybou 404.“ Vrátila se nám odpověď, ale nebyla to 2xx a tohle číslo je její reálný kód. Například: 404 znamená špatnou cestu, 401/403 znamená špatný token, 3xx je přesměrování (které ignorujeme) a 5xx je chyba přímo na tvém serveru.
  • „Zaklepal jsem, ale server neodpovídá.“ Neozval se vůbec nikdo. Příčinou může být neexistující jméno hostitele, zavřený port, spadlá domácí síť, případně zpracování trvalo déle než tvrdý limit osmi sekund.

A ještě jedna věc, na kterou se dívej jako první: Tvoje adresa musí začínat na https://. Dokud na to nezměníš, Pubby se ani nepokusí komunikovat a textové pole zůstane podsvícené červeně.