Is there a better way to do comfort settings for thermostat setpoints?

I have a bunch of thermostats that I want to put on schedules. I was going to copy ecobee’s approach of using comfort settings to determine thermostat setpoints e.g. Home, Away, Asleep.

I have tried the built in schedule helper, but I cannot define attributes for each time block I define. I dont want to use helpers to create different schedules for different comfort levels because (1) they could conflict (2) there are many thermostats each with its own settings (3) I want (optionally) weekdays to be the same.

Instead, I have written a script that computes which schedule to use based on various inputs/overrides-- e.g. weekday, weekend, vacation-- and from that, computes which comfort setting to use based on the schedule for that day. I have made a compact specification that looks like this:

variables:
  weekday:
    "07:00": Home
    "08:00": Away
    "17:00": Home
    "22:00": Asleep
  weekend:
    "07:00": Home
    "22:00": Asleep
  vacation:
    "00:00": Away

I then define this table in an automation using “define variables” so that it is easily editable from the GUI.

This works, but i am forced to put these automations in my automations.yaml, instead of its own package, if I want to be able to edit the schedule from my phone e.g. without having to go into a text editor/VSCode.

I would prefer a solution where I can easily visualize and/or edit the schedules, while keeping the file in its own package, so as not to clog up my automations.yaml file.

Is there a way to define an input dict that I could store the schedules in, and show that in the UI?

Any advice is appreciated.

I do it slightly differently but it could easily be modified to suit your situation so here goes…
I created a bunch of input_selects and input_datetime for time and temperature:

yaml
input_datetime: #---------------------------------------------------------------

  hive_heating_1:
    name: Schedule 1
    icon: mdi:clock-start
    has_date: false
    has_time: true

  # hive_heating_2 starts when input_select.house_mode ➜ "Awake"

  hive_heating_3:
    name: Schedule 3
    icon: mdi:clock-start
    has_date: false
    has_time: true

  hive_heating_4:
    name: Schedule 4
    icon: mdi:clock-start
    has_date: false
    has_time: true

  hive_heating_5: # pre-wake-up temp
    name: Schedule 5
    icon: mdi:clock-start
    has_date: false
    has_time: true

  # hive_heating_6 starts when input_select.house_mode ➜ "Asleep"

input_number: #-----------------------------------------------------------------

  hive_heating_away_temp:
    name: "Away temp"
    unit_of_measurement: °C
    min: 10
    max: 22
    step: 0.5
    icon: mdi:power-off

  hive_heating_nearby_temp:
    name: "Nearby temp"
    unit_of_measurement: °C
    min: 10
    max: 22
    step: 0.5
    icon: mdi:power-off

  hive_heating_open_temp:
    name: "Windows open temp"
    unit_of_measurement: °C
    min: 10
    max: 22
    step: 0.5
    icon: mdi:power-off

  hive_heating_1_temp:
    name: "Pre-heat"
    unit_of_measurement: °C
    min: 12
    max: 22
    step: 0.5
    icon: mdi:thermometer

  hive_heating_2_temp:
    name: "Awake default"
    unit_of_measurement: °C
    min: 12
    max: 22
    step: 0.5
    icon: mdi:thermometer

  hive_heating_3_temp:
    unit_of_measurement: °C
    min: 12
    max: 22
    step: 0.5
    icon: mdi:thermometer

  hive_heating_4_temp:
    unit_of_measurement: °C
    min: 12
    max: 22
    step: 0.5
    icon: mdi:thermometer

  hive_heating_5_temp:
    unit_of_measurement: °C
    min: 12
    max: 22
    step: 0.5
    icon: mdi:thermometer

  hive_heating_6_temp:
    name: "Asleep default"
    unit_of_measurement: °C
    min: 12
    max: 22
    step: 0.5
    icon: mdi:thermometer

  hive_heating_boost_prior_temp:
    name: "Boost prior temp"
    min: 10
    max: 25 # set high to ensure mum's morning towel boost works even when already hot
    step: 1
    initial: 19
    unit_of_measurement: °C
    icon: mdi:thermometer
    mode: box
  
  hive_heating_boost_temp:
    name: "Boost temp"
    min: 0.5
    max: 2
    step: 0.5
    unit_of_measurement: °C
    icon: mdi:plus
    mode: slider

  hive_heating_boost_time:
    name: "Boost time"
    min: 0.5
    max: 4
    step: 0.5
    unit_of_measurement: Hrs
    icon: mdi:plus
    mode: slider

Then created a sensor that works out what the temp should be based on a bunch of variables:

  • am I home or away (or away, but nearby)
  • is a door or window open
  • house_mode (awake, asleep)
  • the afore mentioned time and temp schedule
