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.

Files changed (92) hide show
  1. pymodaq/__init__.py +23 -11
  2. pymodaq/control_modules/__init__.py +1 -0
  3. pymodaq/control_modules/daq_move.py +458 -246
  4. pymodaq/control_modules/daq_move_ui/__init__.py +0 -0
  5. pymodaq/control_modules/daq_move_ui/factory.py +48 -0
  6. pymodaq/control_modules/{daq_move_ui.py → daq_move_ui/ui_base.py} +168 -210
  7. pymodaq/control_modules/daq_move_ui/uis/__init__.py +0 -0
  8. pymodaq/control_modules/daq_move_ui/uis/binary.py +139 -0
  9. pymodaq/control_modules/daq_move_ui/uis/original.py +120 -0
  10. pymodaq/control_modules/daq_move_ui/uis/relative.py +124 -0
  11. pymodaq/control_modules/daq_move_ui/uis/simple.py +126 -0
  12. pymodaq/control_modules/daq_viewer.py +113 -101
  13. pymodaq/control_modules/daq_viewer_ui.py +41 -31
  14. pymodaq/control_modules/mocks.py +2 -2
  15. pymodaq/control_modules/move_utility_classes.py +113 -41
  16. pymodaq/control_modules/thread_commands.py +137 -0
  17. pymodaq/control_modules/ui_utils.py +72 -0
  18. pymodaq/control_modules/utils.py +107 -63
  19. pymodaq/control_modules/viewer_utility_classes.py +13 -17
  20. pymodaq/dashboard.py +1294 -625
  21. pymodaq/examples/qt_less_standalone_module.py +48 -11
  22. pymodaq/extensions/__init__.py +8 -3
  23. pymodaq/extensions/adaptive/__init__.py +2 -0
  24. pymodaq/extensions/adaptive/adaptive_optimization.py +179 -0
  25. pymodaq/extensions/adaptive/loss_function/_1d_loss_functions.py +73 -0
  26. pymodaq/extensions/adaptive/loss_function/_2d_loss_functions.py +73 -0
  27. pymodaq/extensions/adaptive/loss_function/__init__.py +3 -0
  28. pymodaq/extensions/adaptive/loss_function/loss_factory.py +110 -0
  29. pymodaq/extensions/adaptive/utils.py +123 -0
  30. pymodaq/extensions/bayesian/__init__.py +1 -1
  31. pymodaq/extensions/bayesian/acquisition/__init__.py +2 -0
  32. pymodaq/extensions/bayesian/acquisition/acquisition_function_factory.py +80 -0
  33. pymodaq/extensions/bayesian/acquisition/base_acquisition_function.py +105 -0
  34. pymodaq/extensions/bayesian/bayesian_optimization.py +143 -0
  35. pymodaq/extensions/bayesian/utils.py +71 -297
  36. pymodaq/extensions/daq_logger/daq_logger.py +7 -12
  37. pymodaq/extensions/daq_logger/h5logging.py +1 -1
  38. pymodaq/extensions/daq_scan.py +30 -55
  39. pymodaq/extensions/data_mixer/__init__.py +0 -0
  40. pymodaq/extensions/data_mixer/daq_0Dviewer_DataMixer.py +97 -0
  41. pymodaq/extensions/data_mixer/data_mixer.py +262 -0
  42. pymodaq/extensions/data_mixer/model.py +108 -0
  43. pymodaq/extensions/data_mixer/models/__init__.py +0 -0
  44. pymodaq/extensions/data_mixer/models/equation_model.py +91 -0
  45. pymodaq/extensions/data_mixer/models/gaussian_fit_model.py +65 -0
  46. pymodaq/extensions/data_mixer/parser.py +53 -0
  47. pymodaq/extensions/data_mixer/utils.py +23 -0
  48. pymodaq/extensions/h5browser.py +3 -34
  49. pymodaq/extensions/optimizers_base/__init__.py +0 -0
  50. pymodaq/extensions/optimizers_base/optimizer.py +1016 -0
  51. pymodaq/extensions/optimizers_base/thread_commands.py +22 -0
  52. pymodaq/extensions/optimizers_base/utils.py +427 -0
  53. pymodaq/extensions/pid/actuator_controller.py +3 -2
  54. pymodaq/extensions/pid/daq_move_PID.py +107 -30
  55. pymodaq/extensions/pid/pid_controller.py +613 -287
  56. pymodaq/extensions/pid/utils.py +8 -5
  57. pymodaq/extensions/utils.py +17 -2
  58. pymodaq/resources/config_template.toml +57 -0
  59. pymodaq/resources/preset_default.xml +1 -1
  60. pymodaq/utils/config.py +13 -4
  61. pymodaq/utils/daq_utils.py +14 -0
  62. pymodaq/utils/data.py +1 -0
  63. pymodaq/utils/gui_utils/loader_utils.py +25 -15
  64. pymodaq/utils/h5modules/module_saving.py +134 -22
  65. pymodaq/utils/leco/daq_move_LECODirector.py +123 -84
  66. pymodaq/utils/leco/daq_xDviewer_LECODirector.py +84 -97
  67. pymodaq/utils/leco/director_utils.py +32 -16
  68. pymodaq/utils/leco/leco_director.py +104 -27
  69. pymodaq/utils/leco/pymodaq_listener.py +186 -97
  70. pymodaq/utils/leco/rpc_method_definitions.py +43 -0
  71. pymodaq/utils/leco/utils.py +25 -25
  72. pymodaq/utils/managers/batchscan_manager.py +12 -11
  73. pymodaq/utils/managers/modules_manager.py +74 -33
  74. pymodaq/utils/managers/overshoot_manager.py +11 -10
  75. pymodaq/utils/managers/preset_manager.py +100 -64
  76. pymodaq/utils/managers/preset_manager_utils.py +163 -107
  77. pymodaq/utils/managers/remote_manager.py +21 -16
  78. pymodaq/utils/scanner/scan_factory.py +18 -4
  79. pymodaq/utils/scanner/scan_selector.py +1 -3
  80. pymodaq/utils/scanner/scanner.py +35 -6
  81. pymodaq/utils/scanner/scanners/_1d_scanners.py +15 -46
  82. pymodaq/utils/scanner/scanners/_2d_scanners.py +21 -68
  83. pymodaq/utils/scanner/scanners/sequential.py +50 -31
  84. pymodaq/utils/scanner/scanners/tabular.py +45 -28
  85. {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/METADATA +7 -6
  86. pymodaq-5.1.0.dist-info/RECORD +154 -0
  87. {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/entry_points.txt +0 -2
  88. pymodaq/extensions/bayesian/bayesian_optimisation.py +0 -685
  89. pymodaq/utils/leco/desktop.ini +0 -2
  90. pymodaq-5.0.17.dist-info/RECORD +0 -121
  91. {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/WHEEL +0 -0
  92. {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,8 @@
1
1
  import numbers
2
2
 
3
+ from abc import abstractmethod
3
4
  from time import perf_counter
4
- from typing import Union, List, Dict, TYPE_CHECKING, Optional
5
+ from typing import Union, List, Dict, TYPE_CHECKING, Optional, TypeVar
5
6
  from numbers import Number
6
7
  from collections.abc import Iterable
7
8
 
@@ -34,11 +35,19 @@ from pymodaq_utils.serialize.serializer_legacy import DeSerializer, Serializer
34
35
  from pymodaq import Unit
35
36
  from pint.errors import OffsetUnitCalculusError
36
37
 
38
+ from pymodaq.control_modules.thread_commands import ThreadStatus, ThreadStatusMove
39
+ from pymodaq.utils.config import Config as ControlModulesConfig
40
+ from pymodaq.control_modules.daq_move_ui.factory import ActuatorUIFactory
41
+
37
42
  if TYPE_CHECKING:
38
43
  from pymodaq.control_modules.daq_move import DAQ_Move_Hardware
39
44
 
40
45
  logger = set_logger(get_module_name(__file__))
41
- config = configmod.Config()
46
+
47
+ config_utils = configmod.Config()
48
+ config = ControlModulesConfig()
49
+
50
+ HardwareController = TypeVar("HardwareController")
42
51
 
43
52
 
44
53
  def check_units(dwa: DataActuator, units: str):
@@ -115,6 +124,7 @@ class MoveCommand:
115
124
  the value the move should reach
116
125
 
117
126
  """
127
+
118
128
  def __init__(self, move_type, value=0):
119
129
  if move_type not in MOVE_COMMANDS:
120
130
  raise ValueError(f'The allowed move types fro an actuator are {MOVE_COMMANDS}')
@@ -126,7 +136,6 @@ def comon_parameters_fun(is_multiaxes=False, axes_names=None,
126
136
  axis_names: Union[List, Dict] = [],
127
137
  master=True,
128
138
  epsilon: float = config('actuator', 'epsilon_default')):
129
-
130
139
  """Function returning the common and mandatory parameters that should be on the actuator plugin level
131
140
 
132
141
  Parameters
@@ -166,7 +175,7 @@ def comon_parameters_fun(is_multiaxes=False, axes_names=None,
166
175
  'default': 0},
167
176
  {'title': 'Status:', 'name': 'multi_status', 'type': 'list',
168
177
  'value': 'Master' if master else 'Slave', 'limits': ['Master', 'Slave']},
169
- {'title': 'Axis:', 'name': 'axis', 'type': 'list', 'limits': axis_names,
178
+ {'title': 'Axis:', 'name': 'axis', 'type': 'list', 'limits': axis_names.copy(),
170
179
  'value': axis_name},
171
180
  ]},
172
181
  ] + comon_parameters(epsilon)
@@ -177,18 +186,22 @@ params = [
177
186
  {'title': 'Main Settings:', 'name': 'main_settings', 'type': 'group', 'children': [
178
187
  {'title': 'Actuator type:', 'name': 'move_type', 'type': 'str', 'value': '', 'readonly': True},
179
188
  {'title': 'Actuator name:', 'name': 'module_name', 'type': 'str', 'value': '', 'readonly': True},
189
+ {'title': 'UI type:', 'name': 'ui_type', 'type': 'list',
190
+ 'value': config('actuator', 'ui') if config('actuator', 'ui') in ActuatorUIFactory.keys() else
191
+ ActuatorUIFactory.keys()[0],
192
+ 'limits': ActuatorUIFactory.keys()},
180
193
  {'title': 'Plugin Config:', 'name': 'plugin_config', 'type': 'bool_push', 'label': 'Show Config', },
181
194
 
182
195
  {'title': 'Refresh value (ms):', 'name': 'refresh_timeout', 'type': 'int',
183
- 'value': config('actuator', 'refresh_timeout_ms')},
196
+ 'value': config('actuator', 'refresh_timeout_ms')},
184
197
  {'title': 'TCP/IP options:', 'name': 'tcpip', 'type': 'group', 'visible': True, 'expanded': False,
185
198
  'children': [
186
199
  {'title': 'Connect to server:', 'name': 'connect_server', 'type': 'bool_push', 'label': 'Connect',
187
200
  'value': False},
188
201
  {'title': 'Connected?:', 'name': 'tcp_connected', 'type': 'led', 'value': False},
189
202
  {'title': 'IP address:', 'name': 'ip_address', 'type': 'str',
190
- 'value': config('network', 'tcp-server', 'ip')},
191
- {'title': 'Port:', 'name': 'port', 'type': 'int', 'value': config('network', 'tcp-server', 'port')},
203
+ 'value': config_utils('network', 'tcp-server', 'ip')},
204
+ {'title': 'Port:', 'name': 'port', 'type': 'int', 'value': config_utils('network', 'tcp-server', 'port')},
192
205
  ]},
193
206
  {'title': 'LECO options:', 'name': 'leco', 'type': 'group', 'visible': True, 'expanded': False,
194
207
  'children': [
@@ -196,8 +209,9 @@ params = [
196
209
  'value': False},
197
210
  {'title': 'Connected?:', 'name': 'leco_connected', 'type': 'led', 'value': False},
198
211
  {'title': 'Name', 'name': 'leco_name', 'type': 'str', 'value': "", 'default': ""},
199
- {'title': 'Host:', 'name': 'host', 'type': 'str', 'value': config('network', "leco-server", "host"), "default": "localhost"},
200
- {'title': 'Port:', 'name': 'port', 'type': 'int', 'value': config('network', 'leco-server', 'port')},
212
+ {'title': 'Host:', 'name': 'host', 'type': 'str', 'value': config_utils('network', "leco-server", "host"),
213
+ "default": "localhost"},
214
+ {'title': 'Port:', 'name': 'port', 'type': 'int', 'value': config_utils('network', 'leco-server', 'port')},
201
215
  ]},
202
216
  ]},
203
217
  {'title': 'Actuator Settings:', 'name': 'move_settings', 'type': 'group'}
@@ -274,14 +288,14 @@ class DAQ_Move_base(QObject):
274
288
  _epsilons: Union[float, List[float], Dict[str, float]] = None
275
289
  _epsilon = 1.0 # deprecated
276
290
 
277
-
278
291
  params = []
279
292
 
280
293
  data_actuator_type = DataActuatorType.float
281
- data_shape = (1, ) # expected shape of the underlying actuator's value (in general a float so shape = (1, ))
294
+ data_shape = (1,) # expected shape of the underlying actuator's value (in general a float so shape = (1, ))
282
295
 
283
296
  def __init__(self, parent: Optional['DAQ_Move_Hardware'] = None,
284
- params_state: Optional[dict] = None):
297
+ params_state: Optional[dict] = None,
298
+ **kwargs):
285
299
  QObject.__init__(self) # to make sure this is the parent class
