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

I assume that your radiator stays worm for all the time, am I right? That’s opposite behavior from that what I can achieve with Genreic Thermostat

Yes, they do. Or at least they care about opening and closing the valve themselves because they are setpoint devices.

But what I wanted to say is that you maybe don’t need any custom control and are just satisfied with their setpoint capabilities. Have you already tried how good that works?

Nice job! Will try this those days and give feedback

@matt2005 I just wanted to let you know that there have been breaking changes in the schedule system and temperature expressions which should it make more straightforward to include your external logic into schedules. I find your blog post to be very interesting, so please let me know if you need further information about Heaty-related things.

It’s not my blog post. I just saw it a while ago and haven’t yet had chance to give it a go properly as im waiting for hardware to interface with my heating.

Ah, I see. Nevertheless it’s an interesting idea. Maybe I’ll get back to it when I’ve got some time.

Hey Mate. Got some strage issuue

https://github.com/efficiosoft/hass-heaty/issues/1

I opened a ticket… Ifyou have tinme you might help me with this ?

Thanks for this nice piee of software… waiting my 3 IR climate controllers for my AC :slight_smile:

2017-12-14 22:41:24.019486 WARNING ------------------------------------------------------------
2017-12-14 22:41:54.907950 WARNING ------------------------------------------------------------
2017-12-14 22:41:54.917368 WARNING Unexpected error:
2017-12-14 22:41:54.936450 WARNING ------------------------------------------------------------
2017-12-14 22:41:55.350882 WARNING Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 837, in check_config
    new_config[name]["module"], new_config[name]
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 583, in init_object
    conf.objects[name]["object"].initialize()
  File "/usr/local/lib/python3.4/dist-packages/hass_heaty/app.py", line 40, in initialize
    self.cfg = config.parse_config(self.args)
  File "/usr/local/lib/python3.4/dist-packages/hass_heaty/config.py", line 128, in parse_config
    validate_config(cfg)
  File "/usr/local/lib/python3.4/dist-packages/hass_heaty/config.py", line 91, in validate_config
    DefaultValidatingDraft4Validator(schema).validate(cfg)
  File "/usr/local/lib/python3.4/dist-packages/jsonschema/validators.py", line 130, in validate
    raise error
jsonschema.exceptions.ValidationError: Additional properties are not allowed ('master_controls_schedule_switches' was unexpected)

