예제 #1
0
    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
예제 #2
0
    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
예제 #3
0
    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']}"
예제 #4
0
    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,
            )
예제 #5
0
 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
예제 #6
0
 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
예제 #7
0
    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]
예제 #8
0
    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
예제 #9
0
 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
예제 #10
0
 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
예제 #11
0
 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
예제 #12
0
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)
예제 #13
0
    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
예제 #14
0
    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
예제 #15
0
    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()
예제 #16
0
    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()
예제 #17
0
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)
예제 #18
0
 def get_namespace(self):
     ns = Namespace(name=self.name,
                    host=self.host,
                    ns_type=Namespace.DAQSERVER)
     return ns
예제 #19
0
 async def unregister(
         reg_id=Namespace().get_namespace_sig(), type=Namespace.DAQSERVER):
     await DAQRegistry.unregister_no_wait(reg_id=reg_id, type=type)
예제 #20
0
    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
예제 #21
0
    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
예제 #22
0
 async def ping(
         reg_id=Namespace().get_namespace_sig(), type=Namespace.DAQSERVER):
     await DAQRegistry.ping_no_wait(reg_id, type)
예제 #23
0
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()
예제 #24
0
    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