286
300
  self.move_is_done = False
287
301
  self.parent = parent
@@ -307,7 +321,10 @@ class DAQ_Move_base(QObject):
307
321
  self._title = "myactuator"
308
322
 
309
323
  self._axis_units: Union[Dict[str, str], List[str]] = None
310
- self.axis_units = self._controller_units
324
+ if isinstance(self._controller_units, str):
325
+ self.axis_units = self._controller_units
326
+ else:
327
+ self.axis_units = self._controller_units.copy()
311
328
  if self._epsilons is None:
312
329
  self._epsilons = self._epsilon
313
330
  self.epsilons = self._epsilons
@@ -341,7 +358,7 @@ class DAQ_Move_base(QObject):
341
358
  def axis_unit(self, unit: str):
342
359
  self.axis_units[self.axis_index_key] = unit
343
360
  self.settings.child('units').setValue(unit)
344
- self.emit_status(ThreadCommand('units', unit))
361
+ self.emit_status(ThreadCommand(ThreadStatusMove.UNITS, unit))
345
362
 
346
363
  @property
347
364
  def axis_units(self) -> Union[List[str], Dict[str, str]]:
@@ -436,6 +453,8 @@ class DAQ_Move_base(QObject):
436
453
  return self.settings['multiaxes', 'axis']
