pymodaq 5.0.5__py3-none-any.whl → 5.1.0a0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pymodaq might be problematic. Click here for more details.

Files changed (53) hide show
  1. pymodaq/control_modules/daq_move.py +77 -64
  2. pymodaq/control_modules/daq_move_ui.py +16 -15
  3. pymodaq/control_modules/daq_viewer.py +95 -87
  4. pymodaq/control_modules/daq_viewer_ui.py +22 -23
  5. pymodaq/control_modules/mocks.py +2 -2
  6. pymodaq/control_modules/move_utility_classes.py +28 -19
  7. pymodaq/control_modules/thread_commands.py +138 -0
  8. pymodaq/control_modules/utils.py +88 -20
  9. pymodaq/control_modules/viewer_utility_classes.py +8 -17
  10. pymodaq/dashboard.py +90 -27
  11. pymodaq/examples/qt_less_standalone_module.py +48 -11
  12. pymodaq/extensions/__init__.py +7 -3
  13. pymodaq/extensions/adaptive/__init__.py +2 -0
  14. pymodaq/extensions/adaptive/adaptive_optimization.py +159 -0
  15. pymodaq/extensions/adaptive/loss_function/_1d_loss_functions.py +73 -0
  16. pymodaq/extensions/adaptive/loss_function/_2d_loss_functions.py +86 -0
  17. pymodaq/extensions/adaptive/loss_function/__init__.py +3 -0
  18. pymodaq/extensions/adaptive/loss_function/loss_factory.py +106 -0
  19. pymodaq/extensions/adaptive/utils.py +97 -0
  20. pymodaq/extensions/bayesian/__init__.py +1 -1
  21. pymodaq/extensions/bayesian/acquisition/__init__.py +2 -0
  22. pymodaq/extensions/bayesian/acquisition/acquisition_function_factory.py +71 -0
  23. pymodaq/extensions/bayesian/acquisition/base_acquisition_function.py +86 -0
  24. pymodaq/extensions/bayesian/bayesian_optimization.py +121 -0
  25. pymodaq/extensions/bayesian/utils.py +27 -286
  26. pymodaq/extensions/daq_logger/daq_logger.py +7 -12
  27. pymodaq/extensions/daq_logger/h5logging.py +1 -1
  28. pymodaq/extensions/daq_scan.py +18 -47
  29. pymodaq/extensions/h5browser.py +3 -34
  30. pymodaq/extensions/optimizers_base/__init__.py +0 -0
  31. pymodaq/extensions/{bayesian/bayesian_optimisation.py → optimizers_base/optimizer.py} +441 -334
  32. pymodaq/extensions/optimizers_base/thread_commands.py +20 -0
  33. pymodaq/extensions/optimizers_base/utils.py +378 -0
  34. pymodaq/extensions/pid/pid_controller.py +6 -10
  35. pymodaq/extensions/utils.py +12 -0
  36. pymodaq/utils/data.py +1 -0
  37. pymodaq/utils/gui_utils/loader_utils.py +2 -0
  38. pymodaq/utils/h5modules/module_saving.py +134 -22
  39. pymodaq/utils/leco/daq_move_LECODirector.py +73 -73
  40. pymodaq/utils/leco/daq_xDviewer_LECODirector.py +36 -84
  41. pymodaq/utils/leco/director_utils.py +25 -10
  42. pymodaq/utils/leco/leco_director.py +65 -26
  43. pymodaq/utils/leco/pymodaq_listener.py +118 -68
  44. pymodaq/utils/leco/utils.py +24 -24
  45. pymodaq/utils/managers/modules_manager.py +37 -8
  46. pymodaq/utils/scanner/scanners/_1d_scanners.py +0 -38
  47. pymodaq/utils/scanner/scanners/_2d_scanners.py +0 -58
  48. {pymodaq-5.0.5.dist-info → pymodaq-5.1.0a0.dist-info}/METADATA +4 -3
  49. {pymodaq-5.0.5.dist-info → pymodaq-5.1.0a0.dist-info}/RECORD +52 -38
  50. {pymodaq-5.0.5.dist-info → pymodaq-5.1.0a0.dist-info}/entry_points.txt +0 -2
  51. pymodaq/utils/leco/desktop.ini +0 -2
  52. {pymodaq-5.0.5.dist-info → pymodaq-5.1.0a0.dist-info}/WHEEL +0 -0
  53. {pymodaq-5.0.5.dist-info → pymodaq-5.1.0a0.dist-info}/licenses/LICENSE +0 -0
@@ -1,17 +1,20 @@
1
1
  from __future__ import annotations
2
2
  from typing import Optional, Union
3
3
 
4
- from easydict import EasyDict as edict
5
-
6
4
  from pymodaq.control_modules.viewer_utility_classes import DAQ_Viewer_base, comon_parameters, main
7
-
5
+ from pymodaq.control_modules.thread_commands import ThreadStatus, ThreadStatusViewer
6
+ from pymodaq_utils.serialize.factory import SerializableFactory
8
7
  from pymodaq_utils.utils import ThreadCommand, getLineInfo
9
8
 
9
+
10
+ from pymodaq.utils import data # for serialization factory registration # noqa: F401
10
11
  from pymodaq_gui.parameter import Parameter
11
- from pymodaq_utils.serialize.serializer_legacy import DeSerializer
12
12
 
13
13
  from pymodaq.utils.leco.leco_director import LECODirector, leco_parameters
14
14
  from pymodaq.utils.leco.director_utils import DetectorDirector
15
+ from pymodaq_utils.logger import set_logger, get_module_name
16
+
17
+ logger = set_logger(get_module_name(__file__))
15
18
 
16
19
 
17
20
  class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
@@ -25,19 +28,14 @@ class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
25
28
 
26
29
  params_GRABBER = []
27
30
 
28
- message_list = LECODirector.message_list + ["Quit", "Send Data 0D", "Send Data 1D",
29
- "Send Data 2D", "Send Data ND",
30
- "Status", "Done", "Server Closed",
31
- "Info", "Infos", "Info_xml", 'x_axis', 'y_axis']
32
31
  socket_types = ["GRABBER"]
33
32
  params = comon_parameters + leco_parameters
33
+ live_mode_available = True
34
34
 
35
35
  def __init__(self, parent=None, params_state=None, grabber_type: str = "0D", **kwargs) -> None:
36
- super().__init__(parent=parent, params_state=params_state, **kwargs)
37
- self.register_rpc_methods((
38
- self.set_x_axis,
39
- self.set_y_axis,
40
- ))
36
+ DAQ_Viewer_base.__init__(self, parent=parent,
37
+ params_state=params_state)
38
+ LECODirector.__init__(self, host=self.settings['host'])
41
39
  for method in (
42
40
  self.set_data,
43
41
  ):
@@ -62,54 +60,23 @@ class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
62
60
  --------
63
61
  utility_classes.DAQ_TCP_server.init_server, get_xaxis, get_yaxis
64
62
  """
65
- self.status.update(edict(initialized=False, info="", x_axis=None, y_axis=None,
66
- controller=None))
67
- actor_name = self.settings.child("actor_name").value()
68
- self.controller = self.ini_detector_init( # type: ignore
69
- old_controller=controller,
70
- new_controller=DetectorDirector(actor=actor_name, communicator=self.communicator),
71
- )
72
- self.controller.set_remote_name(self.communicator.full_name) # type: ignore
73
- try:
74
- # self.settings.child(('infos')).addChildren(self.params_GRABBER)
75
-
76
- # init axes from image , here returns only None values (to tricky to di it with the
77
- # server and not really necessary for images anyway)
78
- self.x_axis = self.get_xaxis()
79
- self.y_axis = self.get_yaxis()
80
- self.status.x_axis = self.x_axis
81
- self.status.y_axis = self.y_axis
82
- self.status.initialized = True
83
- return self.status
84
-
85
- except Exception as e:
86
- self.status.info = getLineInfo() + str(e)
87
- self.status.initialized = False
88
- return self.status
89
-
90
- def get_xaxis(self):
91
- """
92
- Obtain the horizontal axis of the image.
93
63
 
94
- Returns
95
- -------
96
- 1D numpy array
97
- Contains a vector of integer corresponding to the horizontal camera pixels.
98
- """
99
- pass
100
- return self.x_axis
64
+ actor_name = self.settings["actor_name"]
65
+ if self.is_master:
66
+ self.controller = DetectorDirector(actor=actor_name,
67
+ communicator=self.communicator)
68
+ try:
69
+ self.controller.set_remote_name(self.communicator.full_name) # type: ignore
70
+ except TimeoutError:
71
+ logger.warning("Timeout setting remote name.")
72
+ else:
73
+ self.controller = controller
101
74
 
102
- def get_yaxis(self):
103
- """
104
- Obtain the vertical axis of the image.
75
+ self.controller.get_settings()
105
76
 
106
- Returns
107
- -------
108
- 1D numpy array
109
- Contains a vector of integer corresponding to the vertical camera pixels.
110
- """
111
- pass
112
- return self.y_axis
77
+ initialized = True
78
+ info = 'Viewer Director ready'
79
+ return info, initialized
113
80
 
114
81
  def grab_data(self, Naverage=1, **kwargs):
115
82
  """
@@ -126,32 +93,20 @@ class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
126
93
  --------
127
94
  utility_classes.DAQ_TCP_server.process_cmds
128
95
  """
129
- try:
130
- self.ind_grabbed = 0 # to keep track of the current image in the average
131
- self.Naverage = Naverage
132
- self.controller.set_remote_name(self.communicator.full_name)
133
- self.controller.send_data(grabber_type=self.grabber_type)
134
96
 
135
- except Exception as e:
136
- self.emit_status(ThreadCommand('Update_Status', [getLineInfo() + str(e), "log"]))
97
+ self.ind_grabbed = 0 # to keep track of the current image in the average
98
+ self.Naverage = Naverage
99
+ self.controller.set_remote_name(self.communicator.full_name)
100
+ if kwargs.get('live', False):
101
+ self.controller.send_data_grab()
102
+ else:
103
+ self.controller.send_data_snap()
137
104
 
138
105
  def stop(self):
139
106
  """
140
107
  not implemented.
141
108
  """
142
- pass
143
- return ""
144
-
145
- # Methods for RPC calls
146
- def set_x_axis(self, data, label: str = "", units: str = ""):
147
- # TODO make to work
148
- self.x_axis = dict(data=data, label=label, units=units)
149
- self.emit_x_axis()
150
-
151
- def set_y_axis(self, data, label: str = "", units: str = ""):
152
- # TODO make to work
153
- self.y_axis = dict(data=data, label=label, units=units)
154
- self.emit_y_axis()
109
+ self.controller.stop_grab()
155
110
 
156
111
  def set_data(self, data: Union[list, str, None],
157
112
  additional_payload: Optional[list[bytes]]=None) -> None:
@@ -162,15 +117,12 @@ class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
162
117
 
163
118
  :param data: If None, look for the additional object
164
119
  """
165
- if isinstance(data, str):
166
- deserializer = DeSerializer.from_b64_string(data)
167
- elif additional_payload is not None:
168
- deserializer = DeSerializer(additional_payload[0])
120
+ if additional_payload is not None:
121
+ dte = SerializableFactory().get_apply_deserializer(additional_payload[0])
169
122
  else:
170
123
  raise NotImplementedError("Not implemented to set a list of values.")
171
- dte = deserializer.dte_deserialization()
172
124
  self.dte_signal.emit(dte)
173
125
 
174
126
 
175
127
  if __name__ == '__main__':
176
- main(__file__)
128
+ main(__file__, init=False)
@@ -10,8 +10,11 @@ from pyleco.directors.director import Director
10
10
 
11
11
  import pymodaq_gui.parameter.utils as putils
12
12
  from pymodaq_gui.parameter import Parameter, ioxml
13
- from pymodaq.control_modules.move_utility_classes import DataActuator
14
- from pymodaq.utils.leco.utils import serialize_object
13
+ from pymodaq.utils.data import DataActuator
14
+ from pymodaq.utils.leco.utils import binary_serialization_to_kwargs, SerializableFactory
15
+
16
+ from pymodaq_gui.parameter.utils import ParameterWithPath
17
+
15
18
 
16
19
 
17
20
  class GenericDirector(Director):
@@ -23,24 +26,35 @@ class GenericDirector(Director):
23
26
 
24
27
  def set_info(self, param: Parameter):
25
28
  # It removes the first two parts (main_settings and detector_settings?)
26
- self.set_info_str(path=putils.get_param_path(param)[2:],
27
- param_dict_str=ioxml.parameter_to_xml_string(param).decode())
29
+ pwp = ParameterWithPath(param, putils.get_param_path(param)[2:])
30
+ self.ask_rpc(method="set_info",
31
+ **binary_serialization_to_kwargs(pwp, data_key='parameter'))
28
32
 
29
- def set_info_str(self, path: List[str], param_dict_str: str) -> None:
30
- self.ask_rpc(method="sef_info", path=path, param_dict_str=param_dict_str)
33
+ def get_settings(self,) -> None:
34
+ self.ask_rpc('get_settings')
31
35
 
32
36
 
33
37
  class DetectorDirector(GenericDirector):
