Heaty - a flexible heating control, facilitating schedules and manual intervention

Hey @roschi - OK, I see. Thanks for your forbearance.

So because off_temp defaults to OFF my schedule snippet will actually work - right? (For good order I will actually explicitly include it)

No, it won’t work without a fallback rule that explicitly sets OFF for any time not mentioned before in the schedule.

off_temp: OFF only specifies what to set the thermostats to when the master switch is turned off and has nothing to do with schedules at all.

This wasn’t described correctly in the sample config due to historical reasons, my fault. I now fixed it.

Hi all,

I implemented some enhancements around thermostats which don’t support setting a temperature (as the one @PianSom is using for hot water). Ordinary switch entities should (at least in theory :slight_smile: ) now also work as thermostats when configured appropriately. It would be really cool if some of you could test the new features.

These are the concrete issues:

https://github.com/efficiosoft/hass-apps/issues/15
https://github.com/efficiosoft/hass-apps/issues/16

Best regards
Robert

EDIT: And, of course, you need to install directly from the git repository in order to test the new features. How that works is described in the docs on the Getting started page.

1 Like

Hi,

First TRV finally arrived, with a second due today, and a 3rd tomorrow; after that i have a pending order for 8 more; which will get me started.

I have normalised my installation to a Ubuntu Installation on a NUC, and chosen to do the manual install of Hass.IO, now that i understand the approach taken with docker. From here I have installed the container for AppDeamon.

Sitting in my ./homeassistant/appdaemon/apps folder, I cloned in your application with the following command

sudo git submodule add -f  https://github.com/efficiosoft/hass-apps.git hass-apps

Then, in the same ./homeassistant/appdaemon/apps folder, I copied in the sample, and loaders

sudo cp hass-apps/hass_apps/data/hass_apps_loader.py .
sudo cp hass-apps/docs/apps/heaty/sample-apps.yaml heaty.yaml

To refelect the folder structure I then edited the file hass_apps_loader.py

from hass-apps.hass_apps.loader import *

And, also edited the sample file, which i now call heaty.yaml; pointing to my Spirit TRV

# This is a minimal example configuration that does just basic things.
# If you want to have further control over your heatings, use open window
# detection, set temperature based on entity states etc., please see the
# full example below.
heaty_minimal:
  # Obligatory settings that tell appdaemon where to find the app.
  # You shouldn't need to change these two.
  module: hass_apps_loader
  class: HeatyApp

  rooms:

    # Define such a block for each room you want to control.
    office:
      thermostats:
        climate.eurotronic_eur_spiritz_wall_radiator_thermostat_heat:
      schedule:
      # From Monday to Friday, set temperature to 20.5 °C from 7.45 am
      # to 10.00 pm.
      - { temp: 22.5, start: "07:45", end: "22:00", weekdays: 1-5 }
      # On weekends, set temperature to 20.5 °C from 8.15 am to 11.30 pm.
      - { temp: 22.5, start: "08:15", end: "23:30", weekdays: "6,7" }
      # At all other times, set temperature to 16 °C.
      - { temp: 16 }

  #kitchen:
  #  thermostats:
  #    climate.heating_kitchen:
  #  schedule:
  #  # ...

Finally, AppDeamon is checking all folders for configurations, so i delete the sample in the docs folder

sudo rm hass-apps/docs/apps/heaty/sample-apps.yaml 

With this complete, I then restarted the AppDeamon container, to be greeted with the following log.
It appears that the TRV is updated to the setpoint, but i am not sure why the error

INFO: You are running the latest version of this add-on
[cont-init.d] 02-updates.sh: exited 0.
[cont-init.d] 03-version-requirements.sh: executing... 