437
454
  elif isinstance(limits, dict):
438
455
  return find_keys_from_val(limits, val=self.settings['multiaxes', 'axis'])[0]
456
+ else:
457
+ return ''
439
458
 
440
459
  @axis_name.setter
441
460
  def axis_name(self, name: str):
@@ -495,7 +514,12 @@ class DAQ_Move_base(QObject):
495
514
  """ To be subclassed, in order to init specific attributes needed by the real implementation"""
496
515
  self.controller = None
497
516
 
498
- def ini_stage_init(self, old_controller=None, new_controller=None, slave_controller=None):
517
+ def ini_stage_init(
518
+ self,
519
+ old_controller: Optional[HardwareController] = None,
520
+ new_controller: Optional[HardwareController] = None,
521
+ slave_controller: Optional[HardwareController] = None,
522
+ ) -> Optional[HardwareController]:
499
523
  """Manage the Master/Slave controller issue
500
524
 
501
525
  First initialize the status dictionary
@@ -624,35 +648,36 @@ class DAQ_Move_base(QObject):
624
648
  position = self.settings['bounds', 'min_bound']
625
649
  return position
626
650
 
651
+ @abstractmethod
627
652
  def get_actuator_value(self):
628
653
  if hasattr(self, 'check_position'):
629
654
  deprecation_msg('check_position method in plugins is deprecated, use get_actuator_value',3)
630
- return self.check_position()
655
+ return self.check_position() # type: ignore
631
656
  else:
632
657
  raise NotImplementedError
633
658
 
634
-
635
- def close(self):
659
+ @abstractmethod
660
+ def close(self) -> None:
636
661
  raise NotImplementedError
637
662
 
638
663
  def move_abs(self, value: Union[float, DataActuator]):
639
664
  if hasattr(self, 'move_Abs'):
640
665
  deprecation_msg('move_Abs method in plugins is deprecated, use move_abs', 3)
641
- self.move_Abs(value)
666
+ self.move_Abs(value) # type: ignore
642
667
  else:
643
668
  raise NotImplementedError
644
669
 
645
670
  def move_rel(self, value: Union[float, DataActuator]):
646
671
  if hasattr(self, 'move_Rel'):
647
672
  deprecation_msg('move_Rel method in plugins is deprecated, use move_rel', 3)
648
- self.move_Rel(value)
673
+ self.move_Rel(value) # type: ignore
649
674
  else:
650
675
  raise NotImplementedError
651
676
 
652
677
  def move_home(self, value: Union[float, DataActuator]):
653
678
  if hasattr(self, 'move_Home'):
654
679
  deprecation_msg('move_Home method in plugins is deprecated, use move_home', 3)
655
- self.move_Home()
680
+ self.move_Home() # type: ignore
656
681
  else:
657
682
  raise NotImplementedError
658
683
 
@@ -668,7 +693,7 @@ class DAQ_Move_base(QObject):
668
693
  def emit_value(self, pos: DataActuator):
669
694
  """Convenience method to emit the current actuator value back to the UI"""
670
695
 
671
- self.emit_status(ThreadCommand('get_actuator_value', [pos]))
696
+ self.emit_status(ThreadCommand(ThreadStatusMove.GET_ACTUATOR_VALUE, pos))
672
697
 
673
698
  def commit_settings(self, param: Parameter):
674
699
  """
