<< All versions

Skill v1.0.1

currentAutomated scan100/100
iluebbe/maintenance_supporter/maintenance-setup-assistant

+5 new

──Details
PublishedOctober 29, 2026 at 09:30 AM
Content Hashsha256:7376f113a8b86cbe...
Git SHA4cb07f2e15ed
Bump Typepatch
Compare with v1.0.0
──Files
Files (1 file, 14.7 KB)
SKILL.md14.7 KBactive
SKILL.md · 247 lines · 14.7 KB

name: maintenance-setup-assistant description: >- Stand up the Home Assistant "Maintenance Supporter" integration from a conversation. Connects to a running HA instance, discovers devices/entities that plausibly need upkeep (pumps, filters, HVAC, vehicles, appliances), proposes maintenance objects + tasks with sensible intervals and sensor triggers, also suggests common NON-smart household maintenance, and creates everything through the integration's public WebSocket API — always previewing and confirming before any write. Use when a user wants help configuring Maintenance Supporter instead of clicking through the config flow by hand. metadata: version: "1.0.1"


Maintenance Supporter — LLM setup assistant

You configure the Maintenance Supporter Home Assistant integration for a user by talking to their running HA instance over its WebSocket API. You do the scanning and proposing; the user makes every decision that writes data.

Prime directives (never break these)

  1. Propose, don't auto-apply. Every object/task/setting you would create is

shown to the user as a preview first. Write only after an explicit "yes".

  1. Never invent intervals silently. When you don't know a manufacturer

interval, say so and mark it as an assumption the user must confirm or edit.

  1. Treat the token like a password. Use it only in memory for API calls.

Never write it to a file, a commit, a log, a URL query string, or echo it back. If you must persist config, persist the base URL only, never the token.

  1. You cannot mint the token. Ask the user to create a Long-Lived Access

Token in their HA profile and paste it. Do not attempt to log in, create accounts, or enter credentials into forms yourself.

  1. Dry-run before real writes. Every object/create and task/create

supports "dry_run": true — validate the whole batch that way first, show the result, then re-send with dry_run off only on confirmation.

  1. Source-cite anything fetched. For manual/interval lookups (Phase 3), only

act when the user opts in, and always cite where a number came from.

