Heaty will die, Schedy be born!


I have had similar thoughts. I’m thinking that if I know (for example) I can heat by 1 degree in an hour, and my target is 18, then I need to switch on an hour before with that target temp if it is currently 17. If you keep working backwards at a degree increase every hour, if it needs heating from 13, then it would switch on 5 hours before (so 5 schedules).

If you just specified the target temp 5 hrs before, if the difference was less than 5 degrees, it would be at target long before you needed it.

However, not tried this theory yet…

You could potentially have different schedules depending on outside temperature so if it is much colder it may take longer to increase by 1 degree. I’m not sure if you can use an expression to choose a template schedule or not.


@taste Well, that’s doable with custom Python code in a schedule expression of course, but it’s very special and not straight forward. Two schedules aren’t needed, because everything doable with two schedules can be done with only one as well. Two schedules don’t increase the expressiveness.

I once sketched something to calculate how much to throttle the heating based on the time left until somebody returns home and the outside temperature. Maybe you can adapt it to consider the current room’s temperature and fixed times instead of presence.

remaining_hours = float(state("input_number.global_absence_hours_left") or 0)
outside_temp = float(state("sensor.outside_temperature") or 5)

# Throttle 0.5 °C per hour.
sub = 0.5 * remaining_hours

# Negate the effect of throttling when it's below 5 °C outside.
# 0.25 °C are removed from the throttle value for each degree it is
# below 5 °C.
sub -= max(0, 0.25 * (5 - outside_temp))

# Limit throttling to max 5 °C.
sub = max(0, min(5, sub))

# Align to 0.5 °C steps to avoid changing temperature too often.
sub = math.floor(2 * sub) / 2

result = Add(-sub)


@baz123 That’s an interesting concept, however I think it’s not that simple. If walls are not cooled down yet because e.g. you heated the same room yesterday the target temperature will probably be reached earlier than in a room which hasn’t been heated for three days.

However, the concept seems interesting. Maybe I’ll come up with a function that can be used to do gradual scheduling in an actor type-independent way.


Yes this sort of algorithm is not simple but what I outlined is a fairly simple approximation and can reduce over heating without any special knowledge or expertise (just write a schedule).

I’ve been toying with doing this using Node Red and Javascript to generate the target temperature at any point in time so that a final temperature can be reached by a specified time. Not been able to find any sort of algorithm to get me started though. Lots of variables, as you said, retained heat but also solar gain, outside temperature, wind etc etc. :smile:


Yes, one has to implement his own algorithm considering all the variables available. Such an algorithm can well be implemented in an expression of a schedule rule, but you need the target temperature first, and it would be handy if that could be expressed by a regular Schedy schedule as well.

Maybe you could write a schedule snippet that generates the target temperature and then, in the room’s schedule, evaluate that snippet for different points in time to decide whether you need to start heating or not. But the eval_schedule() method would need to be exposed to the evaluation environment to be able to evaluate the snippet for a given point in time.



I’m still using heaty so if I’m not posting in the right topic, I apologize in advance.
I have some heaty rules which are not applied and I can’t figure out why.
For instance, this morning (tuesday), the temp should have been set to 20 between 6 and 7:30 but it was 16.
Here is my code and I don’t see any errors in appdaemon logs:

      - { temp: "20 if app.get_state('input_boolean.enfants') == 'on' else 16", start: "06:00", end: "07:30", weekdays: 1} #every two mondays in the morning
      - { temp: "20 if app.get_state('input_boolean.enfants') == 'on' else 16", start: "07:00", end: "09:30", weekdays: 6-7} #every two week-ends, morning
      - { temp: "19 if app.get_state('input_boolean.enfants') == 'on' else 16", start: "09:30", end: "18:00", weekdays: 6-7} #every two week-ends, day
      - { temp: "20 if app.get_state('input_boolean.enfants') == 'on' else 16", start: "18:00", end: "21:00", weekdays: 6-7} #every two week-ends, evening
      - { temp: "20 if app.get_state('input_boolean.enfants') == 'on' else 16", start: "18:00", end: "21:00", weekdays: 5} #every two fridays
      - { temp: 20, start: "07:30", end: "18:00", weekdays: 3} #wednesday day
      - { temp: 20, start: "06:00", end: "07:30", weekdays: 2-3} #tuesday and wednesday morning
      - { temp: 20, start: "18:00", end: "20:30", weekdays: 1-2} #monday and tuesday evening
      - { temp: 16 } #rest of the time

      friendly_name: kid1
        - temp: IncludeSchedule(schedule_snippets["enfants"])
      friendly_name: kid2
        - temp: IncludeSchedule(schedule_snippets["enfants"])


