Template switch doesn't preserve state

I’m trying to create a series of switches in order to control at what times my heater should start or stop. Each switch would control a 15 minute interval which could be on or off if I want the heater to run in that interval or not.

I experimented with template switches, but I’m having problems with preserving the switch state. For example this is my entry:

switch:
  - platform: template
    switches:
      heater_timer_00_00:
        friendly_name: Heater timer 00:00
        value_template: "{{ is_state('switch.heater_timer_00_00', 'on') }}"
        turn_on:
          service: automation.trigger
          data:
            entity_id: automation.heater_timer_changed
        turn_off:
          service: automation.trigger
          data:
            entity_id: automation.heater_timer_changed
        icon_template: mdi:fire

I’m not trying to extract the current state from any other element, but from the switch itself.
When I try to enable the switch, it briefly turns on, runs the automation, but the state reverst back to off:

Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: service=turn_on, domain=homeassistant, service_data=entity_id=switch.heater_timer_00_00, service_call_id=547442032200-92>
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: service=turn_on, domain=switch, service_data=entity_id=['switch.heater_timer_00_00'], service_call_id=547442032200-93>
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.helpers.script] Running script
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.helpers.script] Executing step call service
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: service=trigger, domain=automation, service_data=entity_id=automation.heater_timer_changed, service_call_id=547442032200-94>
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.components.automation] Executing Heater timer changed
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event logbook_entry[L]: name=Heater timer changed, entity_id=automation.heater_timer_changed, domain=automation, message=has been triggered>
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.helpers.script] Script Heater timer changed: Running script
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.helpers.script] Script Heater timer changed: Executing step Heater timer changed
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: service=check_heater_timer, domain=script, service_data=, service_call_id=547442032200-95>
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.helpers.script] Script Check heater timer: Running script
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.helpers.script] Script Check heater timer: Executing step call service
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: service=check_heater_timer, domain=shell_command, service_data=, service_call_id=547442032200-96>
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event service_executed[L]: service_call_id=547442032200-96>
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event service_executed[L]: service_call_id=547442032200-95>
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event state_changed[L]: new_state=<state script.check_heater_timer=off; last_triggered=2017-09-27T13:25:38.225969+03:00, friendly_name=Check heater timer @ 2017-09-27T12:22:53.077737+03:00>, entity_id=script.check_heater_timer, old_state=<state script.check_heater_timer=off; last_triggered=2017-09-27T13:25:19.888833+03:00, friendly_name=Check heater timer @ 2017-09-27T12:22:53.077737+03:00>>
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event state_changed[L]: new_state=<state automation.heater_timer_changed=on; id=1506495245, last_triggered=2017-09-27T13:25:38.454630+03:00, friendly_name=Heater timer changed @ 2017-09-27T12:22:59.703722+03:00>, entity_id=automation.heater_timer_changed, old_state=<state automation.heater_timer_changed=on; id=1506495245, last_triggered=2017-09-27T13:25:20.105018+03:00, friendly_name=Heater timer changed @ 2017-09-27T12:22:59.703722+03:00>>
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event service_executed[L]: service_call_id=547442032200-94>
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event service_executed[L]: service_call_id=547442032200-93>
Sep 27 13:25:38 bellatrix hass[27448]: 2017-09-27 13:25:38 INFO (MainThread) [homeassistant.core] Bus:Handling <Event service_executed[L]: service_call_id=547442032200-92>

It seems like the automation for turning it on is executed, but the state doesn’t stick. Any idea what I could change to have the switch stick?
Thanks!

seems like a problem i had long ago.
template switches need to be connected to another entity to keep the state.

that was one of the reasons why i implemented Appdaemon and use an input_boolean that controls an app.

Hmm. My use-case is to use the switches in the GUI so that I can replace my cron entries with something user-selectable.
I guess I could use command_line switches and control the state from a backend script, but that would imply a lot of command_line calls on my system (I will have 96 such switches), which I’d like to avoid.

But input_boolean! That’s the tool I was looking for! I guess it’s rendered as a switch in the frontend, and I can script whatever I need externally.

Thank you for your suggestion.

thats what i do with Appdaemon.
http://appdaemon.readthedocs.io/en/latest/index.html