34
- def send_data(self, grabber_type: str = "") -> None:
35
- self.ask_rpc("send_data", grabber_type=grabber_type)
38
+ def send_data_grab(self, grabber_type: str = "") -> None:
39
+ self.ask_rpc("send_data_grab", grabber_type=grabber_type)
40
+
41
+ def send_data_snap(self, grabber_type: str = "") -> None:
42
+ self.ask_rpc("send_data_snap", grabber_type=grabber_type)
43
+
44
+ def stop_grab(self, grabber_type: str = "") -> None:
45
+ self.ask_rpc("stop_grab", grabber_type=grabber_type)
36
46
 
37
47
 
38
48
  class ActuatorDirector(GenericDirector):
39
49
  def move_abs(self, position: Union[float, DataActuator]) -> None:
40
- self.ask_rpc("move_abs", position=serialize_object(position))
50
+ self.ask_rpc(
51
+ "move_abs", **binary_serialization_to_kwargs(position, data_key="position")
52
+ )
41
53
 
42
54
  def move_rel(self, position: Union[float, DataActuator]) -> None:
43
- self.ask_rpc("move_rel", position=serialize_object(position))
55
+ self.ask_rpc(
56
+ "move_rel", **binary_serialization_to_kwargs(position, data_key="position")
57
+ )
44
58
 
45
59
  def move_home(self) -> None:
46
60
  self.ask_rpc("move_home")
@@ -56,3 +70,4 @@ class ActuatorDirector(GenericDirector):
56
70
  def stop_motion(self,) -> None:
57
71
  # not implemented in DAQ_Move!
58
72
  self.ask_rpc("stop_motion")
73
+
@@ -1,21 +1,42 @@
1
- import random
2
- from typing import Callable, Sequence, List
3
1
 
2
+ import random
4
3
  from pymodaq_utils.enums import StrEnum
5
4
  from typing import Callable, Sequence, List, Optional, Union
6
5
 
7
6
  import pymodaq_gui.parameter.utils as putils
8
7
  # object used to send info back to the main thread:
9
8
  from pymodaq_utils.utils import ThreadCommand
9
+ from pymodaq.utils.config import Config
10
10
  from pymodaq_gui.parameter import Parameter
11
+ from pymodaq_gui.parameter import ioxml
12
+ from pymodaq_gui.parameter.utils import ParameterWithPath
11
13
 
12
14
  from pymodaq.utils.leco.director_utils import GenericDirector
13
15
  from pymodaq.utils.leco.pymodaq_listener import PymodaqListener
16
+ from pymodaq_utils.serialize.factory import SerializableFactory
17
+ from pymodaq.control_modules.thread_commands import ThreadStatusMove
18
+
19
+ config = Config()
20
+
21
+ class DirectorCommands(StrEnum):
22
+ SET_SETTINGS = 'set_settings'
23
+ SET_INFO = 'set_info'
24
+
25
+ SEND_POSITION = 'send_position' # to display the actor position
26
+ SET_MOVE_DONE = 'set_move_done'
27
+ SET_UNITS = 'set_units' # to set units accordingly to the one of the actor
28
+
29
+
30
+ class DirectorReceivedCommands(StrEnum):
31
+ MOVE_DONE = ThreadStatusMove.MOVE_DONE
32
+ GET_ACTUATOR_VALUE = ThreadStatusMove.GET_ACTUATOR_VALUE
14
33
 
15
34
 
16
35
  leco_parameters = [
17
36
  {'title': 'Actor name:', 'name': 'actor_name', 'type': 'str', 'value': "actor_name",
18
37
  'tip': 'Name of the actor plugin to communicate with.'},
38
+ {'title': 'Coordinator Host:', 'name': 'host', 'type': 'str', 'value': config('network', "leco-server", "host")},
39
+ {'title': 'Settings PyMoDAQ Client:', 'name': 'settings_client', 'type': 'group', 'children': []},
19
40
  ]
20
41
 
21
42
 
@@ -23,45 +44,40 @@ class LECODirector:
23
44
  """
24
45
  This is a mixin for a Control module to direct another, remote module (analogous to TCP Server).
25
46
 
26
- ================= ==============================
27
- **Attributes** **Type**
28
- *command_server* instance of Signal
29
- *x_axis* 1D numpy array
30
- *y_axis* 1D numpy array
31
- *data* double precision float array
32
- ================= ==============================
33
-
34
- See Also
35
- --------
36
- utility_classes.DAQ_TCP_server
47
+
37
48
  """
38
- message_list = ["Quit", "Status", "Done", "Server Closed", "Info", "Infos", "Info_xml",
39
- "move_abs", 'move_home', 'move_rel', 'get_actuator_value', 'stop_motion',
40
- 'position_is', 'move_done',
41
- ]
42
- socket_types: List[str]
43
49
 
44
50
  controller: GenericDirector
45
51
  settings: Parameter
52
+ _title: str
46
53
 
47
- def __init__(self, **kwargs) -> None:
48
- super().__init__(**kwargs)
54
+ def __init__(self, host: str = 'localhost', **kwargs) -> None:
49
55
 
50
56
  name = f'{self._title}_{random.randrange(0, 10000)}_director'
51
- # TODO use the same Listener instance as the LECOActorModule
52
- self.listener = PymodaqListener(name=name)
57
+
58
+ self.listener = PymodaqListener(name=name, host=host)
53
59
  self.listener.start_listen()
60
+
54
61
  self.communicator = self.listener.get_communicator()
62
+
63
+ #registering rpc methods common to all Directors
55
64
  self.register_rpc_methods((
65
+ self.set_settings,
66
+ ))
67
+ self.register_binary_rpc_methods((
56
68
  self.set_info,
57
69
  ))
58
70
 
71
+ def register_binary_rpc_methods(self, methods: Sequence[Callable]) -> None:
72
+ for method in methods:
73
+ self.listener.register_binary_rpc_method(method, accept_binary_input=True)
74
+
59
75
  def register_rpc_methods(self, methods: Sequence[Callable]) -> None:
60
76
  for method in methods:
61
77
  self.communicator.register_rpc_method(method=method)
62
78
 
63
- def commit_settings(self, param: Parameter) -> None:
64
- raise NotImplementedError
79
+ def commit_settings(self, param) -> None:
80
+ self.commit_leco_settings(param=param)
65
81
 
66
82
  def commit_leco_settings(self, param: Parameter) -> None:
67
83
  if param.name() == "actor_name":
@@ -70,6 +86,8 @@ class LECODirector:
70
86
  self.controller.set_info(param=param)
71
87
 
72
88
  def close(self) -> None:
89
+ """ Clear the content of the settings_clients setting"""
90
+ self.settings.child('settings_client').clearChildren()
73
91
  self.listener.stop_listen()
74
92
 
75
93
  def stop(self):
@@ -85,5 +103,26 @@ class LECODirector:
85
103
  super().emit_status(status=status) # type: ignore
86
104
 
87
105
  # Methods accessible via remote calls
88
- def set_info(self, path: List[str], param_dict_str: str) -> None:
89
- self.emit_status(ThreadCommand("set_info", attribute=[path, param_dict_str]))
106
+ def set_info(self,
107
+ parameter: Optional[Union[float, str]],
108
+ additional_payload: Optional[List[bytes]] = None,
109
+ ) -> None:
110
+ """ Write the value of a param upfated from the actor to here in the
111
+ Parameter with path: ('move_settings', 'settings_client')
112
+ """
113
+ param: ParameterWithPath = SerializableFactory().get_apply_deserializer(additional_payload[0])
114
+
115
+ try:
116
+ path = ['settings_client']
117
+ path.extend(param.path[1:])
118
+
119
+ self.settings.child(*path).setValue(param.value())
120
+ except Exception as e:
121
+ print(f'could not set the param {param} in the director:\n'
122
+ f'{str(e)}')
123
+
124
+ def set_settings(self, settings: bytes):
125
+ """ Get the content of the actor settings to pe populated in this plugin
126
+ 'settings_client' parameter"""
127
+ params = ioxml.XML_string_to_parameter(settings)
128
+ self.settings.child('settings_client').addChildren(params)
@@ -3,16 +3,18 @@ from pymodaq_utils.enums import StrEnum
3
3
 
4
4
  import logging
5
5
  from threading import Event
6
- from typing import Optional, Union, List, Type
6
+ from typing import cast, Optional, Union, List, Sequence, Type
7
7
 
8
8
  from pyleco.core import COORDINATOR_PORT
9
9
  from pyleco.utils.listener import Listener, PipeHandler
10
10
  from qtpy.QtCore import QObject, Signal # type: ignore
11
11
 
12
+ from pymodaq_data.data import DataWithAxes
13
+ from pymodaq_utils.serialize.factory import SerializableFactory, SerializableBase
12
14
  from pymodaq_utils.utils import ThreadCommand
13
15
  from pymodaq_gui.parameter import ioxml
14
- from pymodaq_data.data import DataWithAxes
15
- from pymodaq_utils.serialize.serializer_legacy import SERIALIZABLE, DeSerializer
16
+ from pymodaq_gui.parameter.utils import ParameterWithPath
17
+
16
18
  from pymodaq.utils.leco.utils import binary_serialization_to_kwargs
17
19
 
18
20
 
@@ -24,15 +26,28 @@ class LECOClientCommands(StrEnum):
24
26
  class LECOCommands(StrEnum):
25
27
  CONNECT = "ini_connection"
26
28
  QUIT = "quit"
29
+ GET_SETTINGS = 'get_settings'
30
+ SET_SETTINGS = 'set_settings'
31
+ SET_INFO = 'set_info'
32
+ SEND_INFO = 'send_info'
27
33
 
28
34
 
29
35
  class LECOMoveCommands(StrEnum):
30
36
  POSITION = 'position_is'
31
37
  MOVE_DONE = 'move_done'
38
+ UNITS_CHANGED = 'units_changed'
39
+ STOP = 'stop_motion'
40
+ MOVE_ABS = 'move_abs'
41
+ MOVE_REL = 'move_rel'
42
+ MOVE_HOME = 'move_home'
43
+ GET_ACTUATOR_VALUE = 'get_actuator_value'
32
44
 
33
45
 
34
46
  class LECOViewerCommands(StrEnum):
35
47
  DATA_READY = 'data_ready'
48
+ GRAB = 'grab'
49
+ SNAP = 'snap'
50
+ STOP = 'stop_grab'
36
51
 
37
52
 
38
53
  class ListenerSignals(QObject):
@@ -53,54 +68,109 @@ class PymodaqPipeHandler(PipeHandler):
53
68
  def __init__(self, name: str, signals: ListenerSignals, **kwargs) -> None:
54
69
  super().__init__(name, **kwargs)
55
70
  self.signals = signals
56
-
71
+ self.register_data_types_for_deserialization()
72
+
73
+ def register_data_types_for_deserialization(
74
+ self, types: Optional[Sequence[type[SerializableBase]]] = None
75
+ ) -> None:
76
+ """Register different data types for deserialization in subclasses."""
77
+ if types is None:
78
+ return
79
+ for cls in types:
80
+ SerializableFactory().register_from_type(
81
+ cls, cls.serialize, cls.deserialize
82
+ )
57
83
 
58
84
  class ActorHandler(PymodaqPipeHandler):
85
+ def register_data_types_for_deserialization(
86
+ self, types: Optional[Sequence[type[SerializableBase]]] = None
87
+ ) -> None:
88
+ all_types: Sequence[type[SerializableBase]] = [DataWithAxes]
89
+ if types:
90
+ all_types.extend(types) # type: ignore
91
+ super().register_data_types_for_deserialization(all_types)
59
92
 
60
93
  def register_rpc_methods(self) -> None:
61
94
  super().register_rpc_methods()
62
- self.register_rpc_method(self.set_info)
63
- self.register_rpc_method(self.send_data)
64
- self.register_rpc_method(self.move_abs)
65
- self.register_rpc_method(self.move_rel)
95
+ self.register_binary_rpc_method(self.set_info, accept_binary_input=True)
96
+ self.register_rpc_method(self.send_data_grab)
97
+ self.register_rpc_method(self.send_data_snap)
98
+ self.register_binary_rpc_method(self.move_abs, accept_binary_input=True)
99
+ self.register_binary_rpc_method(self.move_rel, accept_binary_input=True)
66
100
  self.register_rpc_method(self.move_home)
67
101
  self.register_rpc_method(self.get_actuator_value)
68
102
  self.register_rpc_method(self.stop_motion)
103
+ self.register_rpc_method(self.stop_grab)
104
+ self.register_rpc_method(self.get_settings)
69
105
 
70
106
  @staticmethod
71
- def extract_dwa_object(data_string: str) -> DataWithAxes:
72
- """Extract a DataWithAxes object from the received message."""
73
- desererializer = DeSerializer.from_b64_string(data_string)
74
- return desererializer.dwa_deserialization()
107
+ def extract_pymodaq_object(
108
+ value: Optional[Union[float, str]], additional_payload: Optional[List[bytes]]
109
+ ):
110
+ if value is None and additional_payload:
111
+ return cast(DataWithAxes, SerializableFactory().get_apply_deserializer(additional_payload[0]))
112
+ else:
113
+ return value
75
114
 