INFO: Supervisor version requirements checks passed.
[cont-init.d] 03-version-requirements.sh: exited 0.
[cont-init.d] 20-init-configuration.sh: executing... 
[cont-init.d] 20-init-configuration.sh: exited 0.
[cont-init.d] 21-compiled-dir.sh: executing... 
[cont-init.d] 21-compiled-dir.sh: exited 0.
[cont-init.d] 30-auto-password.sh: executing... 
[cont-init.d] 30-auto-password.sh: exited 0.
[cont-init.d] 31-ha-url.sh: executing... 
[cont-init.d] 31-ha-url.sh: exited 0.
[cont-init.d] 50-compiled-symlink.sh: executing... 
[cont-init.d] 50-compiled-symlink.sh: exited 0.
[cont-init.d] 80-system-packages.sh: executing... 
[cont-init.d] 80-system-packages.sh: exited 0.
[cont-init.d] 81-python-packages.sh: executing... 
[cont-init.d] 81-python-packages.sh: exited 0.
[cont-init.d] done.
[services.d] starting services
starting version 3.2.4
[services.d] done.
2018-03-27 13:14:42.657132 INFO AppDaemon Version 3.0.0 starting
2018-03-27 13:14:42.657274 INFO Configuration read from: /config/appdaemon/appdaemon.yaml
2018-03-27 13:14:42.657690 INFO AppDaemon: Starting Apps
2018-03-27 13:14:42.658887 INFO AppDaemon: Loading Plugin HASS using class HassPlugin from module hassplugin
2018-03-27 13:14:42.665189 INFO AppDaemon: HASS: HASS Plugin Initializing
2018-03-27 13:14:42.665406 INFO AppDaemon: HASS: HASS Plugin initialization complete
2018-03-27 13:14:42.665572 INFO Starting Dashboards
2018-03-27 13:14:42.668185 INFO API is disabled
2018-03-27 13:14:42.671790 INFO AppDaemon: HASS: Connected to Home Assistant 0.66.0.b2
2018-03-27 13:14:42.718688 INFO AppDaemon: Got initial state from namespace default
2018-03-27 13:14:44.715775 INFO AppDaemon: Reading config
2018-03-27 13:14:44.727670 INFO AppDaemon: /config/appdaemon/apps/heaty.yaml added or modified
2018-03-27 13:14:44.727774 INFO AppDaemon: /config/appdaemon/apps/apps.yaml added or modified
2018-03-27 13:14:44.727867 INFO AppDaemon: /config/appdaemon/apps/hass-apps/docs/apps/motion_light/sample-apps.yaml added or modified
2018-03-27 13:14:44.727947 INFO AppDaemon: /config/appdaemon/apps/heaty.yaml added or modified
2018-03-27 13:14:44.728012 INFO AppDaemon: /config/appdaemon/apps/apps.yaml added or modified
2018-03-27 13:14:44.728083 INFO AppDaemon: /config/appdaemon/apps/hass-apps/docs/apps/motion_light/sample-apps.yaml added or modified
2018-03-27 13:14:44.728155 INFO AppDaemon: App 'heaty_minimal' added
2018-03-27 13:14:44.728222 INFO AppDaemon: App 'hello_world' added
2018-03-27 13:14:44.728286 INFO AppDaemon: App 'motion_light' added
2018-03-27 13:14:44.728401 INFO AppDaemon: Adding /config/appdaemon/apps to module import path
2018-03-27 13:14:44.728540 INFO AppDaemon: Adding /config/appdaemon/apps/hass-apps to module import path
2018-03-27 13:14:44.728671 INFO AppDaemon: Adding /config/appdaemon/apps/hass-apps/hass_apps to module import path
2018-03-27 13:14:44.728793 INFO AppDaemon: Adding /config/appdaemon/apps/hass-apps/hass_apps/motion_light to module import path
2018-03-27 13:14:44.728942 INFO AppDaemon: Adding /config/appdaemon/apps/hass-apps/hass_apps/heaty to module import path
2018-03-27 13:14:44.729090 INFO AppDaemon: Adding /config/appdaemon/apps/hass-apps/hass_apps/data to module import path
2018-03-27 13:14:44.729208 INFO AppDaemon: Adding /config/appdaemon/apps/hass-apps/docs to module import path
2018-03-27 13:14:44.729317 INFO AppDaemon: Adding /config/appdaemon/apps/hass-apps/docs/apps to module import path
2018-03-27 13:14:44.729422 INFO AppDaemon: Adding /config/appdaemon/apps/hass-apps/docs/apps/motion_light to module import path
2018-03-27 13:14:44.729535 INFO AppDaemon: Adding /config/appdaemon/apps/hass-apps/docs/apps/heaty to module import path
2018-03-27 13:14:44.730674 INFO AppDaemon: Loading App Module: /config/appdaemon/apps/hass_apps_loader.py
2018-03-27 13:14:44.744765 INFO AppDaemon: Loading App Module: /config/appdaemon/apps/hello.py
2018-03-27 13:14:44.749383 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/setup.py - ignoring
2018-03-27 13:14:44.749503 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/common.py - ignoring
2018-03-27 13:14:44.749616 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/loader.py - ignoring
2018-03-27 13:14:44.749705 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/__init__.py - ignoring
2018-03-27 13:14:44.749789 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/motion_light/app.py - ignoring
2018-03-27 13:14:44.749870 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/motion_light/__init__.py - ignoring
2018-03-27 13:14:44.749947 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/heaty/schedule.py - ignoring
2018-03-27 13:14:44.750019 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/heaty/room.py - ignoring
2018-03-27 13:14:44.750107 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/heaty/util.py - ignoring
2018-03-27 13:14:44.750179 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/heaty/app.py - ignoring
2018-03-27 13:14:44.750249 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/heaty/config.py - ignoring
2018-03-27 13:14:44.750322 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/heaty/thermostat.py - ignoring
2018-03-27 13:14:44.750395 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/heaty/expr.py - ignoring
2018-03-27 13:14:44.750465 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/heaty/__init__.py - ignoring
2018-03-27 13:14:44.750533 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/hass_apps/heaty/window_sensor.py - ignoring
2018-03-27 13:14:44.750601 INFO AppDaemon: Loading App Module: /config/appdaemon/apps/hass-apps/hass_apps/data/hass_apps_loader.py
2018-03-27 13:14:44.750706 WARNING AppDaemon: No app description found for: /config/appdaemon/apps/hass-apps/docs/conf.py - ignoring
2018-03-27 13:14:44.750804 INFO AppDaemon: Initializing app heaty_minimal using class HeatyApp from module hass_apps_loader
2018-03-27 13:14:44.809794 INFO heaty_minimal: --- heaty v0.12.4 initialization started
2018-03-27 13:14:44.812218 INFO heaty_minimal: --- Heaty id is: 'default'
2018-03-27 13:14:44.817138 INFO heaty_minimal: --> [office] [climate.eurotronic_eur_spiritz_wall_radiator_thermostat_heat] Received target temperature 22.5.
2018-03-27 13:14:44.829364 INFO heaty_minimal: --- Initialization done
2018-03-27 13:14:44.829460 INFO AppDaemon: Initializing app hello_world using class HelloWorld from module hello
2018-03-27 13:14:44.830167 INFO hello_world: Hello from AppDaemon
2018-03-27 13:14:44.830716 INFO hello_world: You are now ready to run Apps!
2018-03-27 13:14:44.830791 INFO AppDaemon: Initializing app motion_light using class MotionLightApp from module hass_apps
2018-03-27 13:14:44.830938 WARNING AppDaemon: Unable to find module module hass_apps - motion_light is not initialized
2018-03-27 13:14:44.831221 INFO AppDaemon: App initialization complete
2018-03-27 13:14:45.003809 WARNING AppDaemon: ------------------------------------------------------------
2018-03-27 13:14:45.004084 WARNING AppDaemon: Unexpected error in worker for App heaty_minimal:
2018-03-27 13:14:45.004434 WARNING AppDaemon: Worker Ags: {'name': 'heaty_minimal', 'id': UUID('755b51d8-2773-4da9-a033-78a1f187ee36'), 'type': 'timer', 'function': <bound method HeatyApp._publish_state_timer_cb of <hass_apps.heaty.app.HeatyApp object at 0x7f7cf37ff898>>, 'kwargs': {}}
2018-03-27 13:14:45.004626 WARNING AppDaemon: ------------------------------------------------------------
2018-03-27 13:14:45.005253 WARNING AppDaemon: Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/appdaemon/appdaemon.py", line 529, in worker
    funcref(self.sanitize_timer_kwargs(app, args["kwargs"]))
  File "/config/appdaemon/apps/hass-apps/hass_apps/heaty/app.py", line 120, in _publish_state_timer_cb
    self.publish_state()
  File "/config/appdaemon/apps/hass-apps/hass_apps/heaty/app.py", line 276, in publish_state
    self.set_app_state(entity_id, state)
  File "/config/appdaemon/apps/hass-apps/hass_apps/common.py", line 105, in set_app_state
    self.AD.set_app_state(entity_id, state)