Failed validating 'additionalProperties' in schema:
    {'$schema': 'http://json-schema.org/schema#',
     'additionalProperties': False,
     'definitions': {'optional_entity_name': {'anyOf': [{'type': 'string'},
                                                        {'type': 'null'}]},
                     'python_var': {'pattern': '^[a-zA-Z_]+[a-zA-Z0-9_]*$',
                                    'type': 'string'},
                     'range_string': {'pattern': '^ *\\d+( *\\- '
                                                 '*\\d+)?( *\\, *\\d+( '
                                                 '*\\- *\\d+)?)* *$',
                                      'type': 'string'},
                     'range_string_or_integer': {'anyOf': [{'$ref': '#/definitions/range_string'},
                                                           {'type': 'integer'}]},
                     'room': {'additionalProperties': False,
                              'properties': {'friendly_name': {'type': 'string'},
                                             'replicate_changes': {'default': True,
                                                                   'type': 'boolean'},
                                             'reschedule_delay': {'default': 0,
                                                                  'min': 0,
                                                                  'type': 'integer'},
                                             'schedule': {'$ref': '#/definitions/schedule'},
                                             'thermostats': {'additionalProperties': {'$ref': '#/definitions/thermostat',
                                                                                      'ignoreDefaults': True},
                                                             'type': 'object'},
                                             'window_sensors': {'additionalProperties': {'$ref': '#/definitions/window_sensor',
                                                                                         'ignoreDefaults': True},
                                                                'type': 'object'}},
                              'type': 'object'},
                     'schedule': {'items': {'$ref': '#/definitions/schedule_rule'},
                                  'type': 'array'},
                     'schedule_rule': {'additionalProperties': False,
                                       'properties': {'days': {'$ref': '#/definitions/range_string_or_integer'},
                                                      'end': {'$ref': '#/definitions/time_string'},
                                                      'end_plus_days': {'default': 0,
                                                                        'min': 0,
                                                                        'type': 'integer'},
                                                      'months': {'$ref': '#/definitions/range_string_or_integer'},
                                                      'start': {'$ref': '#/definitions/time_string'},
                                                      'temp': {'$ref': '#/definitions/temp_expr'},
                                                      'weekdays': {'$ref': '#/definitions/range_string_or_integer'},
                                                      'weeks': {'$ref': '#/definitions/range_string_or_integer'},
                                                      'years': {'$ref': '#/definitions/range_string_or_integer'}},
                                       'required': ['temp'],
                                       'type': 'object'},
                     'temp_expr': {'anyOf': [{'type': 'number'},
                                             {'type': 'string'}]},
                     'temp_expression_module': {'additionalProperties': False,
                                                'properties': {'as': {'$ref': '#/definitions/python_var'}},
                                                'type': 'object'},
                     'temperature': {'anyOf': [{'type': 'number'},
                                               {'pattern': '^off$',
                                                'type': 'string'}]},
                     'thermostat': {'additionalProperties': False,
                                    'properties': {'delta': {'default': 0,
                                                             'type': 'number'},
                                                   'ignore_updates': {'default': False,
                                                                      'type': 'boolean'},
                                                   'min_temp': {'anyOf': [{'$ref': '#/definitions/temperature'},
                                                                          {'type': 'null'}],
                                                                'default': None},
                                                   'opmode_heat': {'default': 'Heat',
                                                                   'type': 'string'},
                                                   'opmode_off': {'default': 'Off',
                                                                  'type': 'string'},
                                                   'opmode_service': {'default': 'climate/set_operation_mode',
                                                                      'type': 'string'},
                                                   'opmode_service_attr': {'default': 'operation_mode',
                                                                           'type': 'string'},
                                                   'opmode_state_attr': {'default': 'operation_mode',
                                                                         'type': 'string'},
                                                   'temp_service': {'default': 'climate/set_temperature',
                                                                    'type': 'string'},
                                                   'temp_service_attr': {'default': 'temperature',
                                                                         'type': 'string'},
                                                   'temp_state_attr': {'default': 'temperature',
                                                                       'type': 'string'}},
                                    'type': 'object'},
                     'time_string': {'pattern': '^ *([01]\\d|2[0123]) '
                                                '*[\\:\\.] '
                                                '*([012345]\\d) *$',
                                     'type': 'string'},
                     'window_sensor': {'additionalProperties': False,
                                       'properties': {'delay': {'default': 10,
                                                                'min': 0,
                                                                'type': 'integer'},
                                                      'inverted': {'default': False,
                                                                   'type': 'boolean'}},
                                       'type': 'object'}},
     'properties': {'class': {},
                    'debug': {'default': False, 'type': 'boolean'},
                    'heaty_id': {'anyOf': [{'type': 'string'},
                                           {'type': 'null'}],
                                 'default': None},
                    'master_switch': {'$ref': '#/definitions/optional_entity_name',
                                      'default': None},
                    'module': {},
                    'off_temp': {'$ref': '#/definitions/temperature',
                                 'default': 'off'},
                    'rooms': {'additionalProperties': {'$ref': '#/definitions/room'},
                              'type': 'object'},
                    'schedule_append': {'$ref': '#/definitions/schedule'},
                    'schedule_prepend': {'$ref': '#/definitions/schedule'},
                    'temp_expression_modules': {'additionalProperties': {'$ref': '#/definitions/temp_expression_module'},
                                                'type': 'object'},
                    'thermostat_defaults': {'$ref': '#/definitions/thermostat'},
                    'untrusted_temp_expressions': {'default': False,
                                                   'type': 'boolean'},
                    'window_sensor_defaults': {'$ref': '#/definitions/window_sensor'}},
     'type': 'object'}

On instance:
    {'class': 'Heaty',
     'debug': True,
     'heaty_id': None,
     'master_controls_schedule_switches': True,
     'master_switch': 'input_boolean.heating_master',
     'module': 'heaty_app',
     'off_temp': False,
     'rooms': {'living': {'friendly_name': 'Living Room',
                          'replicate_changes': True,
                          'reschedule_delay': 10,
                          'schedule': [],
                          'schedule_switch': 'input_boolean.heating_schedule_living',
                          'thermostats': {'sensor.multisensor_downstairs_temperature': {'delta': 1.0},
                                          'sensor.multisensor_entrance_temperature': {'delta': 1.0}},
                          'window_sensors': {'binary_sensor.door_window_sensor_158d00019dae34': {},
                                             'binary_sensor.door_window_sensor_158d00019daecd': {},
                                             'binary_sensor.door_window_sensor_158d00019daede': {},
                                             'binary_sensor.door_window_sensor_158d00019daf31': {},
                                             'binary_sensor.door_window_sensor_158d00019daf53': {},
                                             'binary_sensor.door_window_sensor_158d00019f3070': {}}}},
     'schedule_append': [],
     'schedule_prepend': [],
     'temp_expression_modules': {},
     'thermostat_defaults': {'delta': 0.5,
                             'ignore_updates': False,
                             'min_temp': 8,
                             'opmode_heat': 'Heat',
                             'opmode_off': False,
                             'opmode_service': 'climate/set_operation_mode',
                             'opmode_service_attr': 'operation_mode',
                             'opmode_state_attr': 'operation_mode',
                             'temp_service': 'climate/set_temperature',
                             'temp_service_attr': 'temperature',
                             'temp_state_attr': 'temperature'},
     'untrusted_temp_expressions': False,
     'window_sensor_defaults': {'delay': 60, 'inverted': False}}

