horiba-sdk 0.3.3__py3-none-any.whl → 0.5.2__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.
Files changed (27) hide show
  1. horiba_sdk/__init__.py +5 -3
  2. horiba_sdk/communication/websocket_communicator.py +2 -2
  3. horiba_sdk/core/__init__.py +0 -0
  4. horiba_sdk/core/acquisition_format.py +20 -0
  5. horiba_sdk/core/clean_count_mode.py +13 -0
  6. horiba_sdk/core/timer_resolution.py +14 -0
  7. horiba_sdk/core/x_axis_conversion_type.py +18 -0
  8. horiba_sdk/devices/ccd_discovery.py +10 -12
  9. horiba_sdk/devices/device_manager.py +24 -10
  10. horiba_sdk/devices/fake_responses/ccd.json +261 -12
  11. horiba_sdk/devices/fake_responses/monochromator.json +38 -10
  12. horiba_sdk/devices/monochromator_discovery.py +16 -9
  13. horiba_sdk/devices/single_devices/abstract_device.py +46 -1
  14. horiba_sdk/devices/single_devices/ccd.py +388 -143
  15. horiba_sdk/devices/single_devices/monochromator.py +87 -71
  16. horiba_sdk/sync/communication/abstract_communicator.py +2 -3
  17. horiba_sdk/sync/communication/websocket_communicator.py +38 -18
  18. horiba_sdk/sync/devices/device_discovery.py +13 -37
  19. horiba_sdk/sync/devices/device_manager.py +14 -10
  20. horiba_sdk/sync/devices/fake_icl_server.py +9 -6
  21. horiba_sdk/sync/devices/single_devices/abstract_device.py +11 -7
  22. horiba_sdk/sync/devices/single_devices/ccd.py +517 -62
  23. horiba_sdk/sync/devices/single_devices/monochromator.py +288 -25
  24. {horiba_sdk-0.3.3.dist-info → horiba_sdk-0.5.2.dist-info}/METADATA +166 -92
  25. {horiba_sdk-0.3.3.dist-info → horiba_sdk-0.5.2.dist-info}/RECORD +27 -22
  26. {horiba_sdk-0.3.3.dist-info → horiba_sdk-0.5.2.dist-info}/LICENSE +0 -0
  27. {horiba_sdk-0.3.3.dist-info → horiba_sdk-0.5.2.dist-info}/WHEEL +0 -0
horiba_sdk/__init__.py CHANGED
@@ -1,11 +1,11 @@
1
1
  # mypy: disable-error-code="attr-defined"
2
2
  """'horiba-sdk' is a package that provides source code for the development with Horiba devices"""
3
3
 
4
+ from loguru import logger
5
+
4
6
  __version__ = '0.2.0' # It MUST match the version in pyproject.toml file
5
7
  from importlib import metadata as importlib_metadata
6
8
 
7
- from pint import UnitRegistry
8
-
9
9
 
10
10
  def get_version() -> str:
11
11
  try:
@@ -16,4 +16,6 @@ def get_version() -> str:
16
16
 
17
17
  version: str = get_version()
18
18
 
19
- ureg = UnitRegistry()
19
+ # it is good practice to disable the logging for a library, this is done here.
20
+ # on initialization of a device manager, this can be enabled.
21
+ logger.disable(__name__)
@@ -166,13 +166,13 @@ class WebsocketCommunicator(AbstractCommunicator):
166
166
 
167
167
  def register_binary_message_callback(self, callback: Callable[[bytes], Any]) -> None:
168
168
  """Registers a callback to be called with every incoming binary message."""
169
- logger.info('Binary message callback registered.')
169
+ logger.debug('Binary message callback registered.')
170
170
  self.binary_message_callback = callback
171
171
 
172
172
  async def _receive_data(self) -> None:
173
173
  try:
174
174
  async for message in self.websocket: # type: ignore
175
- logger.info(f'Received message: {message!r}')
175
+ logger.debug(f'Received message: {message!r}')
176
176
  if isinstance(message, str):
177
177
  await self.json_message_queue.put(message)
178
178
  elif isinstance(message, bytes):
File without changes
@@ -0,0 +1,20 @@
1
+ from enum import Enum
2
+ from typing import final
3
+
4
+
5
+ @final
6
+ class AcquisitionFormat(Enum):
7
+ """Formats for the acquisition.
8
+
9
+ Attributes:
10
+ SPECTRA: X axis in nm, Y axis in counts
11
+ IMAGE: X axis in pixels, Y axis in counts
12
+ CROP: TBD
13
+ FAST_KINETICS: TBD
14
+
15
+ """
16
+
17
+ SPECTRA = 0
18
+ IMAGE = 1
19
+ CROP = 2
20
+ FAST_KINETICS = 3
@@ -0,0 +1,13 @@
1
+ from enum import Enum
2
+ from typing import final
3
+
4
+
5
+ @final
6
+ class CleanCountMode(Enum):
7
+ """TODO"""
8
+
9
+ NEVER = 0
10
+ FIRST_ONLY = 1
11
+ BETWEEN_ONLY = 2
12
+ EACH = 3
13
+ UNKNOWN = 238
@@ -0,0 +1,14 @@
1
+ from enum import Enum
2
+ from typing import final
3
+
4
+
5
+ @final
6
+ class TimerResolution(Enum):
7
+ """Resolution for the timer for the acquisition time.
8
+
9
+ .. note:: The timer resolution value MICROSECONDS is not supported by all CCDs.
10
+ """
11
+
12
+ MILLISECONDS = 0
13
+ MICROSECONDS = 1
14
+ NOTHING_EVAL = 2
@@ -0,0 +1,18 @@
1
+ from enum import Enum
2
+ from typing import final
3
+
4
+
5
+ @final
6
+ class XAxisConversionType(Enum):
7
+ """
8
+ Conversion types for the x axis of acquired data.
9
+
10
+ Attributes:
11
+ NONE: No conversion.
12
+ FROM_CCD_FIRMWARE: CCD FIT parameters contained in the CCD firmware.
13
+ FROM_ICL_SETTINGS_INI: Mono Wavelength parameters contained in the icl_settings.ini file
14
+ """
15
+
16
+ NONE = 0
17
+ FROM_CCD_FIRMWARE = 1
18
+ FROM_ICL_SETTINGS_INI = 2
@@ -1,4 +1,3 @@
1
- import re
2
1
  from typing import Any, final
3
2
 
4
3
  from loguru import logger
@@ -32,24 +31,23 @@ class ChargeCoupledDevicesDiscovery(AbstractDeviceDiscovery):
32
31
  response: Response = await self._communicator.request_with_response(Command('ccd_discover', {}))
33
32
  if response.results.get('count', 0) == 0 and error_on_no_device:
34
33
  raise Exception('No CCDs connected')
34
+
35
35
  response = await self._communicator.request_with_response(Command('ccd_list', {}))
36
36
 
37
37
  raw_device_list = response.results
38
38
  self._charge_coupled_devices = self._parse_ccds(raw_device_list)
39
- logger.info(f'Found {len(self._charge_coupled_devices)} CCD devices: {self._charge_coupled_devices}')
39
+ logger.info(f'Found {len(self._charge_coupled_devices)} CCD devices')
40
40
 
41
41
  def _parse_ccds(self, raw_device_list: dict[str, Any]) -> list[ChargeCoupledDevice]:
42
42
  detected_ccds: list[ChargeCoupledDevice] = []
