App #6: Window Alert

Hello!

New day == New AppDaemon automation :grinning:

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!

App #6: Window Alert
Notify me when a window has been open for more than an hour

Note: this example sends only a notification, but other actions can be used like: close automatically the window after one hour.

Entities

binary_sensor.bedroom_window
binary_sensor.kitchen_window

groups.yaml

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

window_alert.yaml

window_alert:
  module: window_alert
  class: WindowAlert
  windows: group.windows

windows_alert.py (Final version)
Thanks @Burningstone for your feedback :+1:. The final version is 50% shorter than my initial implementation :grinning:

import appdaemon.plugins.hass.hassapi as hass

class WindowAlert(hass.Hass):

    def initialize(self):
        self.log('initializing ...')
        group = self.get_state(self.args["windows"], attribute = "all")
        # get all sensors of the group
        sensors = group["attributes"]["entity_id"]
       
        for sensor in sensors:
            self.log(f'subscribing to: {sensor}')
            self.listen_state(self.on_windows_open, sensor, new= 'on', duration= 3.600)

    def on_windows_open(self, entity, attribute, old, new, kwargs):
        window_name = self.friendly_name(entity)
        self.log(f'Alert! The {window_name} has been open for more than one hour.') 
        # send your notification

windows_alert.py (Initial version)

import appdaemon.plugins.hass.hassapi as hass

class WindowAlert(hass.Hass):

    def initialize(self):
        self.log('initializing ...')
        self.timers = {}
        group = self.get_state(self.args["windows"], attribute = "all")
        # get all sensors of the group
        sensors = group["attributes"]["entity_id"]
       
        for sensor in sensors:
            self.log('subscribing to: ' + str(sensor))
            # init timer dictionary, each entry represents a window (name->timer) 
            self.timers[str(sensor)] = None
            self.listen_state(self.on_windows_open, sensor)

    def on_windows_open(self, entity, attribute, old, new, kwargs):
        self.log('on_windows_open ' + str(entity))
        timer_key = str(entity)
        friendly_name = self.friendly_name(entity)
        if new == "on":
            self.log(f'Start timer for {friendly_name}')
            self.timers[timer_key] = self.run_in(self.send_notification, 3.600, window= friendly_name, timer= timer_key )
        else:
            timer = self.timers[timer_key]
            if timer != None:
                self.log(f'Canceling timer for {friendly_name}')
                self.timers[timer_key] = self.cancel_timer(timer) 
     

    def send_notification(self, kwargs):
        window_name = kwargs["window"]
        timer_key = kwargs["timer"]
        # forget timer reference
        self.timers[timer_key] = None
        # send your notification   
        self.log(f'Alert! The {window_name} has been open for more than one hour.') 

Happy coding!
Humberto

Previous post: App #5: Smart Radiator (Generic)
Next post: App #7: Boiler Temperature Alert

4 Likes

I think you can use the duration parameter for this. If you specify a duration in the listener, the callback will only fire if the entity has been in the ‘new’ state for the specified duration.

self.listen_state(self.on_windows_open, sensor, new='open', duration=3600)

And in the ‘on_windows_open’ method just send the notification.

1 Like

@Burningstone that’s very cool!

thanks for sharing it :+1: