So maybe this is a bit of an odd blueprint.
I have trouble creating a blueprint that triggers (motion == detected, ergo state is on) the lights that are in the same area as my motion just triggered sensor.
I have the following code to detect if any of my sensors are on, then get the area of that specific sensor and then use the area(s) in the lights.on service.
When I run this blueprint HASS keeps complaining it doesn’t get find following areas (the area names are exactly the same as my area names). These are:
living_room
office
hallway
This is my first time creating a blueprint and don’t know really how I can make this work.
Any advice on how to make this work?
Blueprint yaml:
blueprint:
name: Turn on/off lights based on motion sensor
description: Turn on or off lights based on which motion sensor has detected motion
or stopped detecting motion
domain: automation
input:
motion_entity:
name: Motion Sensor
selector:
entity:
domain: binary_sensor
device_class: motion
multiple: true
actions:
name: Actions
description: Action or similar to be run (e.g. turn on light). {{area}} is replaced with
the area of where the sensors being triggered reside in.
selector:
action: {}
source_url: https://input-url-here-later-on
variables:
areas: |
{% set result = namespace(area=[]) %}
{% for state in states.binary_sensor
| rejectattr('attributes.device_class', 'undefined')
| selectattr('attributes.device_class', '==', 'motion') %}
{%- if state.state == 'on' %}
{## Get the area id so we know what area to turn light on ##}
{% set result.area = result.area + [area_id(state.entity_id)] %}
{% endif %}
{% endfor %}
{{result.area}}
trigger:
- platform: state
entity_id: !input 'motion_entity'
from: "off"
to: "off"
condition: []
action:
- choose: []
default: !input 'actions'
- service: light.turn_on
data: {}
target:
area_id: |
{%- if areas|length > 1 -%}
{%- for area in areas -%}
- {{area}}
{% endfor %}
{%- else -%}
- {{areas}}
{%- endif -%}
mode: single
The template I posted above resolves the original problem you reported:
The error message you posted is complaining about a different problem:
2022-10-28 14:22:19.168 ERROR (MainThread) [homeassistant.components.automation] Blueprint Turn on/off lights based on motion sensor generated invalid automation with inputs OrderedDict([(‘motion_entity’, [‘binary_sensor.sensor3’])]): expected a dictionary for dictionary value @ data[‘variables’]. Got None
If you are using the template I suggested, your blueprint no longer needs the entire variables section so you can safely remove it. In addition, delete any existing automations produced by the blueprint and re-create them after you have executed Reload Automations.
Ah I’m sorry for the confusion. I figured that out and removed that, removed old automating and was typing a new reply which I didn’t send yet.
I get one step further but it now it thinks the output is incorrect:
2022-10-28 14:52:09.628 ERROR (MainThread) [homeassistant.components.automation.test_turn_on_off_lights_based_on_motion_sensor] TEST Turn on/off lights based on motion sensor: Error executing script. Invalid data for call_service at pos 1: template value should be a string @ data['area_id'][0]
My guess it requires the format:
- office
- hallway
Where this is the output in the template developer tool thingy:
The error message indicates the value for area_id should be a string:
2022-10-28 14:52:09.628 ERROR (MainThread) [homeassistant.components.automation.test_turn_on_off_lights_based_on_motion_sensor] TEST Turn on/off lights based on motion sensor: Error executing script. Invalid data for call_service at pos 1: template value should be a string @ data[‘area_id’][0]
I have no idea why it claims it should be a string because area_id definitely accepts a list. It might be a software bug.
EDIT
target permits the use of device_id, entity_id, and area_id. All are designed to accept a list value.
As a comparative example, the following template produces a list of entity_ids. The service call works without producing an error message complaining it must be a string:
Thanks again for everything! I really appreciate it
I converted my code to get the lights from the areas and when I use that in the call it works like a charm :).
This is my code so far:
{% set areas = states.binary_sensor | selectattr('attributes.device_class', 'defined')
| selectattr('attributes.device_class', '==', 'motion')
| selectattr('state', 'eq', 'on') | map(attribute='entity_id')
| map('area_id') | unique | reject('none') | list %}
{%- for area in areas -%}
{{- states.light
| selectattr('state', 'eq', 'off')
| selectattr('entity_id', 'in', area_entities(area))
| map(attribute='entity_id') | reject('none') | list }}
{% endfor %}
Maybe not the prettiest code but it works.
And now to get the states from sensors I enter through a input field because I realised it also tries to find lights in areas where there are no lights so that errors out
Did you test it in your blueprint? I can’t see how it can possibly work because it makes the same mistake as in your original example: it attempts to use a Jinja2 template to generate a list in YAML.
You can’t use a Jinja2 template to generate YAML. Home Assistant processes YAML first then processes Jinja2. Any Jinja2 template that generates YAML is too late because YAML processing comes before Jinja2 processing.