horiba-sdk 0.3.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 (48) hide show
  1. horiba_sdk/__init__.py +19 -0
  2. horiba_sdk/communication/__init__.py +44 -0
  3. horiba_sdk/communication/abstract_communicator.py +59 -0
  4. horiba_sdk/communication/communication_exception.py +19 -0
  5. horiba_sdk/communication/messages.py +87 -0
  6. horiba_sdk/communication/websocket_communicator.py +213 -0
  7. horiba_sdk/core/resolution.py +45 -0
  8. horiba_sdk/devices/__init__.py +11 -0
  9. horiba_sdk/devices/abstract_device_discovery.py +7 -0
  10. horiba_sdk/devices/abstract_device_manager.py +68 -0
  11. horiba_sdk/devices/ccd_discovery.py +57 -0
  12. horiba_sdk/devices/device_manager.py +250 -0
  13. horiba_sdk/devices/fake_device_manager.py +133 -0
  14. horiba_sdk/devices/fake_icl_server.py +56 -0
  15. horiba_sdk/devices/fake_responses/ccd.json +168 -0
  16. horiba_sdk/devices/fake_responses/icl.json +29 -0
  17. horiba_sdk/devices/fake_responses/monochromator.json +187 -0
  18. horiba_sdk/devices/monochromator_discovery.py +48 -0
  19. horiba_sdk/devices/single_devices/__init__.py +5 -0
  20. horiba_sdk/devices/single_devices/abstract_device.py +79 -0
  21. horiba_sdk/devices/single_devices/ccd.py +443 -0
  22. horiba_sdk/devices/single_devices/monochromator.py +395 -0
  23. horiba_sdk/icl_error/__init__.py +34 -0
  24. horiba_sdk/icl_error/abstract_error.py +65 -0
  25. horiba_sdk/icl_error/abstract_error_db.py +25 -0
  26. horiba_sdk/icl_error/error_list.json +265 -0
  27. horiba_sdk/icl_error/icl_error.py +30 -0
  28. horiba_sdk/icl_error/icl_error_db.py +81 -0
  29. horiba_sdk/sync/__init__.py +0 -0
  30. horiba_sdk/sync/communication/__init__.py +7 -0
  31. horiba_sdk/sync/communication/abstract_communicator.py +48 -0
  32. horiba_sdk/sync/communication/test_client.py +16 -0
  33. horiba_sdk/sync/communication/websocket_communicator.py +212 -0
  34. horiba_sdk/sync/devices/__init__.py +15 -0
  35. horiba_sdk/sync/devices/abstract_device_discovery.py +17 -0
  36. horiba_sdk/sync/devices/abstract_device_manager.py +68 -0
  37. horiba_sdk/sync/devices/device_discovery.py +82 -0
  38. horiba_sdk/sync/devices/device_manager.py +209 -0
  39. horiba_sdk/sync/devices/fake_device_manager.py +91 -0
  40. horiba_sdk/sync/devices/fake_icl_server.py +79 -0
  41. horiba_sdk/sync/devices/single_devices/__init__.py +5 -0
  42. horiba_sdk/sync/devices/single_devices/abstract_device.py +83 -0
  43. horiba_sdk/sync/devices/single_devices/ccd.py +219 -0
  44. horiba_sdk/sync/devices/single_devices/monochromator.py +150 -0
  45. horiba_sdk-0.3.2.dist-info/LICENSE +20 -0
  46. horiba_sdk-0.3.2.dist-info/METADATA +438 -0
  47. horiba_sdk-0.3.2.dist-info/RECORD +48 -0
  48. horiba_sdk-0.3.2.dist-info/WHEEL +4 -0
