
Automations are the heart of Home Assistant. It is what makes Home Assistant a home automation platform. It is the glue that binds all the other integrations together, and it is what makes your home smart and comfortable.
Non-working automations, however, are a source of frustration. And sometimes, it can take you a bit to notice there is an issue with an automation. Spook enhances the automation integration of Home Assistant by raising repairs issues in case it detects something is wrong with an automation.

Figure 1:Spook found an issue with an automation that is using non-existing entities.
Devices & entities¶
Spook does not provide any new devices or entities for this integration.
Actions¶
Spook adds the following new actions to your Home Assistant instance:
Snooze¶
Turns an automation off for a while, and turns it back on when the time is up.
Action properties | |
|---|---|
Automation: Snooze 👻 | |
| |
Yes, | |
No response | |
Newly added action | |
Action data parameters | |||
|---|---|---|---|
Attribute | Type | Required | Default / Example |
| Yes |
|
Turning an automation off is the only way to make it stop for an hour, and an automation turned off stays off: past the restart, past the weekend, until somebody notices. The usual way around that is a helper entity and a second automation to turn the first one back on, which is two moving parts for something that should be one.
This is that, in one action. It survives a restart of Home Assistant, because the time it is due back is written down rather than left in a timer that dies with the process.
The other way round, holding one on for a while, is Turn on for.
Turning the automation back on yourself cancels the snooze. Saying so is a clearer statement of what you want than a wake-up time set earlier, so Spook takes it that way and forgets the rest.
An automation can snooze itself, which is the plainest way to write “and not again for an hour”. Snoozing stops an automation starting again; it does not stop the run that asked, so the steps after it still happen.
Example actions in YAML
Quiet the doorbell for an hour:
1 2 3 4 5action: automation.snooze target: entity_id: automation.doorbell_announce data: duration: "01:00:00"
Everything in the bedroom, until the morning:
1 2 3 4 5action: automation.snooze target: area_id: bedroom data: duration: "08:00:00"
Tell me the pool is warm, then leave it alone for twelve hours:
1 2 3 4 5 6 7 8 9actions: - action: notify.mobile_app_phone data: message: "The pool is {{ states('sensor.pool_temperature') }} degrees" - action: automation.snooze target: entity_id: automation.pool_temperature_notification data: duration: "12:00:00"
Known limitations
An automation that is already off is left alone, and Spook says so in the log. Waking it would turn on something you turned off, which is not what snoozing asks for.
Snoozing one that is already asleep moves its wake-up time rather than starting a second one.
The automation is off while it sleeps, so anything reading its state sees exactly that. There is no third state between on and off.
Turn on for¶
Turns an automation on for a while, and turns it back off when the time is up.
Action properties | |
|---|---|
Automation: Turn on for 👻 | |
| |
Yes, | |
No response | |
Newly added action | |
Action data parameters | |||
|---|---|---|---|
Attribute | Type | Required | Default / Example |
| Yes |
|
The other way round from Snooze, and the same trap in reverse: an automation turned on stays on, so “just for tonight” needs somebody to remember. Guest mode you switch on in December and find again in March, holiday lighting that outlives the holiday, a debug automation left running.
This is that, in one action, and it survives a restart of Home Assistant for the same reason: the time it is due back off is written down rather than left in a timer that dies with the process.
Turning the automation off yourself cancels the run, the same way turning one on cancels a snooze.
Example actions in YAML
Guest mode, for the weekend:
1 2 3 4 5action: automation.turn_on_for target: entity_id: automation.guest_mode data: duration: "48:00:00"
The party lighting, until the party is over:
1 2 3 4 5action: automation.turn_on_for target: entity_id: automation.disco_floor data: duration: "04:00:00"
Known limitations
An automation that is already on is left alone, and Spook says so in the log. Turning it off later would switch off something you switched on, which is not what this asks for.
Asking again for one already running moves the time it goes off rather than starting a second one.
The automation is on while it runs, so anything reading its state sees exactly that. There is no third state between on and off.
Repairs¶
While Spook is floating around in your Home Assistant instance, it will raise repairs issues if it has found something that is not right.
Automations that are turned off are left alone. An automation that is off does nothing, so nothing in it can go wrong yet, and it is often turned off exactly because something in it is broken. As soon as you turn it back on, Spook looks at it again and reports what it finds.
The same goes for an entity, device, area, floor or label that only disabled steps, triggers or conditions (enabled: false) name. A disabled step does nothing either, and is usually parked on purpose. Anything a running step names as well is still reported.
Unknown referenced areas¶
Automations are inspected for the use of areas. If an automation is targeting an area in one of its actions that do not exist, Spook will raise a repair issue. The repairs issue raised will contain the name of the automation and the area that is referenced but not found.
Templates are read as well, for area_entities and area_devices, called or as a filter. Handed an area that does not exist, these quietly give an empty list, so an action targeting {{ area_entities('Living room') }} does nothing at all once the area is renamed. Spook looks the value up the way Home Assistant does: an area ID, or the name or an alias of an area, in any case. An entity or device ID is reported too. These take nothing but an area, so area_entities('light.kitchen') never finds anything; area_entities(area_id('light.kitchen')) gives what is in the area of that light.
Only a value written out in the template is checked. One worked out while running, from a variable or by joining pieces, is not, and neither is a lookup called by a name the automation gives a meaning of its own, as a variable.

