class DAI(): def __init__(self, p_id, do_id, d_id): self.p_id = p_id self.do_id = do_id self.d_id = d_id self.dan = Client() def on_data(self, odf_name, data): print(f"[da] {odf_name}: {data}") def on_signal(self, signal, df_list): print('[cmd] %s, %s', signal, df_list) def on_register(self): print('[da] register successfully') def on_deregister(self): print('[da] register fail') def register(self): print(self.d_id) self.dan.register("https://iottalk2.tw/csm", on_signal=self.on_signal, on_data=self.on_data, idf_list=[['Dummy_Sensor', ['int']]], odf_list=[['Dummy_Control', ['int']]], accept_protos=['mqtt'], name=self.d_id, id_=self.d_id, profile={'model': "Dummy_Device"}, on_register=self.on_register, on_deregister=self.on_deregister)
def run(self): # this function will be executed in child process self._check_parameter() self.dan = Client() idf_list = [] odf_list = [] for df in self.device_features.values(): if df.df_type == 'idf': idf_list.append(df.profile()) else: odf_list.append(df.profile()) def f(*args, **kwargs): for key in self.flags: self.flags[key] = False log.debug('on_disconnect: _flag = %s', str(self.flags)) if self.on_disconnect: return self.on_disconnect(*args, **kwargs) self.profile.update({ 'model': self.device_model, 'u_name': self.username, 'extra_setup_webpage': self.extra_setup_webpage, 'device_webpage': self.device_webpage, }) self.dan.register(self.api_url, on_signal=self.on_signal, on_data=self.on_data, accept_protos=['mqtt'], id_=self.device_addr, idf_list=idf_list, odf_list=odf_list, name=self.device_name, profile=self.profile, register_callback=self.register_callback, on_register=self.on_register, on_deregister=self.on_deregister, on_connect=self.on_connect, on_disconnect=f) log.info('Press Ctrl+C to exit DAI.') try: self._event.wait() except KeyboardInterrupt: pass finally: self.finalizer()
class DAI(Process): daemon = True def __init__(self, api_url, device_model, device_addr=None, device_name=None, persistent_binding=False, username=None, extra_setup_webpage='', device_webpage='', register_callback=None, on_register=None, on_deregister=None, on_connect=None, on_disconnect=None, push_interval=1, interval=None, device_features=None): super(DAI, self).__init__() # Do not make the ``Manager`` object as an attribute of DAI object, # since the attribute in DAI need to be picklable on Windows. # The underlying implementation of multiprocessing requires that. self._event = Manager().Event( ) # create Event proxy object at main process self.api_url = api_url self.device_model = device_model self.device_addr = device_addr self.device_name = device_name self.persistent_binding = persistent_binding self.username = username self.extra_setup_webpage = extra_setup_webpage self.device_webpage = device_webpage self.register_callback = register_callback self.on_register = on_register self.on_deregister = on_deregister self.on_connect = on_connect self.on_disconnect = on_disconnect self.push_interval = push_interval self.interval = interval if interval else {} self.device_features = device_features if device_features else {} self.flags = {} def push_data(self, df_name): if not self.device_features[df_name].push_data: return log.debug('%s:%s', df_name, self.flags[df_name]) while self.flags[df_name]: _data = self.device_features[df_name].push_data() if not isinstance(_data, NoData) and _data is not NoData: self.dan.push(df_name, _data) time.sleep(self.interval.get(df_name, self.push_interval)) def on_signal(self, signal, df_list): log.info('Receive signal: \033[1;33m%s\033[0m, %s', signal, df_list) if 'CONNECT' == signal: for df_name in df_list: # race condition if not self.flags.get(df_name): self.flags[df_name] = True t = Thread(target=self.push_data, args=(df_name, )) t.daemon = True t.start() elif 'DISCONNECT' == signal: for df_name in df_list: self.flags[df_name] = False elif 'SUSPEND' == signal: # Not use pass elif 'RESUME' == signal: # Not use pass return True def on_data(self, df_name, data): try: self.device_features[df_name].on_data(data) except: traceback.print_exc() return False return True @staticmethod def df_func_name(df_name): return re.sub(r'-(I|O)$', r'_\1', df_name) def _check_parameter(self): if self.api_url is None: raise RegistrationError('api_url is required') if self.device_model is None: raise RegistrationError('device_model not given.') if isinstance(self.device_addr, UUID): self.device_addr = str(self.device_addr) elif self.device_addr: try: UUID(self.device_addr) except ValueError: try: self.device_addr = str(UUID(int=int(self.device_addr, 16))) except ValueError: log.warning( 'Invalid device_addr. Change device_addr to None.') self.device_addr = None if self.persistent_binding and self.device_addr is None: msg = ('In case of `persistent_binding` set to `True`, ' 'the `device_addr` should be set and fixed.') raise ValueError(msg) if not self.device_features.keys(): raise RegistrationError('Neither idf_list nor odf_list is empty.') return True def finalizer(self): try: if not self.persistent_binding: self.dan.deregister() except Exception as e: log.warning('dai process cleanup exception: %s', e) def start(self, *args, **kwargs): ret = super(DAI, self).start(*args, **kwargs) # conduct deregistration properly, # if one doesn't stop process before main process ends atexit.register(self.terminate) return ret def run(self): # this function will be executed in child process self._check_parameter() self.dan = Client() idf_list = [] odf_list = [] for df in self.device_features.values(): if df.df_type == 'idf': idf_list.append(df.profile()) else: odf_list.append(df.profile()) def f(): for key in self.flags: self.flags[key] = False log.debug('on_disconnect: _flag = %s', str(self.flags)) if self.on_disconnect: return self.on_disconnect() self.dan.register(self.api_url, on_signal=self.on_signal, on_data=self.on_data, accept_protos=['mqtt'], id_=self.device_addr, idf_list=idf_list, odf_list=odf_list, name=self.device_name, profile={ 'model': self.device_model, 'u_name': self.username, 'extra_setup_webpage': self.extra_setup_webpage, 'device_webpage': self.device_webpage, }, register_callback=self.register_callback, on_register=self.on_register, on_deregister=self.on_deregister, on_connect=self.on_connect, on_disconnect=f) log.info('Press Ctrl+C to exit DAI.') try: self._event.wait() except KeyboardInterrupt: pass finally: self.finalizer() def wait(self): try: if platform.system() == 'Windows' or sys.version_info.major == 2: # workaround for https://bugs.python.org/issue35935 while True: time.sleep(86400) else: Event().wait() except KeyboardInterrupt: self.join() # wait for deregistration def terminate(self, *args, **kwargs): ''' Terminate DAI. This is a blocking call. ''' try: self._event.set() except Exception: # this is triggered if the ``run`` function ended already. pass self.join() return super(DAI, self).terminate(*args, **kwargs)
def __init__(self, p_id, do_id, d_id): self.p_id = p_id self.do_id = do_id self.d_id = d_id self.dan = Client()