Hi all,
I’m not a HA guru, or even a YAML or Python one, but I do know how to troubleshoot. Sometimes they call me a pitbull because I cannot let go easily if I encounter a problem with something which seem to be trivial. So, here we go:
I have a parcel box. You can put in a parcel through the drop box, and you can take it out again through a door (which is locked with a key). I added sensors (switch1 and switch2 connected to an ESP01 running Tasmota) for both the drop box and the door and created a template sensor which turns ‘on’ when the drop box is used, and is turned ‘off’ when the door is opened.
This works fine, I added my configuration below. Note that I split up my yaml files over multiple files/folders, so in my configuration.yaml I have:
# Secret trick: load integration multiple times! the word 'split' is free to choose as long as it is unique
automation split: !include_dir_merge_list automations/
binary_sensor: !include_dir_merge_list binary_sensors/
light: !include_dir_merge_list lights/
mqtt: !include_dir_merge_named mqtt/
notify: !include_dir_merge_list notifiers/
rest_command: !include_dir_merge_named rest_commands/
sensor: !include_dir_merge_list sensors/
shell_command: !include_dir_merge_named shell_commands/
switch: !include_dir_merge_list switches/
template: !include_dir_merge_list templates/
tts: !include_dir_merge_list tts/
utility_meter: !include_dir_merge_named utility_meters/
Don’t forget to restart HA to make changes effective!
My sensor is in config/templates/parcelbox.yaml:
- binary_sensor:
- unique_id: parcelbox_status
state: >
{%- set box = states('binary_sensor.template_parcelbox_status') -%}
{%- if is_state('binary_sensor.esp01_03_switch1', 'off') -%}
{%- set box = "on" -%}
{%- endif -%}
{%- if is_state('binary_sensor.esp01_03_switch2', 'off') -%}
{%- set box = "off" -%}
{%- endif -%}
{{- box -}}
trigger:
- platform: state
entity_id: binary_sensor.esp01_03_switch1
- platform: state
entity_id: binary_sensor.esp01_03_switch2
So far, so good (my switches are ‘off’ when the drop box or door are opened).
However, When someone opens the drop box the template-sensor gets ‘on’. There are then two ways to get it ‘off’ again:
- Open the door
- In DevTools → States, change the state of this sensor to ‘off’
I would like a third option: Press a button in the UI to switch it ‘off’ (or toggle it)
There are some services like switch.toggle, light.toggle and even a generic homeassistant.toggle, but they cannot toggle a template sensor. I also tried the ‘turn off’ versions I could find, but none of them work for a template sensor neither.
I also investigated the possibilities of events, but as they seem capable of setting the state, I cannot get it to work from the action within a button card
I do have a solution which feels like a U-turn: You can change a state through the API!
My solution is as follows (I tried to make it as generic as possible, so I can re-use it in other places):
First I need an API key, which can be generated from your personal settings page. I stored that in secrets.yaml. BEWARE: You need the keyword 'Bearer ’ in front of it!
My secrets.yaml line looks like (redacted):
local-apikey: Bearer eyJhbGciOiJIUzI1NiIsIawew6nR5cCI6Ikp....
Next I created a ‘my_set_state.yaml’ in the ‘rest_commands/’ folder (remember I split up my config files):
my_set_state:
url: "http://localhost:8123/api/states/{{ entity_id }}"
method: POST
headers:
authorization: !secret local-apikey
accept: "application/json, text/html"
user-agent: "Mozilla/5.0"
content_type: "application/json; charset=utf-8"
payload: "{{ payload | tojson }}"
The ‘tojson’ filter is crucial, otherwise this will generate strings with ‘single quotes’, which are not accepted by json (only “double quotes” are valid).
If you want it to be even more universal, you can put more variables here (e.g. {{ url }} )
WARNING: There are NO safety checks here! Use at your own risk!
The final step is to call this command from a button. In this example I use a HACS custom-button-card, because this allows me to implement a toggle functionality. If you just hardcode ‘state: off’ at the end of the configuration, then a standard button card will work as well.
My button card looks like:
type: custom:button-card
entity: binary_sensor.template_parcelbox_status
icon: mdi:package
state:
- value: 'off'
color: rgb(0,0,160)
- value: 'on'
color: rgb(0,160,0)
show_name: false
show_label: true
label: Parcel box
tap_action:
action: call-service
service: rest_command.my_set_state
service_data:
entity_id: '[[[ return entity.entity_id ]]]'
payload:
state: |
[[[
if (entity.state == 'on') return 'off';
if (entity.state == 'off') return 'on';
else return 'unknown';
]]]
One last note: In the payload the entity_id to be changed is returned. I use a local variable to obtain the id of the entity monitored in this button (in the “entity:” field, in this case ‘binary_sensor.template_parcelbox_status’), but you can put any valid entity_id here.
I used the DevTools to test the various possibilities, and even configured a local Apache server with ‘dumpio’ to send the API calls to, just to see what was sent and what needed to be sent. It took me quite some hours to figure this out, so I hope someone else can save some time to achieve a similar goal.
But I truly believe there is another, cleaner way of doing this (without this U-turn), as it is also possible through the DevTools. How does that work, anyway?
Any thoughts?
Regards,
Marcel