Figure 2:Spook found an issue with an automation that is using a non-existing area.
To resolve the raised issue, you can either remove the reference to the non-existing area or fix the referenced area. Spook will automatically remove the repair issue once the issue is fixed.
Unknown referenced attributes¶
Automations are inspected for the attributes they use: the attribute of state and numeric state triggers and conditions, the attribute Spook’s own state trigger follows, and attributes named in templates, like state_attr('light.kitchen', 'brightness'). If an automation uses an attribute its entity does not have, Spook will raise a repair issue. The repairs issue raised will contain the name of the automation, the attribute, the entity, and what was most likely meant when Spook is near certain of it.
A trigger waiting on an attribute that never shows up loads fine and never fires, and nothing tells you. That is the ghost this catches.
Many attributes only show up some of the time: a media player that is off drops most of its own, and integrations add their own that come and go. So an attribute is only reported when Spook cannot find it anywhere: not on the entity right now, not as something that kind of entity offers in Home Assistant, and not in anything the recorder remembers the entity having. An entity the recorder does not record is only checked for attributes that differ from a real one in upper and lower case alone, like Brightness. An attribute or entity that is only worked out while running, from a variable for example, is not checked. Neither is a template using states or state_attr when the automation gives that name a meaning of its own, as a variable, a field or a response variable.
Spook does not look right after Home Assistant starts, when the recorder is busy, but ten minutes later. After that it looks again once a reload of automations is done, when a automation is added or removed, when the entity registry changes, when an integration loads or its configuration changes, and once a day. An attribute that newly shows up on an entity is picked up the next time it looks.
To resolve the raised issue, edit the automation and use an attribute the entity has. Spook will automatically remove the repair issue once the issue is fixed.
Unknown referenced states¶
Automations are inspected for the states they wait for and check: the to, from, not_to and not_from of state triggers, the state of state conditions, the same options of Spook’s own state trigger, and in templates is_state('light.kitchen', 'on') and a state compared to text, like states('light.kitchen') == 'on', states.light.kitchen.state != 'off' or states('light.kitchen') in ['on', 'off']. If an automation uses a state its entity is never in, like On for a light that is on or off, Spook will raise a repair issue. The repairs issue raised will contain the name of the automation, the state, the entity, and what was most likely meant when Spook is near certain of it.
A trigger waiting for a state that never comes loads fine and never fires, and nothing tells you. That is the ghost this catches.
Only entities whose states are a fixed set are checked: the ones Home Assistant itself lists for that kind of entity (a light, a cover, a lock, an alarm panel, a media player, and so on), or the options the entity offers right now, like a select, a dropdown helper, or a sensor with a fixed list of values. A plain sensor, a number or a text can be anything, so those are not checked, and neither are persons and device trackers, whose states are zone names. Everything the entity was in counts as well: right now, and anything the recorder remembers. An entity whose state is set from outside of its integration, by a REST call or a Python script for example, is not checked either.
For some kinds of entity, Home Assistant itself makes sure the state is one of the set: lights, switches, binary sensors, covers, locks, valves, climate entities, and the like. There, a state that differs from a real one in upper and lower case alone, like On, is always reported, and anything else outside of the set when Spook has the whole history of the entity from the recorder. For the rest, the set is what is usual rather than all that is possible: a media player made from a template can be in any state it likes, and a select, a dropdown helper or a sensor with a fixed list of values can get new options while running. Those only get a state reported that differs from a real one in case alone, and only when Spook has the whole history of the entity. The same goes for an entity that works out its state in a way of its own.
With an attribute, a state trigger or condition waits for a value of that attribute instead, and those are checked too, in the same issue: like Heating for the hvac_action of a thermostat, which is heating. Only attributes whose values are a fixed set: the ones Home Assistant itself lists for that kind of entity (the action of a thermostat or a humidifier, the device class of a sensor, the repeat mode of a media player, and the like), or whose values the entity offers in another attribute, like the fan modes, preset modes and swing modes of a thermostat, the effects of a light, or the sources of a media player. Home Assistant writes whatever the integration hands it for any of these, so only a value that differs from a real one in how it is written is reported, and only when Spook has the whole history of the entity. That is upper and lower case, or YAML reading what was meant as text as something else: an unquoted off is the boolean false, and 2 is a number, while the attribute holds the text "off" or "2". Such a value is shown the way YAML read it, with the text that was meant in quotes. Spook’s own state trigger is checked the same way when it follows an attribute, with one difference: it makes text of whatever the attribute holds and compares that with the text of its to, from, not_to and not_from. So there, a value in another case is a slip, like Heating for heating, and so is a value YAML read as a boolean or a number whose text the attribute never holds: an unquoted off becomes the text False, which a preset mode off never is. A 2 becomes 2, the same text as a fan mode "2", so that one is fine. A 1.0 becomes 1.0, which is not reported against a "1": a number is never taken for a slip of another number. An attribute the entity never had is not looked at here: that is an unknown attribute, which the automation gets an issue of its own for.
A state or entity that is only worked out while running, from a variable or a template for example, is not checked. In templates, only a comparison with nothing else taking part in it is read: once a filter like | lower, a ~ or anything like it is in between, what is compared is no longer the state itself. A template is not read for states, is_state or state_attr either when the automation gives that name a meaning of its own, as a variable, a field or a response variable.
Spook looks at the same moments as for unknown attributes: ten minutes after Home Assistant starts, after that again once a reload of automations is done, when an automation is added or removed, when the entity registry changes, when an integration loads or its configuration changes, and once a day.
To resolve the raised issue, edit the automation and use a state the entity can be in. Spook will automatically remove the repair issue once the issue is fixed.
Unknown referenced devices¶
Automations are inspected for the use of devices. If an automation is using a device that does not exist, Spook will raise a repair issue. The repairs issue raised will contain the name of the automation and the device that is referenced but not found.
Only values shaped like a device ID are considered. Home Assistant hands those out itself and they are always thirty-two hexadecimal characters. Integrations are free to take a field called device_id meaning their own hardware, and some do: RFLink’s device_id is a protocol address. Those are not devices Home Assistant knows about and never will be, so Spook leaves them alone. A real device that was removed still leaves an ID of the right shape behind, so nothing worth finding is given up.

