App #5: Smart Radiator (Generic)

Tags: #<Tag:0x00007f7c5b98d008>

Hi guys!

In this example, I extend the code of my previous post: App #3: Smart Radiator to turn OFF the radiator of any room of my apartment if one of its windows is open.

In other to make generic this automation, I use a particular naming pattern to associate related items (e.g., livingroom_radiator, livingroom_window ). In other words, by doing some string manipulation (see __get_radiator) I can extract the room where the opened window belongs.

This automation is not final or complete, and probably there is a way to make more generic. My aim is to share examples that maybe can help new members starting with HA+AppDaemon.

Suggestions or recommendations to improve the implementation are welcome!

Entities

binary_sensor.bedroom_window
binary_sensor.kitchen_window
switch.bedroom_radiator
switch.kitchen_radiator

groups.yaml

windows:  
  name: Windows
  view: no
  entities: 
    - binary_sensor.bedroom_window
    - binary_sensor.kitchen_window 
    ...

app.yaml

gen_smart_radiator:
  module: gen_smart_radiator
  class: GenSmartRadiator
  group: group.windows 

gen_smart_radiator.py

import appdaemon.plugins.hass.hassapi as hass

class GenSmartRadiator(hass.Hass):

    def initialize(self):
        self.log('initializing ...')
        group = self.get_state((self.args["group"], attribute = "all")
        sensors = group["attributes"]["entity_id"]
       
        for sensor in sensors:
            self.log('subscribing to: ' + str(sensor))
            self.listen_state(self.on_windows_open, sensor, new="on")
        
    def on_windows_open(self, entity, attribute, old, new, kwargs):
        radiator = self.__get_radiator(entity)
        if self.get_state(radiator) == "on":
            self.log(f'Turning off {radiator}')
            self.turn_off(radiator)
        else: # only for debugging purposes
            self.log(f'The radiator {radiator} is off, enjoy the fresh air ...')

    def __get_radiator(self, entity):
        _device, entity_name = self.split_entity(entity)
        room, _window = entity_name.split('_')
        return f'switch.{room}_radiator'

If you have solved a similar problem using a better approach, please share it! :grinning:

Happy coding!
Humberto

Edit #1 Avoid hardcode entities names in the automation code. Thanks @swiftlyfalling @Burningstone

Previous post: App #4: Boiler Alert
Next post: App #6: Window Alert

I read in your other post, that you want to turn on the radiator again, once all windows are closed. I did something similar for my dehumidifier.

You can add a new method, which checks whether all windows are closed or not. Then add a listener in the initialize method, which will trigger the new method when any of the windows has the new state “closed”.

I would also highly suggest you to not hardcode the groups in your code and rather have them in the .yaml configuration. This way it is reusable and can easily be adapted if you change something in your setup.

I don’t get why you need the __get_radiator method? The entity is already given in the callback. Could you please explain?

Hi @Burningstone

Yes, I plan to do something similar :wink:

The entity that you get in the cb is the window that was opened (e.g., sensor.bedroom_window). So, I do three things in the method __get_radiator:

  1. I extract the entity name using self.split_entity,
  2. I extract the room of the window using entity_name.split('_') (e.g., bedroom),
  3. I build the name of the radiator entity for that room by doing some string interpolation f'sensor.{room}_radiator'

Is now clear for you the need for __get_radiator?

Let me know if you have any other questions :grinning:

I just realized why you need the __get_radiator method, silly me haha.

But why do you hardcode your entities in all your apps?

Are you talking about why I don’t pass the names of the entities by args?
-> Yes, well I always say my posts are just simple examples that can help to start doing some automations, and indeed some of them are too specific like App #1: Doorbell notification, but there are other examples that can be converted to a more generic version

Yes, thats what I mean.

I’m new using both HA and Python, I’m doing things as I need them. Probably I will turn them to a more generic version in the feature, but until now they work for me.

I’m open to suggestions or recommendations to improve my code :wink:

I see. Keep up the good work, I appreciate that you post your apps with a good explanation.

You can check out my Github for some inspirations if you like

And in case you need help, I’m always here to answer your questions as good as I can.

1 Like

Thanks for the link @Burningstone!

I think that I found it here somewhere in the forum, and it was in my TODO list to check it :grinning:

@Burningstone Do you use in your automations a different approach to solve a similar situation?

What’s your opinion about the way I solved this automation?

I used to have something similar for a notification light when a window is opened. I’m currently on vacation, but I can check once I’m home again.

I think your app is solid, the only thing I would change is getting the entities from the args and not hardcode them. I always try not to hardcode anything in the app itself.

The other thing I can recommend is starting to use voluptuous. I wrote a quick introduction to it in this post in case you are interested.

1 Like

Enjoy your holidays!

1 Like

Does this code actually run and work as expected?

I wouldn’t think so. Your __get_radiator returns something formatted like “sensor.ROOM_radiator”, which you then call self.turn_off() on. But, unless you have weird sensors… you can’t turn_off() a sensor. This needs to be a switch, or an input boolean, or something else.

Also, if you don’t want to hardcode the entity naming convention, I use a YAML that looks like this:

gen_smart_radiator:
  module: gen_smart_radiator
  class: GenSmartRadiator
  rooms:
    living:
      radiator: switch.living_radiator
      windows:
        - binary_sensor.living_window_east
        - binary_sensor.living_window_middle
        - binary_sensor.living_window_west
    kitchen:
      radiator: input_boolean.kitchen_heating_device
      windows:
        - binary_sensor.kitchen_window_north
        - binary_sensor.kitchen_window_south
1 Like

Hi @swiftlyfalling

Many thanks for your feedback!

Indeed they are switches, I was using some dummy script to automatically tests the conditions of the examples, instead use the real device.

I will update the post :wink: