pymodaq 5.0.17__py3-none-any.whl → 5.1.0__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.
- pymodaq/__init__.py +23 -11
- pymodaq/control_modules/__init__.py +1 -0
- pymodaq/control_modules/daq_move.py +458 -246
- pymodaq/control_modules/daq_move_ui/__init__.py +0 -0
- pymodaq/control_modules/daq_move_ui/factory.py +48 -0
- pymodaq/control_modules/{daq_move_ui.py → daq_move_ui/ui_base.py} +168 -210
- pymodaq/control_modules/daq_move_ui/uis/__init__.py +0 -0
- pymodaq/control_modules/daq_move_ui/uis/binary.py +139 -0
- pymodaq/control_modules/daq_move_ui/uis/original.py +120 -0
- pymodaq/control_modules/daq_move_ui/uis/relative.py +124 -0
- pymodaq/control_modules/daq_move_ui/uis/simple.py +126 -0
- pymodaq/control_modules/daq_viewer.py +113 -101
- pymodaq/control_modules/daq_viewer_ui.py +41 -31
- pymodaq/control_modules/mocks.py +2 -2
- pymodaq/control_modules/move_utility_classes.py +113 -41
- pymodaq/control_modules/thread_commands.py +137 -0
- pymodaq/control_modules/ui_utils.py +72 -0
- pymodaq/control_modules/utils.py +107 -63
- pymodaq/control_modules/viewer_utility_classes.py +13 -17
- pymodaq/dashboard.py +1294 -625
- pymodaq/examples/qt_less_standalone_module.py +48 -11
- pymodaq/extensions/__init__.py +8 -3
- pymodaq/extensions/adaptive/__init__.py +2 -0
- pymodaq/extensions/adaptive/adaptive_optimization.py +179 -0
- pymodaq/extensions/adaptive/loss_function/_1d_loss_functions.py +73 -0
- pymodaq/extensions/adaptive/loss_function/_2d_loss_functions.py +73 -0
- pymodaq/extensions/adaptive/loss_function/__init__.py +3 -0
- pymodaq/extensions/adaptive/loss_function/loss_factory.py +110 -0
- pymodaq/extensions/adaptive/utils.py +123 -0
- pymodaq/extensions/bayesian/__init__.py +1 -1
- pymodaq/extensions/bayesian/acquisition/__init__.py +2 -0
- pymodaq/extensions/bayesian/acquisition/acquisition_function_factory.py +80 -0
- pymodaq/extensions/bayesian/acquisition/base_acquisition_function.py +105 -0
- pymodaq/extensions/bayesian/bayesian_optimization.py +143 -0
- pymodaq/extensions/bayesian/utils.py +71 -297
- pymodaq/extensions/daq_logger/daq_logger.py +7 -12
- pymodaq/extensions/daq_logger/h5logging.py +1 -1
- pymodaq/extensions/daq_scan.py +30 -55
- pymodaq/extensions/data_mixer/__init__.py +0 -0
- pymodaq/extensions/data_mixer/daq_0Dviewer_DataMixer.py +97 -0
- pymodaq/extensions/data_mixer/data_mixer.py +262 -0
- pymodaq/extensions/data_mixer/model.py +108 -0
- pymodaq/extensions/data_mixer/models/__init__.py +0 -0
- pymodaq/extensions/data_mixer/models/equation_model.py +91 -0
- pymodaq/extensions/data_mixer/models/gaussian_fit_model.py +65 -0
- pymodaq/extensions/data_mixer/parser.py +53 -0
- pymodaq/extensions/data_mixer/utils.py +23 -0
- pymodaq/extensions/h5browser.py +3 -34
- pymodaq/extensions/optimizers_base/__init__.py +0 -0
- pymodaq/extensions/optimizers_base/optimizer.py +1016 -0
- pymodaq/extensions/optimizers_base/thread_commands.py +22 -0
- pymodaq/extensions/optimizers_base/utils.py +427 -0
- pymodaq/extensions/pid/actuator_controller.py +3 -2
- pymodaq/extensions/pid/daq_move_PID.py +107 -30
- pymodaq/extensions/pid/pid_controller.py +613 -287
- pymodaq/extensions/pid/utils.py +8 -5
- pymodaq/extensions/utils.py +17 -2
- pymodaq/resources/config_template.toml +57 -0
- pymodaq/resources/preset_default.xml +1 -1
- pymodaq/utils/config.py +13 -4
- pymodaq/utils/daq_utils.py +14 -0
- pymodaq/utils/data.py +1 -0
- pymodaq/utils/gui_utils/loader_utils.py +25 -15
- pymodaq/utils/h5modules/module_saving.py +134 -22
- pymodaq/utils/leco/daq_move_LECODirector.py +123 -84
- pymodaq/utils/leco/daq_xDviewer_LECODirector.py +84 -97
- pymodaq/utils/leco/director_utils.py +32 -16
- pymodaq/utils/leco/leco_director.py +104 -27
- pymodaq/utils/leco/pymodaq_listener.py +186 -97
- pymodaq/utils/leco/rpc_method_definitions.py +43 -0
- pymodaq/utils/leco/utils.py +25 -25
- pymodaq/utils/managers/batchscan_manager.py +12 -11
- pymodaq/utils/managers/modules_manager.py +74 -33
- pymodaq/utils/managers/overshoot_manager.py +11 -10
- pymodaq/utils/managers/preset_manager.py +100 -64
- pymodaq/utils/managers/preset_manager_utils.py +163 -107
- pymodaq/utils/managers/remote_manager.py +21 -16
- pymodaq/utils/scanner/scan_factory.py +18 -4
- pymodaq/utils/scanner/scan_selector.py +1 -3
- pymodaq/utils/scanner/scanner.py +35 -6
- pymodaq/utils/scanner/scanners/_1d_scanners.py +15 -46
- pymodaq/utils/scanner/scanners/_2d_scanners.py +21 -68
- pymodaq/utils/scanner/scanners/sequential.py +50 -31
- pymodaq/utils/scanner/scanners/tabular.py +45 -28
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/METADATA +7 -6
- pymodaq-5.1.0.dist-info/RECORD +154 -0
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/entry_points.txt +0 -2
- pymodaq/extensions/bayesian/bayesian_optimisation.py +0 -685
- pymodaq/utils/leco/desktop.ini +0 -2
- pymodaq-5.0.17.dist-info/RECORD +0 -121
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/WHEEL +0 -0
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,17 +1,23 @@
|
|
|
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.data import DataFromPlugins, Axis
|
|
7
|
+
from pymodaq_data import DataToExport
|
|
8
|
+
from pymodaq_utils.serialize.factory import SerializableFactory
|
|
8
9
|
from pymodaq_utils.utils import ThreadCommand, getLineInfo
|
|
9
10
|
|
|
11
|
+
from pymodaq.utils import data # for serialization factory registration # noqa: F401
|
|
10
12
|
from pymodaq_gui.parameter import Parameter
|
|
11
|
-
from pymodaq_utils.serialize.serializer_legacy import DeSerializer
|
|
12
13
|
|
|
13
14
|
from pymodaq.utils.leco.leco_director import LECODirector, leco_parameters
|
|
14
15
|
from pymodaq.utils.leco.director_utils import DetectorDirector
|
|
16
|
+
from pymodaq_utils.logger import set_logger, get_module_name
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
logger = set_logger(get_module_name(__file__))
|
|
15
21
|
|
|
16
22
|
|
|
17
23
|
class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
|
|
@@ -25,23 +31,27 @@ class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
|
|
|
25
31
|
|
|
26
32
|
params_GRABBER = []
|
|
27
33
|
|
|
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
34
|
socket_types = ["GRABBER"]
|
|
33
35
|
params = comon_parameters + leco_parameters
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
self
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
live_mode_available = True
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
parent=None,
|
|
41
|
+
params_state=None,
|
|
42
|
+
grabber_type: str = "0D",
|
|
43
|
+
host: Optional[str] = None,
|
|
44
|
+
port: Optional[int] = None,
|
|
45
|
+
**kwargs,
|
|
46
|
+
) -> None:
|
|
47
|
+
DAQ_Viewer_base.__init__(self, parent=parent, params_state=params_state)
|
|
48
|
+
if host is not None:
|
|
49
|
+
self.settings["host"] = host
|
|
50
|
+
if port is not None:
|
|
51
|
+
self.settings["port"] = port
|
|
52
|
+
LECODirector.__init__(self, host=self.settings["host"], port=self.settings["port"])
|
|
53
|
+
|
|
54
|
+
self.register_binary_rpc_methods((self.set_data,))
|
|
45
55
|
|
|
46
56
|
self.client_type = "GRABBER"
|
|
47
57
|
self.x_axis = None
|
|
@@ -50,6 +60,7 @@ class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
|
|
|
50
60
|
self.grabber_type = grabber_type
|
|
51
61
|
self.ind_data = 0
|
|
52
62
|
self.data_mock = None
|
|
63
|
+
self.start_timer()
|
|
53
64
|
|
|
54
65
|
def ini_detector(self, controller=None):
|
|
55
66
|
"""
|
|
@@ -62,54 +73,23 @@ class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
|
|
|
62
73
|
--------
|
|
63
74
|
utility_classes.DAQ_TCP_server.init_server, get_xaxis, get_yaxis
|
|
64
75
|
"""
|
|
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
76
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
77
|
+
actor_name = self.settings["actor_name"]
|
|
78
|
+
if self.is_master:
|
|
79
|
+
self.controller = DetectorDirector(actor=actor_name,
|
|
80
|
+
communicator=self.communicator)
|
|
81
|
+
try:
|
|
82
|
+
self.controller.set_remote_name(self.communicator.full_name)
|
|
83
|
+
except TimeoutError:
|
|
84
|
+
logger.warning("Timeout setting remote name.")
|
|
85
|
+
else:
|
|
86
|
+
self.controller = controller
|
|
101
87
|
|
|
102
|
-
|
|
103
|
-
"""
|
|
104
|
-
Obtain the vertical axis of the image.
|
|
88
|
+
self.controller.get_settings()
|
|
105
89
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
Contains a vector of integer corresponding to the vertical camera pixels.
|
|
110
|
-
"""
|
|
111
|
-
pass
|
|
112
|
-
return self.y_axis
|
|
90
|
+
initialized = True
|
|
91
|
+
info = 'Viewer Director ready'
|
|
92
|
+
return info, initialized
|
|
113
93
|
|
|
114
94
|
def grab_data(self, Naverage=1, **kwargs):
|
|
115
95
|
"""
|
|
@@ -126,35 +106,20 @@ class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
|
|
|
126
106
|
--------
|
|
127
107
|
utility_classes.DAQ_TCP_server.process_cmds
|
|
128
108
|
"""
|
|
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
109
|
|
|
135
|
-
|
|
136
|
-
|
|
110
|
+
self.ind_grabbed = 0 # to keep track of the current image in the average
|
|
111
|
+
self.Naverage = Naverage
|
|
112
|
+
if kwargs.get('live', False):
|
|
113
|
+
self.controller.send_data_grab()
|
|
114
|
+
else:
|
|
115
|
+
self.controller.send_data_snap()
|
|
137
116
|
|
|
138
117
|
def stop(self):
|
|
139
|
-
"""
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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()
|
|
155
|
-
|
|
156
|
-
def set_data(self, data: Union[list, str, None],
|
|
157
|
-
additional_payload: Optional[list[bytes]]=None) -> None:
|
|
118
|
+
"""Stop grabbing."""
|
|
119
|
+
self.controller.stop_grab()
|
|
120
|
+
|
|
121
|
+
def set_data(self, data: Union[dict,list, str, float, None],
|
|
122
|
+
additional_payload: Optional[list[bytes]] = None) -> None:
|
|
158
123
|
"""
|
|
159
124
|
Set the grabbed data signal.
|
|
160
125
|
|
|
@@ -162,15 +127,37 @@ class DAQ_xDViewer_LECODirector(LECODirector, DAQ_Viewer_base):
|
|
|
162
127
|
|
|
163
128
|
:param data: If None, look for the additional object
|
|
164
129
|
"""
|
|
165
|
-
if
|
|
166
|
-
|
|
167
|
-
elif
|
|
168
|
-
|
|
130
|
+
if additional_payload:
|
|
131
|
+
dte = SerializableFactory().get_apply_deserializer(additional_payload[0])
|
|
132
|
+
elif data is not None:
|
|
133
|
+
axes = []
|
|
134
|
+
labels = []
|
|
135
|
+
multichannel = False
|
|
136
|
+
if isinstance(data, dict):
|
|
137
|
+
axes = [
|
|
138
|
+
Axis( label=axis.get('label', ''),
|
|
139
|
+
units=axis.get('units', ''),
|
|
140
|
+
data=np.array(axis.get('data', [])),
|
|
141
|
+
index=ind
|
|
142
|
+
) for ind, axis in enumerate(data.get('axes', []))
|
|
143
|
+
]
|
|
144
|
+
labels = data.get('labels', [])
|
|
145
|
+
multichannel = data.get('multichannel', False)
|
|
146
|
+
data = data.get('data', [])
|
|
147
|
+
if multichannel:
|
|
148
|
+
# data[0] may fail if data is empty, but it shouldn't happen
|
|
149
|
+
ndim = np.array(data[0]).ndim
|
|
150
|
+
data = [np.atleast_1d(d) for d in data]
|
|
151
|
+
else:
|
|
152
|
+
ndim = np.array(data).ndim
|
|
153
|
+
data = [np.atleast_1d(data)]
|
|
154
|
+
|
|
155
|
+
dfp = DataFromPlugins(self.controller.actor, data=data, axes=axes[:ndim], labels=labels)
|
|
156
|
+
dte = DataToExport('Copy', data=[dfp])
|
|
169
157
|
else:
|
|
170
|
-
raise
|
|
171
|
-
dte = deserializer.dte_deserialization()
|
|
158
|
+
raise ValueError("Can't set_data when data is None")
|
|
172
159
|
self.dte_signal.emit(dte)
|
|
173
160
|
|
|
174
161
|
|
|
175
162
|
if __name__ == '__main__':
|
|
176
|
-
main(__file__)
|
|
163
|
+
main(__file__, init=False)
|
|
@@ -10,8 +10,12 @@ 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.
|
|
14
|
-
from pymodaq.utils.leco.utils import
|
|
13
|
+
from pymodaq.utils.data import DataActuator
|
|
14
|
+
from pymodaq.utils.leco.utils import binary_serialization_to_kwargs, SerializableFactory
|
|
15
|
+
from pymodaq.utils.leco.rpc_method_definitions import GenericMethods, MoveMethods, ViewerMethods
|
|
16
|
+
|
|
17
|
+
from pymodaq_gui.parameter.utils import ParameterWithPath
|
|
18
|
+
|
|
15
19
|
|
|
16
20
|
|
|
17
21
|
class GenericDirector(Director):
|
|
@@ -19,31 +23,42 @@ class GenericDirector(Director):
|
|
|
19
23
|
|
|
20
24
|
def set_remote_name(self, name: Optional[str] = None):
|
|
21
25
|
"""Set the remote name of the Module (i.e. where it should send responses to)."""
|
|
22
|
-
self.ask_rpc(method=
|
|
26
|
+
self.ask_rpc(method=GenericMethods.SET_REMOTE_NAME, name=name or self.communicator.name)
|
|
23
27
|
|
|
24
28
|
def set_info(self, param: Parameter):
|
|
25
29
|
# It removes the first two parts (main_settings and detector_settings?)
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
pwp = ParameterWithPath(param, putils.get_param_path(param)[2:])
|
|
31
|
+
self.ask_rpc(method=GenericMethods.SET_INFO,
|
|
32
|
+
**binary_serialization_to_kwargs(pwp, data_key='parameter'))
|
|
28
33
|
|
|
29
|
-
def
|
|
30
|
-
self.ask_rpc(
|
|
34
|
+
def get_settings(self,) -> None:
|
|
35
|
+
self.ask_rpc(GenericMethods.GET_SETTINGS)
|
|
31
36
|
|
|
32
37
|
|
|
33
38
|
class DetectorDirector(GenericDirector):
|
|
34
|
-
def
|
|
35
|
-
self.ask_rpc(
|
|
39
|
+
def send_data_grab(self) -> None:
|
|
40
|
+
self.ask_rpc(ViewerMethods.GRAB)
|
|
41
|
+
|
|
42
|
+
def send_data_snap(self) -> None:
|
|
43
|
+
self.ask_rpc(ViewerMethods.SNAP)
|
|
44
|
+
|
|
45
|
+
def stop_grab(self) -> None:
|
|
46
|
+
self.ask_rpc(ViewerMethods.STOP)
|
|
36
47
|
|
|
37
48
|
|
|
38
49
|
class ActuatorDirector(GenericDirector):
|
|
39
|
-
def move_abs(self, position: Union[float, DataActuator]) -> None:
|
|
40
|
-
self.ask_rpc(
|
|
50
|
+
def move_abs(self, position: Union[list, float, DataActuator]) -> None:
|
|
51
|
+
self.ask_rpc(
|
|
52
|
+
MoveMethods.MOVE_ABS, **binary_serialization_to_kwargs(position, data_key="position")
|
|
53
|
+
)
|
|
41
54
|
|
|
42
|
-
def move_rel(self, position: Union[float, DataActuator]) -> None:
|
|
43
|
-
self.ask_rpc(
|
|
55
|
+
def move_rel(self, position: Union[list, float, DataActuator]) -> None:
|
|
56
|
+
self.ask_rpc(
|
|
57
|
+
MoveMethods.MOVE_REL, **binary_serialization_to_kwargs(position, data_key="position")
|
|
58
|
+
)
|
|
44
59
|
|
|
45
60
|
def move_home(self) -> None:
|
|
46
|
-
self.ask_rpc(
|
|
61
|
+
self.ask_rpc(MoveMethods.MOVE_HOME)
|
|
47
62
|
|
|
48
63
|
def get_actuator_value(self) -> None:
|
|
49
64
|
"""Request that the actuator value is sent later on.
|
|
@@ -51,8 +66,9 @@ class ActuatorDirector(GenericDirector):
|
|
|
51
66
|
Later the `set_data` method will be called.
|
|
52
67
|
"""
|
|
53
68
|
# according to DAQ_Move, this supersedes "check_position"
|
|
54
|
-
self.ask_rpc(
|
|
69
|
+
self.ask_rpc(MoveMethods.GET_ACTUATOR_VALUE)
|
|
55
70
|
|
|
56
71
|
def stop_motion(self,) -> None:
|
|
57
72
|
# not implemented in DAQ_Move!
|
|
58
|
-
self.ask_rpc(
|
|
73
|
+
self.ask_rpc(MoveMethods.STOP_MOTION)
|
|
74
|
+
|
|
@@ -1,21 +1,49 @@
|
|
|
1
|
+
|
|
1
2
|
import random
|
|
2
|
-
from typing import Callable, Sequence, List
|
|
3
3
|
|
|
4
|
+
from pyleco.core import COORDINATOR_PORT
|
|
4
5
|
from pymodaq_utils.enums import StrEnum
|
|
5
|
-
from typing import Callable, Sequence, List, Optional, Union
|
|
6
|
+
from typing import Callable, cast, Sequence, List, Optional, Union
|
|
6
7
|
|
|
8
|
+
from pyleco.json_utils.errors import JSONRPCError, RECEIVER_UNKNOWN
|
|
7
9
|
import pymodaq_gui.parameter.utils as putils
|
|
10
|
+
from pymodaq_utils.config import Config
|
|
8
11
|
# object used to send info back to the main thread:
|
|
9
12
|
from pymodaq_utils.utils import ThreadCommand
|
|
10
13
|
from pymodaq_gui.parameter import Parameter
|
|
14
|
+
from pymodaq_gui.parameter import ioxml
|
|
15
|
+
from pymodaq_gui.parameter.utils import ParameterWithPath
|
|
16
|
+
from qtpy.QtCore import QTimer
|
|
11
17
|
|
|
12
18
|
from pymodaq.utils.leco.director_utils import GenericDirector
|
|
13
19
|
from pymodaq.utils.leco.pymodaq_listener import PymodaqListener
|
|
20
|
+
from pymodaq.utils.leco.rpc_method_definitions import GenericDirectorMethods, MoveDirectorMethods
|
|
21
|
+
from pymodaq_utils.serialize.factory import SerializableFactory
|
|
22
|
+
from pymodaq.control_modules.thread_commands import ThreadStatus, ThreadStatusMove
|
|
23
|
+
|
|
24
|
+
config = Config()
|
|
25
|
+
|
|
26
|
+
class DirectorCommands(StrEnum):
|
|
27
|
+
SET_SETTINGS = GenericDirectorMethods.SET_DIRECTOR_SETTINGS
|
|
28
|
+
SET_INFO = GenericDirectorMethods.SET_DIRECTOR_INFO
|
|
29
|
+
|
|
30
|
+
SEND_POSITION = MoveDirectorMethods.SEND_POSITION # to display the actor position
|
|
31
|
+
SET_MOVE_DONE = MoveDirectorMethods.SET_MOVE_DONE
|
|
32
|
+
SET_UNITS = MoveDirectorMethods.SET_UNITS # to set units accordingly to the one of the actor
|
|
14
33
|
|
|
15
34
|
|
|
35
|
+
class DirectorReceivedCommands(StrEnum):
|
|
36
|
+
MOVE_DONE = ThreadStatusMove.MOVE_DONE
|
|
37
|
+
GET_ACTUATOR_VALUE = ThreadStatusMove.GET_ACTUATOR_VALUE
|
|
38
|
+
|
|
39
|
+
config = Config()
|
|
40
|
+
|
|
16
41
|
leco_parameters = [
|
|
17
42
|
{'title': 'Actor name:', 'name': 'actor_name', 'type': 'str', 'value': "actor_name",
|
|
18
43
|
'tip': 'Name of the actor plugin to communicate with.'},
|
|
44
|
+
{'title': 'Coordinator Host:', 'name': 'host', 'type': 'str', 'value': config('network', "leco-server", "host")},
|
|
45
|
+
{'title': 'Coordinator Port:', 'name': 'port', 'type': 'int', 'value': config('network', "leco-server", "port")},
|
|
46
|
+
{'title': 'Settings PyMoDAQ Client:', 'name': 'settings_client', 'type': 'group', 'children': []},
|
|
19
47
|
]
|
|
20
48
|
|
|
21
49
|
|
|
@@ -23,45 +51,40 @@ class LECODirector:
|
|
|
23
51
|
"""
|
|
24
52
|
This is a mixin for a Control module to direct another, remote module (analogous to TCP Server).
|
|
25
53
|
|
|
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
|
|
54
|
+
|
|
37
55
|
"""
|
|
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
56
|
|
|
44
57
|
controller: GenericDirector
|
|
45
58
|
settings: Parameter
|
|
59
|
+
_title: str
|
|
46
60
|
|
|
47
|
-
def __init__(self, **kwargs) -> None:
|
|
48
|
-
super().__init__(**kwargs)
|
|
61
|
+
def __init__(self, host: str = 'localhost', port : int = COORDINATOR_PORT, **kwargs) -> None:
|
|
49
62
|
|
|
50
63
|
name = f'{self._title}_{random.randrange(0, 10000)}_director'
|
|
51
|
-
|
|
52
|
-
self.listener = PymodaqListener(name=name)
|
|
64
|
+
|
|
65
|
+
self.listener = PymodaqListener(name=name, host=host, port=port)
|
|
53
66
|
self.listener.start_listen()
|
|
67
|
+
|
|
54
68
|
self.communicator = self.listener.get_communicator()
|
|
69
|
+
|
|
70
|
+
#registering rpc methods common to all Directors
|
|
55
71
|
self.register_rpc_methods((
|
|
56
|
-
self.
|
|
72
|
+
self.set_director_settings,
|
|
73
|
+
))
|
|
74
|
+
self.register_binary_rpc_methods((
|
|
75
|
+
self.set_director_info,
|
|
57
76
|
))
|
|
58
77
|
|
|
78
|
+
def register_binary_rpc_methods(self, methods: Sequence[Callable]) -> None:
|
|
79
|
+
for method in methods:
|
|
80
|
+
self.listener.register_binary_rpc_method(method, accept_binary_input=True)
|
|
81
|
+
|
|
59
82
|
def register_rpc_methods(self, methods: Sequence[Callable]) -> None:
|
|
60
83
|
for method in methods:
|
|
61
84
|
self.communicator.register_rpc_method(method=method)
|
|
62
85
|
|
|
63
|
-
def commit_settings(self, param
|
|
64
|
-
|
|
86
|
+
def commit_settings(self, param) -> None:
|
|
87
|
+
self.commit_leco_settings(param=param)
|
|
65
88
|
|
|
66
89
|
def commit_leco_settings(self, param: Parameter) -> None:
|
|
67
90
|
if param.name() == "actor_name":
|
|
@@ -70,8 +93,35 @@ class LECODirector:
|
|
|
70
93
|
self.controller.set_info(param=param)
|
|
71
94
|
|
|
72
95
|
def close(self) -> None:
|
|
96
|
+
""" Clear the content of the settings_clients setting"""
|
|
97
|
+
self.settings.child('settings_client').clearChildren()
|
|
73
98
|
self.listener.stop_listen()
|
|
74
99
|
|
|
100
|
+
def start_timer(self) -> None:
|
|
101
|
+
"""To be called in child classes."""
|
|
102
|
+
self.timer = QTimer()
|
|
103
|
+
self.timer.timeout.connect(self.check_actor_connection)
|
|
104
|
+
try:
|
|
105
|
+
# cast is used by the type checker to infer the returned type (when many are possible)
|
|
106
|
+
timeout = cast(int, config("network", "leco-server", "heartbeat-timeout"))
|
|
107
|
+
except KeyError:
|
|
108
|
+
timeout = 1000
|
|
109
|
+
self.timer.start(timeout) # in milli seconds
|
|
110
|
+
|
|
111
|
+
def check_actor_connection(self) -> None:
|
|
112
|
+
try:
|
|
113
|
+
self.controller.ask_rpc("pong", timeout=0.1)
|
|
114
|
+
except JSONRPCError as exc:
|
|
115
|
+
if exc.rpc_error.code == RECEIVER_UNKNOWN.code:
|
|
116
|
+
self.emit_status(ThreadCommand(ThreadStatus.UPDATE_UI, "do_init", args=[False]))
|
|
117
|
+
else:
|
|
118
|
+
self.emit_status(
|
|
119
|
+
ThreadCommand(
|
|
120
|
+
ThreadStatus.UPDATE_STATUS,
|
|
121
|
+
f"Connection error to actor: {exc.rpc_error.message}",
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
|
|
75
125
|
def stop(self):
|
|
76
126
|
"""
|
|
77
127
|
not implemented.
|
|
@@ -85,5 +135,32 @@ class LECODirector:
|
|
|
85
135
|
super().emit_status(status=status) # type: ignore
|
|
86
136
|
|
|
87
137
|
# Methods accessible via remote calls
|
|
88
|
-
def
|
|
89
|
-
|
|
138
|
+
def set_director_info(self,
|
|
139
|
+
parameter: Optional[Union[float, str]],
|
|
140
|
+
additional_payload: Optional[List[bytes]] = None,
|
|
141
|
+
) -> None:
|
|
142
|
+
""" Write the value of a param updated from the actor to here in the
|
|
143
|
+
Parameter with path: ('move_settings', 'settings_client')
|
|
144
|
+
"""
|
|
145
|
+
GenericDirectorMethods.SET_DIRECTOR_INFO # defined here
|
|
146
|
+
assert additional_payload
|
|
147
|
+
# cast is used by the type checker to infer the returned type (when many are possible)
|
|
148
|
+
param = cast(
|
|
149
|
+
ParameterWithPath, SerializableFactory().get_apply_deserializer(additional_payload[0])
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
path = ['settings_client']
|
|
154
|
+
path.extend(param.path[1:])
|
|
155
|
+
|
|
156
|
+
self.settings.child(*path).setValue(param.value())
|
|
157
|
+
except Exception as e:
|
|
158
|
+
print(f'could not set the param {param} in the director:\n'
|
|
159
|
+
f'{str(e)}')
|
|
160
|
+
|
|
161
|
+
def set_director_settings(self, settings: bytes):
|
|
162
|
+
""" Get the content of the actor settings to pe populated in this plugin
|
|
163
|
+
'settings_client' parameter"""
|
|
164
|
+
GenericDirectorMethods.SET_DIRECTOR_INFO # defined here
|
|
165
|
+
params = ioxml.XML_string_to_parameter(settings)
|
|
166
|
+
self.settings.child('settings_client').addChildren(params)
|