@@ -678,7 +703,8 @@ class DAQ_Move_base(QObject):
678
703
  def commit_common_settings(self, param):
679
704
  pass
680
705
 
681
- def move_done(self, position: Optional[DataActuator] = None): # the position argument is just there to match some signature of child classes
706
+ def move_done(self, position: Optional[
707
+ DataActuator] = None): # the position argument is just there to match some signature of child classes
682
708
  """
683
709
  | Emit a move done signal transmitting the float position to hardware.
684
710
  | The position argument is just there to match some signature of child classes.
@@ -709,7 +735,8 @@ class DAQ_Move_base(QObject):
709
735
  --------
710
736
  DAQ_utils.ThreadCommand, move_done
711
737
  """
712
- if 'TCPServer' not in self.__class__.__name__:
738
+ if not ('TCPServer' in self.__class__.__name__ or
739
+ 'LECODirector' in self.__class__.__name__):
713
740
  self.start_time = perf_counter()
714
741
  if self.ispolling:
715
742
  self.poll_timer.start()
@@ -729,7 +756,24 @@ class DAQ_Move_base(QObject):
729
756
  logger.debug(f'Current position: {self._current_value}')
730
757
  self.move_done(self._current_value)
731
758
 
732
- def _condition_to_reach_target(self) -> bool:
759
+ def _condition_to_reach_target(self, check_absolute_difference=True,) -> bool:
760
+ """Implement the condition for exiting the polling mechanism and specifying that the
761
+ target value has been reached
762
+
763
+ Returns
764
+ -------
765
+ bool: if True, PyMoDAQ considers the target value has been reached
766
+ See Also
767
+ --------
768
+ absolute_difference_condition_to_reach_target
769
+ user_condition_to_reach_target
770
+ """
771
+ cond = True
772
+ if check_absolute_difference:
773
+ cond = self.absolute_difference_condition_to_reach_target()
774
+ return cond and self.user_condition_to_reach_target()
775
+
776
+ def absolute_difference_condition_to_reach_target(self) -> bool:
733
777
  """ Implement the condition for exiting the polling mechanism and specifying that the
734
778
  target value has been reached
735
779
 
@@ -756,7 +800,7 @@ class DAQ_Move_base(QObject):
756
800
  else:
757
801
  raise e
758
802
 
759
- return (epsilon_calculated < self.epsilon) and self.user_condition_to_reach_target()
803
+ return (epsilon_calculated < self.epsilon)
760
804
 
761
805
  def user_condition_to_reach_target(self) -> bool:
762
806
  """ Implement a user defined condition for exiting the polling mechanism and specifying
