Create a template sensor manually in the configuration.yaml file.
In my example, I have an input text which shows the last time a switch was turned off manually. The helpers do appear to allow the person to edit them on the dashboard. Why do I do this? All the code for my motion sensors for turnng lights on, check to see when the light was last turned off manually first, and does not turn the light on if it had been turned off manually within the last 5 minutes. (How annoying would it be to turn off a light and then when you try to walk out of the room the light goes back on again since the motion sensor noticed you moving?)
So, I have an automation that just places the current time into an input_text (but ONLY when the switch was turned off MANUALLY).
So, this sensor shows “physical” if the light is turned off physically:
template:
#
# Bathroom Lights (for accessing these and with the last_changed value):
# {{ states('sensor.bathroom_lights_off_context') }}
# {{ states.sensor['bathroom_lights_off_context'].last_changed }}
#
# 1. Track the 'off' context changing (has to be triggered even if turning on,
# so any change at all will cause logic to be triggered if subsequent objects
# already set as "physical" will still be updated)
#
- trigger:
- platform: state
entity_id: light.bathroom_shelly_1_relay
sensor:
- name: "Bathroom Lights Off Context"
state: >
{% set c_id = trigger.to_state.context.id %}
{% set c_parent = trigger.to_state.context.parent_id %}
{% set c_user = trigger.to_state.context.user_id %}
{% if states('light.bathroom_shelly_1_relay') == 'on' %}
n/a
{% elif c_id != none and c_parent == none and c_user == none %}
physical
{% elif c_id != none and c_parent == none and c_user != none %}
dashboard_ui
{% elif c_id != none and c_parent != none and c_user == none %}
automation
{% else %}
unknown
{% endif %}
unique_id: bathroom_lights_off_context
Then I have an automation which is triggered by the above ‘sensor’ changing to the value of ‘physical’ and then populates the input_text with the exact time the sensor changed to ‘physical’:
alias: >-
Bathroom Lights Off Context -> If Done Manually -> Set Last Manual Off
Timestamp
description: >-
If the bathroom lights are turned off (manually), then make sure the
"last_manual_off-bathroom" timestamp is updated
trigger:
- platform: state
entity_id:
- sensor.bathroom_lights_off_context
to: physical
action:
- service: input_text.set_value
data:
value: >-
{{
as_timestamp(states.sensor['bathroom_lights_off_context'].last_changed)
}}
target:
entity_id: input_text.last_manual_off_bathroom
mode: parallel
max: 1000
So then, my “input_text.last_manual_off_bathroom” has the linux timestamp: 1694105648.839893
but looks like this non-editable label on the dashboard:
Because the above is just showing this sensor (code shown below) from configuration.yaml (and you need to create a sensor like the below which is just displaying the input_whatever sensor value. Yes, it is a pain in the butt, but we all do this because we love technology and coding, right?
sensor:
# Sensors for last a switch was manually turned off:
- platform: template
sensors:
last_manual_off_br:
friendly_name: Bathroom Last Manual Off
value_template: >-
{% set lst1 = (states('input_text.last_manual_off_bathroom') | as_datetime | as_local) %}
{% set lst2 = lst1.strftime('%a %-m/%-d %-I:%M:%S.%f %p') %}
{% set pos = lst2.find(" [A-Z]M") - 5 %}
{{ lst2[:pos] + lst2[pos+4:].lower() }}
icon_template: >-
mdi:clock-digital
unique_id: last_manual_off_bthr
So when the motion sensor detects motion, it checks to see if it was done within the last 5 minutes - just for fun here is the code I use for that motion detection - notice the math won’t work unless the numbers to be compared are both changed to floats:
alias: Bathroom Motion Detected (if not switched off manually within last 5 minutes)
description: ""
trigger:
- type: motion
platform: device
device_id: aea2f20e0a1b340eada447d293217bb0
entity_id: binary_sensor.bathroom_motion_sensor_motion
domain: binary_sensor
condition:
- condition: template
value_template: >-
{{ (float(as_timestamp(now())) -
float(states('input_text.last_manual_off_bathroom'),0)) > 300 }}
action:
- service: script.motion_detected
data:
enablement_input_selector_entity: input_select.automation_bathroom_is
timer_duration_entity: input_number.bathroom_adjust_timer
timer_entity: timer.bathroom_light_timer
mode: parallel
max: 1000
(All my motion detectors call the same script (“script.motion_detected”) as shown at the end above - just the objects with which the script needs to work are passed to it as parameters - so I could remove alot of duplicate code. My lights in this case are turned on by a timer (re)starting and turned off when the timer is stopped or finished - all of that is a story for a different day )
Once you have it working just change the properties for your “input_whatever” to be hidden.
One thing I wanted to do was to be able to programatically create custom entity objects on the fly which I could pass to scripts - or even pass to automations! - but Home Assistant isn’t there yet (and might never get that sophisticated!)