Smart home
Laundry, meet your smart home.
The Wash Guide connects laundry to the smart home in two complementary ways, both free. Local publishing sends events from your phone directly to your own webhook or MQTT broker on your home network; those events never touch The Wash Guide’s servers. The Home Assistant integration connects through The Wash Guide cloud with a revocable connect key, sees the whole household, and keeps working when everyone is out. You can run either, or both. Reading is free on both paths. Acting from the smart home, posting a task, asking the house for a maintenance wash, or recording a clean, needs a PRO control key.
Path one
The Home Assistant integration
Three steps, and the household appears on your dashboard.
- Generate a connect key. In The Wash Guide app: Settings → Smart home → Generate connect key. Copy it; it is shown only once, and you can revoke it from the same place at any time. PRO users can generate a control key here too, and paste both into Home Assistant at once.
- Install the integration. The Wash Guide is in the HACS default store, so this is a plain search: open HACS, search for The Wash Guide, download, and restart. Then Settings → Devices & services → Add integration → The Wash Guide, and paste the key. The control key box on that same screen is optional, and can be filled in later with Configure.
That badge opens your own Home Assistant instance straight onto the repository page in HACS. The integration is open source and lives at github.com/romuluz/thewashguide-homeassistant. For a setup without HACS, copying
custom_components/thewashguideintoconfig/custom_components/does the same job by hand. - That’s it. Entities appear immediately, as one device.
What you get
sensor.pending_tasksWashes waiting on the household board. The pending list rides along as attributes, each task with its id, so a template sensor can slice it per person and the control actions below can name a task precisely. Each task carries a kind, either a wash (a load of laundry) or a machine job (the machine's own maintenance wash).
sensor.detergent_shieldThe weakest item in the shared cupboard, as a percentage. The full cupboard (each product's name, remaining doses and percentage) comes as attributes, which makes this the natural feed for shopping-list automations. Long-term statistics are recorded, so you get detergent burn-rate graphs for free.
sensor.last_washA timestamp for the household's most recent wash, with the item, shade, temperature and who ran it as attributes.
sensor.next_scheduled_washA timestamp for the next standing wash, with what, who and cadence as attributes, plus the full schedule list. Standing schedules are a PRO feature in the app, so in a household without them this sensor simply has no value.
sensor.loads_since_machine_cleanHow many loads the drum has turned since its last maintenance wash, with clean_due, days_since_clean and the interval the app measures against as attributes. Statistics are recorded, so the sawtooth of a well-kept machine draws itself.
sensor.last_machine_cleanA timestamp for when the machine was last cleaned, with who did it, the last filter clean, and the household's recent care record as attributes.
binary_sensor.wash_overdueOn when a pending wash has waited more than a day, or when the app's nudge ladder is already active. The overdue tasks and their nudge levels come as attributes. The laundry-room lamp that slowly turns amber starts here.
binary_sensor.maintenance_wash_dueOn when the drum has earned its empty hot cycle: thirty loads or two months, whichever arrives first. The attributes include whether the job is already on the household board, so a panel can offer to run it rather than ask for it twice.
binary_sensor.filter_dueOn when the pump filter is due, a quarterly job that is time-based only, because a filter fills with lint and coins rather than loads.
sensor.<name>_personalityOne per household member: their wash personality title, with tier, 30-day wash count and 30-day rewards (in the household's own reward currency) as attributes.
Events for automations
Four events land on the Home Assistant bus as fresh activity arrives:
thewashguide_wash_logged(fields: ts, by, item, shade, temp_c)thewashguide_task_created(fields: summary, for, kind, tokens, created_at)thewashguide_task_completed(fields: summary, for, kind, tokens, completed_at)thewashguide_machine_cleaned(fields: kind (MAINTENANCE_WASH or FILTER_CLEAN), ts, by)
automation:
- alias: "Celebrate a finished wash task"
trigger:
- platform: event
event_type: thewashguide_task_completed
action:
- service: notify.family
data:
message: >
{{ trigger.event.data.for }} finished
"{{ trigger.event.data.summary }}"
{% if trigger.event.data.tokens %}
and earned {{ trigger.event.data.tokens }} rewards
{% endif %}.Data updates every 15 minutes, or every minute for a PRO household. The cloud tells the integration which cadence the plan allows and it paces itself, so an upgrade takes effect on the next poll with nothing to reconfigure. Anyone who would rather poll less often than their plan allows can set an interval in the integration’s options; it can never poll more often.
The connect key grants read-only access to the household’s laundry status: tasks, cupboard level, wash personalities, recent washes and the machine’s care record. It cannot log washes, change anything, or read anything outside the household. Revoking the key in the app cuts access on the next refresh.
Taking action (PRO)
With PRO, the smart home stops being read-only. Alongside the free connect key, the app can generate a control key (Settings → Smart home → Generate control key; the key list labels each key’s scope plainly). Paste it into the integration, at setup or later with Configure, and four services appear:
thewashguide.create_task: post an open wash task to the household board, which anyone in the house can claim. The summary, note, load facts and a reward are all optional; a bare call posts a mixed, medium load. Attaching a reward requires an operator.thewashguide.cancel_task: cancel a task still waiting on the board. Operators may cancel any pending task; everyone else, their own.thewashguide.request_maintenance_wash: put the machine’s maintenance wash on the board. Open to the house by default, because the machine is nobody’s in particular; name a member to hand it to them.thewashguide.log_machine_clean: record that the machine was looked after, either the maintenance wash or the filter. If the maintenance wash is already waiting on the board, this completes that task rather than logging a second, parallel truth.
The key’s owner is the actor: your automations act as you, under the same household rules as the app itself. Rewards need an admin or a manager, juniors cannot create tasks at all, and a connect key presented where a control key is required is refused.
One line is worth explaining, because it is a design position rather than a limitation: a wash task cannot be completed from the smart home, and a maintenance wash can. Completing a wash means a person ran a load of laundry, spent detergent from the cupboard and added to their wash history, and an automation cannot honestly claim any of that. A maintenance wash is the opposite case. An empty drum at 90 degrees produces no laundry, spends no detergent and enters no wash log; the only thing it produces is the fact that it ran, and a washing machine that has just finished its cycle knows that fact better than the person who will remember to mention it on Thursday.
automation:
- alias: "The machine asks for its own maintenance wash"
trigger:
- platform: state
entity_id: binary_sensor.maintenance_wash_due
to: "on"
condition: >
{{ not state_attr('binary_sensor.maintenance_wash_due',
'on_the_board') }}
action:
- service: thewashguide.request_maintenance_wash
data:
note: "The drum has done thirty loads since the last one."
- alias: "And logs it when the cycle finishes"
trigger:
- platform: state
entity_id: sensor.washing_machine_power
below: 5
for: "00:05:00"
condition: "{{ is_state('input_boolean.running_maintenance_wash', 'on') }}"
action:
- service: thewashguide.log_machine_clean
data:
kind: maintenance_wash
- service: input_boolean.turn_off
target:
entity_id: input_boolean.running_maintenance_washFor anyone who would rather not install the integration, the control endpoint also answers a plain rest_command. The app shows its address beside the key.
rest_command:
washguide_task:
url: !secret washguide_control_url
method: post
headers: { x-api-key: !secret washguide_control_key }
content_type: application/json
payload: '{"action":"create_open_task","summary":"{{ summary }}"}'Path two
Local webhook and MQTT
In the app: Settings → Smart home → switch on Publish to your smart home, then fill either or both of:
- Webhook URL, e.g.
http://homeassistant.local:8123/api/webhook/washguide - MQTT broker, e.g.
mqtt://192.168.1.10:1883(ormqtts://for TLS), with optional username and password, and a topic prefix (defaultthewashguide).
A Send a test event button confirms the wiring. Events are sent by the phone at the moment things happen, entirely on the local network: they never touch The Wash Guide’s servers, so this is the private-by-construction option, with the natural trade-off that the phone must be home and the app in use for events to flow.
Topics
<prefix>/state carries the retained household snapshot. Fresh activity arrives on <prefix>/event/wash, <prefix>/event/task, <prefix>/event/care and <prefix>/event/test. Every payload carries a type and an ISO ts. The webhook receives all of them at its single URL, and fans out on type.
The retained state carries the household (name, label, pending task count, detergent shield percentage), the machineblock, the cupboard item by item (weakest first), the device’s own active profile and every member.
{
"type": "state",
"ts": "2026-07-14T20:10:00Z",
"household": {"name": "Townsend", "label": "Villa",
"pending_tasks": 2, "shield_pct": 20},
"machine": {"loads_since_clean": 31, "clean_due": true,
"filter_due": false,
"last_clean": "2026-05-30T09:00:00Z",
"last_filter": "2026-06-30T09:00:00Z"},
"cupboard": [{"id": "persil_bio_liquid", "name": "Persil Bio Liquid",
"remaining": 200, "pack_size": 1000, "pct": 20}],
"active_profile": {"name": "Nick", "profile_id": "WASH_WIZARD",
"profile_title": "Titan of the Rinse", "tier": 3},
"members": [...]
}{
"type": "wash_logged",
"ts": "2026-07-06T20:44:57Z",
"profile": {"name": "Hermes", "profile_title": "The Clean Slate", "tier": 0},
"wash": {"item": "TSHIRTS", "shade": "WHITE", "fabric": "COTTON",
"load": "MEDIUM", "temp_c": 40, "detergent": "Ariel Platinum Pods",
"dose": 1, "unit": "pods", "soiled": false, "sensitive": false}
}Task events (task_created, task_claimed, task_completed, task_cancelled) carry a kind of wash or machine, with the summary, who it is for, who acted, and any reward attached. The care event fires the moment the machine is looked after; its loads_since_clean is the count the clean has just reset, which is the number the drum actually ran on.
{
"type": "care_logged",
"ts": "2026-07-14T20:10:00Z",
"kind": "MAINTENANCE_WASH",
"by": "Nick",
"loads_since_clean": 34
}mqtt:
sensor:
- name: "Wash Guide pending tasks"
state_topic: "thewashguide/state"
value_template: "{{ value_json.household.pending_tasks }}"
- name: "Wash Guide loads since machine clean"
state_topic: "thewashguide/state"
unit_of_measurement: "loads"
value_template: "{{ value_json.machine.loads_since_clean }}"
binary_sensor:
- name: "Wash Guide maintenance wash due"
state_topic: "thewashguide/state"
device_class: problem
value_template: "{{ 'ON' if value_json.machine.clean_due else 'OFF' }}"automation:
trigger:
- platform: webhook
webhook_id: washguide
local_only: true
condition: "{{ trigger.json.type == 'wash_logged' }}"
action: ...Zero YAML, if you’d rather
Send a test event also publishes MQTT auto-discovery configs, retained on the broker, so six local sensors appear with no YAML at all: pending tasks, the detergent shield (with the cupboard as attributes), loads since the machine clean, the last maintenance wash, and the two due flags. The manual YAML above becomes optional. MQTT only; a webhook has nothing to discover.
One honest note, because MQTT people will ask: there is no availability topic. The phone connects, publishes and disconnects, so a last will would announce the app offline seconds after every message, and an expiry would retire a perfectly true reading from a household that simply has not washed this week. The retained snapshot is the last thing we knew, and it stays true until we know better.
Questions
The short answers
Which path should I choose?
The integration, unless you specifically want nothing to leave your network; then local MQTT. You can also run both side by side.
What does the cloud path share?
The household's laundry status only: the task board, cupboard level, wash personalities, recent wash summaries and the machine's care record. No account credentials, no location, no contacts. A connect key is read-only, and access dies with the key. A PRO control key can also act on the board, under the same household rules as its owner.
Can Home Assistant control my washing machine?
No, and nothing here pretends to. The Wash Guide knows what your household is washing and how the machine is being kept; your machine's own integration, if it has one, is what starts a cycle. The two work well together: your machine reports that a cycle finished, and The Wash Guide records what it meant.
Does it drain my phone?
No. Local publishing sends tiny messages at the moment you act; the integration polls from Home Assistant, not the phone.
Do I need a subscription or port forwarding?
No. The integration connects outward from Home Assistant, so no remote access, Nabu Casa subscription or router changes are needed. PRO is only needed to act from Home Assistant, never to read.
Is it free?
Reading is, on both paths, for every user, and so is MQTT auto-discovery. Acting needs PRO: posting a task, asking the house for a maintenance wash, or recording that the machine was cleaned.
Can my automations change things, not just watch?
With a PRO control key, yes: they can post tasks to the household board, cancel pending ones, ask for the machine's maintenance wash and record that it was done, as the key's owner and under the household's own rules. A wash task is the one thing they cannot complete; completing means a person ran a load and spent detergent from the cupboard, and an automation cannot honestly claim that. A maintenance wash is the opposite case, and it can.
Over to you
Show us what you build.
The best automations will come from you: the amber lamp, the shopping list that fills itself, the speaker that congratulates whoever emptied the basket. Send your recipes to hello@thewashguide.app and we’ll share the best of them here.