2017-12-14 22:41:55.365200 WARNING ------------------------------------------------------------

Hi,

You seem to use the latest version from git master branch, which is fine. However, all schedule switch related stuff has been removed recently as noted in the git commit logs. Because version is pre 1.0.0, such compatibility-breaking changes may happen. Sorry for that, but it’s necessary.

Simply remove master_controls_schedule_switches and all schedule switches you might have defined in the rooms section. Then it should work.

Well still not working:

2017-12-14 22:55:33.347730 WARNING ------------------------------------------------------------
2017-12-14 22:55:52.563741 WARNING ------------------------------------------------------------
2017-12-14 22:55:52.577660 WARNING Unexpected error:
2017-12-14 22:55:52.584393 WARNING ------------------------------------------------------------
2017-12-14 22:55:52.605634 WARNING Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 837, in check_config
    new_config[name]["module"], new_config[name]
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 583, in init_object
    conf.objects[name]["object"].initialize()
  File "/usr/local/lib/python3.4/dist-packages/hass_heaty/app.py", line 40, in initialize
    self.cfg = config.parse_config(self.args)
  File "/usr/local/lib/python3.4/dist-packages/hass_heaty/config.py", line 128, in parse_config
    validate_config(cfg)
  File "/usr/local/lib/python3.4/dist-packages/hass_heaty/config.py", line 91, in validate_config
    DefaultValidatingDraft4Validator(schema).validate(cfg)
  File "/usr/local/lib/python3.4/dist-packages/jsonschema/validators.py", line 130, in validate
    raise error
jsonschema.exceptions.ValidationError: False is not valid under any of the given schemas

Failed validating 'anyOf' in schema['properties']['off_temp']:
    {'anyOf': [{'type': 'number'}, {'pattern': '^off$', 'type': 'string'}],
     'default': 'off'}

On instance['off_temp']:
    False

2017-12-14 22:55:52.625553 WARNING ------------------------------------------------------------

Could you please upload a new clean config example?

  rooms:

    # Create such a block for every room you want to control.
    living:
      # An alternative friendly name to display in logs.
      # (optional)
      friendly_name: Living Room


      # This setting controls whether changes made locally at one thermostat
      # should automatically be replicated at the other ones in this
      # particular room.
      # (optional, default: true)
      replicate_changes: true

      # Set this value to a number of minutes and Heaty will automatically
      # re-schedule the temperature after a manual change has been made.
      # If you, for instance, change the target temperature at one of your
      # thermostats and this value is set to 120, Heaty will again apply
      # the schedule 2 hours after you made the change.
      # (optional, default: 0)
      reschedule_delay: 10

      # All thermostats of this room go here.
      thermostats:

        sensor.multisensor_downstairs_temperature:
          # We could, for instance, overwrite the delta for this
          # particular thermostat.
          delta: 1.0

        sensor.multisensor_entrance_temperature:
          # ...
          delta: 1.0

      # Window open/closed detection
      window_sensors:

        # Create a sensor item for each window sensor you want to consider
        # and overwrite default parameters if needed.
        # A window sensor may be any binary_sensor that changes states
        # between "on" and "off".
        binary_sensor.door_window_sensor_158d00019dae34:
        binary_sensor.door_window_sensor_158d00019daecd:
        binary_sensor.door_window_sensor_158d00019daede:
        binary_sensor.door_window_sensor_158d00019daf31:
        binary_sensor.door_window_sensor_158d00019daf53:
        binary_sensor.door_window_sensor_158d00019f3070:
         # inverted: true

      # Schedule for this room.
      # The explanation of schedules has been removed from this file,
      # because it is simply to detailled.
      #
      # Please see README.rst.
      #
 #     schedule:
 #       # ...

I uploaded a fix which closes the issue. What I wrote there is valid for off_temp as well. Put the value “off” in quotes to tell YAML you mean the string, not the boolean.