43
- for key, value in raw_device_list.items():
44
- logger.debug(f'Parsing CCD: {key} - {value}')
45
- ccd_index: int = int(key.split(':')[0].replace('index', '').strip())
46
- ccd_type_match = re.search(r'deviceType: (.*?),', value)
47
- if not ccd_type_match:
48
- raise Exception(f'Failed to find ccd type "deviceType" in string "{value}"')
49
- ccd_type: str = str(ccd_type_match.group(1).strip())
50
-
51
- logger.info(f'Detected CCD: {ccd_type}')
52
- detected_ccds.append(ChargeCoupledDevice(ccd_index, self._communicator, self._error_db))
43
+ for device in raw_device_list['devices']:
44
+ try:
45
+ logger.debug(f'Parsing CCD: {device}')
46
+ ccd = ChargeCoupledDevice(device['index'], self._communicator, self._error_db)
47
+ logger.info(f'Detected CCD: {device["deviceType"]}')
48
+ detected_ccds.append(ccd)
49
+ except Exception as e:
50
+ logger.error(f'Error while parsing ChargeCoupledDevice: {e}')
53
51
 
54
52
  return detected_ccds
55
53
 
@@ -63,27 +63,34 @@ class DeviceManager(AbstractDeviceManager):
63
63
  def __init__(
64
64
  self,
65
65
  start_icl: bool = True,
66
- websocket_ip: str = '127.0.0.1',
67
- websocket_port: str = '25010',
66
+ icl_ip: str = '127.0.0.1',
67
+ icl_port: str = '25010',
68
68
  enable_binary_messages: bool = True,
69
+ enable_logging: bool = False
69
70
  ):
70
71
  """
71
72
  Initializes the DeviceManager with the specified communicator class.
72
73
 
73
74
  Args:
74
75
  start_icl (bool) = True: If True, the ICL software is started and communication is established.
75
- websocket_ip (str) = '127.0.0.1': websocket IP
76
- websocket_port (str) = '25010': websocket port
76
+ icl_ip (str) = '127.0.0.1': websocket IP
77
+ icl_port (str) = '25010': websocket port
77
78
  enable_binary_messages (bool) = True: If True, binary messages are enabled.
79
+ enable_logging (bool) = True: If True, logging with the loguru library is enabled.
78
80
  """
81
+ # By default, logging is disabled for a library, so if desired it can be enabled
82
+ root_name_space: str = __name__.split('.')[0]
83
+ if enable_logging:
84
+ logger.info(f"Initializing logger for namespace: {root_name_space}")
85
+ logger.enable(root_name_space)
86
+ else:
87
+ logger.disable(root_name_space)
79
88
  super().__init__()
80
89
  self._start_icl = start_icl
81
- self._icl_communicator: WebsocketCommunicator = WebsocketCommunicator(
82
- 'ws://' + websocket_ip + ':' + str(websocket_port)
83
- )
90
+ self._icl_communicator: WebsocketCommunicator = WebsocketCommunicator('ws://' + icl_ip + ':' + str(icl_port))
84
91
  self._icl_communicator.register_binary_message_callback(self._binary_message_callback)
85
- self._icl_websocket_ip: str = websocket_ip
86
- self._icl_websocket_port: str = websocket_port
92
+ self._icl_websocket_ip: str = icl_ip
93
+ self._icl_websocket_port: str = icl_port
87
94
  self._icl_process: Optional[asyncio.subprocess.Process] = None
88
95
  self._binary_messages: bool = enable_binary_messages
89
96
  self._charge_coupled_devices: list[ChargeCoupledDevice] = []
@@ -109,7 +116,12 @@ class DeviceManager(AbstractDeviceManager):
109
116
 
110
117
  @override
111
118
  async def stop(self) -> None:
112
- await self.stop_icl()
119
+ if self._start_icl:
120
+ await self.stop_icl()
121
+ return
122
+
123
+ if self._icl_communicator.opened():
124
+ await self._icl_communicator.close()
113
125
 
114
126
  async def start_icl(self) -> None:
115
127
  """
@@ -126,6 +138,8 @@ class DeviceManager(AbstractDeviceManager):
126
138
  logger.info('icl not running, starting it...')
127
139
  # subprocess.Popen([r'C:\Program Files\HORIBA Scientific\SDK\icl.exe'])
128
140
  self._icl_process = await asyncio.create_subprocess_exec(r'C:\Program Files\HORIBA Scientific\SDK\icl.exe')
141
+ await asyncio.sleep(4)
142
+
129
143
  # except subprocess.CalledProcessError:
130
144
  # logger.error('Failed to start ICL software.')
131
145
  # TODO: [saga] is this the best way handle exceptions?
@@ -8,12 +8,19 @@
8
8
  "errors": []
9
9
  },
10
10
  "ccd_list": {
11
- "id": 1234,
12
11
  "command": "ccd_list",
12
+ "errors": [],
13
+ "id": 1234,
13
14
  "results": {
14
- "index0: %2" : "{ productId: 13, deviceType: HORIBA Scientific Syncerity, serialNumber: Camera SN: 2244}"
15
- },
16
- "errors": []
15
+ "devices": [
16
+ {
17
+ "deviceType": "HORIBA Scientific Syncerity",
18
+ "index":0,
19
+ "productId":13,
20
+ "serialNumber": "Camera SN: 2244"
21
+ }
22
+ ]
23
+ }
17
24
  },
18
25
  "ccd_listCount": {
19
26
  "id": 1234,
@@ -45,7 +52,190 @@
45
52
  ]
46
53
  },
47
54
  "ccd_restart": {},
48
- "ccd_getConfig": {},
55
+ "ccd_getConfig": {
56
+ "command": "ccd_getConfig",
57
+ "errors": [],
58
+ "id": 1234,
59
+ "results": {
60
+ "configuration": {
61
+ "centerWavelength": 0,
62
+ "chipHSpacing": 260,
63
+ "chipHeight": 256,
64
+ "chipName": "CCD30-11-1-275",
65
+ "chipSerialNumber": "20091-22-21",
66
+ "chipVSpacing": 260,
67
+ "chipWidth": 1024,
68
+ "deviceType": "HORIBA Scientific Syncerity",
69
+ "fitParameters": [
70
+ 0,
71
+ 1,
72
+ 0,
73
+ 0,
74
+ 0
75
+ ],
76
+ "gains": [
77
+ {
78
+ "info": "High Sensitivity",
79
+ "token": 2
80
+ },
81
+ {
82
+ "info": "High Light",
83
+ "token": 0
84
+ },
85
+ {
86
+ "info": "Best Dynamic Range",
87
+ "token": 1
88
+ }
89
+ ],
90
+ "hardwareAvgAvailable": "false",
91
+ "lineScan": "false",
92
+ "productId": "13",
93
+ "serialNumber": "Camera SN: 2244",
94
+ "signals": [
95
+ {
96
+ "events": [
97
+ {
98
+ "name": "Reserved-DO NOT USE",
99
+ "token": 2,
100
+ "types": [
101
+ {
102
+ "name": "TTL Active High",
103
+ "token": 0
104
+ },
105
+ {
106
+ "name": "TTL Active Low",
107
+ "token": 1
108
+ }
109
+ ]
110
+ },
111
+ {
112
+ "name": "Shutter Open",
113
+ "token": 3,
114
+ "types": [
115
+ {
116
+ "name": "TTL Active High",
117
+ "token": 0
118
+ },
119
+ {
120
+ "name": "TTL Active Low",
121
+ "token": 1
122
+ }
123
+ ]
124
+ },
125
+ {
126
+ "name": "Start Experiment",
127
+ "token": 0,
128
+ "types": [
129
+ {
130
+ "name": "TTL Active High",
131
+ "token": 0
132
+ },
133
+ {
134
+ "name": "TTL Active Low",
135
+ "token": 1
136
+ }
137
+ ]
138
+ },
139
+ {
140
+ "name": "Ready For Trigger",
141
+ "token": 1,
142
+ "types": [
143
+ {
144
+ "name": "TTL Active High",
145
+ "token": 0
146
+ },
147
+ {
148
+ "name": "TTL Active Low",
149
+ "token": 1
150
+ }
151
+ ]
152
+ }
153
+ ],
154
+ "name": "Signal Output",
155
+ "token": 0
156
+ }
157
+ ],
158
+ "speeds": [
159
+ {
160
+ "info": " 1 MHz Ultra ",
161
+ "token": 2
162
+ },
163
+ {
164
+ "info": "500 kHz Wrap",
165
+ "token": 127
166
+ },
167
+ {
168
+ "info": "45 kHz ",
169
+ "token": 0
170
+ },
171
+ {
172
+ "info": " 1 MHz ",
173
+ "token": 1
174
+ }
175
+ ],
176
+ "supportedFeatures": {
177
+ "cf_3PositionSlit": "false",
178
+ "cf_CMOSOffsetCorrection": "false",
179
+ "cf_Cleaning": "true",
180
+ "cf_DSP": "false",
181
+ "cf_DSPBin2X": "false",
182
+ "cf_DelayAfterTrigger": "false",
183
+ "cf_Delays": "false",
184
+ "cf_EMCCD": "false",
185
+ "cf_EShutter": "false",
186
+ "cf_HDR": "false",
187
+ "cf_Image": "true",
188
+ "cf_MemorySlots": "true",
189
+ "cf_Metadata": "false",
190
+ "cf_MultipleExposeTimes": "false",
191
+ "cf_MultipleSensors": "false",
192
+ "cf_PulseSummation": "false",
193
+ "cf_ROIs": "true",
194
+ "cf_Signals": "true",
195
+ "cf_Spectra": "true",
196
+ "cf_TriggerQualifier": "false",
197
+ "cf_Triggers": "true"
198
+ },
199
+ "triggers": [
200
+ {
201
+ "events": [
202
+ {
203
+ "name": "Once - Start All",
204
+ "token": 0,
205
+ "types": [
206
+ {
207
+ "name": "TTL Falling Edge",
208
+ "token": 0
209
+ },
210
+ {
211
+ "name": "TTL Rising Edge",
212
+ "token": 1
213
+ }
214
+ ]
215
+ },
216
+ {
217
+ "name": "Each - For Each Acq",
218
+ "token": 1,
219
+ "types": [
220
+ {
221
+ "name": "TTL Falling Edge",
222
+ "token": 0
223
+ },
224
+ {
225
+ "name": "TTL Rising Edge",
226
+ "token": 1
227
+ }
228
+ ]
229
+ }
230
+ ],
231
+ "name": "Trigger Input",
232
+ "token": 0
233
+ }
234
+ ],
235
+ "version": "Syncerity Ver 1.001.7.1"
236
+ }
237
+ }
238
+ },
49
239
  "ccd_getChipSize": {
50
240
  "id": 1234,
51
241
  "command": "ccd_getChipSize",
@@ -90,7 +280,7 @@
90
280
  "command": "ccd_getFitParams",
91
281
  "errors": [],
92
282
  "results": {
93
- "params": "0,1,0,0,0"
283
+ "fitParameters": [0,1,0,0,0]
94
284
  }
95
285
  },
96
286
  "ccd_setFitParams": {},
@@ -108,7 +298,7 @@
108
298
  "command": "ccd_getTimerResolution",
109
299
  "errors": [],
110
300
  "results": {
111
- "resolution": 1000
301
+ "resolutionToken": 0
112
302
  }
113
303
  },
114
304
  "ccd_setTimerResolution": {},
@@ -133,6 +323,40 @@
133
323
  "count": 1
134
324
  }
135
325
  },
326
+ "ccd_getAcquisitionData": {
327
+ "command":"ccd_getAcquisitionData",
328
+ "errors":[],
329
+ "id":0,
330
+ "results": {
331
+ "acquisition":
332
+ [
333
+ {
334
+ "acqIndex":1,
335
+ "roi":
336
+ [
337
+ {
338
+ "roiIndex":1,
339
+ "xBinning":1,
340
+ "xData":
341
+ [
342
+ [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,618,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,641,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,975,976,977,978,979,980,981,982,983,984,985,986,987,988,989,990,991,992,993,994,995,996,997,998,999]
343
+
344
+ ],
345
+ "xOrigin":0,
346
+ "xSize":1000,
347
+ "yBinning":200,
348
+ "yData": [
349
+ [607,605,609,608,605,604,606,607,608,607,606,604,604,606,608,605,606,608,608,606,605,608,607,608,606,607,607,605,608,607,607,607,605,608,608,605,607,606,610,605,605,605,604,606,605,604,604,604,607,606,607,606,605,609,603,607,604,605,603,607,603,606,606,606,606,606,606,604,603,606,606,607,604,607,604,606,605,605,604,607,608,606,605,606,605,603,606,606,607,605,607,608,605,604,607,604,606,607,606,604,606,604,604,606,604,608,603,606,605,606,608,603,604,606,605,607,607,605,606,604,606,606,606,606,606,608,605,606,605,607,607,606,607,607,606,604,604,607,602,605,604,606,606,607,606,605,606,606,608,608,607,605,604,607,606,606,605,605,606,604,606,605,603,606,606,608,607,603,606,605,606,604,605,606,603,607,602,604,606,606,605,606,606,604,606,607,603,603,609,605,605,605,606,606,606,605,605,607,605,608,608,606,606,607,607,608,604,608,604,606,607,605,608,604,605,607,603,607,607,607,606,607,606,605,609,606,603,607,605,605,605,606,604,608,608,607,608,608,606,606,605,611,609,605,604,605,606,608,607,604,607,605,607,604,606,604,609,608,606,606,606,607,605,608,605,606,606,605,607,604,606,606,608,606,606,607,605,604,606,606,606,606,607,608,607,605,604,604,605,606,607,608,604,605,607,606,608,607,606,604,606,605,609,605,608,607,608,608,606,608,608,607,606,607,608,607,606,605,607,607,609,606,605,607,607,606,606,607,607,607,606,607,605,607,608,607,606,609,609,607,607,605,607,609,603,608,607,605,608,605,608,607,607,607,608,607,607,606,609,607,609,608,607,608,605,605,606,607,608,607,608,607,605,606,609,608,606,607,607,606,608,606,606,608,606,607,608,607,606,606,606,606,605,609,607,608,608,610,605,608,609,607,606,605,609,607,608,606,606,609,606,607,609,606,608,607,606,604,608,606,605,606,608,609,604,604,605,607,607,608,607,610,605,606,606,608,606,607,606,605,606,607,606,606,609,607,606,606,607,607,607,606,606,609,609,607,606,607,607,607,605,606,607,606,605,605,607,608,607,605,608,608,603,606,606,607,607,607,608,607,607,607,606,605,608,608,607,604,606,607,608,607,609,605,608,605,606,607,606,607,607,606,607,606,605,604,607,605,608,605,607,606,605,608,605,607,606,607,607,605,606,608,606,607,606,609,605,607,608,606,606,608,604,606,606,608,605,604,605,607,607,609,604,605,607,603,608,604,605,608,607,609,603,609,606,607,606,608,605,606,605,608,606,606,605,606,605,606,605,606,605,607,608,609,607,606,606,609,607,606,604,606,607,607,606,606,608,607,608,605,606,609,610,606,609,606,606,606,607,610,606,607,607,604,605,606,607,606,612,606,605,606,607,608,604,606,608,608,607,607,609,609,605,607,605,607,606,607,606,607,607,607,605,606,605,605,605,607,605,608,606,608,607,607,608,605,607,607,605,608,609,606,604,606,608,606,607,604,605,606,607,607,607,607,605,606,605,606,606,608,607,604,607,609,606,608,606,606,608,606,608,605,604,606,606,604,607,607,605,606,605,605,607,607,606,604,607,608,604,608,605,607,606,605,607,608,603,606,607,606,609,606,609,606,607,607,607,606,605,605,606,606,608,605,605,606,606,607,608,606,606,605,604,603,604,608,606,609,608,606,606,609,607,606,604,606,607,607,605,606,605,609,605,606,606,606,609,608,607,606,608,607,607,608,609,609,604,603,606,607,607,606,605,606,608,607,605,605,602,606,609,607,605,607,604,606,606,607,607,606,606,608,606,607,608,606,607,607,608,607,607,606,607,608,606,606,608,607,606,607,608,607,605,608,606,606,605,605,606,606,606,604,607,608,604,605,606,604,605,605,608,608,605,604,607,606,604,606,608,609,606,605,606,605,606,606,608,608,607,608,608,607,607,609,606,606,607,608,604,605,607,606,606,607,606,605,606,606,607,607,607,608,604,606,605,604,608,606,607,608,606,606,607,608,608,604,606,607,607,608,605,605,604,605,603,607,605,606,607,608,606,604,606,606,608,605,607,609,606,606,606,607,609,606,606,607,605,605,608,606,607,603,605,607,604,606,606,605,607,609,607,608,607,606,606,603,605,605,606,605,608,606,606,607,609,609,604,606,604,608,605,605,607,607,606,605,606,605,605,605,607,606,606,603,606,605,608,607,607,604,605,606,608,605,607,606,608,606,614,608,605,608,604,606,608,607,606,607,607,608,605,610,607,607,607,609,605,609,607,607]
350
+ ],
351
+ "yOrigin":0,
352
+ "ySize":200
353
+ }
354
+ ]
355
+ }
356
+ ],
357
+ "timestamp":"2024.04.22 15:07:50.096"
358
+ }
359
+ },
136
360
  "ccd_setAcqCount": {},
137
361
  "ccd_getCleanCount": {
138
362
  "command": "ccd_getCleanCount",
@@ -157,12 +381,37 @@
157
381
  "errors": [],
158
382
  "id": 0,
159
383
  "results": {
160
- "addressWhere": -1,
161
- "eventWhen": -1,
162
- "sigTypeHow": -1
384
+ "address": -1,
385
+ "event": -1,
386
+ "signalType": -1
163
387
  }
164
388
  },
165
389
  "ccd_setTriggerIn": {},
166
- "ccd_getSignalOut": {},
167
- "ccd_setSignalOut": {}
390
+ "ccd_getSignalOut": {
391
+ "command": "ccd_getSignalOut",
392
+ "errors": [],
393
+ "id": 1234,
394
+ "results": {
395
+ "address": 0,
396
+ "event": 0,
397
+ "signalType":0
398
+ }
399
+ },
400
+ "ccd_setSignalOut": {},
401
+ "ccd_getAcquisitionReady": {
402
+ "command": "ccd_getAcquisitionReady",
403
+ "errors": [],
404
+ "id": 1234,
405
+ "results": {
406
+ "ready": true
407
+ }
408
+ },
409
+ "ccd_getAcquisitionBusy": {
410
+ "command": "ccd_getAcquisitionBusy",
411
+ "errors": [],
412
+ "id": 1234,
413
+ "results": {
414
+ "isBusy": false
415
+ }
416
+ }
168
417
  }
@@ -9,15 +9,19 @@
9
9
  "errors": []
10
10
  },
11
11
  "mono_list": {
12
- "id": 1234,
13
12
  "command": "mono_list",
14
- "results": {
15
- "list": [
16
- "0;iHR550;sn12345",
17
- "1;iHR320;snabscde"
13
+ "errors": [],
14
+ "id": 0,
15
+ "results":
16
+ {
17
+ "devices": [
18
+ {
19
+ "deviceType": "HORIBA Scientific iHR",
20
+ "index": 0,
21
+ "serialNumber":"1745B-2017-iHR320 "
22
+ }
18
23
  ]
19
- },
20
- "errors": []
24
+ }
21
25
  },
22
26
  "mono_listCount": {
23
27
  "id": 1234,
@@ -61,10 +65,33 @@
61
65
  "mono_getConfig": {
62
66
  "id": 1234,
63
67
  "command": "mono_getConfig",
64
- "results":{
68
+ "results": {
69
+ "configuration": {
70
+ "filterWheels": [
71
+ {"location":1},
72
+ {"location":2}
73
+ ],
74
+ "gratings": [
75
+ {"blaze":0,"grooveDensity":1800,"positionIndex":0},
76
+ {"blaze":0,"grooveDensity":1200,"positionIndex":1},
77
+ {"blaze":0,"grooveDensity":300,"positionIndex":2}
78
+ ],
79
+ "mirrors": [
80
+ {"blaze":0,"grooveDensity":1800,"positionIndex":0},
81
+ {"blaze":0,"grooveDensity":1200,"positionIndex":1},
82
+ {"blaze":0,"grooveDensity":300,"positionIndex":2}
83
+ ],
84
+ "monoModel":"iHR320",
85
+ "ports": [
86
+ {"monoPortLocation":1,"slitType":2},
87
+ {"monoPortLocation":2,"slitType":2},
88
+ {"monoPortLocation":4,"slitType":2}
89
+ ],
90
+ "procuctId":"257",
91
+ "serialNumber":""
92
+ }
65
93
  },
66
94
  "errors": []
67
-
68
95
  },
69
96
  "mono_setConfig": {},
70
97
  "mono_getPosition": {
@@ -160,7 +187,8 @@
160
187
  "id": 1234,
161
188
  "command": "mono_getShutterStatus",
162
189
  "results": {
163
- "position": 0
190
+ "shutter 1": 0,
191
+ "shutter 2": 1
164
192
  },
165
193
  "errors": []
166
194
  },
@@ -20,6 +20,10 @@ class MonochromatorsDiscovery(AbstractDeviceDiscovery):
20
20
  async def execute(self, error_on_no_device: bool = False) -> None:
21
21
  """