I’ll start reading. You’re right, there is no point in reinventing the wheel. :slight_smile:

1 Like

its actually quite simple.

after you installed appdaemon you can create a simple app like:


import appdaemon.appapi as appapi


class heater(appapi.AppDaemon):

  def initialize(self):
    self.listen_state(self.callback,"input_boolean.heater_timer_00")

  def callback(self, entity, attribute, old, new, kwargs):
    if new == "on":
      do your automation stuff for on
    else:
      do your automation stuff for off

but i think you will use something else the 96 booleans in the end.
you could use a spreadsheet with a table from 24x4 or even a simple text script and read that out.

The use case is this - create some sort of manual thermostat where the user can select in which intervals the heater should run.

The backend/appdaemon script should do the following:
0. Obtain a list of input_boolean items from HA. I suppose this can either be done with your API, or by querying the HA API to get a list of components and parse out the ones I need.

  1. React to a input_boolean being toggled (this can be done with what you suggest) and I would need to register a callback for each input_boolean (in a loop).
  2. The callback function would realise which boolean has been triggered, and if the current time is within the interval which the input_boolean represents, turn on or off the heater accordingly.
  3. Have a periodic (e.g. every 15 minutes) callback of a function which checks the current time, checks the corresponding input_boolean state and turns on or off the heater. This would replace the “cron” part of the automation.

Once all of this is working (and I hope I get it working soon, because winter is coming!), I will need to add/find a way to save the values for the input_booleans, so that they can be restored on HA restart. I have a rough idea on how to do that, but - does such an APP exist already? Save the state of select components to a file (periodically) and restore the state on HA startup?

yup, its even in the default example apps.

i understand your use case but i would go for something that can be easily and nicely presented.

Great! I’ll look for it.

Do you recommend a different approach to set arbitrary time intervals with HA/AppDaemon?

i think i would create a sensor that you could update with an custom widget in hadashboard.
the sensor would contain an X or a O for every 15 minutes and in de widget i would read that sensor and make a checkbox for every X (checked) or O(unchecked)
that way you could have a nice dashboard with a widget that would look like:

   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
00               v v  v  v  v  v  v  v  v  v  v  v  v  
15               v v  v  v  v  v  v  v  v  v  v  v  v
30               v v  v  v  v  v  v  v  v  v  v  v  v  v
45               v v  v  v  v  v  v  v  v  v  v  v  v  v

the sensor would have value:
OOOOOOOXXXXXXXXXXXXXOOOOOOOOOOOXXXXXXXXXXXXXOOOOOOOOOOOXXXXXXXXXXXXXXOOOOOOOOOOXXXXXXXXXXXXXXOOO

and you would have an app that listens to state change from the sensor and it would have a run_every(callback,15*60) that would check if the heater needs to be on the next 15 minutes.

I see, thank you.
But would I be able to interact with the sensor from HA directly? I think that only if I add it as an iframe and point it back to the dashboard page.
It’s an interesting approach. I’ll think about it, thanks!

from within the HA gui its not possible to create a nice approach.
then your 96 input_booleans is the only way.

but an iframe that points to a dashboard page should work.

Ok, I took the plunge and implemented it in HA + AppDaemon.

This script will generate the HomeAssistant input_boolean + group configuration:

This is how it looks in the GUI:

This is the AppDaemon component:

It’s still being tested, but so far it seems to be working fine. It can be compiled into a dashboard by adding the 96 items to a grid display (maybe I’ll do it later).
I will also document this when it’s done…
Thanks for the help!

1 Like

I’m very new to HA but I had the same problem today. I was able to fix it to preserve state by making my switch optimistic. This makes Home Assistant assume that the last change state trigger worked (held). The default is not optimistic / negative and assumes the trigger did not hold and so reverts it back to off.

switch:
  - platform: template
    name: RF Power Button
    optimistic: true  # Preserves last state
    id: rf_power_switch  
    turn_on_action:
      - remote_transmitter.transmit_rc_switch_raw:
          code: 'xxxxxx'
          protocol: 1
          repeat:
            times: 10
            wait_time:  0s
    turn_off_action:
      - remote_transmitter.transmit_rc_switch_raw:
          code: 'xxxxxx'
          protocol: 1
          repeat:
            times: 10
            wait_time: 0s