Duty Cycle: Having an automation call itself like a loop

I have a heated mattress pad that gets too hot on the “low” setting, so I’m using home assistant to modulate it on and off using a duty cycle. I thought it was going to be a simple loop with a timer and it took 4 hours of hair pulling to get it working. Wanted to share in case anyone has feedback or finds this in a future search.

I created three helpers. A toggle for the dashboard that can be set between 1% and 100%, and two sensors that calculate the on time and off time in the form of seconds, which are mathematically tied to the toggle.

Then I created an automation that has a while loop built in. I tried having 2 automations call back and forth between each other, and also tried having one automation that calls itself. But for the life of me I could not get that working despite trying various services and modes (single, restart, etc.).

The loop is called repeat and uses while and sequence keys.

If i was to do this (though I’d be quite reticent as it has the potential for going very wrong if home assistant stops) I’d do it this way:

One input number for required duty cycle (1 to 100%)
One input boolean for heating control on/off.

Two automations (or one if you want to combine them with trigger ids and choose actions):

I’ve chosen 60 seconds as the period of the heating cycle, but choose what works for you.

turns on the heater

trigger:
  - platform: state
    entity_id: switch.bed_heater
    to: 'off'
    for: "{{ 60 - (60 * states('input_number.duty_cycle')|int(0)/100)|round(0)|int }}"
  - platform: state
    entity_id: input_boolean.bed_heater
    to: 'on' # to start the cycle
condition:
  - condition: state # to stop the cycle if you turn off the input boolean
    entity_id: input_boolean.bed_heater
    state: 'on'
action:
  - service: switch.turn_on
    target:
      entity_id: switch.bed_heater

turns off the heater

trigger:
  platform: state
  entity_id: switch.bed_heater
  to: 'on'
  for: "{{ (60 * states('input_number.duty_cycle')|int(0)/100)|round(0)|int }}"
action:
  - service: switch.turn_off
    target:
      entity_id: switch.bed_heater

These two automations will cycle the switch on and off until the input boolean is turned off.

Personally I would do this with a temperature sensor and the generic thermostat. But as you don’t have the temperature sensor this will have to do.

Thank you for the details. It won’t create a hazard or anything if home assistant stops, so it shouldn’t matter too much if it gets stuck.

Your math and logic definitely looks better than mine. If I end up switching to it I will let you know if there’s any issues.

Good point about the temperature sensor, I would add that in if I had more time