And, by the way, I see that you have added a sensor to the thermostats section. Thermostats have to be setpoint devices using the climate platform… Just wanted to make that clear.

I don’t understand … I have a z wave climate component… What can i put there?

I think you are very familiar with python and might be interested in developing another app? I’d like having the braodlink CLimate custom component for Xiaomi Chuagnir . There is a Switch custom component for the xiaomi ir blaster but no climate component. Would you mind throwing an eye on this? Would be awesome. Like this i could use those for my setup :slight_smile:

Probably, your Z-Wave climate component generates multiple entities. Mine do as well. There should be an entity starting with climate. besides the sensor. you used. Just look it up in Home Assistant’s web interface. Best would be to go under Settings -> Customize -> Select the entity that has climate, probably at the end of its name. Then, look up the new_entity_id at the right sight. That’s it.

Maybe one Z-Wave thermostat produces even multiple climate entities. Mine generate three per thermostat. You have to take the one you also use to set the temperature manually via the web interface.

Sorry, but I’ve got none of these. And, at the moment, I’ve got enough work with Heaty :slight_smile:
But the community is large and there might be someone having these units at home and wanting to integrate them.

2017-12-14 23:17:17.008765 INFO heaty_full: --> [Living Room] sensor.multisensor_downstairs_temperature: attribute operation_mode is None
2017-12-14 23:17:19.463068 INFO /home/pi/appdaemon_dashboard/appdaemon/conf/apps.yaml modified
2017-12-14 23:17:20.784653 INFO App 'heaty_full' changed - reloading
2017-12-14 23:17:20.802961 INFO Loading Object heaty_full using class Heaty from module heaty_app
2017-12-14 23:17:20.859161 INFO heaty_full: --- Heaty v0.5.0 initialization started.
2017-12-14 23:17:20.914506 INFO heaty_full: --- Parsing the configuration.
2017-12-14 23:17:21.085640 INFO heaty_full: --- Importing modules for temperature expressions.
2017-12-14 23:17:21.118546 INFO heaty_full: --- Importing module 'my_custom_module' as 'alt_name'.
2017-12-14 23:17:21.195240 INFO heaty_full: !!! Error while importing module 'my_custom_module': ImportError("No module named 'my_custom_module'",)
2017-12-14 23:17:21.252332 INFO heaty_full: !!! Module won't be available.
2017-12-14 23:17:21.375052 INFO heaty_full: --- Importing module 'math' as 'math'.
2017-12-14 23:17:21.399818 INFO heaty_full: --- Getting current temperatures from thermostats.
2017-12-14 23:17:21.413584 INFO heaty_full: --> [Living Room] climate.ac_controller_cooling_1: attribute operation_mode is Heat
2017-12-14 23:17:21.426648 INFO heaty_full: --> [Living Room] climate.ac_controller_cooling_1: attribute temperature is 13.0
2017-12-14 23:17:21.462373 WARNING Logged an error to /home/pi/appdaemon_dashboard/appdaemon/logs/appdaemon_error.log
2017-12-14 23:17:21.467160 WARNING Excessive time spent in scheduler loop: 2016.0ms
2017-12-14 23:17:21.470412 WARNING Scheduler clock skew detected - delta = 1.0222949981689453 - resetting
2017-12-14 23:17:21.461050 WARNING ------------------------------------------------------------
2017-12-14 23:21:09.427970 WARNING ------------------------------------------------------------
2017-12-14 23:21:09.432625 WARNING Unexpected error:
2017-12-14 23:21:09.436758 WARNING ------------------------------------------------------------
2017-12-14 23:21:09.441876 WARNING Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 837, in check_config
    new_config[name]["module"], new_config[name]
  File "/usr/local/lib/python3.4/dist-packages/appdaemon/appdaemon.py", line 583, in init_object
    conf.objects[name]["object"].initialize()
  File "/usr/local/lib/python3.4/dist-packages/hass_heaty/app.py", line 82, in initialize
    "no_reschedule": True})
  File "/usr/local/lib/python3.4/dist-packages/hass_heaty/app.py", line 305, in thermostat_state_cb
    temp = expr.Temp(temp) - therm["delta"]
  File "/usr/local/lib/python3.4/dist-packages/hass_heaty/expr.py", line 109, in __sub__
    .format(repr(type(self)), repr(type(other))))
TypeError: can't subtract <class 'hass_heaty.expr.Temp'> and <class 'float'>

2017-12-14 23:21:09.443773 WARNING ------------------------------------------------------------