76
115
  # generic commands
77
- def set_info(self, path: List[str], param_dict_str: str) -> None:
78
- self.signals.cmd_signal.emit(ThreadCommand("set_info", attribute=[path, param_dict_str]))
116
+ def set_info(self,
117
+ parameter: Optional[Union[float, str]],
118
+ additional_payload: Optional[List[bytes]] = None,
119
+ ) -> None:
120
+ param: ParameterWithPath = SerializableFactory().get_apply_deserializer(additional_payload[0])
121
+ self.signals.cmd_signal.emit(ThreadCommand(LECOCommands.SET_INFO, attribute=param))
122
+
123
+ def get_settings(self):
124
+ self.signals.cmd_signal.emit(ThreadCommand(LECOCommands.GET_SETTINGS))
79
125
 
80
126
  # detector commands
81
- def send_data(self, grabber_type: str = "") -> None:
82
- self.signals.cmd_signal.emit(ThreadCommand(f"Send Data {grabber_type}"))
127
+ def send_data_grab(self,) -> None:
128
+ self.signals.cmd_signal.emit(ThreadCommand(LECOViewerCommands.GRAB))
83
129
 
84
- # actuator commands
85
- def move_abs(self, position: Union[float, str]) -> None:
86
- pos = self.extract_dwa_object(position) if isinstance(position, str) else position
87
- self.signals.cmd_signal.emit(ThreadCommand("move_abs", attribute=[pos]))
130
+ # detector commands
131
+ def send_data_snap(self,) -> None:
132
+ self.signals.cmd_signal.emit(ThreadCommand(LECOViewerCommands.SNAP))
88
133
 
89
- def move_rel(self, position: Union[float, str]) -> None:
90
- pos = self.extract_dwa_object(position) if isinstance(position, str) else position
91
- self.signals.cmd_signal.emit(ThreadCommand("move_rel", attribute=[pos]))
134
+ # actuator commands
135
+ def move_abs(
136
+ self,
137
+ position: Optional[Union[float, str]],
138
+ additional_payload: Optional[List[bytes]] = None,
139
+ ) -> None:
140
+ """Move to an absolute position.
141
+
142
+ :param position: Deprecated, should be None and content transferred binary.
143
+ :param additional_payload: binary frames containing the position as PyMoDAQ `DataActuator`.
144
+ """
145
+ pos = self.extract_pymodaq_object(position, additional_payload)
146
+ self.signals.cmd_signal.emit(ThreadCommand(LECOMoveCommands.MOVE_ABS, pos))
147
+
148
+ def move_rel(
149
+ self,
150
+ position: Optional[Union[float, str]],
151
+ additional_payload: Optional[List[bytes]] = None,
152
+ ) -> None:
153
+ """Move by a relative position.
154
+
155
+ :param position: Deprecated, should be None and content transferred binary.
156
+ :param additional_payload: binary frames containing the position as PyMoDAQ `DataActuator`.
157
+ """
158
+ pos = self.extract_pymodaq_object(position, additional_payload)
159
+ self.signals.cmd_signal.emit(ThreadCommand(LECOMoveCommands.MOVE_REL, pos))
92
160
 
93
161
  def move_home(self) -> None:
94
- self.signals.cmd_signal.emit(ThreadCommand("move_home"))
162
+ self.signals.cmd_signal.emit(ThreadCommand(LECOMoveCommands.MOVE_HOME))
95
163
 
96
164
  def get_actuator_value(self) -> None:
97
165
  """Request that the actuator value is sent later on."""
98
166
  # according to DAQ_Move, this supersedes "check_position"
99
- self.signals.cmd_signal.emit(ThreadCommand("get_actuator_value"))
167
+ self.signals.cmd_signal.emit(ThreadCommand(LECOMoveCommands.GET_ACTUATOR_VALUE))
100
168
 
101
169
  def stop_motion(self,) -> None:
102
- # not implemented in DAQ_Move!
103
- self.signals.cmd_signal.emit(ThreadCommand("stop_motion"))
170
+ self.signals.cmd_signal.emit(ThreadCommand(LECOMoveCommands.STOP))
171
+
172
+ def stop_grab(self,) -> None:
173
+ self.signals.cmd_signal.emit(ThreadCommand(LECOViewerCommands.STOP))
104
174
 
105
175
 
106
176
  # to be able to separate them later on
