def configure_daq_local(self): self.status2.set_config_status(Status.CONFIGURING) self.read_current_config() if self.config: try: self.namespace = Namespace().from_dict( self.config["namespace"]) except KeyError: pass try: self.autoenable_daq = self.config["autoenable_daq"] except KeyError: pass try: self.uri = self.config["uri"] except KeyError: pass self.status2.set_config_status(Status.NOT_CONFIGURED) try: if self.config["ENVDAQ_CONFIG"]: self.status2.set_config_status(Status.CONFIGURED) except KeyError: pass else: self.status2.set_config_status(Status.NOT_CONFIGURED) print(f"self.config: {self.config}") # have tried to configure, now connect to UI self.do_ui_connection = True
async def register( reg_id=Namespace().get_namespace_sig(), namespace=Namespace().to_dict(), type=Namespace.DAQSERVER, config=dict(), ): # if not reg_id2: # reg_id2 = Namespace().get_namespace_sig() # registration = await DAQRegistry.register_no_wait( # reg_id=reg_id, # reg_id2=reg_id2, # namespace=namespace, # type=type, # config=config, # config2=config2, # ) registration = await DAQRegistry.register_no_wait( reg_id=reg_id, namespace=namespace, type=type, config=config, ) # if not registration: # registration = await DAQRegistry.update_registration(namespace, type, config) return registration
def get_server_id(server_id=None): if not server_id: # server_id = PlotManager.DEFAULT_ID server_id = Namespace() server_sig = server_id.get_namespace_comp_sig( component=Namespace.DAQSERVER) return f"{server_sig['host']}:{server_sig['name']}"
def update_server(config=None, server_id=None, app_list=None, force=False): # print(f'update_server: {config}, {server_id}') # use config to create PlotApps if config: server_id = "" pass elif not server_id: # server_id = PlotManager.DEFAULT_ID server_id = Namespace() plotserver_id = PlotManager.get_server_id(server_id) plotserver_port = PlotManager.get_free_port(plotserver_id) if not plotserver_port: return # print(f'server_id = {server_id}, {PlotManager.__server_map}') if (server_id in PlotManager.__server_map) or force: PlotManager.__server_map[plotserver_id] = PlotServer( server_id=plotserver_id, host=PlotManager.PLOTSERVER_HOST, port=plotserver_port, app_list=app_list, )
def get_namespace(self): # ns = Namespace(name=self.name, host=self.host, ns_type=Namespace.DAQSERVER) parent_ns = self.controller.get_namespace() ns = Namespace(name=self.name, ns_type=Namespace.INSTRUMENT, parent_ns=parent_ns) # print(f"ns::: {ns.to_dict()}") return ns
async def get_registration( reg_id=Namespace().get_namespace_sig(), type=Namespace.DAQSERVER): # registration = await DAQRegistry.get_registration_no_wait( # reg_id=reg_id, reg_id2=reg_id2, type=type # ) registration = await DAQRegistry.get_registration_no_wait( reg_id=reg_id, type=type) return registration
def get_server(server_id=None): if not server_id: # server_id = PlotManager.DEFAULT_ID server_id = Namespace() plotserver_id = PlotManager.get_server_id(server_id) if plotserver_id not in PlotManager.__server_map: PlotManager.add_server(server_id=server_id) return PlotManager.__server_map[plotserver_id]
def read_current_config(self): # read current config file fname = self.current_config_file if not os.path.isabs(self.current_config_file): fname = os.path.join( os.path.dirname(os.path.realpath(__file__)), self.current_config_file, ) if not os.path.exists(fname): self.clear_current_config() try: # with open(self.last_config_file) as cfg: with open(fname) as cfg: self.config = json.load(cfg) # print(f"{self.config}") try: self.uri = self.config["uri"] except KeyError: pass try: ns = self.config["namespace"] self.namespace = Namespace().from_dict(ns) except KeyError: pass try: self.autoenable = self.config["autoenable_daq"] except KeyError: pass # print(f"self.config***: {self.config}") except FileNotFoundError as e: print(e) pass except JSONDecodeError as e: self.config = dict() except TypeError: self.clear_current_config() pass
def unregister_no_wait( reg_id=Namespace().get_namespace_sig(), type=Namespace.DAQSERVER): try: # print(f"unregister:{reg_id}") # reg = DAQRegistration.objects.get(reg_id2=reg_id2, daq_type=type) reg = DAQRegistration.objects.get(reg_id=reg_id, daq_type=type) # print(f"Unregistering: {reg}") reg.delete() # print(f"success") except DAQRegistration.DoesNotExist: # print(f"unregister: reg_id does not exist {reg_id}") pass
async def update_registration( reg_id=Namespace().get_namespace_sig(), namespace=Namespace().to_dict(), type=Namespace.DAQSERVER, config=dict(), registration=None, ): # reg = await DAQRegistry.update_registration_no_wait( # reg_id=reg_id, # reg_id2=reg_id2, # namespace=namespace, # type=type, # registration=registration, # ) reg = await DAQRegistry.update_registration_no_wait( reg_id=reg_id, namespace=namespace, type=type, registration=registration, ) return reg
def get_namespace(self): # ns = Namespace(name=self.name, host=self.host, ns_type=Namespace.DAQSERVER) if self.server: parent_ns = self.server.get_namespace() elif self.parent_controller: parent_ns = self.parent_controller.get_namespace() else: return None ns = Namespace(name=self.name, ns_type=Namespace.CONTROLLER, parent_ns=parent_ns) # print(f"ns::: {ns.to_dict()}") return ns
def index(request): net_map = {} networks = Network.objects.all() for net in networks: net_map[net.name] = { "description": net.description, "active": net.active } daq_reg_map = {} daq_regs = DAQRegistration.objects.all() for reg in daq_regs: ns = Namespace().from_dict(reg.namespace) daq_reg_map[ns.get_namespace()] = { "host": ns.get_host(), "name": ns.name, # "signature": ns.get_namespace_sig(), "type": reg.daq_type, # "status": reg.status } # daq_reg_map[reg.reg_id] = { # "type": reg.daq_type, # "status": reg.status # } context = { "network_map": net_map, "daq_reg_map": daq_reg_map, } return render(request, 'index.html', context)
def get_registration_no_wait( reg_id=Namespace().get_namespace_sig(), type=Namespace.DAQSERVER): # theoretically, we should not be pinging local here # if not regkey and config and (regkey in config): # regkey = config["regkey"] # if regkey: print(f"get_reg: {reg_id}") try: # reg = DAQRegistration.objects.get(reg_id2=reg_id2, daq_type=type) reg = DAQRegistration.objects.get(reg_id=reg_id, daq_type=type) # reg.status = "CONNECTED" # srv = ServiceRegistration.objects.get(regkey=config["regkey"]) # reg.save(do_update=True) # update modified time stamp return reg.get_registration() except DAQRegistration.DoesNotExist: pass return None
def ping_no_wait( reg_id=Namespace().get_namespace_sig(), type=Namespace.DAQSERVER): # theoretically, we should not be pinging local here # if not regkey and config and (regkey in config): # regkey = config["regkey"] # if regkey: try: # print(f"ping server reg: {reg_id}") # reg = DAQRegistration.objects.get(reg_id2=reg_id2, daq_type=type) reg = DAQRegistration.objects.get(reg_id=reg_id, daq_type=type) reg.status = "CONNECTED" status2 = Status().from_dict(reg.status2) status2.set_connection_status(Status.CONNECTED) reg.status2 = status2.to_dict() # srv = ServiceRegistration.objects.get(regkey=config["regkey"]) reg.save(do_update=True) # update modified time stamp # print(f"ping success") except DAQRegistration.DoesNotExist: pass
def __init__(self, config=None, server_name=None, ui_config=None): self.controller_list = [] self.controller_map = dict() self.task_list = [] self.ui_task_list = [] self.last_data = {} self.run_flag = False self.registration_key = None self.run_state = "STOPPED" self.config_state = "NOT_CONFIGURED" # defaults self.server_name = "" self.ui_config = { "host": "localhost", "port": 8001, } self.base_file_path = "/tmp" self.current_run_config = {} # daq_id: used by ui to delineate between different daq_servers - {nodename}-{namespace} self.daq_id = "localhost-default" self.uri = "localhost" # self.namespace = { # "daq_server": "localhost-default", # } self.namespace = Namespace(name="default", host="localhost", ns_type=Namespace.DAQSERVER) self.autoenable_daq = False self.enable_daq = True self.loop = asyncio.get_event_loop() # try to import config from daq_settings.py try: daq_settings = import_module("config.daq_settings") server_config = daq_settings.server_config if "name" in server_config: self.server_name = server_config["name"] if "ui_config" in server_config: self.ui_config = server_config["ui_config"] if "base_file_path" in server_config: self.base_file_path = server_config["base_file_path"] if "daq_id" in server_config: fqdn = server_config["daq_id"]["fqdn"] namespace = server_config["daq_id"]["namespace"] # self.uri = fqdn # self.daq_id = f"{fqdn.split('.')[0]}-{namespace}" # self.namespace["daq_server"] = self.daq_id.replace(" ", "") self.namespace.host = fqdn self.namespace.name = namespace.replace(" ", "") self.daq_id = self.namespace.get_namespace_sig()["name"] self.uri = self.namespace.get_namespace_sig()["host"] self.current_config_file = "./current_config.json" if "current_config_file" in server_config: self.current_config_file = server_config["current_config_file"] self.config = dict() # if "last_config_file" in server_config: # # dir_path = os.path.dirname(os.path.realpath(__file__)) # # print(dir_path) # self.last_config_file = server_config["last_config_file"] # fname = self.last_config_file # if not os.path.isabs(self.last_config_file): # fname = os.path.join( # os.path.dirname(os.path.realpath(__file__)), # self.last_config_file, # ) # try: # # with open(self.last_config_file) as cfg: # with open(fname) as cfg: # self.config = json.load(cfg) # except FileNotFoundError as e: # print(e) # pass # except TypeError: # pass # if self.config: # self.config_state = "CONFIGURED" # if "current_run_config" in server_config: # self.current_run_config = server_config["current_run_config"] # if self.current_run_config: # self.config = self.current_run_config except ModuleNotFoundError: print("settings file not found, using defaults") self.server_name = "" # TODO I don't think these override any more...get rid of them? # override config file settings if server_name: self.server_name = server_name if ui_config: self.ui_config = ui_config if config: self.config = config # self.do_ui_connection = auto_connect_ui self.do_ui_connection = False # change this when try config self.reg_client = None self.ui_client = None self.status = { # 'run_status': 'STOPPED', "ready_to_run": False, "connected_to_ui": False, "health": "OK", } self.status2 = Status() # start managers SysManager.start() # Create message buffers self.to_ui_buf = None self.from_child_buf = None self.create_msg_buffers() # Begin startup self.run_task = None self.start_daq()
def __init__( self, config, ui_config=None, base_file_path=None, auto_connect_ui=True, namespace=None, **kwargs, ): # non-abstract DAQ children need to set this to True # in order for system to recognize as valid # TODO: make an abstract method to retrieve value # to force children to deal with it? # TODO: Should DAQ have generic in/out buffers? print("init DAQ") self.loop = asyncio.get_event_loop() self.config = config self.ui_config = ui_config self.do_ui_connection = auto_connect_ui self.task_list = [] self.ui_task_list = [] self.enable_task_list = [] self.message_loop_tasks = [] self.registration_key = None self.plot_app = None self.datafile = None self.keepalive_ping = False # set base file path for all file saves # base_file_path = '/tmp' if base_file_path: self.base_file_path = base_file_path # parameters to include metadata in output self.include_metadata = True # set interval to 0 to always send metadata self.include_metadata_interval = 60 # self.daq_definition = dict() # self.daq_definition['DEFINITION'] = dict() # self.INSTANTIABLE = False self.name = None self.label = None if "LABEL" in config: self.label = config["LABEL"] # print(f"id: {self.get_id()}") # print(f"16namespace = {self.namespace} - {self.alias}") # if namespace is passed, store a copy self.namespace = Namespace() if namespace: self.namespace = Namespace().from_dict(namespace) # self.namespace = namespace.copy() # self.parent_id = "parent-default" # if parent_id: # self.parent_id = parent_id # self.daq_id = f"{self.parent_id}-default" # in case we want to add heierarchy # parent = { # class: 'CONTROLLER', # id: <controller_name>, # } self.parent = None self.parent_map = dict() self.data_request_list = [] # Message buffers (Queues) # to/from parent self.to_parent_buf = None self.from_parent_buf = None # to/from child self.to_child_buf = None self.from_child_buf = None # to/from gui self.to_ui_buf = None self.from_ui_buf = None self.create_msg_buffers() # ui client self.ui_client = None # controls self.controls = dict() self.status = { "run_status": "STOPPED", "ready_to_run": False, "connected_to_ui": False, "health": "OK", } self.status2 = Status() self.current_run_settings = dict()
class DAQ(abc.ABC): # TODO: how to do this more elegantly? INSTANTIABLE = False # daq_definition = {'DEFINITION': {}} def __init__( self, config, ui_config=None, base_file_path=None, auto_connect_ui=True, namespace=None, **kwargs, ): # non-abstract DAQ children need to set this to True # in order for system to recognize as valid # TODO: make an abstract method to retrieve value # to force children to deal with it? # TODO: Should DAQ have generic in/out buffers? print("init DAQ") self.loop = asyncio.get_event_loop() self.config = config self.ui_config = ui_config self.do_ui_connection = auto_connect_ui self.task_list = [] self.ui_task_list = [] self.enable_task_list = [] self.message_loop_tasks = [] self.registration_key = None self.plot_app = None self.datafile = None self.keepalive_ping = False # set base file path for all file saves # base_file_path = '/tmp' if base_file_path: self.base_file_path = base_file_path # parameters to include metadata in output self.include_metadata = True # set interval to 0 to always send metadata self.include_metadata_interval = 60 # self.daq_definition = dict() # self.daq_definition['DEFINITION'] = dict() # self.INSTANTIABLE = False self.name = None self.label = None if "LABEL" in config: self.label = config["LABEL"] # print(f"id: {self.get_id()}") # print(f"16namespace = {self.namespace} - {self.alias}") # if namespace is passed, store a copy self.namespace = Namespace() if namespace: self.namespace = Namespace().from_dict(namespace) # self.namespace = namespace.copy() # self.parent_id = "parent-default" # if parent_id: # self.parent_id = parent_id # self.daq_id = f"{self.parent_id}-default" # in case we want to add heierarchy # parent = { # class: 'CONTROLLER', # id: <controller_name>, # } self.parent = None self.parent_map = dict() self.data_request_list = [] # Message buffers (Queues) # to/from parent self.to_parent_buf = None self.from_parent_buf = None # to/from child self.to_child_buf = None self.from_child_buf = None # to/from gui self.to_ui_buf = None self.from_ui_buf = None self.create_msg_buffers() # ui client self.ui_client = None # controls self.controls = dict() self.status = { "run_status": "STOPPED", "ready_to_run": False, "connected_to_ui": False, "health": "OK", } self.status2 = Status() self.current_run_settings = dict() # start loop to maintain ui # if ( # 'do_ui_connection' in self.ui_config and # self.ui_config['do_ui_connection'] is False # ): # print('no ui connection') # pass # else: # self.task_list.append( # asyncio.ensure_future(self.run_ui_connection()) # ) # # make ui connection # self.ui_task_list.append( # asyncio.ensure_future(self.open_ui_connection()) # ) def get_namespace_as_string(self): names = [k for k, v in self.namespace.items()] ns = "-".join(names) return ns def open_datafile(self): cfg = self.get_datafile_config() if cfg: self.datafile = DataFile( # base_path=self.get_base_filepath(), config=self.get_datafile_config()) if self.datafile: self.datafile.open() def get_datafile_config(self): bfp = self.get_base_filepath() if bfp: config = { "base_path": self.get_base_filepath(), } return config return None def get_base_filepath(self): # system_base = '/home/horton/derek/tmp/envDataSystem/' # inst_base = 'instrument/' # definition = self.get_definition_instance() # inst_base += definition['DEFINITION']['type']+'/' # inst_base += definition['DEFINITION']['mfg']+'/' # inst_base += definition['DEFINITION']['model']+'_' # inst_base += self.serial_number+'/' if self.base_file_path: return self.base_file_path + "/" + self.alias["name"] return None # return system_base+inst_base @abc.abstractmethod def setup(self): print("daq.setup") self.start_connections() # @abc.abstractmethod def setup_datafile(self): pass def start_connections(self): print("start_connections") self.start_ui_connection() def start_ui_connection(self): print("start_ui_connection") self.task_list.append(asyncio.ensure_future(self.run_ui_connection())) # TODO: convert all to_parent_buffers to # registration process def register_parent(self, parent_id, to_parent_buffer=None): if parent_id in self.parent_map: return self.parent_map[parent_id] = {"to_parent_buffer": to_parent_buffer} def deregister_parent(self, parent_id): try: del self.parent_map[parent_id] except KeyError: pass def register_data_request(self, entry): if entry and entry not in self.data_request_list: self.data_request_list.append(entry) def get_id(self): id = self.__class__.__name__ if self.namespace: id += "_" + self.namespace.get_namespace_sig()["namespace"] # if self.label is not None: # id += "_"+self.label return id def current_run_settings_file(self) -> Path: ns_path = Path("config") / "run" # ns_path = ["config", "run"] # if "daq_server" in self.namespace: # # ns_path.append(self.namespace['daq_server']) # ns_path /= self.namespace['daq_server'] # if "controller" in self.namespace: # # ns_path.append(self.namespace['controller']) # ns_path /= self.namespace['controller'] # if "instrument" in self.namespace: # # ns_path.append(self.namespace['instrument']) # ns_path /= self.namespace['instrument'] # # if not os.path.exists(os.path.join(ns_path)): # # os.makedirs(ns_path) # # Path.mkdir(ns_path, parents=True, exist_ok=True) ns_path = self.namespace.get_namespace_as_path() fname = ns_path / "current_run_settings.json" return fname def get_current_run_settings(self): if not self.controls: definition = self.get_definition_instance() try: self.controls = definition["DEFINITION"]["measurement_config"][ "controls"] except KeyError: print("no run settings to get") return fname = self.current_run_settings_file() Path.mkdir(fname.parent, parents=True, exist_ok=True) try: with open(fname) as cfg: self.current_run_settings = json.load(cfg) # print(f"{self.current_run_settings}") except (FileNotFoundError, JSONDecodeError, TypeError): self.set_current_run_settings_default() # saved settings not valid for some reason, set to default need_save = False for control, config in self.controls.items(): if control not in self.current_run_settings: self.current_run_settings[control] = None need_save = True if "default_value" in config: self.current_run_settings[control] = config[ "default_value"] if need_save: self.save_current_run_settings() def update_current_run_settings(self): if self.controls: for control, settings in self.controls.items(): try: # print(f"{control}, {settings}") self.current_run_settings[control] = settings["value"] except KeyError: pass # print(f"update crs error: {control}") # print(f"updated run settings: {self.current_run_settings}") self.save_current_run_settings() def save_current_run_settings(self): if self.current_run_settings: fname = self.current_run_settings_file() Path.mkdir(fname.parent, parents=True, exist_ok=True) try: # test = json.dumps(self.current_run_settings) # print(test) with open(fname, "w") as cfg: json.dump(self.current_run_settings, cfg) except (FileNotFoundError, JSONDecodeError, TypeError) as e: print(f"Could not save current_run_settigns: {fname}: {e}") def set_current_run_settings_default(self): if not self.controls: definition = self.get_definition_instance() try: self.controls = definition["DEFINITION"]["measurement_config"][ "controls"] except KeyError: print("no run settings to get") return for control, config in self.controls.items(): self.current_run_settings[control] = None if "default_value" in config: # TODO: on start, have to go through and send all # control values to instrument self.current_run_settings[control] = config[ "default_value"] # self.set_control_att( # control, 'value', config['default_value'] # ) self.save_current_run_settings() def get_controls(self): return self.controls def get_control(self, control): if control: controls = self.get_controls() if control in controls: return controls[control] return None async def set_controls(self, controls): if controls: for control, value in controls.items(): await self.set_control(control, value) # self.controls = controls async def set_control(self, control, value): if control and value is not None: await self.handle_control_action(control, value) if await self.control_action_success(control): self.set_control_att(control, "value", value) self.update_current_run_settings() else: print(f"Setting {control} unsuccessful") # TODO: setting control should trigger action # print(f'set_control[{control}] = {value}') # TODO: implement this as an abstract method # @abc.abstractmethod async def handle_control_action(self, control, value): # default control actions if control and value is not None: if control == "start_stop": if value == "START": self.start() elif value == "STOP": self.stop() def set_control_att(self, control, att, value): if control not in self.controls: self.controls[control] = dict() try: self.controls[control][att] = value # self.controls[control]['action_state'] = state except Exception as e: print(f"exc: {e}") def get_control_att(self, control, att): if control in self.controls: try: return self.controls[control][att] except Exception as e: print(f"No attribute {att} in {control}: {e}") return "" async def control_action_success(self, control): timeout = 50 # seconds * 10 for faster response cnt = 0 while cnt < timeout: try: # print( # f'success; {self.get_control_att(control, "action_state")}' # ) if self.get_control_att(control, "action_state") == "OK": self.set_control_att(control, "action_state", "IDLE") return True except Exception as e: print(f"exception: {e}") await asyncio.sleep(0.1) cnt += 0.1 return False # TODO: add this abstract method to all daq # @abc.abstractclassmethod def get_definition(): pass @abc.abstractclassmethod def get_definition_instance(): pass # @classmethod # def can_instantiate(): # return object.__class__().INSTANTIATE # @classmethod # def get_instantiable(): # return DAQ.INSTANTIABLE # @classmethod # def set_instantiable(val): # if val: # DAQ.INSTANTIABLE = True # else: # DAQ.INSTANTIABLE = False @abc.abstractmethod def get_ui_address(self): pass async def register_with_UI(self): pass async def deregister_from_UI(self): pass async def connect_to_ui(self): print(f"connecting to ui: {self}") # build ui_address ui_address = f'ws://{self.ui_config["host"]}' ui_address += f':{self.ui_config["port"]}' ui_address += "/ws/" + self.get_ui_address().replace(" ", "") # ui_address.replace(" ", "") print(f"ui_address: {ui_address}") # self.ui_client = WSClient(uri=quote(ui_address)) self.ui_client = WSClient(uri=ui_address) while self.ui_client.isConnected() is not True: # self.gui_client = WSClient(uri=gui_ws_address) # print(f"gui client: {self.gui_client.isConnected()}") await asyncio.sleep(1) async def run_ui_connection(self): # # start ui queues # self.ui_task_list.append( # asyncio.ensure_future(self.to_ui_loop()) # ) # self.ui_task_list.append( # asyncio.ensure_future(self.from_ui_loop()) # ) while True: if self.do_ui_connection and (self.ui_client is None or not self.ui_client.isConnected()): self.status2.set_connection_status(Status.CONNECTING) # close tasks for current ui if any for t in self.ui_task_list: t.cancel() # make connection print("connect to ui") await self.connect_to_ui() # start ui queues self.ui_task_list.append( asyncio.ensure_future(self.to_ui_loop())) self.ui_task_list.append( asyncio.ensure_future(self.from_ui_loop())) if self.keepalive_ping: self.ui_task_list.append( asyncio.create_task(self.ping_ui_server())) await self.register_with_UI() self.status2.set_connection_status(Status.CONNECTED) await asyncio.sleep(1) # async def open_ui_connection(self): # while self.ui_client.isConnected() is False: # # if self.ui_client.isConnected() is False: # self.ui_client = self.connect_to_ui() def send_status(self, note=""): # print(f'send_status: {self.name}, {self.status}') status = Message( sender_id=self.get_id(), msgtype="GENERIC", subject="STATUS", body={ "purpose": "UPDATE", "status": self.status, # 'note': note, }, ) status = self.status2.to_message(sender_id=self.get_id()) # print(f'send no wait: {self.name}, {self.status}') self.message_to_ui_nowait(status) # self.message_to_ui_nowait(status) async def send_settings_to_ui(self): if self.current_run_settings: settings = Message( sender_id=self.get_id(), msgtype=self.class_type, subject="SETTINGS", body={ "purpose": "UPDATE", "settings": self.current_run_settings, # 'note': note, }, ) await self.message_to_ui(settings) async def update_settings_loop(self): # overload this function if you want an update # settings loop. pass # # print(f'send_status: {self.name}, {self.status}') # if not self.current_run_settings: # self.get_current_run_settings() # while True: # # while self.current_run_settings: # if self.status2.get_run_status() in [Status.READY_TO_RUN, Status.STOPPED]: # settings = Message( # sender_id=self.get_id(), # msgtype=self.class_type, # subject="SETTINGS", # body={ # 'purpose': 'UPDATE', # 'settings': self.current_run_settings, # # 'note': note, # } # ) # await self.message_to_ui(settings) # await asyncio.sleep(2) async def send_metadata_loop(self): while True: if self.include_metadata_interval > 0: # wt = utilities.util.time_to_next( # self.include_metadata_interval # ) # print(f'wait time: {wt}') await asyncio.sleep( time_to_next(self.include_metadata_interval)) self.include_metadata = True else: self.include_metadata = True asyncio.sleep(1) def enable(self): if self.status2.get_enabled_status() != Status.ENABLED: # if self.status['run_status'] != 'STARTED': self.enable_task_list.append( asyncio.ensure_future(self.from_parent_loop())) self.enable_task_list.append( asyncio.ensure_future(self.from_child_loop())) self.enable_task_list.append( asyncio.create_task(self.update_settings_loop())) self.status2.set_enabled_status(Status.ENABLED) def disable(self): if self.status2.get_enabled_status() == Status.ENABLED: # print("here:01") self.stop() # print("here:02") for t in self.enable_task_list: # print("here:03") t.cancel() # print("here:04") self.status2.set_enabled_status(Status.DISABLED) def start(self, cmd=None): # self.create_msg_buffers() self.status2.set_run_status(Status.STARTING) # only need to start this, will be cancelled by # daq on stop self.include_metadata = True self.task_list.append(asyncio.ensure_future(self.send_metadata_loop())) # if self.status2.get_run_status() != Status.RUNNING: # # if self.status['run_status'] != 'STARTED': # self.task_list.append( # asyncio.ensure_future(self.from_parent_loop()) # ) # self.task_list.append( # asyncio.ensure_future(self.from_child_loop()) # ) self.status["run_status"] = "STARTED" self.status2.set_run_status(Status.RUNNING) self.send_status() def stop(self, cmd=None): # print("here:01") self.status2.set_run_status(Status.STOPPING) # for t in self.task_list: # t.cancel() # print("here:01") self.status["run_status"] = "STOPPED" # print("here:02") self.status2.set_run_status(Status.STOPPED) # print("here:03") self.send_status() # print("here:04") async def ping_ui_server(self): # wait for things to get started before pinging await asyncio.sleep(5) while self.ui_client.isConnected(): msg = Message( sender_id=self.get_id(), msgtype="PING", subject="PING", body={ # "id": self.daq_id "namespace": self.namespace.to_dict() }, ) await self.to_ui_buf.put(msg) await asyncio.sleep(2) async def shutdown(self): print("daq shutdown") # if self.started: # print(f'wait for shutdown...') # return self.status2.set_run_status(Status.SHUTTING_DOWN) while self.status2.get_registration_status() != Status.UNREGISTERING: await asyncio.sleep(1) for t in self.ui_task_list: # print(t) t.cancel() if self.ui_client is not None: # self.loop.run_until_complete(self.gui_client.close()) self.ui_client.sync_close() # self.disable() # for t in self.ui_task_list: # t.cancel() self.status2.set_run_status(Status.SHUTDOWN) def create_msg_buffers(self, config=None): """ Create all buffers controlled by this instance. """ self.from_parent_buf = asyncio.Queue(loop=self.loop) self.from_child_buf = asyncio.Queue(loop=self.loop) self.to_ui_buf = asyncio.Queue(loop=self.loop) # I don't think we need a from_ui_buf # self.from_ui_buf = asyncio.Queue(loop=self.loop) @abc.abstractmethod async def handle(self, msg, type=None): if type == "FromUI": if msg.subject == "STATUS" and msg.body["purpose"] == "REQUEST": # print(f"msg: {msg.body}") self.send_status() elif msg.subject == "CONTROLS" and msg.body["purpose"] == "REQUEST": # print(f"msg: {msg.body}") await self.set_control(msg.body["control"], msg.body["value"]) elif msg.subject == "RUNCONTROLS" and msg.body[ "purpose"] == "REQUEST": # print(f"msg: {msg.body}") await self.handle_control_action(msg.body["control"], msg.body["value"]) # await self.set_control(msg.body['control'], msg.body['value']) elif msg.subject == "REGISTRATION": print(f"reg: {msg.subject}") if msg.body["purpose"] == "SUCCESS": self.registration_key = msg.body["regkey"] # if content["BODY"]["config"]: # self.config = content["BODY"]["config"] # self.save_current_config(json.loads(content["BODY"]["config"])) self.status2.set_registration_status(Status.REGISTERED) # if content["BODY"]["ui_reconfig_request"]: # await self.resend_config_to_ui() elif msg.subject == "UNREGISTRATION": # print(f"unreg: {content['BODY']}") if msg.body["purpose"] == "SUCCESS": self.status2.set_registration_status(Status.NOT_REGISTERED) # print(f"unreg: {self.status2.get_registration_status()}") async def from_parent_loop(self): while True: msg = await self.from_parent_buf.get() # print(f'daq from parent: {msg.to_json()}') await self.handle(msg, type="FromParent") # await asyncio.sleep(.1) async def from_child_loop(self): # print(f'started from_child_loop: {self.name} {self.from_child_buf}') # while self.from_child_buf is None: # pass while True: msg = await self.from_child_buf.get() # print(f'****from_child_loop: {msg.to_json()}') # print(f'from_child: {self.get_id()}') await self.handle(msg, type="FromChild") # await asyncio.sleep(.1) async def to_ui_loop(self): while True: message = await self.to_ui_buf.get() # print(f'&&&&&&&&&&&&&&&send server message: {message.to_json()}') await self.ui_client.send_message(message) async def from_ui_loop(self): # print(f'starting daq from_ui_loop') while True: message = await self.ui_client.read_message() # print(f'message = {message.to_json()}') await self.handle(message, type="FromUI") async def message_to_parent(self, msg): # while True: # print(f'message_to_parent: {self.get_id()}, {msg.to_json()}') await self.to_parent_buf.put(msg) async def message_to_parents(self, msg): # while True: # print(f'message_to_parents: {self.get_id()}, {msg.to_json()}') for id, parent in self.parent_map.items(): if parent["to_parent_buffer"]: # print(f'mtp: {msg.to_json()}') await parent["to_parent_buffer"].put(msg) def message_to_ui_nowait(self, msg): # print(f'no wait: {msg.to_json()}') asyncio.ensure_future(self.message_to_ui(msg)) async def message_to_ui(self, msg): # while True: # print('******message_to_ui') # print(f'message_to_ui: {msg.to_json()}') await self.to_ui_buf.put(msg) async def message_from_parent(self, msg): """ This is to be used by parent to send messages to children """ # while True: await self.from_parent_buf.put(msg)
def get_namespace(self): ns = Namespace(name=self.name, host=self.host, ns_type=Namespace.DAQSERVER) return ns
async def unregister( reg_id=Namespace().get_namespace_sig(), type=Namespace.DAQSERVER): await DAQRegistry.unregister_no_wait(reg_id=reg_id, type=type)
def update_registration_no_wait( reg_id=Namespace().get_namespace_sig(), namespace=Namespace().to_dict(), type=Namespace.DAQSERVER, config=dict(), registration=None, ): # if config: # network = "default" # if local: # network = ServiceRegistry.local_network.name # else: # try: # network = config["network"] # except KeyError: # pass # defaults to "default" try: # srv = ServiceRegistration.objects.get(regkey=config["regkey"]) # reg = DAQRegistration.objects.get(reg_id2=reg_id2, daq_type=type) reg = DAQRegistration.objects.get(reg_id=reg_id, daq_type=type) except DAQRegistration.DoesNotExist: reg = None # if reg.get_age() > DAQRegistry.auto_clean_limit: # reg.delete() # elif config and reg.regkey in config and config["regkey"] != reg.regkey: # reg.delete() # else: config = {} # regkey = None if registration: config = registration["config"] # config2 = registration["config2"] # regkey = registration["regkey"] if not reg: # reg = DAQRegistration( # reg_id2=reg_id2, # namespace=namespace, # daq_type=type, # config=config, # config2=config2, # ) reg = DAQRegistration( reg_id=reg_id, namespace=namespace, daq_type=type, config=config, ) if reg: # reg.reg_id2 = reg_id2 reg.reg_id = reg_id reg.namespace = namespace reg.daq_type = type reg.config = config # reg.config2 = config2 reg.status = "CONNECTED" status2 = Status() status2.set_connection_status(Status.CONNECTED) reg.status2 = status2.to_dict() # if regkey: # reg.regkey = regkey # srv.service_list = config.service_list reg.save(do_update=True) # TODO: update service # reg.add_services(config["service_list"]) # srv.save() # if local: # ServiceRegistry.local_network.add_registration(srv) # reg.join_network(ServiceRegistry.get_network_name(local, config)) return reg.get_registration() # print(f"3:{registration}") # return registration else: return None
def register_no_wait( reg_id=Namespace().get_namespace_sig(), namespace=Namespace().to_dict(), type=Namespace.DAQSERVER, config=dict(), ): # print(f"register daq: {config}") # if config: # print(config["host"]) # if not reg_id2: # reg_id2 = Namespace().get_namespace_sig() try: # print(f'{config["HOST"]}, {config["PORT"]}') # registration = DAQRegistration.objects.get(reg_id2=reg_id2, daq_type=type) registration = DAQRegistration.objects.get(reg_id=reg_id, daq_type=type) if registration: registration.delete() except DAQRegistration.MultipleObjectsReturned: # result = DAQRegistration.objects.filter(reg_id2=reg_id2, daq_type=type) result = DAQRegistration.objects.filter(reg_id=reg_id, daq_type=type) for s in result: s.delete() except DAQRegistration.DoesNotExist: pass network = "default" # if local: # network = ServiceRegistry.local_network.name # else: # try: # network = config["network"] # except KeyError: # pass # defaults to "default" # create new Reg # registration = DAQRegistration( # reg_id=reg_id, # reg_id2=reg_id2, # namespace=namespace, # daq_type=type, # config=config, # config2=config2, # status="CONNECTED", # ) status2 = Status() status2.set_connection_status(Status.CONNECTED) print(f"register: {reg_id}, {namespace}") registration = DAQRegistration( reg_id=reg_id, namespace=namespace, daq_type=type, config=config, status="CONNECTED", status2=status2.to_dict(), ) registration.save() # TODO: update service definition to include this reg registration = registration.get_registration() return registration
async def ping( reg_id=Namespace().get_namespace_sig(), type=Namespace.DAQSERVER): await DAQRegistry.ping_no_wait(reg_id, type)
class DAQServer: def __init__(self, config=None, server_name=None, ui_config=None): self.controller_list = [] self.controller_map = dict() self.task_list = [] self.ui_task_list = [] self.last_data = {} self.run_flag = False self.registration_key = None self.run_state = "STOPPED" self.config_state = "NOT_CONFIGURED" # defaults self.server_name = "" self.ui_config = { "host": "localhost", "port": 8001, } self.base_file_path = "/tmp" self.current_run_config = {} # daq_id: used by ui to delineate between different daq_servers - {nodename}-{namespace} self.daq_id = "localhost-default" self.uri = "localhost" # self.namespace = { # "daq_server": "localhost-default", # } self.namespace = Namespace(name="default", host="localhost", ns_type=Namespace.DAQSERVER) self.autoenable_daq = False self.enable_daq = True self.loop = asyncio.get_event_loop() # try to import config from daq_settings.py try: daq_settings = import_module("config.daq_settings") server_config = daq_settings.server_config if "name" in server_config: self.server_name = server_config["name"] if "ui_config" in server_config: self.ui_config = server_config["ui_config"] if "base_file_path" in server_config: self.base_file_path = server_config["base_file_path"] if "daq_id" in server_config: fqdn = server_config["daq_id"]["fqdn"] namespace = server_config["daq_id"]["namespace"] # self.uri = fqdn # self.daq_id = f"{fqdn.split('.')[0]}-{namespace}" # self.namespace["daq_server"] = self.daq_id.replace(" ", "") self.namespace.host = fqdn self.namespace.name = namespace.replace(" ", "") self.daq_id = self.namespace.get_namespace_sig()["name"] self.uri = self.namespace.get_namespace_sig()["host"] self.current_config_file = "./current_config.json" if "current_config_file" in server_config: self.current_config_file = server_config["current_config_file"] self.config = dict() # if "last_config_file" in server_config: # # dir_path = os.path.dirname(os.path.realpath(__file__)) # # print(dir_path) # self.last_config_file = server_config["last_config_file"] # fname = self.last_config_file # if not os.path.isabs(self.last_config_file): # fname = os.path.join( # os.path.dirname(os.path.realpath(__file__)), # self.last_config_file, # ) # try: # # with open(self.last_config_file) as cfg: # with open(fname) as cfg: # self.config = json.load(cfg) # except FileNotFoundError as e: # print(e) # pass # except TypeError: # pass # if self.config: # self.config_state = "CONFIGURED" # if "current_run_config" in server_config: # self.current_run_config = server_config["current_run_config"] # if self.current_run_config: # self.config = self.current_run_config except ModuleNotFoundError: print("settings file not found, using defaults") self.server_name = "" # TODO I don't think these override any more...get rid of them? # override config file settings if server_name: self.server_name = server_name if ui_config: self.ui_config = ui_config if config: self.config = config # self.do_ui_connection = auto_connect_ui self.do_ui_connection = False # change this when try config self.reg_client = None self.ui_client = None self.status = { # 'run_status': 'STOPPED', "ready_to_run": False, "connected_to_ui": False, "health": "OK", } self.status2 = Status() # start managers SysManager.start() # Create message buffers self.to_ui_buf = None self.from_child_buf = None self.create_msg_buffers() # Begin startup self.run_task = None self.start_daq() def start_daq(self): self.run_task = asyncio.ensure_future(self.open()) async def restart_daq(self): self.status2.set_run_status(Status.RESTARTING) # await asyncio.sleep(1) # await self.shutdown() # await asyncio.sleep(5) # self.start_daq() def create_msg_buffers(self): # if need config, use self.config # self.read_buffer = MessageBuffer(config=config) self.to_ui_buf = asyncio.Queue(loop=self.loop) self.from_child_buf = asyncio.Queue(loop=self.loop) def add_controllers(self): print("add_controllers()") config = self.config print(config) print(config["ENVDAQ_CONFIG"]) # print(config['ENVDAQ_CONFIG']['CONT_LIST']) for k, icfg in config["ENVDAQ_CONFIG"]["CONT_LIST"].items(): # for ctr in config['CONT_LIST']: print(f"key: {k}") # print(F'key = {k}') # self.iface_map[iface.name] = iface # print(ifcfg['IFACE_CONFIG']) # controller = ControllerFactory().create(icfg['CONT_CONFIG']) controller = ControllerFactory().create( icfg, ui_config=self.ui_config, base_file_path=self.base_file_path, # namespace=self.namespace, ) print(controller) controller.to_parent_buf = self.from_child_buf self.controller_map[controller.get_id()] = controller async def send_message(self, message): # TODO: Do I need queues? Message and string methods? # await self.sendq.put(message.to_json()) await self.to_ui_buf.put(message) async def to_ui_loop(self): # print("send_ui_loop init") while True: message = await self.to_ui_buf.get() # print('send server message') await self.ui_client.send_message(message) # await asyncio.sleep(1) async def from_ui_loop(self): # print('read_ui_loop init') while True: msg = await self.ui_client.read_message() # print(f'msg = {msg.to_json()}') await self.handle(msg, src="FromUI") # print(msg) # print('read_loop: {}'.format(msg)) async def output_to_screen(self): while True: # TODO: use controller_msg_buffer here # for controller in self.controller_list: # # data = controller.get_last() # # parse data # print('data: {}'.format(data)) ts = datetime.utcnow().isoformat(timespec="seconds") msgstr = "This is a test {}".format(ts) data = { "message": msgstr, } # print('data msg: {}'.format(data)) await self.to_ui_buf.put(json.dumps(data)) # FEServer.send_to_clients(data) await asyncio.sleep(util.time_to_next(1)) # TODO: add run() to check for broken connections async def register_with_UI(self): req = Message( sender_id="daq_server", msgtype="DAQServer", subject="REGISTRATION", body={ "purpose": "ADD", "regkey": self.registration_key, # "id": self.daq_id, # "uri": self.uri, "namespace": self.namespace.to_dict(), "config": self.config, # "config2": json.dumps(self.config), "status": self.status2.to_dict(), }, ) print(f"daq_server:register_with_UI: {req.to_dict()}") print( f"Registering with UI server: {self.namespace.get_namespace_sig()}" ) self.status2.set_registration_status(Status.REGISTERING) await self.to_ui_buf.put(req) self.run_state = "REGISTERING" # await reg_client.close() async def deregister_from_UI(self): # print(f'config: {json.dumps(self.config)}') req = Message( sender_id="daq_server", msgtype="DAQServer", subject="REGISTRATION", body={ "purpose": "REMOVE", "regkey": self.registration_key, "namespace": self.namespace.to_dict(), # "id": self.daq_id, # "uri": self.uri, # "namespace": self.namespace, # "config": self.config, # "config2": json.dumps(self.config), # "status": self.status2 }, ) print( f"Deregistering FROM UI server: {self.namespace.get_namespace_sig()}" ) # self.status2.set_registration_status(Status.UNREGISTERING) await self.to_ui_buf.put(req) self.status2.set_registration_status(Status.UNREGISTERING) self.run_state = "UNREGISTERING" # await reg_client.close() async def connect_to_ui(self): ns_sig = self.namespace.get_namespace_sig() print(f"connecting to ui: {self}") # build ui_address ui_address = f'ws://{self.ui_config["host"]}' ui_address += f':{self.ui_config["port"]}' # ui_address += f"/ws/envdaq/daqserver/{self.daq_id.replace(' ', '')}" # ui_address += f"/ws/envdaq/daqserver/{self.namespace['daq_server']}/" # ui_address += f"/ws/envdaq/{self.namespace.ns_type}/{self.namespace.get_local_namespace()}/" ui_address += f"/ws/envdaq/{self.namespace.ns_type}/{ns_sig['host']}/{ns_sig['namespace']}/" print(f"ui_address: {ui_address}") # self.ui_client = WSClient(uri=quote(ui_address)) self.ui_client = WSClient(uri=ui_address) while self.ui_client.isConnected() is not True: self.status2.set_connection_status(Status.CONNECTING) # self.gui_client = WSClient(uri=gui_ws_address) # print(f"gui client: {self.gui_client.isConnected()}") await asyncio.sleep(1) async def run_ui_connection(self): while True: if self.do_ui_connection and (self.ui_client is None or not self.ui_client.isConnected()): self.status2.set_connection_status(Status.NOT_CONNECTED) # close tasks for current ui if any for t in self.ui_task_list: t.cancel() # make connection print("connect to ui") await self.connect_to_ui() # start ui queues self.ui_task_list.append( asyncio.ensure_future(self.to_ui_loop())) self.ui_task_list.append( asyncio.ensure_future(self.from_ui_loop())) self.ui_task_list.append( asyncio.create_task(self.ping_ui_server())) self.status2.set_connection_status(Status.CONNECTED) await self.register_with_UI() # self.status2.set_connection_status(Status.CONNECTED) await asyncio.sleep(1) def start_connections(self): print("start_connections") self.start_ui_connection() def start_ui_connection(self): print("start_ui_connection") self.task_list.append(asyncio.create_task(self.run_ui_connection())) def enable(self): if self.config and (self.enable_daq or self.autoenable_daq): print("enabling") self.status2.set_enabled_status(Status.ENABLING) self.add_controllers() self.status2.set_enabled_status(Status.ENABLED) asyncio.create_task(self.check_ready_to_run()) asyncio.create_task(self.send_ready_to_run()) def disable(self): if self.status2.get_enabled_status() == Status.ENABLED: self.status2.set_enabled_status(Status.DISABLING) self.stop() self.remove_controllers() self.status2.set_enabled_status(Status.DISABLED) async def open(self): # task = asyncio.ensure_future(self.read_loop()) # self.task_list.append(task) cfg_fetch_freq = 10 # seconds self.status2.set_run_status(Status.STARTING) self.configure_daq_local() self.start_connections() # will only enable if allowed to do so self.enable() # print(f"UI client is connected: {self.ui_client.isConnected()}") # Start heartbeat ping # asyncio.create_task(self.ping_ui_server()) # print("Creating message loops") # self.to_ui_buf = asyncio.Queue() # self.start_ui_message_loops() # self.run_state != "READY_TO_REGISTER": # await self.register_with_UI() # This should only be done on request do_this = False if do_this: print("sync DAQ") # system_def = SysManager.get_definitions_all() # print(f'system_def: {system_def}') sys_def = Message( sender_id="daqserver", msgtype="DAQServer", subject="CONFIG", body={ "purpose": "SYNC", "type": "SYSTEM_DEFINITION", "data": SysManager.get_definitions_all(), }, ) await self.to_ui_buf.put(sys_def) # wait for registration if do_this: while self.status2.get_config_status() != Status.CONFIGURED: # while self.run_state != "READY_TO_RUN": print(f"config: {self.status2.get_config_status()}") await self.configure_daq() await asyncio.sleep(1) if do_this: # once configured, add controllers print("Add controllers...") self.add_controllers() if do_this: # if self.config_state != "CONFIGURED": print("set self.config") while self.config is None: # get config from gui print("Getting config from gui") req = Message( sender_id="daqserver", msgtype="DAQServer", subject="CONFIG", body={ "purpose": "REQUEST", "type": "ENVDAQ_CONFIG", "server_name": self.server_name, }, ) await self.to_ui_buf.put(req) await asyncio.sleep(cfg_fetch_freq) self.config_state = "CONFIGURED" # print('Waiting for config...') # while self.config is None: # pass # print(self.config) # print("Create message buffers...") # self.create_msg_buffers() print("Add controllers...") self.add_controllers() # TODO: Create 'health monitor' to check for status # this should allow for all components to register # so we know when things are ready, broken, etc # for now...sleep for a set amount of time to allow # everything to get set up print("Waiting for setup...") # await asyncio.sleep(10) # asyncio.create_task(self.check_ready_to_run()) # self.ui_task_list.append(asyncio.create_task(self.check_ready_to_run())) # self.ui_task_list.append(asyncio.create_task(self.send_ready_to_run())) if do_this: # if True: print(f"run_status: {self.status2.get_run_status()}") while self.status2.get_run_status() != Status.READY_TO_RUN: # while not self.status["ready_to_run"]: print(f"run_status: {self.status2.get_run_status()}") await asyncio.sleep(1) print("Waiting for setup...done.") # PlotManager.get_server().start() await self.send_ready_to_ui() self.status2.set_run_status(Status.RUNNING) self.run_state = "RUNNING" # status = Message( # sender_id="DAQ_SERVER", # msgtype="GENERIC", # subject="READY_STATE", # body={ # "purpose": "STATUS", # "status": "READY", # # 'note': note, # }, # ) # print(f"_____ send no wait _____: {status.to_json()}") # await self.to_ui_buf.put(status) # end tmp if statement async def send_ready_to_ui(self): status = Message( sender_id="DAQ_SERVER", msgtype="GENERIC", subject="READY_STATE", body={ "purpose": "STATUS", "status": "READY", "namespace": self.namespace.to_dict(), # 'note': note, }, ) # print(f"_____ send no wait _____: {status.to_json()}") # print(f"** daq_server ({self.namespace['daq_server']}) ready") print(f"** daq_server ({self.namespace.get_namespace_sig()}) ready") await self.to_ui_buf.put(status) def read_current_config(self): # read current config file fname = self.current_config_file if not os.path.isabs(self.current_config_file): fname = os.path.join( os.path.dirname(os.path.realpath(__file__)), self.current_config_file, ) if not os.path.exists(fname): self.clear_current_config() try: # with open(self.last_config_file) as cfg: with open(fname) as cfg: self.config = json.load(cfg) # print(f"{self.config}") try: self.uri = self.config["uri"] except KeyError: pass try: ns = self.config["namespace"] self.namespace = Namespace().from_dict(ns) except KeyError: pass try: self.autoenable = self.config["autoenable_daq"] except KeyError: pass # print(f"self.config***: {self.config}") except FileNotFoundError as e: print(e) pass except JSONDecodeError as e: self.config = dict() except TypeError: self.clear_current_config() pass def clear_current_config(self): self.config = dict() self.save_current_config(self.config) def save_current_config(self, config): # read current config file # print(config) # if config: if True: if "uri" not in config: config["uri"] = self.uri if "namespace" not in config: config["namespace"] = self.namespace.to_dict() if "autoenable" not in config: config["autoenable_daq"] = self.autoenable_daq self.config = config fname = self.current_config_file if not os.path.isabs(self.current_config_file): fname = os.path.join( os.path.dirname(os.path.realpath(__file__)), self.current_config_file, ) try: # test = json.dumps(config) # print(test) # with open(self.last_config_file) as cfg: with open(fname, "w") as cfg: json.dump(config, cfg) # self.config = json.load(cfg) except FileNotFoundError as e: print(e) pass except TypeError: print(f"Couldn't save configuration file: {fname}") pass def configure_daq_local(self): self.status2.set_config_status(Status.CONFIGURING) self.read_current_config() if self.config: try: self.namespace = Namespace().from_dict( self.config["namespace"]) except KeyError: pass try: self.autoenable_daq = self.config["autoenable_daq"] except KeyError: pass try: self.uri = self.config["uri"] except KeyError: pass self.status2.set_config_status(Status.NOT_CONFIGURED) try: if self.config["ENVDAQ_CONFIG"]: self.status2.set_config_status(Status.CONFIGURED) except KeyError: pass else: self.status2.set_config_status(Status.NOT_CONFIGURED) print(f"self.config: {self.config}") # have tried to configure, now connect to UI self.do_ui_connection = True async def configure_daq(self): # should check/read file every second. If no cfg_fetch_freq = 2 # seconds cfg_fetch_time = 5 # seconds cfg_fetch_current = 6 # force try on first loop print("set self.config") while not self.config: self.status2.set_config_status(Status.CONFIGURING) self.read_current_config() if False: # if self.config: # print(f"self.config: {self.config}") if not self.config and (cfg_fetch_current > cfg_fetch_time): # get config from gui print("Getting config from gui") req = Message( sender_id="daqserver", msgtype="DAQServer", subject="CONFIG", body={ "purpose": "REQUEST", "type": "ENVDAQ_CONFIG", "server_name": self.server_name, }, ) await self.to_ui_buf.put(req) cfg_fetch_current = 0 await asyncio.sleep(1) cfg_fetch_current += 1 # await asyncio.sleep(cfg_fetch_freq) # increase time between requests to avoid traffic cfg_fetch_freq += 1 if cfg_fetch_freq > 30: cfg_fetch_freq = 30 # print("Create message buffers...") # self.create_msg_buffer() # self.status2.set_config_status(Status.CONFIGURED) # print("Add controllers...") # self.add_controllers() if self.config: self.status2.set_config_status(Status.CONFIGURED) # self.run_state = "READY_TO_RUN" # reset back to original cfg_fetch_freq = 2 async def resend_config_to_ui(self): for k, ctl in self.controller_map.items(): ctl.resend_config_to_ui() await asyncio.sleep(5) # wait for config to be sent await self.send_ready_to_ui() def start(self): pass def stop(self): # TODO: check if stopped already # self.gui_client.sync_close() self.status2.set_run_status(Status.STOPPING) for k, controller in self.controller_map.items(): print(f"controller.stop: {k}") controller.stop() # for instrument in self.inst_map: # # print(sensor) # instrument.stop() # tasks = asyncio.Task.all_tasks() # for t in self.task_list: # # print(t) # t.cancel() self.status2.set_run_status(Status.STOPPED) async def from_child_loop(self): # print(f'started from_child_loop: {self.name} {self.from_child_buf}') # while self.from_child_buf is None: # pass while True: msg = await self.from_child_buf.get() # print(f"daq_server:from_child_loop: {msg}") await self.handle(msg, src="FromChild") # await asyncio.sleep(.1) async def read_loop(self): while True: # msg = await self.inst_msg_buffer.get() # TODO: should handle be a async? If not, could block # await self.handle(msg) await asyncio.sleep(0.1) async def handle(self, msg, src=None): # print(f"****controller handle: {src} - {msg.to_json()}") if src == "FromUI": d = msg.to_dict() if "message" in d: content = d["message"] if content["SUBJECT"] == "CONFIG": if content["BODY"]["purpose"] == "REPLY": config = content["BODY"]["config"] # self.config = config # test = json.dumps(config) # print(test) self.save_current_config(config) elif content["BODY"]["purpose"] == "PUSH": config = content["BODY"]["config"] print(f"new config: {config}") self.save_current_config(config) await asyncio.sleep(1) await self.restart_daq() # TODO check for enable # disable current config # self.disable() # # enable new config # self.enable_daq = True # self.enable() elif content["BODY"]["purpose"] == "ENABLE": enable_daq = content["BODY"]["value"] if enable_daq: # enable new config self.enable_daq = True self.enable() else: self.enable_daq = False self.disable() elif content["BODY"]["purpose"] == "AUTOENABLE": # config = content["BODY"]["config"] autoenable_daq = content["BODY"]["value"] self.config["autoenable_daq"] = autoenable_daq self.save_current_config(self.config) # enable if True else leave running if autoenable_daq: self.enable_daq = True self.enable() elif content["BODY"]["purpose"] == "SYNCREQUEST": print("sync DAQ") system_def = SysManager.get_definitions_all() print(f'system_def: {system_def}') sys_def = Message( sender_id="daqserver", msgtype="DAQServer", subject="CONFIG", body={ "purpose": "SYNC", "type": "SYSTEM_DEFINITION", "data": SysManager.get_definitions_all(), }, ) await self.to_ui_buf.put(sys_def) elif content["SUBJECT"] == "STATUS": print(f"DAQServerStatus: {content}") if content["BODY"]["purpose"] == "REQUEST": print(f"Status Request: {content}") await self.send_status() elif content["SUBJECT"] == "REGISTRATION": print(f"reg: {content['BODY']}") if content["BODY"]["purpose"] == "SUCCESS": self.registration_key = content["BODY"]["regkey"] # if content["BODY"]["config"]: # self.config = content["BODY"]["config"] # self.save_current_config(json.loads(content["BODY"]["config"])) self.status2.set_registration_status(Status.REGISTERED) print(f"server reg success: {self.status2.to_dict()}") if content["BODY"]["ui_reconfig_request"]: await self.resend_config_to_ui() elif content["SUBJECT"] == "UNREGISTRATION": print(f"unreg: {content['BODY']}") if content["BODY"]["purpose"] == "SUCCESS": self.status2.set_registration_status( Status.NOT_REGISTERED) print( f"unreg: {self.status2.get_registration_status()}") elif src == "FromChild": content = "" if "message" in d: content = d["message"] # print(f"fromChild: {content}") await asyncio.sleep(0.01) async def check_ready_to_run(self): print("check_ready_to_run") wait = True while wait: wait = False for k, v in self.controller_map.items(): if not v.status["ready_to_run"]: wait = True print(f"Waiting for controller: {k}") break await asyncio.sleep(1) self.status["ready_to_run"] = True self.status2.set_run_status(Status.READY_TO_RUN) async def send_ready_to_run(self): print(f"run_status: {self.status2.get_run_status()}") while self.status2.get_run_status() != Status.READY_TO_RUN: # while not self.status["ready_to_run"]: print(f"run_status: {self.status2.get_run_status()}") await asyncio.sleep(1) print("Waiting for setup...done.") # PlotManager.get_server().start() await self.send_ready_to_ui() self.status2.set_run_status(Status.RUNNING) self.run_state = "RUNNING" async def send_status(self): # for now, only done by request but we could do like ping msg = Message( sender_id="DAQ_SERVER", msgtype="DAQServerStatus", subject="DAQServerStatus", body={ # "id": self.daq_id "purpose": "UPDATE", "status": self.status2.to_dict(), }, ) await self.to_ui_buf.put(msg) async def ping_ui_server(self): # wait for things to get started before pinging await asyncio.sleep(5) while self.ui_client.isConnected(): msg = Message( sender_id="DAQ_SERVER", msgtype="PING", subject="PING", body={ # "id": self.daq_id "namespace": self.namespace.to_dict() }, ) # print(f"ping server: {self.namespace.to_dict()}") await self.to_ui_buf.put(msg) await asyncio.sleep(2) def remove_controllers(self): for k in self.controller_map.keys(): self.remove_controller(k, do_pop=False) self.controller_map.clear() def remove_controller(self, controller_key, do_pop=True): print("removing controllers: ") if controller_key in self.controller_map: print(f"key: {controller_key}") asyncio.create_task(self.controller_map[controller_key].shutdown()) if do_pop: self.controller_map.pop(controller_key) async def shutdown(self): # print(f"daq_server ({self.namespace['daq_server']}) shutting down...") print( f"daq_server ({self.namespace.get_namespace_sig()}) shutting down..." ) self.stop() self.disable() await self.deregister_from_UI() print("here1") wait_secs = 0 while (self.status2.get_registration_status() != Status.NOT_REGISTERED and wait_secs < 10): wait_secs += 1 await asyncio.sleep(1) # try: # await asyncio.sleep(5) # except Exception as e: # print(e) print("here2") self.status2.set_run_status(Status.SHUTTING_DOWN) # asyncio.get_event_loop().run_until_complete(self.ws_client.shutdown()) # if self.ws_client is not None: # self.ws_client.sync_close() # wait_time = 0 # print(self.status2.get_registration_status()) # while self.status2.get_registration_status() != Status.NOT_REGISTERED: # await asyncio.sleep(1) # print(self.status2.get_registration_status()) # while self.status2.get_registration_status() != Status.NOT_REGISTERED and wait_time<5: # await asyncio.sleep(1) # print(self.status2.get_registration_status()) # wait_time+=1 # self.remove_controllers() self.do_ui_connection = False print("cancel ui task list") for t in self.ui_task_list: # print(t) t.cancel() if self.ui_client is not None: print("closing ui client") # self.loop.run_until_complete(self.ui_client.close()) # self.ui_client.close() # await self.ui_client_close() self.ui_client = None # await asyncio.sleep(2) # self.remove_controllers() # for k, controller in self.controller_map.items(): # print(f"shutdown controller: {k}") # controller.shutdown() # await asyncio.sleep(1) # for controller in self.controller_list: # # print(sensor) # controller.stop() # self.start_ui_message_loops() # asyncio.get_event_loop().stop() # self.server.close() # await asyncio.sleep(5) # print("shutdown complete.") # self.controller_list = [] # self.controller_map.clear() self.run_state = "SHUTDOWN" self.status2.set_run_status(Status.SHUTDOWN) def start_ui_message_loops(self): self.ui_task_list.append(asyncio.ensure_future(self.to_ui_loop())) self.ui_task_list.append(asyncio.ensure_future(self.from_ui_loop())) def stop_ui_message_loops(self): # tasks = asyncio.Task.all_tasks() for t in self.ui_task_list: # print(t) t.cancel()
def add_apps(config): # PlotManager.start_server() # print(f'##### add_apps -> {config}') server_namespace = "" if ("namespace") in config: ns = Namespace().from_dict(config["namespace"]) # server_id = PlotManager.get_server_id(ns) # server_id = ns.get_namespace_comp_sig() server_id = PlotManager.get_server_id(ns) if "daq_server" in config["namespace"]: server_namespace += config["namespace"]["daq_server"] if "controller" in config["namespace"]: server_namespace += "-" + config["namespace"]["controller"] else: ns = Namespace() if "plot_meta" in config and "plots" in config["plot_meta"]: app_list = [] for plot_name, plot_def in config["plot_meta"]["plots"].items(): # print(f'####### add_plots: {plot_name} - {plot_def}') if "app_type" in plot_def: if plot_def["app_type"] == "TimeSeries1D": PlotManager.add_app( TimeSeries1D( # config, plot_def, # server_id=server_id, plot_name=plot_name, app_name=plot_def["app_name"], ), server_id=ns, start_after_add=False, ) app_list.append(plot_def["app_name"]) PlotManager.register_app_source(plot_def) elif plot_def["app_type"] == "SizeDistribution": # print(f'SizeDistribution add app') PlotManager.add_app( SizeDistribution( # config, plot_def, plot_name=plot_name, app_name=plot_def["app_name"], ), server_id=ns, start_after_add=False, ) app_list.append(plot_def["app_name"]) PlotManager.register_app_source(plot_def) elif plot_def["app_type"] == "GeoMapPlot": # print(f'SizeDistribution add app') PlotManager.add_app( GeoMapPlot( # config, plot_def, plot_name=plot_name, app_name=plot_def["app_name"], ), server_id=ns, start_after_add=False, ) app_list.append(plot_def["app_name"]) PlotManager.register_app_source(plot_def) key = config["NAME"] if "alias" in config: key = config["alias"]["name"] # print(f'{app_list}, {PlotManager.__app_list_map}') PlotManager.__app_list_map[key] = app_list