pingwa + Home Assistant
Your smart home already knows when the doorbell rings, the alarm
trips, or the nightly backup fails. Give it a WhatsApp voice with one
rest_command — works with plain YAML you already know, or grab
the native integration for a one-click install.
Add the rest_command
In configuration.yaml, wire an outbound notify to
POST /v1/notify. Get an API key by texting join to
pingwa on WhatsApp (see home), then store it in
secrets.yaml.
# configuration.yaml
rest_command:
pingwa_notify:
url: "https://pingwa.dev/v1/notify"
method: POST
headers:
Authorization: !secret pingwa_bearer
Content-Type: application/json
payload: '{"text": {{ message | tojson }} }'
# secrets.yaml
pingwa_bearer: "Bearer pw_your_key_here"
Add pingwa_ask for confirmations
The same pattern works for POST /v1/ask, which
sends a question and waits for you to tap a button on WhatsApp — handy for
anything you want to confirm rather than just be told about. The real request
body is {"text": ..., "buttons": [...]} (a plain list of up to 3
short strings; omit buttons for a free-text reply instead).
The server holds the connection open for up to 90
seconds waiting for your reply, then returns 408 — so
give the rest_command a matching timeout (HA's default is only
10s and would cut it off). A late reply isn't lost: it's still retrievable
from the inbox/reply endpoints below.
# configuration.yaml — add pingwa_ask under the SAME rest_command: # block as pingwa_notify (one rest_command: key holds all commands) pingwa_ask: url: "https://pingwa.dev/v1/ask" method: POST timeout: 95 headers: Authorization: !secret pingwa_bearer Content-Type: application/json payload: '{"text": {{ message | tojson }}, "buttons": ["Yes", "No"]}'
Example automations
Three common triggers, all under one automation:
key (or drop the list items into automations.yaml if that's how
you split your config). The alarm example shows the flagship two-way move:
capture the reply with response_variable and branch on which
button was tapped. rest_command hands back the HTTP response as
{status, content}, so the parsed JSON body lives under
.content. Reply buttons get stable ids in order — b0
is the first button ("Yes"), b1 the second
("No") — read at reply.content.reply.button_id.
# configuration.yaml automation: # Doorbell pressed — one-way notify - alias: "Doorbell -> WhatsApp" trigger: - platform: state entity_id: binary_sensor.front_door_doorbell to: "on" action: - service: rest_command.pingwa_notify data: message: "Someone's at the front door 🔔" # Alarm triggered — ask, then act on the answer - alias: "Alarm triggered -> ask on WhatsApp" trigger: - platform: state entity_id: alarm_control_panel.home to: "triggered" action: - service: rest_command.pingwa_ask data: message: "🚨 Alarm triggered at home. Call the keyholder?" response_variable: reply # reply.content.reply.button_id is "b0" for "Yes", "b1" for "No" # (on a 408 timeout reply.status is 408 — falls to the default branch) - choose: - conditions: "{{ reply.content.reply.button_id == 'b0' }}" sequence: - service: script.call_keyholder default: - service: rest_command.pingwa_notify data: message: "No 'Yes' tap — not calling the keyholder." # Nightly backup failed — one-way notify - alias: "Backup failed -> WhatsApp" trigger: - platform: state entity_id: sensor.backup_status to: "failed" action: - service: rest_command.pingwa_notify data: message: "Nightly backup FAILED — check the logs"
Two-way: pingwa pushes replies into HA
Outbound (HA → your phone)
is the rest_command above. For inbound (your WhatsApp
reply → HA) pingwa can now PUSH each reply straight to a Home
Assistant webhook — no polling loop.
- Register your HA webhook URL once:
POST /v1/webhooks {"url": "https://ha.example.com/api/webhook/<id>"}. It returns asecret(whsec_…) shown only once; the URL must be public HTTPS (up to 5 per account). - On every inbound message pingwa POSTs a JSON body
{event, message_id, body, button_id, reply_to_message_id, wa_message_id, window_open, created_at}—button_idisb0/b1/… for a tapped button (null for free text). HA's built-inplatform: webhooktrigger fires on that POST and your automation acts on it. - A voice message adds a
mediaobject{kind:"audio", voice:true, mime_type, url}(andbodyis empty).GET media.urlto fetch the audio — no API key needed (the signature authorizes it), but the link is short-lived (~1h), so fetch promptly. Feed the URL to amedia_playeror download it in your automation. - Each request carries an
X-Pingwa-Signature: sha256=<hmac>header (HMAC-SHA256 of the raw body with your secret). HA's webhook trigger can't verify that HMAC on its own — treat the raw endpoint as unauthenticated, keep the HA webhook id (the one in the URL) secret, and verify the signature in a template condition — or install the native integration, which registers the webhook and verifies the HMAC for you. Don't skip this on an internet-exposed HA. - If a delivery keeps failing, pingwa retries with backoff and
auto-deactivates the webhook after repeated exhausted attempts — check
GET /v1/webhooks(active,failure_count) and re-create it once HA is reachable again.
Fallback: polling still works if you'd
rather HA ask — a rest sensor or a short-interval automation
can call GET /v1/inbox?since=<cursor> and react to new
messages the same way.
Native integration (HACS)
Prefer entities and services over hand-rolled YAML? The
pingwa-hass integration wires everything up for you. Install
it via HACS as a
custom repository
(github.com/grzgrzgrz3/pingwa-hass), add your API key, and you
get:
- a
notify.pingwaentity for one-way alerts; - a
pingwa.askservice that sends a question and hands the answer back viaresponse_variable— notimeouttuning, no.contentparsing; - a signature-verified inbound webhook: it registers the HA webhook,
checks the
X-Pingwa-SignatureHMAC for you, and fires apingwa_replyevent your automations can trigger on.
Requires Home Assistant 2024.12+. The
plain rest_command path above stays the zero-install
alternative — pick whichever fits your setup.
Why the official Cloud API, not a bridge
pingwa sends through the official Meta WhatsApp Cloud API on its own number, so wiring it into your home automation can't get your personal WhatsApp banned. That is a real distinction from two other kinds of tools people wire into Home Assistant today:
- Unofficial WhatsApp-Web bridges that link your own device by QR scan (the technique behind libraries like Baileys) — fast to set up, but they reverse-engineer WhatsApp's client protocol, violate its terms, and put your personal number at real risk of a permanent ban. See the full comparison.
- One-way webhook-only notifiers — great for a single alert, but they have no concept of a reply, so they can't turn "alarm triggered" into a tap-to-confirm question.
Sized for alerts, not alert spam
The free plan covers 30 paid-route notifications a month (replies inside your 24h WhatsApp window are free and unlimited). That's not built for streaming every state change in your house — it's built for the handful of things actually worth a phone buzz: someone's at the door, the alarm tripped, the backup failed. Keep high-frequency sensor chatter in HA's own logbook/notifications, and reserve pingwa for the low-volume, high-value pings.
Solo, self-funded, official Cloud API. If pingwa saves you a ban or a bridge headache, a coffee keeps the free tier free — entirely optional, and it unlocks nothing.
Not affiliated with Home Assistant or the Home Assistant
Foundation. rest_command is a standard Home Assistant
integration; see their own docs for the full option set. pingwa is an
independent, self-hosted service. See about and
privacy.