Yes, there are five other posts with this error message in the title, but the answers are all to specific situations. My questions are:
- What does the message mean?
- Why on earth does a boolean need an attribute ‘lower’? What does ‘lower’ mean?
- Is there also an attribute ‘upper’? And if so, what does it mean?
- Most importantly: how do I find out what object the message refers to?
- And what should I do about it?
Comments on my draft code (not working) are welcome, but rather than giving me a fish, I would prefer a fishing rod
### ------------------------------------------------------------------------------------
###
### NIGHT WALK
### ----- ----
###
### Controls one or more lights from one or more motion and illuminance sensors
### ... but delays first, in case user operates lights him/her self
### ... and fades up slowly to avoid confusion to dementia sufferer
###
### 17-Jun-24 | Andy Symons | First complete version
### 18-Jun-24 | Andy Symons | (a) Added stagger times (b) reversed order for turning off
### 19-Jun-24 | Andy Symons | Added optional start and end times.
### Moved response conditions to variables, see 'respond_to_motion'.
### Logs start conditions.
###
### ------------------------------------------------------------------------------------
blueprint:
name: Night Walk
description:
Fade up lights slowly when motion detected, but only if dark and if not
already turned on manually or by voice assistant.
Converse for turning off and only after a minimum on time.
domain: automation
input:
motion_sensors:
name: Motion sensor(s)
selector:
entity:
filter:
domain: binary_sensor
device_class: motion
multiple: true
dimmable_lights:
name: Dimmable light(s)
description: Light(s) to be faded up and down
selector:
entity:
filter:
domain: light
multiple: true
default: []
non_dimmable_lights:
name: Non-dimmable light(s)
description: Light(s) to be simply turned on and off
selector:
entity:
filter:
- domain: light
multiple: true
default: []
test_mode_switch:
name: Test mode switch
description: Switch or sensor that can be turned on to override the Night time / darkness conditions
selector:
entity:
filter:
- domain:
- binary_sensor
- input_boolean
- switch
multiple: false
default: ""
night_sensor:
name: Night sensor
description: Sensor that is 'true' for night time (the hours of darkness or low sun elevation)
selector:
entity:
filter:
- domain:
- binary_sensor
- switch
multiple: false
default: ""
illuminance_sensors:
name: Luminance sensor(s)
selector:
entity:
filter:
domain: sensor
device_class: illuminance
multiple: true
default: []
stagger_time:
name: Stagger time
description: Gap between fade or switch starting times for of each light
selector:
number:
min: 0
max: 30
unit_of_measurement: seconds
default: 3
start_time:
name: Start time
description: Earliest time at which this automation is in operation
selector:
time:
default: "00:00"
end_time:
name: Start time
description: Earliest time at which this automation is in operation
selector:
time:
default: "00:00"
fade_up_time:
name: Fade up time
description: Time to fade up from 0 to 100%
selector:
number:
min: 0
max: 30
unit_of_measurement: seconds
default: 20
fade_down_time:
name: Fade down time
description: Time to fade down from 100 to 0%
selector:
number:
min: 0
max: 30
unit_of_measurement: seconds
default: 15
on_delay:
name: On delay
description: Wait time before acting on detected motion
selector:
number:
min: 0
max: 120
unit_of_measurement: seconds
default: 3
off_delay:
name: Off delay
description: Time to leave the lights on after last motion is detected.
selector:
number:
min: 0
max: 120
unit_of_measurement: seconds
default: 3
on_timer:
name: On timer
description: The timer to be used to time the on-time
selector:
entity:
filter:
- domain:
- timer
multiple: false
minimum_on_time:
name: Minimum on time
description: Wait time before automatically turning off
selector:
number:
min: 0
max: 60
unit_of_measurement: minutes
default: 5
logging_service_name:
name: LOGGING - Specify the service for logging
description: Enter service name (not filename) as a string
default: ""
mode: queued
max_exceeded: silent
trigger:
# motion detected
- platform: state
id: motion_detected
entity_id: !input motion_sensors
to: "on"
for: !input on_delay
# motion clear
- platform: state
id: motion_clear
entity_id: !input motion_sensors
to: "off"
for: !input off_delay
# On timer end
- platform: state
id: timer_ended
entity_id: !input on_timer
to: idle
variables:
#
# Log message preamble identifies the source of the log messages
#
log_message_preamble: "{{ this.attributes.friendly_name }}"
#
# Determine if we are currently in test mode. Defaults to False if there is no test switch.
#
input_test_mode_switch: !input test_mode_switch
test_mode: >
{% if states(input_test_mode_switch) is defined %}
{{ states(input_test_mode_switch) == 'on' }}
{% else %}
{{ False }}
{% endif %}
#
# Determine if we are currently witihn the operating time range
#
input_start_time: !input start_time
input_end_time: !input end_time
within_time_range: >
{% set start_timestamp = as_timestamp(today_at(input_start_time)) %}
{% set end_timestamp = as_timestamp(today_at(input_end_time)) %}
{% set now_timestamp = as_timestamp(now()) %}
{% if end_timestamp == start_timestamp %}
{{ True }}
{% elif end_timestamp > start_timestamp %}
{{ now_timestamp >= start_timestamp and now_timestamp < end_timestamp }}
{% else %}
{{ now_timestamp >= start_timestamp or now_timestamp < end_timestamp }}
{% endif %}
#
# Determine if it is night. If there is no sensor then defaults to false.
#
input_night_sensor: !input night_sensor
is_night: >
{% if states(input_night_sensor) is defined %}
{{ states(input_night_sensor) }}
{% else %}
{{ False }}
{% endif %}
#
# Determine if luminance is low. If there is no sensor then defaults to false.
#
input_illuminance_sensors: !input illuminance_sensors
illuminance_is_low: >
{% set ns = namespace(is_dark = false) %}
{% for sensor in input_illuminance_sensors %}
{% if states(sensor) is defined %}
{% if states(sensor) < 50 %}
{% set ns.is_dark = true %}
{% endif %}
{% endif %}
{% endfor %}
{{ ns.is_dark}}
#
# Determine whether to respond to motion (based on the above).
#
respond_to_motion: >
{% if states(test_mode) %}
{{ True }}
{% elif not states(within_time_range) %}
{{ False }}
{% else %}
{{ states(is_night) or states(illuminance_is_iow) }}
{% endif %}
#
# Identify the lights to change
#
input_dimmable_lights: !input dimmable_lights
input_non_dimmable_lights: !input non_dimmable_lights
# 1 Lights to fade up = dimmable lights in listed order that are currently off
lights_to_fade_up: >
{% set input_list = input_dimmable_lights %}
{% set ns = namespace(output_list=[]) %}
{% for light in input_list %}
{% if states(light) == 'off' %}
{% set ns.output_list = ns.output_list + [light] %}
{% endif %}
{% endfor %}
{{ ns.output_list }}
# 2 Lights to turn on = non-dimmable lights in listed order that are currently off
lights_to_turn_on: >
{% set input_list = input_non_dimmable_lights %}
{% set ns = namespace(output_list=[]) %}
{% for light in input_list %}
{% if states(light) == 'off' %}
{% set ns.output_list = ns.output_list + [light] %}
{% endif %}
{% endfor %}
{{ ns.output_list }}
# 3 Lights to fade down = dimmable lights in reverse of listed order that are currently on
lights_to_fade_down: >
{% set input_list = input_dimmable_lights %}
{% set ns = namespace(output_list=[]) %}
{% for light in input_list | reverse %}
{% if states(light) == 'on' %}
{% set ns.output_list = ns.output_list + [light] %}
{% endif %}
{% endfor %}
{{ ns.output_list }}
# 4 Lights to turn off = non-dimmable lights in reverse of listed order that are currently on
lights_to_turn_off: >
{% set input_list = input_non_dimmable_lights %}
{% set ns = namespace(output_list=[]) %}
{% for light in input_list | reverse %}
{% if states(light) == 'on' %}
{% set ns.output_list = ns.output_list + [light] %}
{% endif %}
{% endfor %}
{{ ns.output_list }}
action:
## -------------------------------------------------------------------------------------------------
## ACTION[0,1,2] -- LOG BLANK LINE, THE TRIGGER AND THE STARTING CONDITIONS
## -------------------------------------------------------------------------------------------------
# First a blank line to start the new entry
- service: script.logfile_entry
data:
notification_service: !input logging_service_name
logfile_title: Night Walk
message_preamble: "{{ log_message_preamble }}"
message_body: ---
# Then the trigger details line
- service: script.logfile_entry
data:
notification_service: !input logging_service_name
logfile_title: Night Walk
message_preamble: "{{ log_message_preamble }}"
message_body: >
{% if trigger.id is undefined %}
{{ "Run manually." }}
{% elif trigger.entity_id is undefined %}
{{ "Triggered by: " + trigger.id | string + " (no entity id)" }}
{% else %}
{{ "Triggered by: " + trigger.id | string + " from '" + state_attr(trigger.entity_id, 'friendly_name')
+ "', state = " + states(trigger.entity_id) }}
{% endif %}
# Then log the starting conditions line
- service: script.logfile_entry
data:
notification_service: !input logging_service_name
logfile_title: Night Walk
message_preamble: "{{ log_message_preamble }}"
message_body: >
{{ "Conditions: test_mode = " + states(test_mode)|string }}
## -------------------------------------------------------------------------------------------------
## ACTION[3] -- ACT ON THE TRIGGER
## -------------------------------------------------------------------------------------------------
- choose:
#
# ACTION[3]CHOOSE[0] Motion detected and it is within the operating time range AND dark OR in test mode
#
- conditions:
- alias: "Motion detected"
condition: trigger
id: motion_detected
- alias: "Respond to motion (see variables definitions)"
condition: template
value_template: "{{ states(respond_to_motion) }}"
# Note: this condition only appears here, so fade and turn off will still happen if the conditions change in the meantime
sequence:
# ACTION[3]CHOOSE[0]SEQUENCE[0] Fade up dimmable lights
- if:
- condition: template
value_template: "{{ lights_to_fade_up | count > 0 }}"
then:
- repeat:
for_each: "{{ lights_to_fade_up }}"
sequence:
- service: light.turn_on
data:
brightness_pct: 100
transition: !input fade_up_time
target:
entity_id: "{{ repeat.item }}"
# timer started only if a light is actually turned on
- service: timer.start
metadata: {}
data:
duration:
minutes: !input minimum_on_time
target:
entity_id: !input on_timer
# stagger the start times
- delay:
seconds: !input stagger_time
# ACTION[3]CHOOSE[0]SEQUENCE[1] Turn on any non-dimmable lights
- if:
- condition: template
value_template: "{{ lights_to_turn_on | count > 0 }}"
then:
- repeat:
for_each: "{{ lights_to_turn_on }}"
sequence:
- service: light.turn_on
data: {}
target:
entity_id: "{{ repeat.item }}"
# timer started only if a light is actually turned on
- service: timer.start
metadata: {}
data:
duration:
minutes: !input minimum_on_time
target:
entity_id: !input on_timer
# stagger the start times
- delay:
seconds: !input stagger_time
#
# ACTION[3]CHOOSE[1] Motion clear
#
- conditions:
- alias: "Motion clear"
condition: trigger
id: motion_clear
- alias: "The on timer is not still running"
condition: state
entity_id: !input on_timer
state: "idle"
sequence:
# Turn off non-dimmable lights
- if:
- condition: template
value_template: "{{ lights_to_turn_off | count > 0 }}"
then:
- repeat:
for_each: "{{ lights_to_turn_off }}"
sequence:
- service: light.turn_off
data: {}
target:
entity_id: "{{ repeat.item }}"
# stagger the turn-off times
- delay:
seconds: !input stagger_time
# Fade down dimmable lights
- if:
- condition: template
value_template: "{{ lights_to_fade_down | count > 0 }}"
then:
- repeat:
for_each: "{{ lights_to_fade_down }}"
sequence:
- service: light.turn_on
data:
brightness_pct: 0
transition: !input fade_down_time
target:
entity_id: "{{ repeat.item }}"
# stagger the fade-down start times
- delay:
seconds: !input stagger_time
#
# ACTION[3]CHOOSE[2] Timer ended
#
- conditions:
- alias: " timer ended"
condition: trigger
id: timer_ended
- alias: "All motion sensors clear"
condition: state
entity_id: !input motion_sensors
state: "off"
sequence:
# Turn off non-dimmable lights
- if:
- condition: template
value_template: "{{ lights_to_turn_off | count > 0 }}"
then:
- repeat:
for_each: "{{ lights_to_turn_off }}"
sequence:
- service: light.turn_off
data: {}
target:
entity_id: "{{ repeat.item }}"
# stagger the turn-off times
- delay:
seconds: !input stagger_time
# Fade down dimmable lights
- if:
- condition: template
value_template: "{{ lights_to_fade_down | count > 0 }}"
then:
- repeat:
for_each: "{{ lights_to_fade_down }}"
sequence:
- service: light.turn_on
data:
brightness_pct: 0
transition: !input fade_down_time
target:
entity_id: "{{ repeat.item }}"
# stagger the fade-down start times
- delay:
seconds: !input stagger_time