@@ -0,0 +1,443 @@
1
+ from enum import Enum
2
+ from types import TracebackType
3
+ from typing import Any, Optional, final
4
+
5
+ import pint
6
+ from loguru import logger
7
+ from overrides import override
8
+
9
+ from horiba_sdk import ureg
10
+ from horiba_sdk.communication import AbstractCommunicator, Response
11
+ from horiba_sdk.core.resolution import Resolution
12
+ from horiba_sdk.icl_error import AbstractErrorDB
13
+
14
+ from .abstract_device import AbstractDevice
15
+
16
+
17
+ @final
18
+ class ChargeCoupledDevice(AbstractDevice):
19
+ """Charge Coupled Device
20
+
21
+ This class should not be instanced by the end user. Instead, the :class:`horiba_sdk.devices.DeviceManager`
22
+ should be used to access the detected CCDs on the system.
23
+ """
24
+
25
+ @final
26
+ class Gain(Enum):
27
+ HIGH_LIGHT = 0
28
+ BEST_DYNAMIC_RANGE = 1
29
+ HIGH_SENSITIVITY = 2
30
+
31
+ @final
32
+ class Speed(Enum):
33
+ SLOW_45_kHz = 0
34
+ MEDIUM_1_MHz = 1
35
+ FAST_1_MHz_Ultra = 2
36
+
37
+ @final
38
+ class AcquisitionFormat(Enum):
39
+ SPECTRA = 0
40
+ IMAGE = 1
41
+ CROP = 2
42
+ FAST_KINETICS = 3
43
+
44
+ @final
45
+ class CleanCountMode(Enum):
46
+ Mode1 = 238
47
+
48
+ @final
49
+ class XAxisConversionType(Enum):
50
+ """
51
+ Enumeration of possible XAxisConversionTypes
52
+ None = 0, CCD-Firmware = 1, ICL ini settings file = 2
53
+ """
54
+
55
+ NONE = 0
56
+ FROM_CCD_FIRMWARE = 1
57
+ FROM_ICL_SETTINGS_INI = 2
58
+
59
+ def __init__(self, device_id: int, communicator: AbstractCommunicator, error_db: AbstractErrorDB) -> None:
60
+ super().__init__(device_id, communicator, error_db)
61
+
62
+ async def __aenter__(self) -> 'ChargeCoupledDevice':
63
+ await self.open()
64
+ return self
65
+
66
+ async def __aexit__(
67
+ self, exc_type: type[BaseException], exc_value: BaseException, traceback: Optional[TracebackType]
68
+ ) -> None:
69
+ is_open = await self.is_open()
70
+ if not is_open:
71
+ logger.debug('CCD is already closed')
72
+ return
73
+
74
+ await self.close()
75
+
76
+ @override
77
+ async def open(self) -> None:
78
+ """Opens the connection to the Charge Coupled Device
79
+
80
+ Raises:
81
+ Exception: When an error occurred on the device side
82
+ """
83
+ await super().open()
84
+ await super()._execute_command('ccd_open', {'index': self._id})
85
+
86
+ @override
87
+ async def close(self) -> None:
88
+ """Closes the connection to the ChargeCoupledDevice
89
+
90
+ Raises:
91
+ Exception: When an error occurred on the device side
92
+ """
93
+ await super()._execute_command('ccd_close', {'index': self._id})
94
+
95
+ async def is_open(self) -> bool:
96
+ """Checks if the connection to the charge coupled device is open.
97
+
98
+ Raises:
99
+ Exception: When an error occurred on the device side
100
+ """
101
+ response: Response = await super()._execute_command('ccd_isOpen', {'index': self._id})
102
+ return bool(response.results['open'])
103
+
104
+ async def restart(self) -> None:
105
+ """Restarts the charge coupled device
106
+ This command only works if the camera has been opened before.
107
+ The connection to the camera stays open after the restart.
108
+
109
+ Raises:
110
+ Exception: When an error occurred on the device side
111
+ """
112
+ await super()._execute_command('ccd_restart', {'index': self._id})
113
+
114
+ async def get_configuration(self) -> dict[str, Any]:
115
+ """Returns the configuration of the CCD
116
+
117
+ Returns:
118
+ dict[str, Any]: Configuration of the CCD
119
+
120
+ Raises:
121
+ Exception: When an error occurred on the device side
122
+ """
123
+ response: Response = await super()._execute_command('ccd_getConfig', {'index': self._id})
124
+ return response.results
125
+
126
+ async def get_number_of_averages(self) -> int:
127
+ """Returns the number of averages of the CCD
128
+
129
+ Returns:
130
+ int: Number of averages
131
+
132
+ Raises:
133
+ Exception: When an error occurred on the device side
134
+ """
135
+ response: Response = await super()._execute_command('ccd_getNumberOfAvgs', {'index': self._id})
136
+ return int(response.results['count'])
137
+
138
+ async def set_number_of_averages(self, number_of_averages: int) -> None:
139
+ """Sets the number of averages of the CCD
140
+
141
+ Args:
142
+ number_of_averages (int): Number of averages
143
+
144
+ Raises:
145
+ Exception: When an error occurred on the device side
146
+ """
147
+ await super()._execute_command('ccd_setNumberOfAvgs', {'index': self._id, 'count': number_of_averages})
148
+
149
+ async def get_gain(self) -> str:
150
+ """Returns the gain of the CCD
151
+
152
+ Returns:
153
+ str: Gain
154
+
155
+ Raises:
156
+ Exception: When an error occurred on the device side
157
+ """
158
+ response: Response = await super()._execute_command('ccd_getGain', {'index': self._id})
159
+ return str(response.results['info'])
160
+
161
+ async def set_gain(self, gain: Gain) -> None:
162
+ """Sets the gain of the CCD
163
+
164
+ Args:
165
+ gain (Gain): Gain
166
+
167
+ Raises:
168
+ Exception: When an error occurred on the device side
169
+ """
170
+ await super()._execute_command('ccd_setGain', {'index': self._id, 'token': gain.value})
171
+
172
+ async def get_speed(self) -> str:
173
+ """Returns the speed of the CCD
174
+
175
+ Returns:
176
+ str: Speed
177
+
178
+ Raises:
179
+ Exception: When an error occurred on the device side
180
+ """
181
+ response: Response = await super()._execute_command('ccd_getSpeed', {'index': self._id})
182
+ return str(response.results['info'])
183
+
184
+ async def set_speed(self, speed: Speed) -> None:
185
+ """Sets the speed of the CCD
186
+
187
+ Args:
188
+ speed (Speed): Speed
189
+
190
+ Raises:
191
+ Exception: When an error occurred on the device side
192
+ """
193
+ await super()._execute_command('ccd_setSpeed', {'index': self._id, 'token': speed.value})
194
+
195
+ async def get_fit_params(self) -> str:
196
+ """Returns the fit parameters of the CCD
197
+
198
+ Returns:
199
+ str: Fit parameters
200
+
201
+ Raises:
202
+ Exception: When an error occurred on the device side
203
+ """
204
+ response: Response = await super()._execute_command('ccd_getFitParams', {'index': self._id})
205
+ return str(response.results['params'])
206
+
207
+ async def set_fit_params(self, fit_params: str) -> None:
208
+ """Sets the fit parameters of the CCD
209
+
210
+ Args:
211
+ fit_params (str): Fit parameters
212
+
213
+ Raises:
214
+ Exception: When an error occurred on the device side
215
+ """
216
+ await super()._execute_command('ccd_setFitParams', {'index': self._id, 'params': fit_params})
217
+
218
+ async def get_timer_resolution(self) -> int:
219
+ """Returns the timer resolution of the CCD
220
+
221
+ Returns:
222
+ int: Timer resolution
223
+
224
+ Raises:
225
+ Exception: When an error occurred on the device side
226
+ """
227
+ response: Response = await super()._execute_command('ccd_getTimerResolution', {'index': self._id})
228
+ return int(response.results['resolution'])
229
+
230
+ async def set_timer_resolution(self, timer_resolution: int) -> None:
231
+ """Sets the timer resolution of the CCD
232
+
233
+ Args:
234
+ timer_resolution (int): Timer resolution
235
+
236
+ Raises:
237
+ Exception: When an error occurred on the device side
238
+ """
239
+ await super()._execute_command('ccd_setTimerResolution', {'index': self._id, 'resolution': timer_resolution})
240
+
241
+ async def set_acquisition_format(self, number_of_rois: int, acquisition_format: AcquisitionFormat) -> None:
242
+ """Sets the acquisition format and the number of ROIs (Regions of Interest) or areas. After using this command
243
+ to set the number of ROIs and format, the ccd_setRoi command should be used to define each ROI.
244
+ Note: The Crop (2) and Fast Kinetics (3) acquisition formats are not supported by every CCD.
245
+
246
+ Args:
247
+ acquisition_format (AcquisitionFormat): Acquisition format
248
+ number_of_rois (int): Number of regions of interest
249
+
250
+ Raises:
251
+ Exception: When an error occurred on the device side
252
+ """
253
+ await super()._execute_command(
254
+ 'ccd_setAcqFormat', {'index': self._id, 'format': acquisition_format.value, 'numberOfRois': number_of_rois}
255
+ )
256
+
257
+ async def set_x_axis_conversion_type(self, conversion_type: XAxisConversionType) -> None:
258
+ """Sets the X-axis pixel conversion type to be used when retrieving the acquisition data with the
259
+ ccd_getAcquisitionData command.
260
+ 0 = None (default)
261
+ 1 = CCD FIT parameters contained in the CCD firmware
262
+ 2 = Mono Wavelength parameters contained in the icl_settings.ini file
263
+
264
+ Args:
265
+ conversion_type (XAxisConversionType): Conversion type Integer. The X-axis pixel conversion type to be used.
266
+
267
+ """
268
+ await super()._execute_command('ccd_setXAxisConversionType', {'index': self._id, 'type': conversion_type.value})
269
+
270
+ async def get_x_axis_conversion_type(self) -> XAxisConversionType:
271
+ """Gets the conversion type of the x axis.
272
+ 0 = None (default)
273
+ 1 = CCD FIT parameters contained in the CCD firmware
274
+ 2 = Mono Wavelength parameters contained in the icl_settings.ini file
275
+ """
276
+ response: Response = await super()._execute_command('ccd_getXAxisConversionType', {'index': self._id})
277
+ return self.XAxisConversionType(self.XAxisConversionType(response.results['type']))
278
+
279
+ async def set_acquisition_count(self, count: int) -> None:
280
+ """Sets the number of acquisitions to be performed. The acquisition count is used to perform multiple
281
+ acquisitions in a row.
282
+ Args:
283
+ count (int): The number of acquisitions to be performed.
284
+ """
285
+ await super()._execute_command('ccd_setAcqCount', {'index': self._id, 'count': count})
286
+
287
+ async def get_acquisition_count(self) -> int:
288
+ """Gets the number of acquisitions to be performed. The acquisition count is used to perform multiple
289
+ acquisitions in a row.
290
+ """
291
+ response: Response = await super()._execute_command('ccd_getAcqCount', {'index': self._id})
292
+ return int(response.results['count'])
293
+
294
+ async def get_clean_count(self) -> str:
295
+ """Gets the clean count mode of the CCD and the according mode"""
296
+ response: Response = await super()._execute_command('ccd_getCleanCount', {'index': self._id})
297
+ answer: str = 'count: ' + str(response.results['count']) + ' ' + 'mode: ' + str(response.results['mode'])
298
+ return answer
299
+
300
+ async def set_clean_count(self, count: int, mode: CleanCountMode) -> None:
301
+ """Sets the clean count mode of the CCD and the according mode
302
+ Args:
303
+ count (int): The number of acquisitions to be performed.
304
+ mode (CleanCountMode): The mode of the clean count
305
+ """
306
+ await super()._execute_command('ccd_setCleanCount', {'index': self._id, 'count': count, 'mode': mode.value})
307
+
308
+ async def get_data_size(self) -> int:
309
+ """Returns the size of the data of the CCD
310
+
311
+ Returns:
312
+ int: Size of the data
313
+
314
+ Raises:
315
+ Exception: When an error occurred on the device side
316
+ """
317
+ response: Response = await super()._execute_command('ccd_getDataSize', {'index': self._id})
318
+ return int(response.results['size'])
319
+
320
+ async def get_temperature(self) -> pint.Quantity:
321
+ """Chip temperature of the CCD.
322
+
323
+ Returns:
324
+ pint.Quantity: chip's temperature in degree Celsius
325
+
326
+ Raises:
327
+ Exception: When an error occurred on the device side
328
+ """
329
+ response: Response = await super()._execute_command('ccd_getChipTemperature', {'index': self._id})
330
+ return ureg.Quantity(response.results['temperature'], ureg.degC) # type: ignore
331
+
332
+ async def get_chip_size(self) -> Resolution:
333
+ """Chip resolution of the CCD.
334
+
335
+ Returns:
336
+ Resolution: chip resolution (width, height)
337
+
338
+ Raises:
339
+ Exception: When an error occurred on the device side
340
+ """
341
+ response: Response = await super()._execute_command('ccd_getChipSize', {'index': self._id})
342
+ width: int = response.results['x']
343
+ height: int = response.results['y']
344
+ resolution: Resolution = Resolution(width, height)
345
+ return resolution
346
+
347
+ async def get_exposure_time(self) -> int:
348
+ """Returns the exposure time in ms
349
+
350
+ Returns:
351
+ pint.Quantity: Exposure time in ms
352
+ Raises:
353
+ Exception: When an error occurred on the device side
354
+ """
355
+ response: Response = await super()._execute_command('ccd_getExposureTime', {'index': self._id})
356
+ exposure = int(response.results['time'])
357
+ return exposure
358
+
359
+ async def set_exposure_time(self, exposure_time_ms: int) -> None:
360
+ """Sets the exposure time in ms
361
+
362
+ Args:
363
+ exposure_time_ms (int): Exposure time in ms
364
+ Raises:
365
+ Exception: When an error occurred on the device side
366
+ """
367
+
368
+ await super()._execute_command('ccd_setExposureTime', {'index': self._id, 'time': exposure_time_ms})
369
+
370
+ async def get_acquisition_ready(self) -> bool:
371
+ """Returns true if the CCD is ready to acquire
372
+
373
+ Returns:
374
+ bool: True if the CCD is ready to acquire
375
+ Raises:
376
+ Exception: When an error occurred on the device side
377
+ """
378
+ response: Response = await super()._execute_command('ccd_getAcquisitionReady', {'index': self._id})
379
+ return bool(response.results['ready'])
380
+
381
+ async def set_acquisition_start(self, open_shutter: bool) -> None:
382
+ """Starts the acquisition of the CCD
383
+
384
+ Args:
385
+ open_shutter (bool): Whether the shutter of the camera should be open
386
+ Raises:
387
+ Exception: When an error occurred on the device side
388
+ """
389
+ await super()._execute_command('ccd_setAcquisitionStart', {'index': self._id, 'openShutter': open_shutter})
390
+
391
+ async def set_region_of_interest(
392
+ self,
393
+ roi_index: int = 1,
394
+ x_origin: int = 0,
395
+ y_origin: int = 0,
396
+ x_size: int = 1024,
397
+ y_size: int = 256,
398
+ x_bin: int = 1,
399
+ y_bin: int = 256,
400
+ ) -> None:
401
+ """Sets the region of interest of the CCD
402
+ an example json command looks like this:
403
+
404
+ Args:
405
+ roi_index (int, optional): Index of the region of interest. Defaults to 1.
406
+ x_origin (int, optional): X origin of the region of interest. Defaults to 0.
407
+ y_origin (int, optional): Y origin of the region of interest. Defaults to 0.
408
+ x_size (int, optional): X size of the region of interest. Defaults to 1024.
409
+ y_size (int, optional): Y size of the region of interest. Defaults to 256.
410
+ x_bin (int, optional): X bin of the region of interest. Defaults to 1.
411
+ y_bin (int, optional): Y bin of the region of interest. Defaults to 256.
412
+
413
+ Raises:
414
+ Exception: When an error occurred on the device side
415
+ """
416
+ await super()._execute_command(
417
+ 'ccd_setRoi',
418
+ {
419
+ 'index': self._id,
420
+ 'roiIndex': roi_index,
421
+ 'xOrigin': x_origin,
422
+ 'yOrigin': y_origin,
423
+ 'xSize': x_size,
424
+ 'ySize': y_size,
425
+ 'xBin': x_bin,
426
+ 'yBin': y_bin,
427
+ },
428
+ )
429
+
430
+ async def get_acquisition_data(self) -> dict[Any, Any]:
431
+ """Returns the acquisition data of the CCD
432
+ nina: atm this returns data still formatted for telnet communication, not formatted as json"""
433
+ response: Response = await super()._execute_command('ccd_getAcquisitionData', {'index': self._id})
434
+ return response.results
435
+
436
+ async def get_acquisition_busy(self) -> bool:
437
+ """Returns true if the CCD is busy with the acquisition"""
438
+ response: Response = await super()._execute_command('ccd_getAcquisitionBusy', {'index': self._id})
439
+ return bool(response.results['isBusy'])
440
+
441
+ async def set_acquisition_abort(self) -> None:
442
+ """Stops the acquisition of the CCD"""
443
+ await super()._execute_command('ccd_setAcquisitionAbort', {'index': self._id})