@@ -182,7 +252,6 @@ class ActorListener(PymodaqListener):
182
252
  """Define what the name of the remote for answers is."""
183
253
  self.remote_name = name
184
254
 
185
- # @Slot(ThreadCommand)
186
255
  def queue_command(self, command: ThreadCommand) -> None:
187
256
  """Queue a command to send it via LECO to the server."""
188
257
 
@@ -203,15 +272,7 @@ class ActorListener(PymodaqListener):
203
272
  finally:
204
273
  self.cmd_signal.emit(ThreadCommand('disconnected'))
205
274
 
206
- elif command.command == 'update_connection':
207
- # self.ipaddress = command.attribute['ipaddress']
208
- # self.port = command.attribute['port']
209
- pass # TODO change name?
210
-
211
275
  elif command.command == LECOViewerCommands.DATA_READY:
212
- # code from the original:
213
- # self.data_ready(data=command.attribute)
214
- # def data_ready(data): self.send_data(datas[0]['data'])
215
276
  value = command.attribute # type: ignore
216
277
  self.communicator.ask_rpc(
217
278
  receiver=self.remote_name,
@@ -219,52 +280,41 @@ class ActorListener(PymodaqListener):
219
280
  **binary_serialization_to_kwargs(value),
220
281
  )
221
282
 
222
- elif command.command == 'send_info':
223
- path = command.attribute['path'] # type: ignore
224
- param = command.attribute['param'] # type: ignore
283
+ elif command.command == LECOCommands.SEND_INFO:
225
284
  self.communicator.ask_rpc(
226
285
  receiver=self.remote_name,
227
286
  method="set_info",
228
- path=path,
229
- param_dict_str=ioxml.parameter_to_xml_string(param).decode())
287
+ **binary_serialization_to_kwargs(command.attribute, data_key='parameter'))
230
288
 
231
289
  elif command.command == LECOMoveCommands.POSITION:
232
- value = command.attribute[0] # type: ignore
290
+ value = command.attribute
291
+ if isinstance(value, (list, tuple)):
292
+ value = value[0] # for backward compatibility with attributes list
233
293
  self.communicator.ask_rpc(receiver=self.remote_name,
234
- method="set_position",
235
- **binary_serialization_to_kwargs(value, data_key="position"),
294
+ method="send_position",
295
+ **binary_serialization_to_kwargs(pymodaq_object=value, data_key="position"),
236
296
  )
237
297
 
238
298
  elif command.command == LECOMoveCommands.MOVE_DONE:
239
- value = command.attribute[0] # type: ignore
299
+ value = command.attribute
300
+ if isinstance(value, (list, tuple)):
301
+ value = value[0] # for backward compatibility with attributes list
240
302
  self.communicator.ask_rpc(receiver=self.remote_name,
241
303
  method="set_move_done",
242
304
  **binary_serialization_to_kwargs(value, data_key="position"),
243
305
  )
244
306
 
245
- elif command.command == 'x_axis':
246
- value = command.attribute[0] # type: ignore
247
- if isinstance(value, SERIALIZABLE):
248
- self.communicator.ask_rpc(receiver=self.remote_name,
249
- method="set_x_axis",
250
- **binary_serialization_to_kwargs(value),
251
- )
252
- elif isinstance(value, dict):
253
- self.communicator.ask_rpc(receiver=self.remote_name, method="set_x_axis", **value)
254
- else:
255
- raise ValueError("Nothing to send!")
256
-
257
- elif command.command == 'y_axis':
258
- value = command.attribute[0] # type: ignore
259
- if isinstance(value, SERIALIZABLE):
260
- self.communicator.ask_rpc(receiver=self.remote_name,
261
- method="set_y_axis",
262
- **binary_serialization_to_kwargs(value),
263
- )
264
- elif isinstance(value, dict):
265
- self.communicator.ask_rpc(receiver=self.remote_name, method="set_y_axis", **value)
266
- else:
267
- raise ValueError("Nothing to send!")
307
+ elif command.command == LECOMoveCommands.UNITS_CHANGED:
308
+ units: str = command.attribute
309
+ self.communicator.ask_rpc(receiver=self.remote_name,
310
+ method="set_units",
311
+ units=units.encode(),
312
+ )
313
+
314
+ elif command.command == LECOCommands.SET_SETTINGS:
315
+ self.communicator.ask_rpc(receiver=self.remote_name,
316
+ method='set_settings',
317
+ settings=command.attribute.decode())
268
318
 
269
319
  else:
270
320
  raise IOError('Unknown TCP client command')