Figure 3:Spook found an issue with an automation that is using a non-existing device.
To resolve the raised issue, you can either remove the reference to the non-existing device or fix the referenced device. Spook will automatically remove the repair issue once the issue is fixed.
Unknown referenced integration entries¶
Automations are inspected for the integration entries they hand their actions. Plenty of integrations have actions that ask which of their integration entries to use, like Nord Pool’s prices or Mealie’s recipes. If an automation hands one an integration entry that does not exist, Spook will raise a repair issue. The same goes for an integration entry of another integration than the action asks for, which happens when a step is copied from an action of another integration. The repairs issue raised will contain the name of the automation and the integration entries that go nowhere.
Home Assistant only refuses these when the step runs, so an automation that runs once in a while fails exactly then. This usually happens after an integration was removed and added again: that gives it a new integration entry, with a new ID, and every action still holds the old one.
Spook only looks at the fields an action itself says take an integration entry, never at a field because of its name. Only actions that are there right now say what they take, so the actions of an integration that is not loaded are not checked. An integration entry that exists but is not loaded right now, because it is disabled or failed to set up, is not reported either: that is the state of the integration, not a mistake in the automation. An integration entry worked out while running, from a template or a variable, is not checked, and neither is a disabled step.
To resolve the raised issue, edit the automation and pick the integration entry again in these actions. Spook will automatically remove the repair issue once the issue is fixed.
Unknown referenced entities¶
Automations are inspected for the use of entities. If an automation is using an entity ID that does not exist, Spook will raise a repair issue. The repairs issue raised will contain the name of the automation and the entity ID that is referenced but not found.