@radar As always, without a log with debug: true - no chance, sorry.

Have you verified the time shown in the AppDaemon logs has the right time zone? If you’re e.g. using AppDaemon in docker, you need to mount /etc/localtime to the container in order to have the hosts time zone passed through to AppDaemon…

Is there any reason you’re not using Schedy?

Could you switch over to Schedy and try to reproduce the issue there?


@roschi and @baz123 Thanks for your replies, as not being a SW guy I need some time to think this trough :slight_smile:
The advantage in this case is it does not need to be very accurate 1-2 degrees off at the target moment is still acceptable. There is in winter a big delta , 10-15 degrees between the internal temp and the target temp so a first order algorithm will already improve comfort a lot.
I think I will start with @roschi suggestion since this will be easier to modify in case things change.


I had nothing significant in the logs and, actually, I figured out that if the apps.yaml is wrongly written, then the logs stop at --- Validating the app's configuration. without telling that something is wrong. And I had an error in my conf file, where weekdays: 6, 7 is not accepted in schedule_snippets.

Is there any reason you’re not using Schedy?

Only the fact that the stable doc does not contain any entry for Schedy. So, I started with Heaty. I’ll switch to Schedy soon.



@radar A traceback is generated when config validation fails, and that goes to the appdaemon error log. Maybe you’ve redirected the error log to a different place than the normal log?

weekdays: 6, 7 is well accepted, but when you write your rules as one-liners, the YAML parsers thinks you’re starting a new dict item after the comma. Just Put 6, 7 in quotes. This would have been told you in the error log as well.

And, please don’t post all the logs here, this is really specific and an issue to be reported via GitHub to not generate to much noise here.


@taste If you refer to the time-ahead evaluation of schedule snippets to see what happens in the future, that’s not yet possible without a function to evaluate schedules manually.


@roschi, thank you very much.


Hi @roschi, I’m really sorry but I cannot understand why my heaty is not working as it should. I’m pretty sure I’m the reason but can’t figure it out. So please, help.
The conf file is here.
As you can see, kids (1, 2, and 3) should have their room set at 16° on wednesday at 6pm, right?
But at that exact moment, temperature is not changed and remains at 19.
Appdaemon log (from 5:55pm to 6:45pm) is here and error logs did not print any output since this morning (wednesday) 9am.


@radar Right, That’s an issue recently fixed in Schedy. The problem is that schedules aren’t re-evaluated when rules of schedule snippets start or end, only the native room’s rules are considered therefor.

Switch to Schedy and you’re done. :slight_smile:

Even your open window detection will benefit, as that was a bit fragile in Heaty.


Is it possible to use expressions in defining the schedule time limits? I’d like to define schedules with start or end at sunrise or sunset and it’s not quite obvious how to do it. At the moment I have such schedules define with four discrete automations and I’d love to consolidate them with Schedy.


Another, unrelated question: I have existing Home Assistant groups with thermostats in many of them. For example, group.living_room has two climate devices in it, along a few other unrelated entities. I’d like to define a schedule for the living room thermostats, but preferably without having to list the devices twice. With plain Home Assistant automations, I can set the temperature for group.living_room, and it works correctly, but Schedy didn’t seem to appreciate the indirection. Is it possible to define e.g. thermostat actors as climate devices within an existing group? Or would such a feature be difficult to implement?


I think you can add more than one actor to a single room in Schedy. They both get sent the same value.

If you want different values at the same schedule, I think you can do a schedule template and apply it to separate ‘rooms’.


@baz123 I know I can add more than one actor to a single room, but that was what I wanted to avoid. :smiley: I’ve already defined the groupings elsewhere and would prefer to not repeat myself. It’s not a dealbreaker, of course, because I can still get the desired functionality, but ideally I’d just like to define the grouping once and just refer to that grouping.


What about using this to schedule irrigation, that would need to be based on weather data (either from a weather api providing with data if it rained or not and regarding the temperature or from physical moisture sensors) - it should cancel the irrigation if it rained yesterday or today for example. Does it sound doable?


@marksev1 that should be quite straightforward. Assuming the irrigation is controlled by a switch, if you can only define an expression whether you should irrigate or not, then you can create a fixed schedule and have the expression as such:

- x: "on" if should_irrigate() else "off"