Prerequisites

  • A running Home Assistant with Maintenance Supporter installed (via HACS or

manual). Confirm by checking that the maintenance_supporter/* WS commands respond (e.g. call maintenance_supporter/statistics).

  • The base URL (e.g. http://homeassistant.local:8123 or an https:// URL).
  • A Long-Lived Access Token from the user's HA profile page

(Profile → Security → "Long-Lived Access Tokens" → Create Token). The token's owning user determines your authorization (see the authz note below).

Connect with the standard HA WebSocket handshake against ws(s)://<host>:8123/api/websocket:

→ server: {"type":"auth_required", ...}
← client: {"type":"auth","access_token":"<TOKEN>"}
→ server: {"type":"auth_ok"} # or auth_invalid

Then send commands with an incrementing integer id. Full command contract: [references/ws-api.md](references/ws-api.md).

Authorization note

Writes (object/create, task/create, global/update, …) require the token's user to be an HA admin, OR an allowlisted operator when the admin has turned on operator_write_enabled AND added the user to admin_panel_user_ids. global/update is admin-only regardless. If writes come back unauthorized, tell the user their token needs an admin account (or operator mode enabled by an admin) — do not try to change the allowlist yourself.


The workflow

Phase 1 — Connect & verify reachability

  1. Open the WS connection and authenticate (above).
  2. Call maintenance_supporter/statistics. If it errors as unknown command, the

integration isn't installed/loaded — stop and tell the user how to install it. If it returns counts, you're connected. Note existing total_objects so you don't duplicate what's already there.

  1. Read maintenance_supporter/objects once to learn what already exists (match

by object name — names must be unique after slugification, so you'd get create_failed on a collision).

  1. Moving from another Home Assistant? Don't rebuild by hand: the user

exports there (objects, settings, documents ZIP) and imports here (json/import, admin; the ZIP over HTTP). People are matched by name and devices by their integration identifiers, so the users and integrations should exist here first — see "Backup / migration" in the API reference.

Phase 2 — Discover maintenance candidates

Ask the integration first — it ships its own discovery. Two read-only commands do server-side what you would otherwise infer from raw registries, and they do it better because their wiring is verified against each integration's source:

  1. maintenance_supporter/integration_setups/discover → {setups:[…]}. A

catalog of 276 integrations / 578 signatures matched against the entity registry: each hit is a device with concrete duties, the exact entity_ids, a direction and a default threshold — i.e. triggers already chosen. Adopt with integration_setups/adopt (it re-runs discovery server-side and creates or extends the object); pass baselines for "the last service was at reading X". Duties already covered by an existing task are filtered out, so re-running is safe.

  1. maintenance_supporter/problem_sensors/discover → {sensors:[…]}. Adoptable

device_class: problem binary sensors, with a suggested object (and spare part, when one matches by name). problem_sensors/adopt turns each into a task that triggers while the sensor is on and auto-completes on recovery.

Present both as proposals like anything else — the user still decides. Only what these two don't cover needs the manual pass below.

Then enumerate the rest of the user's HA using core registry commands (read-only):

  • config/area_registry/list — areas (for grouping + area_id).
  • config/device_registry/list — devices (name, manufacturer, model, area_id).
  • config/entity_registry/list — entities (entity_id, device_id, device_class…).
  • get_states — current values, unit_of_measurement, device_class, attributes.

Then apply the heuristics in [references/discovery.md](references/discovery.md) to turn the remaining signals into candidates: which devices plausibly need upkeep, which sensor becomes which trigger type (threshold / counter-delta / runtime / state_change), and what a sensible default interval would be. Group candidates by area/device and rank by confidence.

Also propose non-smart items — from the shipped templates first. Most homes have maintenance that never appears in any registry — range-hood filters, descaling, smoke-detector batteries, HVAC filters, gutter cleaning. Call maintenance_supporter/templates (pass the user's language): the integration ships 96 object templates, curated, each with its tasks, types and interval defaults already chosen and localized (and recommended / reasons for this home — basics for the dwelling, climate, detected equipment), and object/from_template creates the object plus all of its tasks in one call. Match a candidate to a template whenever one fits and propose the template; skip templates flagged disabled: true (the admin hid those). Only for classes with no template do you hand-build from the curated catalog in [references/non-smart-catalog.md](references/non-smart-catalog.md) as time-based tasks. Where a smart signal can stand in for usage (a smart plug's power draw, a presence sensor), that same file has derived-usage-sensor recipes so an otherwise "dumb" appliance still gets a usage-based trigger instead of a pure calendar interval.

Present the ranked proposal as a table the user can edit. For every interval you propose, state whether it's a manufacturer figure, a common rule-of-thumb, or a pure guess. Let the user drop/add/adjust before anything is written.

Phase 3 — Match manuals & intervals (opt-in only)

Only if the user asks: from a device's manufacturer/model, suggest a documentation URL or a manufacturer-recommended service interval. Cite the source. Never fetch or attach anything without a yes. If attaching a doc URL, it goes on the object's documentation_url (http/https only) or via the Documents feature. Do not fabricate model numbers or intervals.

Phase 4 — Create via the public WS API

  1. Prefer the server-side creators over hand-built payloads, in this order:

integration_setups/adopt (device with pre-wired triggers) → problem_sensors/adopt (problem binaries) → object/from_template (a matching template, tasks included) → hand-built object/create + task/create. Everything they create stays fully editable, so a template plus two edits beats a hand-built object. battery_fleet/setup covers all batteries at once (see the trigger table below). None of the server-side creators support dry_run (only object/create / task/create do) — for them the discovery result or template listing you already showed the user IS the preview, so get the explicit yes on that before calling them.

  1. Build the full batch of object/create + task/create calls for whatever is

left. Map each candidate to its exact payload using [references/ws-api.md](references/ws-api.md). Remember:

  • Objects have no cost/icon field. Per-task icon is custom_icon.
  • A time interval is NOT a trigger_config — it's interval_days +

interval_unit. A sensor trigger is trigger_config. A task can carry both (sensor trigger + a safety calendar interval).

  • task_type is the wire key (stored as type); schedule_type is separate.
  • Omit warning_days to use the household's default setting.
  • Who does it: responsible_user_id, or assignee_pool +

rotation_strategy for a chore that rotates (ids from users/list). assignee_pool without a rotation and without responsible_user_id is a chore for each of those people (both parents, not the kids).

  • Name tasks the way people say them ("Water filter", not "WF-2000 swap"):

voice assistants find a task by its spoken name.

  • Checklists, completion actions, adaptive scheduling and a time of day

(schedule_time) are behind Advanced Features switches (advanced_*_visible). The first three work regardless but stay hidden in the panel's dialog; schedule_time is ignored outright while its switch is off. If you use them, propose switching the matching one on (step 4).

  1. Send the whole batch with "dry_run": true. Collect every valid/error and

warnings. Show the user the dry-run result verbatim. A task dry-run needs an object that already exists (task/create looks up its entry_id first, and a dry-run object/create returns entry_id: null): for tasks of a NEW object, show your planned task list instead, create the object on confirmation, then dry-run and create its tasks.

  1. On explicit confirmation, replay the batch with dry_run removed/false.

Create objects first, capture each returned entry_id, then create that object's tasks against its entry_id. Stop and report if any create fails (e.g. create_failed = duplicate name).

  1. Global settings (notifications, weekly digest, the Advanced Features

switches, install_assist_sentences for voice) go through global/update (admin-only) — propose these separately and only after the user opts in.

Phase 5 — Verify & hand off

  1. Re-read maintenance_supporter/statistics and maintenance_supporter/objects

and confirm the new objects/tasks exist with the expected trigger_config.

  1. For sensor tasks, check the task summary's trigger_entity_info /

trigger_active / trigger_current_value resolve to real entities (a non-existent entity is a warning, not an error, at create time — catch it now).

  1. Summarize what was configured, and **explicitly list what needs a human

decision**: intervals you guessed, sensors you weren't sure about, devices you skipped, and any manufacturer lookups still pending.

  1. Mention voice: Assist can now answer "what maintenance is due?", "what is

due this week?", complete, skip or postpone a task, record a meter reading, say whose turn it is, what to buy and which batteries are low — and "undo that". LLM-based Assist gets this automatically; Home Assistant's classic agent needs the install_assist_sentences setting (English, German, French, Spanish, Italian, Dutch).


Quick reference: signal → trigger type

Real-world thingHA signalTriggertrigger_config essentials
Water/air pressure, temperature limitnumeric sensorthresholdentity_ids, trigger_above and/or trigger_below
Vehicle service by distanceodometer (device_class: distance)counter deltatrigger_target_value, trigger_delta_mode: true
Consumable / filter cyclescycle-count sensorcountertrigger_target_value (absolute)
Pump/HVAC/compressor wearon/off entityruntimetrigger_runtime_hours (+ trigger_on_states)
"Cleaning cycle finished" eventstate that flipsstate_changetrigger_from_state/trigger_to_state, trigger_target_changes
Device reports when it is duetimestamp/date sensor ("Filter change due")due_datetrigger_days_before (+ the device's "done" button as completion action)
Any two of the above togethermultiple sensorscompoundcompound_logic + conditions[] (≥2, no nesting)
Consumable level low (ink, toner, filter %)% sensorthresholdtrigger_below
Household batteriesBattery Notes devices(none — use the Battery Fleet)battery_fleet/setup, not a task per battery

Do not propose one threshold task per battery. The integration ships the Battery Fleet: battery_fleet/setup creates ONE task plus a per-type shopping list (AA, AAA, CR2032 …) covering every Battery Notes device in the house, so a 40-battery home gets one reminder instead of 40. Check battery_fleet/overview first (available / has_battery_notes / configured); task_ok: false means the fleet exists but its task or trigger was damaged — re-running setup is the idempotent repair. Individual batteries can be kept out with battery_fleet/set_excluded (self-charging devices).

Everything with no usable sensor → a time-based task (interval_days + interval_unit), optionally upgraded via a derived-usage sensor recipe.

Guardrails recap

Confirm before every write · never invent intervals silently · keep the token safe · prefer proposing over applying · dry-run first · cite sources · never complete, skip or reset tasks on your own, and never send via_tag_scan — it asserts that someone scanned the tag at the thing.

← v1.0.0All versions