template sensor for target temperature
- sensor:
    - name: "Hive heating target temp"
      unique_id: hive_heating_target_temp
      device_class: temperature
      unit_of_measurement: °C
      availability: "{{ has_value('binary_sensor.hive_heating_doors_windows_open') }}"
      attributes:
      # influence shows (on dashboard) what is setting the temp
        influence: >
          {% set sched1 = states('input_boolean.hive_heating_1_scheduled') %}
          {% set sched2 = states('input_boolean.hive_heating_2_scheduled') %}
          {% set sched3 = states('input_boolean.hive_heating_3_scheduled') %}
          {% set sched4 = states('input_boolean.hive_heating_4_scheduled') %}
          {% set sched5 = states('input_boolean.hive_heating_5_scheduled') %}
          {% set sched6 = states('input_boolean.hive_heating_6_scheduled') %}
    
          {% set on1  = states('input_datetime.hive_heating_1')[:5] %}
          {% set on3  = states('input_datetime.hive_heating_3')[:5] %}
          {% set on4  = states('input_datetime.hive_heating_4')[:5] %}
          {% set on5  = states('input_datetime.hive_heating_5')[:5] %}
    
          {% set mode =     states('input_select.hive_heating_target_mode') %}
          {% set boost =    states('timer.hive_heating_boost') %}
          {% set bathroom = states('timer.hive_heating_boost_bathroom') %}
          {% set dr_win =   states('binary_sensor.hive_heating_doors_windows_open') %}
          {% set home =     states('zone.home') %}
          {% set time =     states('sensor.time') %}
          {% set house =    states('input_select.house_mode') %}
          {% set nearby =   states('binary_sensor.nearby') %}
        
          {%   if mode        == 'heat' %}
            {%   if boost     == 'active' %}                              Boost
            {% elif bathroom  == 'active' %}                              Bathroom
            {% elif dr_win    == 'on' %}                                  Dr/Win
            {% elif home      != '0' %}
    
              {%   if house   == 'Awake' %}
                {%   if sched5 == 'on' and (time >= on5 or time < on1) %} Schedule 5
                {% elif sched4 == 'on' and (time >= on4 or time < on1) %} Schedule 4
                {% elif sched3 == 'on' and (time >= on3 or time < on1) %} Schedule 3
                {% else %}                                                Schedule 2
                {% endif %}
              {% elif sched1 == 'on' and ('12:00' > time >= on1) %}       Schedule 1
              {% else %}                                                  Schedule 6
              {% endif %}
    
            {% elif nearby == 'on' %}                                     Nearby
            {% else %}                                                    Away
            {% endif %}
          {% else %}                                                      Off
          {% endif %}
      state: >
        {% set influence =  state_attr('sensor.hive_heating_target_temp','influence') %}
    
        {% set temp1 =    states('input_number.hive_heating_1_temp')|float %}
        {% set temp2 =    states('input_number.hive_heating_2_temp')|float %}
        {% set temp3 =    states('input_number.hive_heating_3_temp')|float %}
        {% set temp4 =    states('input_number.hive_heating_4_temp')|float %}
        {% set temp5 =    states('input_number.hive_heating_5_temp')|float %}
        {% set temp6 =    states('input_number.hive_heating_6_temp')|float %}
        {% set open =     states('input_number.hive_heating_open_temp')|float %}
        {% set nearby =   states('input_number.hive_heating_nearby_temp')|float %}
        {% set away =     states('input_number.hive_heating_away_temp')|float %}
        {% set boostpre = states('input_number.hive_heating_boost_prior_temp')|float %}
        {% set boostby =  states('input_number.hive_heating_boost_temp')|float %}
      
        {%   if influence == 'Boost' %}       {{ boostpre + boostby }}
        {% elif influence == 'Bathroom' %}    {{ boostpre + 0.5 }}
        {% elif influence == 'Dr/Win' %}      {{ open }}
        {% elif influence == 'Schedule 1' %}  {{ temp1 }}
        {% elif influence == 'Schedule 2' %}  {{ temp2 }}
        {% elif influence == 'Schedule 3' %}  {{ temp3 }}
        {% elif influence == 'Schedule 4' %}  {{ temp4 }}
        {% elif influence == 'Schedule 5' %}  {{ temp5 }}
        {% elif influence == 'Schedule 6' %}  {{ temp6 }}
        {% elif influence == 'Nearby' %}      {{ nearby }}
        {% elif influence == 'Away' %}        {{ away }}
        {% elif influence == 'Off' %}         12
        {% else %}                            15
        {% endif %}
      state_class: measurement
      icon: >
        {% set influence = state_attr('sensor.hive_heating_target_temp','influence') %}
        
        {%   if influence == 'Boost' %}       mdi:timer
        {% elif influence == 'Bathroom' %}    mdi:shower
        {% elif influence == 'Dr/Win' %}      mdi:door-open
        {% elif influence[:5] == 'Sched' %}   mdi:calendar-check-outline
        {% elif influence == 'Nearby' %}      mdi:walk
        {% elif influence == 'Away' %}        mdi:car
        {% elif influence == 'Off' %}         mdi:power-off
        {% else %}                            mdi:help
        {% endif %}

…and then a super-simple automation that sets the target temperature whenever that sensor changes.

Now I can set everything in the UI and it looks like this:

Default settings drop-down:
Screenshot 2024-12-16 at 09.58.20