TypeError: set_app_state() missing 1 required positional argument: 'state'

2018-03-27 13:14:45.005486 WARNING AppDaemon: ------------------------------------------------------------

@DamianFlynn

The docs don’t tell you to copy the whole git repository into the apps directory. :slight_smile: If you follow the official steps, you won’t ever need to edit any *.py file.

Don’t use appdaemon 3.0.0 final, use 3.0.0b5 instead.

You know that you need to compile openzwave yourself to get the spirit thermostats working…

All of this has already been discussed here, but if you have further questions beyond what’s explained in the docs and issues, feel free to ask.

Thank you,

Appears that the Hass.IO supplied AppDaemon has autoupdafed to the latest release, despite the configuration set to not update. I have logged a bug on that issue, and manually rolled back the runtime version.

I understand that i deviated from the guide for installing, but as i wish to keep the upgrading process clean, using the git submodule approach enables me to run a production and development environment with a consistent configuration from GIT.

For the issue with the Spirit thermostats, I was able to accomplish the isolation required, to allow staying current with the HomeAssistant releases, yet benefit from the speed and simplicity of docker. If anyone is curious, this is the step i adopted, and has been working well so far. Eurotronic Spirit temperature not changing

Thanks for all your amazing work on this solution, hopefully something here will be of value to other Hass.io users

cheers
Damian

@DamianFlynn Ok, the submodule approach seems reasonable, but maybe you can clone the repo one directory level above and just symlink hass_apps and hass_apps_loader.py into apps?

And reports of working setups are always welcome. :slight_smile:

Hi Robert,

I want to ask you if it is possible to use dynamic time and temprature setup and take values from HA. That way it would be much more comforable to change the setting instead of editing the configuration files.

Something like examples bellow.

Off temperature:

heaty:
  module: hass_apps_loader
  class: HeatyApp
  off_temp: app.get_state("input_number.summer_temperature")

Schedules:

schedule:
- temp: app.get_state("input_number.bedroom_high_temperature")
  start: app.get_state("input_number.bedroom_hour_first_on")
  end: app.get_state("input_number.bedroom_hour_first_off")

Or even more complex:

schedule:
- temp: app.get_state("input_number.bedroom_high_temperature") if app.get_state("binary_sensor.workday_sensor") == "off" else Ignore()
  start: app.get_state("input_number.bedroom_hour_first_on")
  end: app.get_state("input_number.bedroom_hour_first_off")
- temp: app.get_state("input_number.bedroom_low_temperature")

I have to say that I did not yet test myself. And before playing in deep I want to know if I am not trying to go out of the Heaty borders.

Thanks.

Hi @TriStone

This has already been discussed in this thread. Dynamic start/end times are not possible. Heaty works with an event-drivven approach to dynamically configure temperatures. So you’d need to write a rule without start/end time constraints which decides the temperature based on time of the day. The time object is available for that purpose in the evaluation environment of temperature expressions. And then fire a re-schedule event whenever one of the variables involved in the temperature expression changes, just as normal.

Something like this should work:

{ temp: 20 if time.hour >= int(app.get_state("input_number.start_hour")) and time.hour <= int(app.get_state("input_number.end_hour")) else Ignore() }

Or this shorter one:

{ temp: 20 if time.hour in range(int(app.get_state("input_number.start_hour")), int(app.get_state("input_number.end_hour")) + 1) else Ignore() }

Best regards
Robert

Another way would be a custom script that re-writes the configuration when one of the values changes… Should be doable in your favourite scripting language with a bit of thinking.

Hi @roschi

That’s clear, thanks.
Just what about the dynamic temperature value - in your examples you have the conditions dynamicaly but the temperature value is still static.

If I understood correctly the documentation I will have to write my own module cause inline expressions are not able to handle that, right?

Cheers,
Jarda

Inline expressions are just normal Python code, so they are turing-complete and can potentially do everything. :slight_smile: Outsourcing code into an external module just makes writing logic a lot easier and more readable.

If you want to have another temperature when the rule mentioned above isn’t active (evaluates to Ignore()), you should just add additional rules below that one to express your needs. Rules are processed sequentially, and the first one that evaluates to a temperature wins.

There are some nice schedule examples that were discussed and reworked throughout this thread. They demonstrate the processing of schedules pretty well… Maybe you want to have a look at them?

Hi @roschi

Thanks for patience so far. I went through the whole thread and in fact the conditions and Ignore clause are quite clear. You example above is self explanatory:

{ temp: 20 if time.hour in range(int(app.get_state("input_number.start_hour")), int(app.get_state("input_number.end_hour")) + 1) else Ignore() }

What I found nowhere so far (thread, documentation) if it is possible to use the value of temperature from HA instead of fixed one. Currently everyone was solving the dynamic times or temperature difference (Add) etc. but the temperature value was always statically present in Heaty conf.

I am not Python expert so not sure if something like this can work (modified your example). Can it?

{ temp: int(app.get_state("input_number.day_temperature")) if time.hour in range(int(app.get_state("input_number.start_hour")), int(app.get_state("input_number.end_hour")) + 1) else Ignore() }

Thanks,
Jarda

Yes, that would work. But you can leave out the int() around the temperature, because Heaty does accept strings as well…

And don’t worry about my patience. :slight_smile: It is a pleasure for me to help people integrating and enjoying Heaty in their lifes. As long as I see that those who ask have read the documentation (which I put a lot of effort into exactly for that purpose) asking questions is fine.

I now added this to the docs as well:

http://hass-apps.readthedocs.io/en/latest/apps/heaty/tips-and-tricks.html#schedule-rules-with-dynamic-start-and-end-times

1 Like

Hi @roschi

I made a real test and we need to make few cosmetical changes :slight_smile:

For setting just temperature, the last rule, it works like this, easy:

{ temp: app.get_state("input_number.bedroom_low_temperature") }

But for the more complex things two problem compared to above occured.
First the whole expression must be closed in ’ ’
Second HA is providing the input_number values as float and the int conversion is not working. It must be double converted:

{ temp: 'app.get_state("input_number.bedroom_high_temperature") if time.hour in range(int(float(app.get_state("input_number.bedroom_hour_second_on"))), int(float(app.get_state("input_number.bedroom_hour_second_off"))) + 1) else Ignore()' }

Ah, didn’t consider that it were floats. The quotes are needed for those single-line YAML mappings enclosed in curly brackets. You could do:

- temp: app.get_state("input_number.bedroom_high_temperature") if time.hour in range(int(float(app.get_state("input_number.bedroom_hour_second_on"))), int(float(app.get_state("input_number.bedroom_hour_second_off"))) + 1) else Ignore()

I updated the docs with your fixes, thanks.

@TriStone The example in the docs is now a little simpler and removes unnecessary type casts, just in case you may want to adopt it.

http://hass-apps.readthedocs.io/en/latest/apps/heaty/tips-and-tricks.html#schedule-rules-with-dynamic-start-and-end-times

Hi Robert

I’ve been holding off my heaty implementation until it works with a released (rather than beta) version of Appdaemon 3. I see that AD3.0.1 is now live - is this heaty-friendly?

Did you try AppDaemon 3.0.1 with heaty?