diff --git a/phoenix_bec/devices/falcon_phoenix.py b/phoenix_bec/devices/falcon_phoenix.py index 9e9d24b..66b1578 100644 --- a/phoenix_bec/devices/falcon_phoenix.py +++ b/phoenix_bec/devices/falcon_phoenix.py @@ -387,15 +387,15 @@ class FalconPhoenix(PSIDetectorBase): # Parameters for individual detector elements # Note: need to wrote 'dxp: here, but not dxp' dxp1 = Cpt(EpicsDXPFalcon, "dxp1:") - dxp2 = Cpt(EpicsDXPFalcon, "dxp2:") - dxp3 = Cpt(EpicsDXPFalcon, "dxp3:") - dxp4 = Cpt(EpicsDXPFalcon, "dxp4:") + # dxp2 = Cpt(EpicsDXPFalcon, "dxp2:") + # dxp3 = Cpt(EpicsDXPFalcon, "dxp3:") + # dxp4 = Cpt(EpicsDXPFalcon, "dxp4:") # need to write 'mca1', but not 'mca1:' mca1 = Cpt(EpicsMCARecord, "mca1") - mca2 = Cpt(EpicsMCARecord, "mca2") - mca3 = Cpt(EpicsMCARecord, "mca3") - mca4 = Cpt(EpicsMCARecord, "mca4") + # mca2 = Cpt(EpicsMCARecord, "mca2") + # mca3 = Cpt(EpicsMCARecord, "mca3") + # mca4 = Cpt(EpicsMCARecord, "mca4") # other general parameters hdf5 = Cpt(FalconHDF5Plugins, "HDF1:") @@ -435,4 +435,4 @@ class FalconPhoenix(PSIDetectorBase): if __name__ == "__main__": - falcon = FalconPHOENIX(name="falcon_hdf5", prefix="X07MB-SITORO:", sim_mode=True) + falcon = FalconPhoenix(name="falcon_hdf5", prefix="X07MB-SITORO:", sim_mode=True) diff --git a/phoenix_bec/local_scripts/Code_to_test_devices/MyLogfile.txt b/phoenix_bec/local_scripts/Code_to_test_devices/MyLogfile.txt new file mode 100644 index 0000000..7450206 --- /dev/null +++ b/phoenix_bec/local_scripts/Code_to_test_devices/MyLogfile.txt @@ -0,0 +1,240 @@ +335.86742186546326 sec Dummy_device Dummy_PSIDetector.__init__ +335.87204146385193 sec Dummy_device Dummy_PSIDetector._update_scaninfo +335.8751003742218 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +335.8772876262665 sec Dummy_device Dummy_PSIDetector._update_filewriter +335.87958455085754 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +335.88146352767944 sec Dummy_device Dummy_PSIDetector._init +335.8835377693176 sec Dummy_device Dummy_PSIDetector._init ... done +335.88587188720703 sec Dummy_device Dummy_PSIDetector._update_service_config +335.88780546188354 sec Dummy_device Dummy_PSIDetector._update_scaninfo +335.8908131122589 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +335.8929853439331 sec Dummy_device Dummy_PSIDetector._update_filewriter +335.89518213272095 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +335.8972976207733 sec Dummy_device Dummy_PSIDetector._init +335.8996033668518 sec Dummy_device Dummy_PSIDetector._init ... done +335.9022822380066 sec Dummy_device Dummy_PSIDetector.__init__ .. done +300.2472941875458 sec Dummy_device Dummy_PSIDetector.__init__ +300.2497909069061 sec Dummy_device Dummy_PSIDetector._update_scaninfo +300.2532637119293 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +300.2575738430023 sec Dummy_device Dummy_PSIDetector._update_filewriter +300.25977396965027 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +300.26182532310486 sec Dummy_device Dummy_PSIDetector._init +300.263964176178 sec Dummy_device Dummy_PSIDetector._init ... done +300.26622343063354 sec Dummy_device Dummy_PSIDetector._update_service_config +300.2685146331787 sec Dummy_device Dummy_PSIDetector._update_scaninfo +300.27183842658997 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +300.27371311187744 sec Dummy_device Dummy_PSIDetector._update_filewriter +300.27582836151123 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +300.27784299850464 sec Dummy_device Dummy_PSIDetector._init +300.27999567985535 sec Dummy_device Dummy_PSIDetector._init ... done +300.28196930885315 sec Dummy_device Dummy_PSIDetector.__init__ .. done +328.7905592918396 sec Dummy_device Dummy_PSIDetector.__init__ +328.7932097911835 sec Dummy_device Dummy_PSIDetector._update_scaninfo +328.7954728603363 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +328.79737162590027 sec Dummy_device Dummy_PSIDetector._update_filewriter +328.7993049621582 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +328.80120611190796 sec Dummy_device Dummy_PSIDetector._init +328.8031406402588 sec Dummy_device Dummy_PSIDetector._init ... done +328.80515456199646 sec Dummy_device Dummy_PSIDetector._update_service_config +328.807252407074 sec Dummy_device Dummy_PSIDetector._update_scaninfo +328.81015849113464 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +328.81217980384827 sec Dummy_device Dummy_PSIDetector._update_filewriter +328.81431341171265 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +328.81639194488525 sec Dummy_device Dummy_PSIDetector._init +328.8186950683594 sec Dummy_device Dummy_PSIDetector._init ... done +328.82083559036255 sec Dummy_device Dummy_PSIDetector.__init__ .. done +475.4403340816498 sec Dummy_device Dummy_PSIDetector.__init__ +475.4432635307312 sec Dummy_device Dummy_PSIDetector._update_scaninfo +475.44979977607727 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +475.4522285461426 sec Dummy_device Dummy_PSIDetector._update_filewriter +475.4545283317566 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +475.456636428833 sec Dummy_device Dummy_PSIDetector._init +475.45890951156616 sec Dummy_device Dummy_PSIDetector._init ... done +475.4610731601715 sec Dummy_device Dummy_PSIDetector._update_service_config +475.46812438964844 sec Dummy_device Dummy_PSIDetector._update_scaninfo +475.4717495441437 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +475.47418761253357 sec Dummy_device Dummy_PSIDetector._update_filewriter +475.4776928424835 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +475.48009753227234 sec Dummy_device Dummy_PSIDetector._init +475.4822597503662 sec Dummy_device Dummy_PSIDetector._init ... done +475.4843051433563 sec Dummy_device Dummy_PSIDetector.__init__ .. done +90.38811612129211 sec Dummy_device Dummy_PSIDetector.__init__ +90.39096760749817 sec Dummy_device Dummy_PSIDetector._update_scaninfo +90.39355659484863 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +90.39581418037415 sec Dummy_device Dummy_PSIDetector._update_filewriter +90.39806294441223 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +90.40018606185913 sec Dummy_device Dummy_PSIDetector._init +90.40238237380981 sec Dummy_device Dummy_PSIDetector._init ... done +90.40471291542053 sec Dummy_device Dummy_PSIDetector._update_service_config +90.4069573879242 sec Dummy_device Dummy_PSIDetector._update_scaninfo +90.41017866134644 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +90.41258692741394 sec Dummy_device Dummy_PSIDetector._update_filewriter +90.41526460647583 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +90.41762042045593 sec Dummy_device Dummy_PSIDetector._init +90.42192840576172 sec Dummy_device Dummy_PSIDetector._init ... done +90.42451310157776 sec Dummy_device Dummy_PSIDetector.__init__ .. done +109.83998537063599 sec Dummy_device Dummy_PSIDetector.__init__ +109.84398102760315 sec Dummy_device Dummy_PSIDetector._update_scaninfo +109.84782004356384 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +109.8508472442627 sec Dummy_device Dummy_PSIDetector._update_filewriter +109.85375642776489 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +109.85648727416992 sec Dummy_device Dummy_PSIDetector._init +109.85949063301086 sec Dummy_device Dummy_PSIDetector._init ... done +109.8626561164856 sec Dummy_device Dummy_PSIDetector._update_service_config +109.8660044670105 sec Dummy_device Dummy_PSIDetector._update_scaninfo +109.86980724334717 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +109.8729784488678 sec Dummy_device Dummy_PSIDetector._update_filewriter +109.87575602531433 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +109.87866473197937 sec Dummy_device Dummy_PSIDetector._init +109.88176965713501 sec Dummy_device Dummy_PSIDetector._init ... done +109.8846321105957 sec Dummy_device Dummy_PSIDetector.__init__ .. done +113.19893550872803 sec Dummy_device Dummy_PSIDetector.__init__ +113.20220613479614 sec Dummy_device Dummy_PSIDetector._update_scaninfo +113.20514917373657 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +113.2079541683197 sec Dummy_device Dummy_PSIDetector._update_filewriter +113.21054434776306 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +113.21308469772339 sec Dummy_device Dummy_PSIDetector._init +113.21552276611328 sec Dummy_device Dummy_PSIDetector._init ... done +113.21809101104736 sec Dummy_device Dummy_PSIDetector._update_service_config +113.2209620475769 sec Dummy_device Dummy_PSIDetector._update_scaninfo +113.22531485557556 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +113.23195886611938 sec Dummy_device Dummy_PSIDetector._update_filewriter +113.23536491394043 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +113.23783016204834 sec Dummy_device Dummy_PSIDetector._init +113.24021744728088 sec Dummy_device Dummy_PSIDetector._init ... done +113.24268960952759 sec Dummy_device Dummy_PSIDetector.__init__ .. done +162.08518886566162 sec Dummy_device Dummy_PSIDetector.__init__ +162.08826613426208 sec Dummy_device Dummy_PSIDetector._update_scaninfo +162.09175372123718 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +162.0940601825714 sec Dummy_device Dummy_PSIDetector._update_filewriter +162.09600925445557 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +162.09812116622925 sec Dummy_device Dummy_PSIDetector._init +162.10056066513062 sec Dummy_device Dummy_PSIDetector._init ... done +162.10289812088013 sec Dummy_device Dummy_PSIDetector._update_service_config +162.10535383224487 sec Dummy_device Dummy_PSIDetector._update_scaninfo +162.1090052127838 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +162.11114287376404 sec Dummy_device Dummy_PSIDetector._update_filewriter +162.1133759021759 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +162.1152641773224 sec Dummy_device Dummy_PSIDetector._init +162.11768627166748 sec Dummy_device Dummy_PSIDetector._init ... done +162.11997199058533 sec Dummy_device Dummy_PSIDetector.__init__ .. done +233.90994000434875 sec Dummy_device Dummy_PSIDetector.__init__ +233.91418266296387 sec Dummy_device Dummy_PSIDetector._update_scaninfo +233.91928625106812 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +233.92156839370728 sec Dummy_device Dummy_PSIDetector._update_filewriter +233.92394065856934 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +233.9268913269043 sec Dummy_device Dummy_PSIDetector._init +233.9293007850647 sec Dummy_device Dummy_PSIDetector._init ... done +233.9316327571869 sec Dummy_device Dummy_PSIDetector._update_service_config +233.9339635372162 sec Dummy_device Dummy_PSIDetector._update_scaninfo +233.939471244812 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +233.94238090515137 sec Dummy_device Dummy_PSIDetector._update_filewriter +233.9449393749237 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +233.94733595848083 sec Dummy_device Dummy_PSIDetector._init +233.95000672340393 sec Dummy_device Dummy_PSIDetector._init ... done +233.9525544643402 sec Dummy_device Dummy_PSIDetector.__init__ .. done +271.92675018310547 sec Dummy_device Dummy_PSIDetector.__init__ +271.93059253692627 sec Dummy_device Dummy_PSIDetector._update_scaninfo +271.93377327919006 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +271.9364731311798 sec Dummy_device Dummy_PSIDetector._update_filewriter +271.9393870830536 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +271.9427864551544 sec Dummy_device Dummy_PSIDetector._init +271.94557547569275 sec Dummy_device Dummy_PSIDetector._init ... done +271.9482548236847 sec Dummy_device Dummy_PSIDetector._update_service_config +271.95098328590393 sec Dummy_device Dummy_PSIDetector._update_scaninfo +271.9548728466034 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +271.9576189517975 sec Dummy_device Dummy_PSIDetector._update_filewriter +271.96227741241455 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +271.9647195339203 sec Dummy_device Dummy_PSIDetector._init +271.9670441150665 sec Dummy_device Dummy_PSIDetector._init ... done +271.9696171283722 sec Dummy_device Dummy_PSIDetector.__init__ .. done +274.2615315914154 sec Dummy_device Dummy_PSIDetector.__init__ +274.2650673389435 sec Dummy_device Dummy_PSIDetector._update_scaninfo +274.2682113647461 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +274.2709422111511 sec Dummy_device Dummy_PSIDetector._update_filewriter +274.27347803115845 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +274.27603006362915 sec Dummy_device Dummy_PSIDetector._init +274.27846097946167 sec Dummy_device Dummy_PSIDetector._init ... done +274.28107810020447 sec Dummy_device Dummy_PSIDetector._update_service_config +274.28359174728394 sec Dummy_device Dummy_PSIDetector._update_scaninfo +274.2874596118927 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +274.2898247241974 sec Dummy_device Dummy_PSIDetector._update_filewriter +274.29388880729675 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +274.29678750038147 sec Dummy_device Dummy_PSIDetector._init +274.2992432117462 sec Dummy_device Dummy_PSIDetector._init ... done +274.30156898498535 sec Dummy_device Dummy_PSIDetector.__init__ .. done +294.353533744812 sec Dummy_device Dummy_PSIDetector.__init__ +294.3567740917206 sec Dummy_device Dummy_PSIDetector._update_scaninfo +294.35972356796265 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +294.3630163669586 sec Dummy_device Dummy_PSIDetector._update_filewriter +294.36538767814636 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +294.3680098056793 sec Dummy_device Dummy_PSIDetector._init +294.37078166007996 sec Dummy_device Dummy_PSIDetector._init ... done +294.3731310367584 sec Dummy_device Dummy_PSIDetector._update_service_config +294.3752555847168 sec Dummy_device Dummy_PSIDetector._update_scaninfo +294.37840962409973 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +294.38084959983826 sec Dummy_device Dummy_PSIDetector._update_filewriter +294.38422083854675 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +294.38660955429077 sec Dummy_device Dummy_PSIDetector._init +294.38908863067627 sec Dummy_device Dummy_PSIDetector._init ... done +294.3915419578552 sec Dummy_device Dummy_PSIDetector.__init__ .. done +304.78483295440674 sec Dummy_device Dummy_PSIDetector.__init__ +304.7881119251251 sec Dummy_device Dummy_PSIDetector._update_scaninfo +304.7934236526489 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +304.79776787757874 sec Dummy_device Dummy_PSIDetector._update_filewriter +304.8020315170288 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +304.8044664859772 sec Dummy_device Dummy_PSIDetector._init +304.8082823753357 sec Dummy_device Dummy_PSIDetector._init ... done +304.81395411491394 sec Dummy_device Dummy_PSIDetector._update_service_config +304.8168818950653 sec Dummy_device Dummy_PSIDetector._update_scaninfo +304.82032346725464 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +304.8228225708008 sec Dummy_device Dummy_PSIDetector._update_filewriter +304.82708072662354 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +304.83106684684753 sec Dummy_device Dummy_PSIDetector._init +304.8337640762329 sec Dummy_device Dummy_PSIDetector._init ... done +304.8364191055298 sec Dummy_device Dummy_PSIDetector.__init__ .. done +338.80613946914673 sec Dummy_device Dummy_PSIDetector.__init__ +338.8091824054718 sec Dummy_device Dummy_PSIDetector._update_scaninfo +338.81241273880005 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +338.8149781227112 sec Dummy_device Dummy_PSIDetector._update_filewriter +338.8177545070648 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +338.82268142700195 sec Dummy_device Dummy_PSIDetector._init +338.8252160549164 sec Dummy_device Dummy_PSIDetector._init ... done +338.82740783691406 sec Dummy_device Dummy_PSIDetector._update_service_config +338.8297481536865 sec Dummy_device Dummy_PSIDetector._update_scaninfo +338.83335185050964 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +338.8363780975342 sec Dummy_device Dummy_PSIDetector._update_filewriter +338.8388833999634 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +338.84141182899475 sec Dummy_device Dummy_PSIDetector._init +338.84392642974854 sec Dummy_device Dummy_PSIDetector._init ... done +338.8477563858032 sec Dummy_device Dummy_PSIDetector.__init__ .. done +344.0475420951843 sec Dummy_device Dummy_PSIDetector.__init__ +344.05141711235046 sec Dummy_device Dummy_PSIDetector._update_scaninfo +344.0571393966675 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +344.060818195343 sec Dummy_device Dummy_PSIDetector._update_filewriter +344.06363105773926 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +344.0659351348877 sec Dummy_device Dummy_PSIDetector._init +344.06850934028625 sec Dummy_device Dummy_PSIDetector._init ... done +344.070965051651 sec Dummy_device Dummy_PSIDetector._update_service_config +344.0734348297119 sec Dummy_device Dummy_PSIDetector._update_scaninfo +344.07675218582153 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +344.0791103839874 sec Dummy_device Dummy_PSIDetector._update_filewriter +344.08180046081543 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +344.08495712280273 sec Dummy_device Dummy_PSIDetector._init +344.0874013900757 sec Dummy_device Dummy_PSIDetector._init ... done +344.0897550582886 sec Dummy_device Dummy_PSIDetector.__init__ .. done +376.99036693573 sec Dummy_device Dummy_PSIDetector.__init__ +376.99428820610046 sec Dummy_device Dummy_PSIDetector._update_scaninfo +376.99768900871277 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +377.0007600784302 sec Dummy_device Dummy_PSIDetector._update_filewriter +377.003769159317 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +377.00663924217224 sec Dummy_device Dummy_PSIDetector._init +377.01268792152405 sec Dummy_device Dummy_PSIDetector._init ... done +377.0166575908661 sec Dummy_device Dummy_PSIDetector._update_service_config +377.0196464061737 sec Dummy_device Dummy_PSIDetector._update_scaninfo +377.02573013305664 sec Dummy_device Dummy_PSIDetector._update_scaninfo .. done +377.0286810398102 sec Dummy_device Dummy_PSIDetector._update_filewriter +377.03132462501526 sec Dummy_device Dummy_PSIDetector._update_filewriter .. done +377.0341477394104 sec Dummy_device Dummy_PSIDetector._init +377.0375759601593 sec Dummy_device Dummy_PSIDetector._init ... done +377.0406606197357 sec Dummy_device Dummy_PSIDetector.__init__ .. done diff --git a/phoenix_bec/local_scripts/Code_to_test_devices/devicemanager.py b/phoenix_bec/local_scripts/Code_to_test_devices/devicemanager.py new file mode 100644 index 0000000..1e7b71a --- /dev/null +++ b/phoenix_bec/local_scripts/Code_to_test_devices/devicemanager.py @@ -0,0 +1,568 @@ +""" +This module contains the DeviceManagerDS class, which is a subclass of +the DeviceManagerBase class and is the main device manager for devices +in BEC. It is the only place where devices are initialized and managed. +""" + +from __future__ import annotations + +import inspect +import time +import traceback +from functools import reduce + +import numpy as np +import ophyd +import ophyd_devices as opd +from ophyd.ophydobj import OphydObject +from ophyd.signal import EpicsSignalBase +from typeguard import typechecked + +from bec_lib import messages, plugin_helper +from bec_lib.bec_errors import DeviceConfigError +from bec_lib.bec_service import BECService +from bec_lib.device import DeviceBase +from bec_lib.devicemanager import DeviceManagerBase +from bec_lib.endpoints import MessageEndpoints +from bec_lib.logger import bec_logger +from bec_server.device_server.devices.config_update_handler import ConfigUpdateHandler +from bec_server.device_server.devices.device_serializer import get_device_info + +logger = bec_logger.logger + + +def rgetattr(obj, attr, *args): + """See https://stackoverflow.com/questions/31174295/getattr-and-setattr-on-nested-objects""" + + def _getattr(obj, attr): + return getattr(obj, attr, *args) + + return reduce(_getattr, [obj] + attr.split(".")) + + +class DSDevice(DeviceBase): + def __init__(self, name, obj, config, parent=None): + super().__init__(name=name, config=config, parent=parent) + self.obj = obj + self.metadata = {} + self.initialized = False + + def __getattr__(self, name: str) -> inspect.Any: + if hasattr(self.obj, name): + # compatibility with ophyd devices accessed on the client side + return rgetattr(self.obj, name) + return super().__getattr__(name) + + def initialize_device_buffer(self, connector): + """initialize the device read and readback buffer on redis with a new reading""" + dev_msg = messages.DeviceMessage(signals=self.obj.read(), metadata={}) + dev_config_msg = messages.DeviceMessage(signals=self.obj.read_configuration(), metadata={}) + if hasattr(self.obj, "low_limit_travel") and hasattr(self.obj, "high_limit_travel"): + limits = { + "low": {"value": self.obj.low_limit_travel.get()}, + "high": {"value": self.obj.high_limit_travel.get()}, + } + else: + limits = None + pipe = connector.pipeline() + connector.set_and_publish(MessageEndpoints.device_readback(self.name), dev_msg, pipe=pipe) + connector.set_and_publish( + topic=MessageEndpoints.device_read(self.name), msg=dev_msg, pipe=pipe + ) + connector.set_and_publish( + MessageEndpoints.device_read_configuration(self.name), dev_config_msg, pipe=pipe + ) + if limits is not None: + connector.set_and_publish( + MessageEndpoints.device_limits(self.name), + messages.DeviceMessage(signals=limits), + pipe=pipe, + ) + pipe.execute() + self.initialized = True + + +class DeviceManagerDS(DeviceManagerBase): + def __init__( + self, + service: BECService, + config_update_handler: ConfigUpdateHandler = None, + status_cb: list = None, + ): + super().__init__(service, status_cb) + self._config_request_connector = None + self._device_instructions_connector = None + self._config_update_handler_cls = config_update_handler + self.config_update_handler = None + self.failed_devices = [] + + def initialize(self, bootstrap_server) -> None: + self.config_update_handler = ( + self._config_update_handler_cls + if self._config_update_handler_cls is not None + else ConfigUpdateHandler(device_manager=self) + ) + super().initialize(bootstrap_server) + + def _reload_action(self) -> None: + pass + + @staticmethod + def _get_device_class(dev_type: str) -> type: + """Get the device class from the device type""" + return plugin_helper.get_plugin_class(dev_type, [opd, ophyd]) + + def _load_session(self, *_args, **_kwargs): + delayed_init = [] + if not self._is_config_valid(): + self._reset_config() + return + + try: + self.failed_devices = {} + for dev in self._session["devices"]: + name = dev.get("name") + enabled = dev.get("enabled") + logger.info(f"Adding device {name}: {'ENABLED' if enabled else 'DISABLED'}") + dev_cls = self._get_device_class(dev.get("deviceClass")) + if issubclass(dev_cls, (opd.DeviceProxy, opd.ComputedSignal)): + delayed_init.append(dev) + continue + obj, config = self.construct_device_obj(dev, device_manager=self) + try: + self.initialize_device(dev, config, obj) + # pylint: disable=broad-except + except Exception: + msg = traceback.format_exc() + self.failed_devices[name] = msg + + for dev in delayed_init: + name = dev.get("name") + obj, config = self.construct_device_obj(dev, device_manager=self) + try: + self.initialize_delayed_devices(dev, config, obj) + # pylint: disable=broad-except + except Exception: + msg = traceback.format_exc() + self.failed_devices[name] = msg + self.config_update_handler.handle_failed_device_inits() + except Exception as exc: + content = traceback.format_exc() + logger.error( + f"Failed to initialize device: {dev}: {content}. The config will be reset." + ) + self._reset_config() + raise DeviceConfigError( + f"Failed to initialize device: {dev}: {content}. The config will be reset." + ) from exc + + def initialize_delayed_devices(self, dev: dict, config: dict, obj: OphydObject) -> None: + """Initialize delayed device after all other devices have been initialized.""" + name = dev.get("name") + enabled = dev.get("enabled") + logger.info(f"Adding device {name}: {'ENABLED' if enabled else 'DISABLED'}") + + obj = self.initialize_device(dev, config, obj) + + if hasattr(obj.obj, "lookup"): + self._register_device_proxy(name) + + def _register_device_proxy(self, name: str) -> None: + obj_lookup = self.devices.get(name).obj.lookup + for key in obj_lookup.keys(): + signal_name = obj_lookup[key].get("signal_name") + if key not in self.devices: + raise DeviceConfigError( + f"Failed to init DeviceProxy {name}, no device {key} found in device manager." + ) + dev_obj = self.devices[key].obj + registered_proxies = dev_obj.registered_proxies + if not hasattr(dev_obj, signal_name): + raise DeviceConfigError( + f"Failed to init DeviceProxy {name}, no signal {signal_name} found for device {key}." + ) + if key not in registered_proxies: + # pylint: disable=protected-access + self.devices[key].obj._registered_proxies.update({name: signal_name}) + continue + if key in registered_proxies and signal_name not in registered_proxies[key]: + # pylint: disable=protected-access + self.devices[key].obj._registered_proxies.update({name: signal_name}) + continue + if key in registered_proxies.keys() and signal_name in registered_proxies[key]: + raise RuntimeError( + f"Failed to init DeviceProxy {name}, device {key} already has a registered DeviceProxy for {signal_name}. Only one DeviceProxy can be active per signal." + ) + + def _reset_config(self): + current_config = self._session["devices"] + if current_config: + # store the current config in the history + current_config_msg = messages.AvailableResourceMessage( + resource=current_config, metadata={"removed_at": time.time()} + ) + self.producer.lpush( + MessageEndpoints.device_config_history(), current_config_msg, max_size=50 + ) + msg = messages.AvailableResourceMessage(resource=[]) + self.producer.set(MessageEndpoints.device_config(), msg) + reload_msg = messages.DeviceConfigMessage(action="reload", config={}) + self.producer.send(MessageEndpoints.device_config_update(), reload_msg) + + @staticmethod + def update_config(obj: OphydObject, config: dict) -> None: + """Update an ophyd device's config + + Args: + obj (Ophydobj): Ophyd object that should be updated + config (dict): Config dictionary + + """ + if hasattr(obj, "_update_device_config"): + obj._update_device_config(config) + else: + for config_key, config_value in config.items(): + # first handle the ophyd exceptions... + if config_key == "limits": + if hasattr(obj, "low_limit_travel") and hasattr(obj, "high_limit_travel"): + low_limit_status = obj.low_limit_travel.set(config_value[0]) + high_limit_status = obj.high_limit_travel.set(config_value[1]) + low_limit_status.wait() + high_limit_status.wait() + continue + if config_key == "labels": + if not config_value: + config_value = set() + # pylint: disable=protected-access + obj._ophyd_labels_ = set(config_value) + continue + if not hasattr(obj, config_key): + raise DeviceConfigError( + f"Unknown config parameter {config_key} for device of type" + f" {obj.__class__.__name__}." + ) + + config_attr = getattr(obj, config_key) + if isinstance(config_attr, ophyd.Signal): + config_attr.set(config_value) + elif callable(config_attr): + config_attr(config_value) + else: + setattr(obj, config_key, config_value) + + @staticmethod + def construct_device_obj(dev: dict, device_manager: DeviceManagerDS) -> (OphydObject, dict): + """ + Construct a device object from a device config dictionary. + + Args: + dev (dict): device config dictionary + device_manager (DeviceManagerDS): device manager instance + + Returns: + (OphydObject, dict): device object and updated config dictionary + """ + name = dev.get("name") + dev_cls = DeviceManagerDS._get_device_class(dev["deviceClass"]) + device_config = dev.get("deviceConfig") + device_config = device_config if device_config is not None else {} + config = device_config.copy() + config["name"] = name + + # pylint: disable=protected-access + device_classes = [dev_cls] + if issubclass(dev_cls, ophyd.Signal): + device_classes.append(ophyd.Signal) + if issubclass(dev_cls, EpicsSignalBase): + device_classes.append(EpicsSignalBase) + if issubclass(dev_cls, ophyd.OphydObject): + device_classes.append(ophyd.OphydObject) + + # get all init parameters of the device class and its parents + class_params = set() + for device_class in device_classes: + class_params.update(inspect.signature(device_class)._parameters) + class_params_and_config_keys = class_params & config.keys() + + init_kwargs = {key: config.pop(key) for key in class_params_and_config_keys} + device_access = config.pop("device_access", None) + if device_access or (device_access is None and config.get("device_mapping")): + init_kwargs["device_manager"] = device_manager + + signature = inspect.signature(dev_cls) + if "device_manager" in signature.parameters: + init_kwargs["device_manager"] = device_manager + + # initialize the device object + obj = dev_cls(**init_kwargs) + return obj, config + + def initialize_device(self, dev: dict, config: dict, obj: OphydObject) -> DSDevice: + """ + Prepares a device for later usage. + This includes inspecting the device class signature, + initializing the object, refreshing the device info and buffer, + as well as adding subscriptions. + + Args: + dev (dict): device config dictionary + config (dict): device config dictionary + obj (OphydObject): device object + + Returns: + DSDevice: initialized device object + """ + name = dev.get("name") + enabled = dev.get("enabled") + + self.update_config(obj, config) + + # refresh the device info + pipe = self.connector.pipeline() + self.reset_device_data(obj, pipe) + self.publish_device_info(obj, pipe) + pipe.execute() + + # insert the created device obj into the device manager + opaas_obj = DSDevice(name=name, obj=obj, config=dev, parent=self) + + # pylint:disable=protected-access # this function is shared with clients and it is currently not foreseen that clients add new devices + self.devices._add_device(name, opaas_obj) + + if not enabled: + return opaas_obj + + # update device buffer for enabled devices + # try: + self.initialize_enabled_device(opaas_obj) + # pylint:disable=broad-except + # except Exception: + # error_traceback = traceback.format_exc() + # logger.error( + # f"{error_traceback}. Failed to stage {opaas_obj.name}. The device will be disabled." + # ) + # opaas_obj.enabled = False + + obj = opaas_obj.obj + # add subscriptions + if not hasattr(obj, "event_types"): + return opaas_obj + + if "readback" in obj.event_types: + obj.subscribe(self._obj_callback_readback, run=opaas_obj.enabled) + elif "value" in obj.event_types: + obj.subscribe(self._obj_callback_readback, run=opaas_obj.enabled) + + if "device_monitor_2d" in obj.event_types: + obj.subscribe(self._obj_callback_device_monitor_2d, run=False) + if "done_moving" in obj.event_types: + obj.subscribe(self._obj_callback_done_moving, event_type="done_moving", run=False) + if "flyer" in obj.event_types: + obj.subscribe(self._obj_flyer_callback, event_type="flyer", run=False) + if "progress" in obj.event_types: + obj.subscribe(self._obj_progress_callback, event_type="progress", run=False) + if hasattr(obj, "motor_is_moving"): + obj.motor_is_moving.subscribe(self._obj_callback_is_moving, run=opaas_obj.enabled) + + if hasattr(obj, "component_names"): + for component_name in obj.component_names: + component = getattr(obj, component_name) + if not getattr(component, "_auto_monitor", False): + continue + if component.kind in (ophyd.Kind.normal, ophyd.Kind.hinted): + component.subscribe(self._obj_callback_readback, run=False) + elif component.kind == ophyd.Kind.config: + component.subscribe(self._obj_callback_configuration, run=False) + + return opaas_obj + + def initialize_enabled_device(self, opaas_obj): + """connect to an enabled device and initialize the device buffer""" + self.connect_device(opaas_obj.obj) + opaas_obj.initialize_device_buffer(self.connector) + + @staticmethod + def disconnect_device(obj): + """disconnect from a device""" + if not obj.connected: + return + if hasattr(obj, "controller"): + obj.controller.off() + return + obj.destroy() + + def reset_device(self, obj: DSDevice): + """reset a device""" + obj.initialized = False + + @staticmethod + def connect_device(obj, wait_for_all=False): + """establish a connection to a device""" + try: + if obj.connected: + return + if hasattr(obj, "controller"): + obj.controller.on() + return + if hasattr(obj, "wait_for_connection"): + try: + obj.wait_for_connection(all_signals=wait_for_all, timeout=30) + except TypeError: + obj.wait_for_connection(timeout=30) + return + logger.error( + f"Device {obj.name} does not implement the socket controller interface nor" + " wait_for_connection and cannot be turned on." + ) + raise ConnectionError(f"Failed to establish a connection to device {obj.name}") + except Exception: + error_traceback = traceback.format_exc() + logger.error(f"{error_traceback}. Failed to connect to {obj.name}.") + raise ConnectionError(f"Failed to establish a connection to device {obj.name}") + + def publish_device_info(self, obj: OphydObject, pipe=None) -> None: + """ + Publish the device info to redis. The device info contains + inter alia the class name, user functions and signals. + + Args: + obj (_type_): _description_ + """ + + interface = get_device_info(obj) + self.connector.set( + MessageEndpoints.device_info(obj.name), + messages.DeviceInfoMessage(device=obj.name, info=interface), + pipe, + ) + + def reset_device_data(self, obj: OphydObject, pipe=None) -> None: + """delete all device data and device info""" + self.connector.delete(MessageEndpoints.device_status(obj.name), pipe) + self.connector.delete(MessageEndpoints.device_read(obj.name), pipe) + self.connector.delete(MessageEndpoints.device_info(obj.name), pipe) + + def _obj_callback_readback(self, *_args, obj: OphydObject, **kwargs): + if not obj.connected: + return + name = obj.root.name + signals = obj.root.read() + metadata = self.devices.get(obj.root.name).metadata + dev_msg = messages.DeviceMessage(signals=signals, metadata=metadata) + pipe = self.connector.pipeline() + self.connector.set_and_publish(MessageEndpoints.device_readback(name), dev_msg, pipe) + pipe.execute() + + def _obj_callback_configuration(self, *_args, obj: OphydObject, **kwargs): + if not obj.connected: + return + name = obj.root.name + signals = obj.root.read_configuration() + metadata = self.devices.get(obj.root.name).metadata + dev_msg = messages.DeviceMessage(signals=signals, metadata=metadata) + pipe = self.connector.pipeline() + self.connector.set_and_publish( + MessageEndpoints.device_read_configuration(name), dev_msg, pipe + ) + pipe.execute() + + @typechecked + def _obj_callback_device_monitor_2d( + self, *_args, obj: OphydObject, value: np.ndarray, timestamp: float | None = None, **kwargs + ): + """ + Callback for ophyd monitor events. Sends the data to redis. + Introduces a check of the data size, and incoporates a limit which is defined in max_size (in MB) + + Args: + obj (OphydObject): ophyd object + value (np.ndarray): data from ophyd device + + """ + # Convert sizes from bytes to MB + dsize = len(value.tobytes()) / 1e6 + max_size = 1000 + if dsize > max_size: + logger.warning( + f"Data size of single message is too large to send, current max_size {max_size}." + ) + return + if obj.connected: + name = obj.root.name + metadata = self.devices[name].metadata + msg = messages.DeviceMonitor2DMessage( + device=name, + data=value, + metadata=metadata, + timestamp=timestamp if timestamp else time.time(), + ) + stream_msg = {"data": msg} + self.connector.xadd( + MessageEndpoints.device_monitor_2d(name), + stream_msg, + max_size=min(100, int(max_size // dsize)), + ) + + def _obj_callback_acq_done(self, *_args, **kwargs): + device = kwargs["obj"].root.name + status = 0 + metadata = self.devices[device].metadata + self.connector.set( + MessageEndpoints.device_status(device), + messages.DeviceStatusMessage(device=device, status=status, metadata=metadata), + ) + + def _obj_callback_done_moving(self, *args, **kwargs): + self._obj_callback_readback(*args, **kwargs) + # self._obj_callback_acq_done(*args, **kwargs) + + def _obj_callback_is_moving(self, *_args, **kwargs): + device = kwargs["obj"].root.name + status = int(kwargs.get("value")) + metadata = self.devices[device].metadata + self.connector.set( + MessageEndpoints.device_status(device), + messages.DeviceStatusMessage(device=device, status=status, metadata=metadata), + ) + + def _obj_flyer_callback(self, *_args, **kwargs): + obj = kwargs["obj"] + data = kwargs["value"].get("data") + ds_obj = self.devices[obj.root.name] + metadata = ds_obj.metadata + if "scan_id" not in metadata: + return + + if not hasattr(ds_obj, "emitted_points"): + ds_obj.emitted_points = {} + + emitted_points = ds_obj.emitted_points.get(metadata["scan_id"], 0) + + # make sure all arrays are of equal length + max_points = min(len(d) for d in data.values()) + bundle = messages.BundleMessage() + for ii in range(emitted_points, max_points): + timestamp = time.time() + signals = {} + for key, val in data.items(): + signals[key] = {"value": val[ii], "timestamp": timestamp} + bundle.append( + messages.DeviceMessage(signals=signals, metadata={"point_id": ii, **metadata}) + ) + ds_obj.emitted_points[metadata["scan_id"]] = max_points + pipe = self.connector.pipeline() + self.connector.send(MessageEndpoints.device_read(obj.root.name), bundle, pipe=pipe) + msg = messages.DeviceStatusMessage( + device=obj.root.name, status=max_points, metadata=metadata + ) + self.connector.set_and_publish( + MessageEndpoints.device_progress(obj.root.name), msg, pipe=pipe + ) + pipe.execute() + + def _obj_progress_callback(self, *_args, obj, value, max_value, done, **kwargs): + metadata = self.devices[obj.root.name].metadata + msg = messages.ProgressMessage( + value=value, max_value=max_value, done=done, metadata=metadata + ) + self.connector.set_and_publish(MessageEndpoints.device_progress(obj.root.name), msg) diff --git a/phoenix_bec/local_scripts/Code_to_test_devices/test_falcon.py b/phoenix_bec/local_scripts/Code_to_test_devices/test_falcon.py new file mode 100644 index 0000000..0a660e2 --- /dev/null +++ b/phoenix_bec/local_scripts/Code_to_test_devices/test_falcon.py @@ -0,0 +1,17 @@ +# against all rues, make sure ff and falcon are really +# creates newly + + +ff = 0 +falcon = 0 + +from ophyd import Component as Cpt +import phoenix_bec.devices.falcon_phoenix as ff + +falcon = ff.FalconPhoenix(name="falcon_hdf5", prefix="X07MB-SITORO:") + +# make a 'get to read all epics channels +# there will be an error message, if device contains a channel whcih does not exist +w = falcon.get() + +print(w) diff --git a/phoenix_bec/local_scripts/Examples/Learn_about_ophyd/DefiningEpics_Channels.py b/phoenix_bec/local_scripts/Examples/Learn_about_ophyd/DefiningEpics_Channels.py index 75eba1f..828e4a7 100644 --- a/phoenix_bec/local_scripts/Examples/Learn_about_ophyd/DefiningEpics_Channels.py +++ b/phoenix_bec/local_scripts/Examples/Learn_about_ophyd/DefiningEpics_Channels.py @@ -1,42 +1,44 @@ from ophyd import Device, EpicsMotor, EpicsSignal, EpicsSignalRO from ophyd import Component as Cpt -#option I via direct acces to classes +# option I via direct acces to classes -def print_dic(clname,cl): - print('') - print('-------- ',clname) + +def print_dic(clname, cl): + print("") + print("-------- ", clname) for ii in cl.__dict__: - if '_' not in ii: + if "_" not in ii: try: - print(ii,' ---- ',cl.__getattribute__(ii)) + print(ii, " ---- ", cl.__getattribute__(ii)) except: print(ii) - -ScanX = EpicsMotor(name='ScanX',prefix='X07MB-ES-MA1:ScanX') -ScanY = EpicsMotor(name='ScanY',prefix='X07MB-ES-MA1:ScanY') -DIODE = EpicsSignal(name='SI',read_pv='X07MB-OP2-SAI_07:MEAN') -SMPL = EpicsSignal(name='SMPL',read_pv='X07MB-OP2:SMPL') -CYCLES = EpicsSignal(name='SMPL',read_pv='X07MB-OP2:TOTAL-CYCLES',write_pv='X07MB-OP2:TOTAL-CYCLES') +ScanX = EpicsMotor(name="ScanX", prefix="X07MB-ES-MA1:ScanX") +ScanY = EpicsMotor(name="ScanY", prefix="X07MB-ES-MA1:ScanY") +DIODE = EpicsSignal(name="SI", read_pv="X07MB-OP2-SAI_07:MEAN") +SMPL = EpicsSignal(name="SMPL", read_pv="X07MB-OP2:SMPL") +CYCLES = EpicsSignal( + name="SMPL", read_pv="X07MB-OP2:TOTAL-CYCLES", write_pv="X07MB-OP2:TOTAL-CYCLES" +) -#prefix='XXXX:' -y_cpt = Cpt(EpicsMotor, 'ScanX') +# prefix='XXXX:' +y_cpt = Cpt(EpicsMotor, "ScanX") # Option 2 using component -device_ins=Device('X07MB-ES-MA1:',name=('device_name')) -print(' initialzation of device_in=Device(X07MB-ES-MA1:,name=(device_name)') -print('device_ins.__init__') +device_ins = Device("X07MB-ES-MA1:", name=("device_name")) +print(" initialzation of device_in=Device(X07MB-ES-MA1:,name=(device_name)") +print("device_ins.__init__") print(device_ins.__init__) -print_dic('class Device',Device) -print_dic('instance of device device_ins',device_ins) +print_dic("class Device", Device) +print_dic("instance of device device_ins", device_ins) -print(' ') -print('DEFINE class StageXY... prefix variable not defined ') +print(" ") +print("DEFINE class StageXY... prefix variable not defined ") class StageXY(Device): @@ -48,20 +50,19 @@ class StageXY(Device): # hard to understand, moist likely using calss methods.. # - x = Cpt(EpicsMotor, 'ScanX') - y = Cpt(EpicsMotor, 'ScanY') + x = Cpt(EpicsMotor, "ScanX") + y = Cpt(EpicsMotor, "ScanY") + + # end class - - print() -print('init xy_stage, use input parameter from Device and prefix is defined in call ') -xy_stage = StageXY('X07MB-ES-MA1:', name='stageXXX') - -print_dic('class StageXY',StageXY) -print_dic('instance of StageXY',xy_stage) +print("init xy_stage, use input parameter from Device and prefix is defined in call ") +xy_stage = StageXY("X07MB-ES-MA1:", name="stageXXX") +print_dic("class StageXY", StageXY) +print_dic("instance of StageXY", xy_stage) ############################################# @@ -81,7 +82,7 @@ print_dic('instance of StageXY',xy_stage) # ######################################################### -print('xy_stage.x.prefix') +print("xy_stage.x.prefix") print(xy_stage.x.prefix) xy_stage.__dict__