@@ -779,7 +823,7 @@ class DAQ_Move_base(QObject):
779
823
 
780
824
  logger.debug(f'Check move_is_done: {self.move_is_done}')
781
825
  if self.move_is_done:
782
- self.emit_status(ThreadCommand('Move has been stopped', ))
826
+ self.emit_status(ThreadCommand(ThreadStatus.UPDATE_STATUS, 'Move has been stopped', ))
783
827
  logger.info('Move has been stopped')
784
828
  self.current_value = self.get_actuator_value()
785
829
  self.emit_value(self._current_value)
@@ -787,7 +831,7 @@ class DAQ_Move_base(QObject):
787
831
 
788
832
  if perf_counter() - self.start_time >= self.settings['timeout']:
789
833
  self.poll_timer.stop()
790
- self.emit_status(ThreadCommand('raise_timeout', ))
834
+ self.emit_status(ThreadCommand(ThreadStatus.RAISE_TIMEOUT, ))
791
835
  logger.info('Timeout activated')
792
836
  else:
793
837
  self.poll_timer.stop()
@@ -804,17 +848,19 @@ class DAQ_Move_base(QObject):
804
848
  for param, change, data in changes:
805
849
  path = self.settings.childPath(param)
806
850
  if change == 'childAdded':
807
- self.emit_status(ThreadCommand('update_settings',
851
+ self.emit_status(ThreadCommand(ThreadStatus.UPDATE_SETTINGS,
808
852
  [self.parent_parameters_path + path, [data[0].saveState(), data[1]],
809
853
  change])) # send parameters values/limits back to the GUI. Send kind of a copy back the GUI otherwise the child reference will be the same in both th eUI and the plugin so one of them will be removed
810
854
  elif change == 'value' or change == 'limits' or change == 'options':
811
- self.emit_status(ThreadCommand('update_settings', [self.parent_parameters_path + path, data,
812
- change])) # send parameters values/limits back to the GUI
855
+ self.emit_status(ThreadCommand(ThreadStatus.UPDATE_SETTINGS,
856
+ [self.parent_parameters_path + path, data,
857
+ change])) # send parameters values/limits back to the GUI
813
858
  elif change == 'parent':
814
859
  pass
815
860
  elif change == 'limits':
816
- self.emit_status(ThreadCommand('update_settings', [self.parent_parameters_path + path, data,
817
- change]))
861
+ self.emit_status(ThreadCommand(ThreadStatus.UPDATE_SETTINGS,
862
+ [self.parent_parameters_path + path, data,
863
+ change]))
818
864
 
819
865
  def get_position_with_scaling(self, pos: DataActuator) -> DataActuator:
820
866
  """ Get the current position from the hardware with scaling conversion.
@@ -868,12 +914,14 @@ class DAQ_Move_base(QObject):
868
914
  except ValueError:
869
915
  apply_settings = False
870
916
  elif change == 'parent':
871
- children = putils.get_param_from_name(self.settings, param.name())
872
-
873
- if children is not None:
874
- path = putils.get_param_path(children)
875
- self.settings.child(*path[1:-1]).removeChild(children)
917
+ try:
918
+ children = putils.get_param_from_name(self.settings, param.name())
876
919
 
920
+ if children is not None:
921
+ path = putils.get_param_path(children)
922
+ self.settings.child(*path[1:-1]).removeChild(children)
923
+ except IndexError:
924
+ logger.debug(f'Could not remove children from {param.name()}')
877
925
  self.settings.sigTreeStateChanged.connect(self.send_param_status)
878
926
  if apply_settings:
879
927
  self.commit_common_settings(param)
@@ -884,6 +932,29 @@ class DAQ_Move_base(QObject):
884
932
  elif param.name() == 'epsilon':
885
933
  self.epsilon = param.value()
886
934
 
935
+ # abstract methods to be overwritten by the concrete implementations
936
+ @abstractmethod
937
+ def ini_stage(self, controller: Optional[HardwareController] = None) -> tuple[str, bool]:
938
+ """Actuator communication initialization
939
+
940
+ Parameters
941
+ ----------
942
+ controller: (object)
943
+ custom object of a PyMoDAQ plugin (Slave case). None if only one actuator by controller (Master case)
944
+
945
+ Returns
946
+ -------
947
+ info: str
948
+ initialized: bool
949
+ False if initialization failed otherwise True
950
+ """
951
+ pass
952
+
953
+ @abstractmethod
954
+ def stop_motion(self, value: DataActuator) -> None:
955
+ """Stop the actuator and emit move_done signal."""
956
+ pass
957
+
887
958
 
888
959
  class DAQ_Move_TCP_server(DAQ_Move_base, TCPServer):
889
960
  """
@@ -933,20 +1004,21 @@ class DAQ_Move_TCP_server(DAQ_Move_base, TCPServer):
933
1004
 
934
1005
  pos = self.get_position_with_scaling(pos)
935
1006
  self._current_value = pos
936
- self.emit_status(ThreadCommand('get_actuator_value', pos))
1007
+ self.emit_status(ThreadCommand(ThreadStatusMove.GET_ACTUATOR_VALUE, pos))
937
1008
 
938
1009
  elif command == 'move_done':
939
1010
  pos = DeSerializer(sock).dwa_deserialization()
940
1011
  pos = self.get_position_with_scaling(pos)
941
1012
  self._current_value = pos
942
- self.emit_status(ThreadCommand('move_done', pos))
1013
+ self.emit_status(ThreadCommand(ThreadStatusMove.MOVE_DONE, pos))
943
1014
  else:
944
1015
  self.send_command(sock, command)
945
1016
 
946
1017
  def commit_settings(self, param):
947
1018
 
948
1019
  if param.name() in putils.iter_children(self.settings.child('settings_client'), []):
949
- actuator_socket: Socket = [client['socket'] for client in self.connected_clients if client['type'] == 'ACTUATOR'][0]
1020
+ actuator_socket: Socket = \
1021
+ [client['socket'] for client in self.connected_clients if client['type'] == 'ACTUATOR'][0]
950
1022
  actuator_socket.check_sended_with_serializer('set_info')
951
1023
  path = putils.get_param_path(param)[2:]
952
1024
  # get the path of this param as a list starting at parent 'infos'
@@ -0,0 +1,137 @@
1
+ from pymodaq_utils.enums import StrEnum
2
+
3
+
4
+ class ThreadStatus(StrEnum):
5
+ """ Allowed Generic commands sent from a plugin using the method: emit_status
6
+
7
+ Valid both for DAQ_Move and DAQ_Viewer control modules
8
+
9
+ See Also
10
+ --------
11
+ ControlModule.thread_status
12
+ """
13
+ UPDATE_STATUS = 'update_status'
14
+ CLOSE = 'close'
15
+ UPDATE_SETTINGS = 'update_settings'
16
+ UPDATE_MAIN_SETTINGS = 'update_main_settings'
17
+ UPDATE_UI = 'update_ui'
18
+ RAISE_TIMEOUT = 'raise_timeout'
19
+ SHOW_SPLASH = 'show_splash'
20
+ CLOSE_SPLASH = 'close_splash'
21
+
22
+
23
+ class ThreadStatusMove(StrEnum):
24
+ """ Allowed Generic commands sent from a plugin using the method: emit_status
25
+
26
+ Valid only for DAQ_Move control module
27
+
28
+ See Also
29
+ --------
30
+ DAQ_Move.thread_status
31
+ """
32
+ INI_STAGE = 'ini_stage'
33
+ GET_ACTUATOR_VALUE = 'get_actuator_value'
34
+ MOVE_DONE = 'move_done'
35
+ OUT_OF_BOUNDS = 'outofbounds'
36
+ SET_ALLOWED_VALUES = 'set_allowed_values'
37
+ STOP = 'stop'
38
+ UNITS = 'units'
39
+
40
+
41
+ class ThreadStatusViewer(StrEnum):
42
+ """ Allowed Generic commands sent from a plugin using the method: emit_status
43
+
44
+ Valid only for DAQ_Viewer control module
45
+
46
+ See Also
47
+ --------
48
+ DAQ_Viewer.thread_status
49
+ """
50
+ INI_DETECTOR = 'ini_detector'
51
+ GRAB = 'grab'
52
+ GRAB_STOPPED = 'grab_stopped'
53
+ INI_LCD = 'init_lcd'
54
+ LCD = 'lcd'
55
+ STOP = 'stop'
56
+ UPDATE_CHANNELS = 'update_channels'
57
+
58
+
59
+
60
+ class ControlToHardwareMove(StrEnum):
61
+ """ Allowed commands sent from a DAQ_Move to its DAQ_Move_Hardware in another thread
62
+ using the method: command_hardware
63
+
64
+ Valid only for DAQ_Move command_hardware commands
65
+
66
+ """
67
+ INI_STAGE = 'ini_stage'
68
+ STOP_MOTION = 'stop_motion'
69
+ RESET_STOP_MOTION = 'reset_stop_motion'
70
+ MOVE_ABS = 'move_abs'
71
+ MOVE_REL = 'move_rel'
72
+ MOVE_HOME = 'move_home'
73
+ GET_ACTUATOR_VALUE = 'get_actuator_value'
74
+ CLOSE = 'close'
75
+
76
+ class ControlToHardwareViewer(StrEnum):
77
+ """ Allowed commands sent from a DAQ_Viewer to its DAQ_Detector in another thread
78
+ using the method: command_hardware
79
+
80
+ Valid only for DAQ_Viewer command_hardware commands
81
+
82
+ """
83
+ INI_DETECTOR = 'ini_detector'
84
+
85
+ SINGLE = 'single'
86
+ GRAB = 'grab'
87
+ STOP_GRAB = 'stop_grab'
88
+ ROI_SELECT = 'roi_select'
89
+ UPDATE_SCANNER = 'update_scanner' # may be deprecated
90
+ CROSSHAIR = 'crosshair'
91
+ UPDATE_WAIT_TIME = 'update_wait_time'
92
+ CLOSE = 'close'
93
+
94
+
95
+ class UiToMainMove(StrEnum):
96
+ """ Allowed Commands to be sent from the DAQ_Move_UI to the DAQ_Move
97
+ """
98
+ INIT = 'init'
99
+ QUIT = 'quit'
100
+ SHOW_LOG = 'show_log'
101
+ SHOW_CONFIG = 'show_config'
102
+ STOP = 'stop'
103
+
104
+ MOVE_ABS = 'move_abs'
105
+ MOVE_REL = 'move_rel'
106
+
107
+ ACTUATOR_CHANGED = 'actuator_changed'
108
+
109
+ GET_VALUE = 'get_value'
110
+
111
+ FIND_HOME = 'find_home'
112
+ REL_VALUE = 'rel_value'
113
+
114
+ LOOP_GET_VALUE = 'loop_get_value'
115
+
116
+
117
+ class UiToMainViewer(StrEnum):
118
+ """ Allowed Commands to be sent from the DAQ_Viewer_UI to the DAQ_Viewer
119
+ """
120
+ INIT = 'init'
121
+ QUIT = 'quit'
122
+ SHOW_LOG = 'show_log'
123
+ SHOW_CONFIG = 'show_config'
124
+ STOP = 'stop'
125
+
126
+ SNAP = 'snap'
127
+ GRAB = 'grab'
128
+ SAVE_CURRENT = 'save_current'
129
+ SAVE_NEW = 'save_new'
130
+ OPEN = 'open'
131
+
132
+ DETECTOR_CHANGED = 'detector_changed'
133
+ VIEWERS_CHANGED = 'viewers_changed'
134
+ DAQ_TYPE_CHANGED = 'daq_type_changed'
135
+
136
+ DO_BKG = 'do_bkg'
137
+ TAKE_BKG = 'take_bkg'
@@ -0,0 +1,72 @@
1
+ from importlib import import_module
2
+ from pathlib import Path
3
+
4
+ from qtpy import QtCore
5
+
6
+
7
+ from pymodaq_gui.utils import CustomApp
8
+
9
+ from pymodaq_utils.utils import ThreadCommand
10
+ from pymodaq_utils.config import Config as ConfigUtils
11
+ from pymodaq.utils.config import Config
12
+
13
+ config_utils = ConfigUtils()
14
+ config = Config()
15
+
16
+
17
+ class ControlModuleUI(CustomApp):
18
+ """ Base Class for ControlModules UIs
19
+
20
+ Attributes
21
+ ----------
22
+ command_sig: Signal[Threadcommand]
23
+ This signal is emitted whenever some actions done by the user has to be
24
+ applied on the main module. Possible commands are:
25
+ See specific implementation
26
+
27
+ See Also
28
+ --------
29
+ :class:`daq_move_ui.DAQ_Move_UI`, :class:`daq_viewer_ui.DAQ_Viewer_UI`
30
+ """
31
+ command_sig = QtCore.Signal(ThreadCommand)
32
+
33
+ def __init__(self, parent):
34
+ super().__init__(parent)
35
+ self.config = config
36
+
37
+ def display_status(self, txt, wait_time=config_utils('general', 'message_status_persistence')):
38
+ if self.statusbar is not None:
39
+ self.statusbar.showMessage(txt, wait_time)
40
+
41
+ def do_init(self, do_init=True):
42
+ """Programmatically press the Init button
43
+ API entry
44
+ Parameters
45
+ ----------
46
+ do_init: bool
47
+ will fire the Init button depending on the argument value and the button check state
48
+ """
49
+ raise NotImplementedError
50
+
51
+ def send_init(self, checked: bool):
52
+ """Should be implemented to send to the main app the fact that someone (un)checked init."""
53
+ raise NotImplementedError
54
+
55
+
56
+ def register_uis(parent_module_name: str = 'pymodaq.control_modules.daq_move_ui'):
57
+ uis = []
58
+ try:
59
+ scanner_module = import_module(f'{parent_module_name}.uis')
60
+
61
+ scanner_path = Path(scanner_module.__path__[0])
62
+
63
+ for file in scanner_path.iterdir():
64
+ if file.is_file() and 'py' in file.suffix and file.stem != '__init__':
65
+ try:
66
+ uis.append(import_module(f'.{file.stem}', scanner_module.__name__))
67
+ except (ModuleNotFoundError, Exception) as e:
68
+ pass
69
+ except ModuleNotFoundError:
70
+ pass
71
+ finally:
72
+ return uis