Figure 4:Spook found an issue with an automation that is using non-existing entities.
An entity spelled out after states, like states.light.kitchen.state, is not checked when that states is not Home Assistant’s: when a template defines its own with a macro or {% set %}, or the automation gives the name a meaning of its own, as a variable, a field or a response variable. Used as a filter, like 'light.kitchen' | states, it still is Home Assistant’s, and still checked. An entity ID in quotes is checked wherever it is, whatever it is handed to.
To resolve the raised issue, you can either remove the reference to the non-existing entity ID or fix the referenced entity ID. Spook will automatically remove the repair issue once the issue is fixed.
Unknown referenced actions¶
Automations are inspected for the use of actions. If an automation is using a action that does not exist, Spook will raise a repair issue. The repairs issue raised will contain the name of the automation and the action that is referenced but not found.
Actions of an integration you disabled are not reported: switched off on purpose is not gone. Once you enable the integration again, they are checked as usual.
To resolve the raised issue, you can either remove the reference to the non-existing actions. Spook will automatically remove the repair issue once the issue is fixed.
Unknown icons¶
Automations are inspected for the icons their actions hand out. Only actions that say they take an icon are looked at, like group.set, and the actions of Spook that create areas, labels or helpers. When one of those is handed an mdi: icon that is not in the Material Design Icons that come with Home Assistant, whatever it sets is drawn with an empty spot for an icon. Spook raises a repair issue naming the automation and the icons, and suggests the icon you most likely meant when it is nearly certain.
This usually happens with a typo, an icon that was renamed or removed, or one picked from the Material Design Icons website that is newer than the version Home Assistant comes with.
To resolve the raised issue, edit the automation and replace these with icons that exist. Spook will automatically remove the repair issue once the issue is fixed.
Known limitations
Only icons starting with
mdi:are checked. The olderhass:prefix, and icons from sets you added, like those from HACS, are left alone.An icon that is a template is not checked. What it ends up as cannot be known without running it.
Actions that are turned off are not checked: they never run.
The list of icons is read from the frontend Home Assistant has installed. A frontend run from a development build is not taken into account, and a frontend without that list means nothing is checked.
Unknown referenced floors¶
Automations are inspected for the use of floors. If an automation is targeting a floor in one of its actions that does not exist, Spook will raise a repair issue. The repairs issue raised will contain the name of the automation and the floor that is referenced but not found.
Templates are read as well, for floor_areas and floor_entities, called or as a filter, in the same way as for areas: a floor ID, or the name or an alias of a floor, in any case. Home Assistant tries the value as an area first, though. When it is the name or an alias of an area that sits on a floor, it is taken as a floor ID, and nothing is found. So with an area called Attic on a floor, floor_areas('Attic') finds nothing, even when there is a floor called Attic, and Spook reports it. Use the ID of the floor instead, like floor_areas('attic'). An entity or device ID never finds a floor either.
To resolve the raised issue, you can either remove the reference to the non-existing floor or fix the referenced floor. Spook will automatically remove the repair issue once the issue is fixed.
Unknown referenced labels¶
Automations are inspected for the use of labels. If an automation is targeting a label that does not exist, Spook will raise a repair issue. The repairs issue raised will contain the name of the automation and the label that is referenced but not found.
Templates are read as well, for label_areas, label_devices and label_entities, called or as a filter, in the same way as for areas: a label ID, or the name of a label, in any case. Labels have no aliases.
To resolve the raised issue, you can either remove the reference to the non-existing label or fix the referenced label. Spook will automatically remove the repair issue once the issue is fixed.
Unknown referenced conditions¶
Automations are inspected for the conditions they use. Conditions are provided by integrations, so a condition that no installed integration can provide cannot be evaluated. An automation like that fails validation outright and becomes unavailable, which is why Spook deliberately inspects unavailable automations: they are the broken ones.
Home Assistant does notice, but it raises a generic issue about the automation. Spook names the exact conditions, which is the part you need in order to fix it.
This usually means the integration that provided the condition was removed. To resolve the raised issue, you can either remove the use of these conditions or restore the integration that provides them. Spook will automatically remove the repair issue once the issue is fixed.
Unknown referenced triggers¶
Automations are inspected for the triggers they use. Like conditions, triggers come from integrations, and if no installed integration can provide a trigger, the whole automation goes down with it: it fails validation and becomes unavailable.
So this is not a silent failure, it is a nameless one. Home Assistant raises a generic issue about the automation without saying which trigger caused it. Spook names the trigger.
To resolve the raised issue, you can either remove the use of these triggers or restore the integration that provides them. Spook will automatically remove the repair issue once the issue is fixed.
Unknown referenced trigger IDs¶
Automations are inspected for the trigger IDs they check for: the id of every trigger condition, at the top of the automation and anywhere in its actions (in a choose, an if, a repeat, a condition step, nested in and, or or not, and so on), and in templates trigger.id compared to text, like trigger.id == 'arrived', trigger.id != 'left' or trigger.id in ['arrived', 'left']. If an automation checks for an ID none of its own triggers has, Spook will raise a repair issue. The repairs issue raised will contain the name of the automation and the trigger IDs it checks for that no trigger has.
A trigger condition asking for an ID that no trigger hands over loads fine and never passes, so whatever it guards never runs, and nothing tells you. That is the ghost this catches. It usually happens when a trigger was renamed or removed, or the ID has a typo: trigger IDs are case-sensitive.
A trigger without an ID of its own goes by its position in the list of triggers, counting from 0, so a check for 1 is fine as long as the automation has a second trigger. Triggers you disabled (enabled: false) still count: their IDs are not unknown, they are parked.
Some things are not checked, so Spook does not guess:
An ID that is only worked out while running, from a variable or a template for example. In templates, only a comparison with nothing else taking part in it is read, and
wait.trigger.idis the trigger a wait ended on, not the one that started the automation.An automation that gives
triggera meaning of its own, as a variable or a response variable, and a template that does the same with{% set %}or the like.An automation that failed to load. Home Assistant reports that one itself.
An automation on a blueprint is checked with its inputs filled in, the way Home Assistant runs it. Spook looks again whenever automations are reloaded, which saving one in the editor does.
To resolve the raised issue, edit the automation and use the ID of one of its triggers, or give the trigger the ID the automation checks for. Spook will automatically remove the repair issue once the issue is fixed.
Templates that can never pass¶
Automations are inspected for templates that, because of how they are written, can never render what Home Assistant needs for them to pass: the value_template of template conditions and template triggers, shorthand template conditions (conditions: "{{ ... }}"), and wait_template. Wherever they are: at the top of the automation, and anywhere in its actions (an if, a choose, the while or until of a repeat, a condition step, nested in and, or or not, a wait_for_trigger). If one can never pass, Spook will raise a repair issue. The repairs issue raised will contain the name of the automation and the templates that can never pass.
What passes differs per kind. A template condition passes only when it renders true (any case). A template trigger fires when its template turns into something that reads as true: true, on, yes, enable, 1 or another number that is not zero. It has to see something that does not read as true first, so one that only ever renders on or yes never fires. A wait_template is checked like a condition first. After that it ends when its template renders again into something that reads as true. One without any Jinja, or made of fixed text alone, is never rendered again, so only true ends it.
The shapes this catches, all seen on the forums:
Quotes around the template in a block. With
value_template: >-followed by"{{ is_state('light.hall', 'on') }}", the quotes are text, so the result is"True", quotes included.No
{{ }}at all.value_template: "is_state('light.hall', 'on')"is not a template, it is that text. One missing{{does the same.YAML pasted into the template field of the editor, like
- condition: templatefollowed by itsvalue_template:. All of it is text around the template, and ends up in the result.A YAML
#comment inside the Jinja. Jinja does not know YAML comments: it prints them.A condition that can only render
on,offor another fixed text besidestrue, like{{ 'on' if is_state('light.hall', 'on') else 'off' }}. Fine for a trigger, never passing for a condition.
A template condition, trigger or wait like that loads fine and never passes. The condition is false, the wait only ends on its timeout, the trigger never fires, and nothing tells you. That is the ghost this catches.
Only the text of the template is read. Spook raises the issue only when that alone settles it: text that is always part of the result and can never be part of true, a result that always starts with something nothing true starts with, or every result the template can give, whichever way it goes, failing. Anything that depends on a state, a variable or the moment it runs is never judged. Some things are not reported on purpose:
A template trigger without any Jinja that does read as true, like
trueoron. It never changes, so it never fires either, but that is not what this repair is about.A comment after the template in a trigger, like
{{ is_state('light.hall', 'on') }} # hall. Home Assistant reads a trigger’s result like Python, and Python skips that comment, so it works.Text that is only printed in some branches of an
{% if %}or a loop.An automation that failed to load. Home Assistant reports that one itself.
An automation on a blueprint is checked with its inputs filled in, the way Home Assistant runs it. Spook looks again whenever automations are reloaded, which saving one in the editor does.
To resolve the raised issue, edit the automation and make the template render true when it should pass: remove the quotes around it, wrap it in {{ }}, remove what was pasted around it, use {# #} for comments, or compare to get true instead of on. Spook will automatically remove the repair issue once the issue is fixed.
Removed users¶
Automations are inspected for the users they name by their ID: the user_id an event trigger waits for in its context, also in a wait_for_trigger, and in templates the ID of a user compared to text. That is the user behind something, like trigger.to_state.context.user_id == '…', trigger.event.context.user_id in ['…', '…'] or context.user_id != '…', and the user of a person, like state_attr('person.frenck', 'user_id') == '…' or is_state_attr('person.frenck', 'user_id', '…'). If an automation names a user that no longer exists, Spook will raise a repair issue. The repairs issue raised will contain the name of the automation and the user IDs it cannot find.
Home Assistant gives every user a random ID and never hands the same one out twice, so an ID no user has belongs to a user that was removed. A trigger waiting for that user never fires for them, and a template comparing with that ID never matches. Home Assistant does not tell you.
Some things are not checked, so Spook does not guess:
Something that is not shaped like a user ID. A user written down by name never matched anybody, and is not a user that was removed.
user_idin theevent_dataof an event trigger, or in the data of an event in a template. What an event callsuser_idis up to whoever fires it, like the Telegram user of a Telegram command.An attribute called
user_idof anything but a person.A comparison something else takes part in, like a filter, and a template or automation that gives
trigger,contextor the like a meaning of its own.A disabled step or trigger, and an automation that is turned off or failed to load.
Spook looks again whenever a user is added or removed, and whenever automations are reloaded, which saving one in the editor does.
To resolve the raised issue, edit the automation and use the ID of a user that exists, or remove the check. Spook will automatically remove the repair issue once the issue is fixed.
Feature requests, ideas, and support¶
If you have an idea on how to further enhance this integration, for example, by adding a new action, entity, or repairs detection; feel free to let us know in our discussion forums.
Are you stuck using these new features? Or maybe you’ve run into a bug? Please check the Support page on where to go for help.