22
22
  Discovers the connected Monochromators and saves them internally.
23
+
24
+ Raises:
25
+ Exception: When no Monochromators are discovered and that `error_on_no_device` is set. Or when there is an
26
+ issue parsing the Monochromators list
23
27
  """
24
28
  if not self._communicator.opened():
25
29
  await self._communicator.open()
@@ -29,18 +33,21 @@ class MonochromatorsDiscovery(AbstractDeviceDiscovery):
29
33
  raise Exception('No Monochromators connected')
30
34
 
31
35
  response = await self._communicator.request_with_response(Command('mono_list', {}))
32
- raw_device_list = response.results['list']
36
+
37
+ raw_device_list = response.results
33
38
  self._monochromators = self._parse_monos(raw_device_list)
34
- logger.info(f'Found {len(self._monochromators)} Monochromator devices: {self._monochromators}')
39
+ logger.info(f'Found {len(self._monochromators)} Monochromator devices')
35
40
 
36
41
  def _parse_monos(self, raw_device_list: dict[str, Any]) -> list[Monochromator]:
37
- detected_monos = []
38
- for device_string in raw_device_list:
39
- mono_index: int = int(device_string.split(';')[0])
40
- mono_type: str = device_string.split(';')[1]
41
-
42
- logger.info(f'Detected Monochromator: {mono_type}')
43
- detected_monos.append(Monochromator(mono_index, self._communicator, self._error_db))
42
+ detected_monos: list[Monochromator] = []
43
+ for device in raw_device_list['devices']:
44
+ try:
45
+ logger.debug(f'Parsing Monochromator: {device}')
46
+ mono = Monochromator(device['index'], self._communicator, self._error_db)
47
+ logger.info(f'Detected Monochromator: {device["deviceType"]}')
48
+ detected_monos.append(mono)
49
+ except Exception as e:
50
+ logger.error(f'Error while parsing Monochromator: {e}')
44
51
 
45
52
  return detected_monos
46
53