import appdaemon.plugins.hass.hassapi as hass import pickle import os class EventDispatcher: def __init__(self,ad_api,event_name,callback,event_data,reset_data,event_context): self.event_name = event_name self.callback = callback self.event_data = event_data self.reset_data = reset_data self.waiting_for_reset = False self.event_context = event_context self.ad_api = ad_api if event_data == None: self.ad_api.listen_event(self.on_event,event_name) else: event_kwargs = {} for key,value in event_data.items(): #when we have dict in event_data, we usually only want a partial match, we deal with that in process_event if not isinstance(value,dict): event_kwargs[key] = value self.ad_api.listen_event(self.on_event,event_name,**event_kwargs) if reset_data: reset_data_kwargs = {} for key,value in reset_data.items(): #when we have dict in event_data, we usually only want a partial match, we deal with that in process_event if not isinstance(value,dict): reset_data_kwargs[key] = value if reset_data_kwargs != event_kwargs: self.ad_api.listen_event(self.on_event,event_name,**reset_data_kwargs) def on_event(self, event_name, data, kwargs): self.process_event(data) def process_event(self,data): def are_data_matching(ref_data, data): if ref_data != None: for key in ref_data: if not key in data: return False if isinstance(ref_data[key],dict): if not are_data_matching(ref_data[key],data[key]): return False elif ref_data[key] != data[key]: return False return True #lets see if those args match match_event_data = are_data_matching(self.event_data,data) match_reset_data = are_data_matching(self.reset_data,data) #special threatment for event if match_event_data and not self.waiting_for_reset: if self.reset_data != None: self.waiting_for_reset = True self.callback(self.event_name, self.event_data ,self.event_context) return True if self.reset_data != None and match_reset_data: self.waiting_for_reset = False return False class EventHandler: def __init__(self, ad_api,events_block,callback,event_context = None): #event_context is passed back to the CB has a context def register_event_with_params(event_block,callback,event_context): self.add_dispatcher(event_block['event_name'],callback,event_block['event_data'] if 'event_data' in event_block else None, event_block['reset_data'] if 'reset_data' in event_block else None,event_context) self.__ad_api = ad_api self.event_dispatchers = [] #try: for event_block in events_block.values(): register_event_with_params(event_block,callback,event_context) #except (AttributeError): # self.log(f"Format not supported : {events_block}") def log(self,message,**kwargs): self.__ad_api.log(message,**kwargs) def add_dispatcher(self,event_name,callback,event_data = None,reset_data = None ,event_context = None): self.log(f'Registering dispatcher {callback.__name__} for event "{event_name}" ({event_data})') dispatcher = EventDispatcher(self.__ad_api,event_name,callback,event_data,reset_data,event_context) self.event_dispatchers.append(dispatcher) # if not event_name in self.event_dispatchers: # self.event_dispatchers[event_name] = list() # self.log(f"listening event {event_name}") # self.__ad_api.listen_event(self._on_event_internal,event_name) # self.event_dispatchers[event_name].append(dispatcher) # def _on_event_internal(self, event_name, data, kwargs): # if event_name in self.event_dispatchers: # for dispatcher in self.event_dispatchers[event_name]: # if dispatcher.process_event(data) == True: # break # else: # self.log(f"{event_name} has no dispatcher registered",level="WARNING")