@roschi
Thanks for the advise and examples, I landed up doing the following although I am sure there are cleaner ways to do the rules, but hey they are working for me
They turn things on/off when needed based on watched entities (input_boolean , input_select and sensors states) such as summer/winter (Temperature based), who’s home and who’s not
Main thing is I now have a much shorter codebase
So, I created two automations that turn on or off an input_boolean at the times the heaters should be on/off and set this as a watched entity
I then added the following rule into each room, could not use the append or prepend as I have room specific rules and schedulesnippits that conflict although I do use both for other
- x: "17 if active_time() == 'off' else Next()"
Here is an example of a standard room
rooms:
entrance:
rescheduling_delay: 60
actors:
climate.entrance_heater:
schedule:
- weekdays: 1-7
rules:
- x: "23 if octopus_price() == 'Plunge' else Next()"
- x: "17 if heating_bedtime() == 'on' else Next()"
- x: "10 if is_on('binary_sensor.frontdoor_contact') else Next()"
- x: "10 if is_on('binary_sensor.backdoor_contact') else Next()"
- x: "10 if is_on('binary_sensor.slidingdoor_contact') else Next()"
- x: "17 if active_time() == 'off' else Next()"
- x: "IncludeSchedule(schedule_snippets['special']) if heating_mode() == 'Special' else Next()"
- x: "IncludeSchedule(schedule_snippets['home']) if heating_mode() == 'MJPAway' else Next()"
- x: "IncludeSchedule(schedule_snippets['home']) if heating_mode() == 'Home' else Next()"
- v: 17
If anyone is interested, here is my full heating schedule
10 rooms, 13 heaters
It monitors if:
- Doors are open
- Summer/Winter Season
- Variable electricity tarif (Octopus Agile or Go)
- Who’s home
- High house total energy (V & A)
- If at Work or Off work (We work from Home)
- Holiday, Home or Away modes etc
schedy_heating_season: # This is our app instance name.
module: hass_apps_loader
class: SchedyApp
actor_type: thermostat
expression_environment: |
def heating_mode():
return state("input_select.heating_mode")
def heating_season():
return state("input_select.heating_season")
def front_door():
return state("binary_sensor.frontdoor_contact")
def back_door():
return state("binary_sensor.backdoor_contact")
def sliding_door():
return state("binary_sensor.slidingdoor_contact")
def octopus_price():
return state("input_select.octopus_price")
def octopus_tariff():
return state("input_select.octopus_tariff")
def power_saving():
return state("input_boolean.power_saving")
def heating_bedtime():
return state("input_boolean.heating_bedtime")
def gdp_location():
return state("input_select.gdp_status")
def bsp_location():
return state("input_select.bsp_status")
def mjp_location():
return state("input_select.mjp_status")
def jmp_location():
return state("input_select.jmp_status")
def mandj_location():
return state("input_select.mandj_status")
def heating_active_minutes():
return state("input_boolean.heating_active_minutes")
watched_entities:
- input_select.heating_mode
- input_select.heating_season
- input_boolean.heating_active_minutes
- input_select.octopus_price
- input_select.octopus_tariff
- input_boolean.power_saving
- input_boolean.heating_bedtime
- binary_sensor.frontdoor_contact
- binary_sensor.backdoor_contact
- binary_sensor.slidingdoor_contact
- input_select.mjp_status
- input_select.jmp_status
- input_select.gdp_status
- input_select.bsp_status
- input_select.mandj_status
schedule_snippets:
bedrooms:
- { v: 17, start: "07:00", end: "20:00" }
- { v: 20, start: "20:00", end: "22:00" }
- { v: 18, start: "22:00", end: "07:00" }
bedroom4_mjpaway:
- { v: 17, start: "00:00", end: "18:00" }
- { v: 20.1, start: "18:00", end: "22:00" }
- { v: 18, start: "22:00", end: "00:00" }
home: # Used with rules - x: "IncludeSchedule(schedule_snippets['home']) if heating_mode() == 'Home' else Next()"
- { v: 17, start: "00:00", end: "08:00" }
- { v: 18, start: "08:00", end: "20:00" }
- { v: 17, start: "20:00", end: "00:00" }
holiday: # Used with rules - x: "IncludeSchedule(schedule_snippets['holiday']) if heating_mode() == 'Holiday' else Next()"
- { v: 17, start: "00:00", end: "00:00" }
default: # Used with rules - { "IncludeSchedule(schedule_snippets['default']) }
- { v: 17.2, start: "00:00", end: "00:00" }
octopusagile: # Used with rules - { "IncludeSchedule(schedule_snippets['default']) }
- { v: 17, start: "16:00", end: "19:00" }
officehours:
- { v: 17, start: "00:00", end: "07:00" }
- { v: 21, start: "07:00", end: "17:00" }
- { v: 17, start: "17:00", end: "00:00" }
lounge:
- { v: 17, start: "00:00", end: "08:00" }
- { v: 18, start: "08:00", end: "16:00" }
- { v: 21, start: "16:00", end: "22:00" }
- { v: 17, start: "22:00", end: "00:00" }
lounge_offwork:
- { v: 17, start: "00:00", end: "08:00" }
- { v: 18, start: "08:00", end: "09:00" }
- { v: 21, start: "09:00", end: "22:00" }
- { v: 17, start: "22:00", end: "00:00" }
lounge_mjpaway:
- { v: 17, start: "00:00", end: "08:00" }
- { v: 18, start: "08:00", end: "16:00" }
- { v: 21, start: "16:00", end: "20:00" }
- { v: 17, start: "20:00", end: "00:00" }
schedule_prepend:
- x: "16 if octopus_price() == 'Peak' else Next()"
- x: "16 if power_saving() == 'On' else Next()"
- x: "16 if heating_mode() == 'Away' else Next()"
- x: "18 if heating_season() == 'Summer' else Next()"
- x: "17 if heating_mode() == 'Holiday' else Next()"
schedule_apppend:
- x: "IncludeSchedule(schedule_snippets['octopusagile']) if octopus_tariff() == 'Agile'"
rooms:
entrance:
rescheduling_delay: 60
actors:
climate.entrance_heater:
schedule:
- weekdays: 1-7
rules:
- x: "23 if octopus_price() == 'Plunge' else Next()"
- x: "17 if heating_bedtime() == 'on' else Next()"
- x: "10 if is_on('binary_sensor.frontdoor_contact') else Next()"
- x: "10 if is_on('binary_sensor.backdoor_contact') else Next()"
- x: "10 if is_on('binary_sensor.slidingdoor_contact') else Next()"
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
- x: "IncludeSchedule(schedule_snippets['default']) if mandj_location() == 'Away' else Next()"
- x: "IncludeSchedule(schedule_snippets['home']) if heating_mode() == 'Home' else Next()"
- v: 17
downstairsufh:
rescheduling_delay: 60
actors:
climate.entrance_ufh:
climate.passage_ufh:
climate.diningroom_ufh:
schedule:
- weekdays: 1-7
rules:
- x: "23 if octopus_price() == 'Plunge' else Next()"
- x: "17 if heating_bedtime() == 'on' else Next()"
- x: "10 if is_on('binary_sensor.frontdoor_contact') else Next()"
- x: "10 if is_on('binary_sensor.backdoor_contact') else Next()"
- x: "10 if is_on('binary_sensor.slidingdoor_contact') else Next()"
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
- x: "IncludeSchedule(schedule_snippets['default']) if mandj_location() == 'Away' else Next()"
- x: "IncludeSchedule(schedule_snippets['home']) if heating_mode() == 'Home' else Next()"
- v: 17
diningroom:
rescheduling_delay: 60
actors:
climate.diningroom_heater:
schedule:
- weekdays: 1-7
rules:
- x: "23 if octopus_price() == 'Plunge' else Next()"
- x: "17 if heating_bedtime() == 'on' else Next()"
- x: "10 if is_on('binary_sensor.frontdoor_contact') else Next()"
- x: "10 if is_on('binary_sensor.backdoor_contact') else Next()"
- x: "10 if is_on('binary_sensor.slidingdoor_contact') else Next()"
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
- x: "IncludeSchedule(schedule_snippets['default']) if mandj_location() == 'Away' else Next()"
- x: "IncludeSchedule(schedule_snippets['home']) if heating_mode() == 'Home' else Next()"
- v: 17
kitchen:
rescheduling_delay: 60
actors:
climate.kitchen_heater:
schedule:
- weekdays: 1-7
rules:
- x: "23 if octopus_price() == 'Plunge' else Next()"
- x: "17 if heating_bedtime() == 'on' else Next()"
- x: "10 if is_on('binary_sensor.frontdoor_contact') else Next()"
- x: "10 if is_on('binary_sensor.backdoor_contact') else Next()"
- x: "10 if is_on('binary_sensor.slidingdoor_contact') else Next()"
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
- x: "IncludeSchedule(schedule_snippets['default']) if mandj_location() == 'Away' else Next()"
- x: "IncludeSchedule(schedule_snippets['home']) if heating_mode() == 'Home' else Next()"
- v: 17
lounge:
rescheduling_delay: 60
actors:
climate.lounge_front_heater:
climate.lounge_side_heater:
schedule:
- weekdays: 1-5
rules:
- x: "23 if octopus_price() == 'Plunge' else Next()"
- x: "17 if heating_bedtime() == 'on' else Next()"
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
- x: "IncludeSchedule(schedule_snippets['lounge_offwork']) if heating_mode() == 'OffWork' else Next()"
- x: "IncludeSchedule(schedule_snippets['default']) if mandj_location() == 'Away' else Next()"
- x: "IncludeSchedule(schedule_snippets['lounge_mjpaway']) if mjp_location() == 'Away' else Next()"
- x: "IncludeSchedule(schedule_snippets['lounge']) if heating_mode() == 'Home' else Next()"
- v: 17
- weekdays: 6-7
rules:
- x: "23 if octopus_price() == 'Plunge' else Next()"
- x: "17 if heating_bedtime() == 'on' else Next()"
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
- x: "IncludeSchedule(schedule_snippets['lounge_offwork']) if heating_mode() == 'OffWork' else Next()"
- x: "IncludeSchedule(schedule_snippets['default']) if mandj_location() == 'Away' else Next()"
- x: "IncludeSchedule(schedule_snippets['lounge_mjpaway']) if mjp_location() == 'Away' else Next()"
- x: "IncludeSchedule(schedule_snippets['lounge']) if heating_mode() == 'Home' else Next()"
- v: 17
office:
rescheduling_delay: 60
actors:
climate.office_side_heater:
climate.office_front_heater:
schedule:
- weekdays: 1-5
rules:
- x: "23 if octopus_price() == 'Plunge' else Next()"
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
- x: "IncludeSchedule(schedule_snippets['default']) if heating_mode() == 'OffWork' else Next()"
- x: "IncludeSchedule(schedule_snippets['default']) if mandj_location() == 'Away' else Next()"
- x: "IncludeSchedule(schedule_snippets['officehours']) if mjp_location() == 'Away' else Next()"
- x: "IncludeSchedule(schedule_snippets['officehours']) if heating_mode() == 'Home' else Next()"
- v: 17
- weekdays: 6-7
rules:
- x: "23 if octopus_price() == 'Plunge' else Next()"
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
- v: 17
masterbathroom:
rescheduling_delay: 60
actors:
climate.master_bathroom_heater:
schedule:
- weekdays: 1-7
rules:
- x: "23 if octopus_price() == 'Plunge' else Next()"
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
- v: 17
guestbathroom:
rescheduling_delay: 60
actors:
climate.guest_bathroom_heater:
schedule:
- weekdays: 1-7
rules:
- x: "23 if octopus_price() == 'Plunge' else Next()"
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
- v: 17
bedroom1:
rescheduling_delay: 60
actors:
climate.bedroom1_heater:
schedule:
- weekdays: 1-7
rules:
- x: "17 if gdp_location() == 'Away' else Next()"
# - x: "20 if heating_bedtime() == 'on' else Next()"
# - x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
# - x: "IncludeSchedule(schedule_snippets['bedrooms'])"
- v: 17
bedroom2:
rescheduling_delay: 60
actors:
climate.bedroom2_heater:
schedule:
- weekdays: 1-7
rules:
# - x: "20 if heating_bedtime() == 'on' else Next()" # With guests
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
# - x: "IncludeSchedule(schedule_snippets['bedrooms'])" # With guests
# - v: 17 # With guests
- v: 17
bedroom3:
rescheduling_delay: 60
actors:
climate.bedroom3_heater:
schedule:
- weekdays: 1-7
rules:
- x: "17 if bsp_location() == 'Away' else Next()"
- x: "20 if heating_bedtime() == 'on' else Next()"
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
- x: "IncludeSchedule(schedule_snippets['bedrooms']) if heating_mode() == 'Home' else Next()"
- v: 17
bedroom4:
rescheduling_delay: 60
actors:
climate.bedroom4_heater:
schedule:
- weekdays: 1-7
rules:
- x: "20 if heating_bedtime() == 'on' else Next()"
- x: "17 if heating_active_minutes() == 'off' else Next()" # Used to turn heating on @ xx:00 & xx:30 and off @ xx:15 & xx:45
- x: "IncludeSchedule(schedule_snippets['default']) if mandj_location() == 'Away' else Next()"
- x: "IncludeSchedule(schedule_snippets['bedroom4_mjpaway']) if mjp_location() == 'Away' else Next()"
- x: "IncludeSchedule(schedule_snippets['bedrooms']) if heating_mode() == 'Home' else Next()"
- v: 17