Skip to main content

Glue integrations

A glue integration is a small, standalone Home Assistant integration whose only job is to bridge another integration to Home Keeper. It owns no schedule logic and no UI of its own. It watches the other integration's signals and translates them into Home Keeper service calls (and listens for Home Keeper completions to translate back).

This is the lightest way to make a third-party integration "Home Keeper aware" without modifying it. The reference example is Home Keeper / Battery Notes, which connects Battery Notes to Home Keeper.

When to use a glue integration

Reach for the glue pattern when:

  • The source integration already exposes the state you care about (an event, a sensor, a binary_sensor) but knows nothing about Home Keeper.
  • You can't or don't want to modify the source integration (it's third-party, or the Home-Keeper link is opt-in and shouldn't be a hard dependency).
  • The mapping is essentially "when this condition is true, a task is due; when it's resolved, the task is done."

If you own the source integration, you don't need glue. Call the Home Keeper services directly from it (see INTEGRATING.md). Glue exists precisely for the case where the two sides must stay decoupled.

The shape of the glue

A glue integration is a normal custom integration with a config entry. In async_setup_entry it:

  1. Discovers the things to track from the source integration (e.g. enumerates Battery Notes devices, or subscribes to its events).
  2. Maps each one to a Home Keeper triggered task (armed when the condition is true, dormant otherwise) using home_keeper.add_task / home_keeper.trigger_task / home_keeper.complete_task.
  3. Listens to home_keeper_task_completed so a completion made in Home Keeper is reflected back into the source integration (and vice-versa), with loop prevention.

Everything it does is the triggered-task contract already documented in INTEGRATING.md §7. The glue integration is just a thin client of it. Guard every call with hass.services.has_service("home_keeper", "<service>") so the glue degrades to a no-op when Home Keeper isn't installed.

Worked example: Battery Notes

Battery Notes tracks each device's battery and flips a low-battery signal when it needs replacing. The glue maps that one-to-one onto a Home Keeper triggered task:

Battery Notes says…Glue callsResult in Home Keeper
battery went low (first seen)add_task with recurrence_type: "triggered"a "Replace battery" task, armed / due-now, attached to the battery's device
battery went low again laterhome_keeper.trigger_taskthe existing task re-arms (history preserved)
battery replacedhome_keeper.complete_task (with an origin)the task records a completion and goes dormant
user ticks the task off in Home Keeper(listener reacts to home_keeper_task_completed, origin = None)glue tells Battery Notes the battery was replaced

Because the task persists across cycles instead of being deleted and recreated, its completion history accumulates, so you learn the real cadence ("this smoke-detector battery lasts ~13 months") instead of losing it on every replacement.

Keeping the two sides in sync without loops

The danger is a feedback loop: a replacement completes the task → Home Keeper fires home_keeper_task_completed → the glue's listener marks it replaced in Battery Notes → which might complete the task again. Break it exactly as INTEGRATING.md §4 describes:

  • When the glue completes a task, pass a recognizable origin (e.g. your domain), and have the listener ignore events whose origin is its own.
  • On the inbound path (a completion the glue did not initiate), apply the side-effect without calling complete_task again.

Either guard closes the loop. Use both.

Reconciling on restart

Triggered tasks are persistent, so on async_setup_entry the glue should reconcile rather than blindly recreate:

  • Call home_keeper.list_tasks and match on your source namespace to find tasks you already created.
  • For each tracked thing: if no task exists, add_task; then arm or clear it (trigger_task / complete_task) to match the source integration's current state.
  • Only delete_task when the tracked thing disappears for good.

See INTEGRATING.md §5 for the full lifecycle, and INTEGRATING.md §6 for declaring managed_by so Home Keeper shows a "Managed by …" chip, locks fields the user shouldn't edit, and cleans up orphaned tasks if the glue is removed.

Testing

Test the glue end-to-end against Home Keeper's bundled fake (no panel, storage, or entities required). See INTEGRATING.md → Testing your integration.