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.
- horiba_sdk/__init__.py +19 -0
- horiba_sdk/communication/__init__.py +44 -0
- horiba_sdk/communication/abstract_communicator.py +59 -0
- horiba_sdk/communication/communication_exception.py +19 -0
- horiba_sdk/communication/messages.py +87 -0
- horiba_sdk/communication/websocket_communicator.py +213 -0
- horiba_sdk/core/resolution.py +45 -0
- horiba_sdk/devices/__init__.py +11 -0
- horiba_sdk/devices/abstract_device_discovery.py +7 -0
- horiba_sdk/devices/abstract_device_manager.py +68 -0
- horiba_sdk/devices/ccd_discovery.py +57 -0
- horiba_sdk/devices/device_manager.py +250 -0
- horiba_sdk/devices/fake_device_manager.py +133 -0
- horiba_sdk/devices/fake_icl_server.py +56 -0
- horiba_sdk/devices/fake_responses/ccd.json +168 -0
- horiba_sdk/devices/fake_responses/icl.json +29 -0
- horiba_sdk/devices/fake_responses/monochromator.json +187 -0
- horiba_sdk/devices/monochromator_discovery.py +48 -0
- horiba_sdk/devices/single_devices/__init__.py +5 -0
- horiba_sdk/devices/single_devices/abstract_device.py +79 -0
- horiba_sdk/devices/single_devices/ccd.py +443 -0
- horiba_sdk/devices/single_devices/monochromator.py +395 -0
- horiba_sdk/icl_error/__init__.py +34 -0
- horiba_sdk/icl_error/abstract_error.py +65 -0
- horiba_sdk/icl_error/abstract_error_db.py +25 -0
- horiba_sdk/icl_error/error_list.json +265 -0
- horiba_sdk/icl_error/icl_error.py +30 -0
- horiba_sdk/icl_error/icl_error_db.py +81 -0
- horiba_sdk/sync/__init__.py +0 -0
- horiba_sdk/sync/communication/__init__.py +7 -0
- horiba_sdk/sync/communication/abstract_communicator.py +48 -0
- horiba_sdk/sync/communication/test_client.py +16 -0
- horiba_sdk/sync/communication/websocket_communicator.py +212 -0
- horiba_sdk/sync/devices/__init__.py +15 -0
- horiba_sdk/sync/devices/abstract_device_discovery.py +17 -0
- horiba_sdk/sync/devices/abstract_device_manager.py +68 -0
- horiba_sdk/sync/devices/device_discovery.py +82 -0
- horiba_sdk/sync/devices/device_manager.py +209 -0
- horiba_sdk/sync/devices/fake_device_manager.py +91 -0
- horiba_sdk/sync/devices/fake_icl_server.py +79 -0
- horiba_sdk/sync/devices/single_devices/__init__.py +5 -0
- horiba_sdk/sync/devices/single_devices/abstract_device.py +83 -0
- horiba_sdk/sync/devices/single_devices/ccd.py +219 -0
- horiba_sdk/sync/devices/single_devices/monochromator.py +150 -0
- horiba_sdk-0.3.2.dist-info/LICENSE +20 -0
- horiba_sdk-0.3.2.dist-info/METADATA +438 -0
- horiba_sdk-0.3.2.dist-info/RECORD +48 -0
- horiba_sdk-0.3.2.dist-info/WHEEL +4 -0
@@ -0,0 +1,187 @@
|
|
1
|
+
{
|
2
|
+
"mono_discover": {
|
3
|
+
"id": 1234,
|
4
|
+
"command": "mono_discover",
|
5
|
+
"results": {
|
6
|
+
"count": 1
|
7
|
+
|
8
|
+
},
|
9
|
+
"errors": []
|
10
|
+
},
|
11
|
+
"mono_list": {
|
12
|
+
"id": 1234,
|
13
|
+
"command": "mono_list",
|
14
|
+
"results": {
|
15
|
+
"list": [
|
16
|
+
"0;iHR550;sn12345",
|
17
|
+
"1;iHR320;snabscde"
|
18
|
+
]
|
19
|
+
},
|
20
|
+
"errors": []
|
21
|
+
},
|
22
|
+
"mono_listCount": {
|
23
|
+
"id": 1234,
|
24
|
+
"command": "mono_listCount",
|
25
|
+
"results": {
|
26
|
+
"count": 2
|
27
|
+
},
|
28
|
+
"errors": []
|
29
|
+
},
|
30
|
+
"mono_open": {
|
31
|
+
"id": 1234,
|
32
|
+
"command": "mono_open",
|
33
|
+
"errors": []
|
34
|
+
},
|
35
|
+
"mono_close": {
|
36
|
+
"id": 1234,
|
37
|
+
"command": "mono_close",
|
38
|
+
"errors": []
|
39
|
+
},
|
40
|
+
"mono_isOpen": {
|
41
|
+
"id": 1234,
|
42
|
+
"command": "mono_isOpen",
|
43
|
+
"results":{
|
44
|
+
"open": true
|
45
|
+
},
|
46
|
+
"errors": []
|
47
|
+
},
|
48
|
+
"mono_isBusy": {
|
49
|
+
"id": 1234,
|
50
|
+
"command": "mono_isBusy",
|
51
|
+
"results":{
|
52
|
+
"busy": false
|
53
|
+
},
|
54
|
+
"errors": []
|
55
|
+
},
|
56
|
+
"mono_init": {
|
57
|
+
"id": 1234,
|
58
|
+
"command": "mono_init",
|
59
|
+
"errors": []
|
60
|
+
},
|
61
|
+
"mono_getConfig": {
|
62
|
+
"id": 1234,
|
63
|
+
"command": "mono_getConfig",
|
64
|
+
"results":{
|
65
|
+
},
|
66
|
+
"errors": []
|
67
|
+
|
68
|
+
},
|
69
|
+
"mono_setConfig": {},
|
70
|
+
"mono_getPosition": {
|
71
|
+
"id": 1234,
|
72
|
+
"command": "mono_getPosition",
|
73
|
+
"results":{
|
74
|
+
"wavelength": 320.0
|
75
|
+
},
|
76
|
+
"errors": []
|
77
|
+
},
|
78
|
+
"mono_setPosition": {
|
79
|
+
"id": 1234,
|
80
|
+
"command": "mono_setPosition",
|
81
|
+
"errors": []
|
82
|
+
},
|
83
|
+
"mono_moveToPosition": {
|
84
|
+
"id": 1234,
|
85
|
+
"command": "mono_moveToPosition",
|
86
|
+
"errors": []
|
87
|
+
},
|
88
|
+
"mono_getGratingPosition": {
|
89
|
+
"id": 1234,
|
90
|
+
"command": "mono_getPosition",
|
91
|
+
"results":{
|
92
|
+
"position": 1
|
93
|
+
},
|
94
|
+
"errors": []
|
95
|
+
},
|
96
|
+
"mono_moveGrating": {
|
97
|
+
"id": 1234,
|
98
|
+
"command": "mono_getPosition",
|
99
|
+
"results":{
|
100
|
+
"position": 1
|
101
|
+
},
|
102
|
+
"errors": []
|
103
|
+
},
|
104
|
+
"mono_getFilterWheelPosition": {
|
105
|
+
"id": 1234,
|
106
|
+
"command": "mono_getFilterWheelPosition",
|
107
|
+
"results":{
|
108
|
+
"position": 0
|
109
|
+
},
|
110
|
+
"errors": []
|
111
|
+
},
|
112
|
+
"mono_moveFilterWheel": {
|
113
|
+
"id": 1234,
|
114
|
+
"command": "mono_moveFilterWheel",
|
115
|
+
"results":{
|
116
|
+
},
|
117
|
+
"errors": []
|
118
|
+
},
|
119
|
+
"mono_getMirrorPosition": {
|
120
|
+
"id": 1234,
|
121
|
+
"command": "mono_getMirrorPosition",
|
122
|
+
"results": {
|
123
|
+
"position": 0
|
124
|
+
},
|
125
|
+
"errors": []
|
126
|
+
},
|
127
|
+
"mono_moveMirror": {
|
128
|
+
"id": 1234,
|
129
|
+
"command": "mono_moveMirror",
|
130
|
+
"results": {},
|
131
|
+
"errors": []
|
132
|
+
},
|
133
|
+
"mono_getSlitPositionInMM": {
|
134
|
+
"id": 1234,
|
135
|
+
"command": "mono_getSlitPositionInMM",
|
136
|
+
"results": {
|
137
|
+
"position": 0
|
138
|
+
},
|
139
|
+
"errors": []
|
140
|
+
},
|
141
|
+
"mono_moveSlitMM": {
|
142
|
+
"id": 1234,
|
143
|
+
"command": "mono_moveSlitMM",
|
144
|
+
"results": {},
|
145
|
+
"errors": []
|
146
|
+
},
|
147
|
+
"mono_shutterOpen": {
|
148
|
+
"id": 1234,
|
149
|
+
"command": "mono_shutterOpen",
|
150
|
+
"results": {},
|
151
|
+
"errors": []
|
152
|
+
},
|
153
|
+
"mono_shutterClose": {
|
154
|
+
"id": 1234,
|
155
|
+
"command": "mono_shutterClose",
|
156
|
+
"results": {},
|
157
|
+
"errors": []
|
158
|
+
},
|
159
|
+
"mono_getShutterStatus": {
|
160
|
+
"id": 1234,
|
161
|
+
"command": "mono_getShutterStatus",
|
162
|
+
"results": {
|
163
|
+
"position": 0
|
164
|
+
},
|
165
|
+
"errors": []
|
166
|
+
},
|
167
|
+
"mono_getSlitStepPosition": {
|
168
|
+
"command": "mono_getSlitStepPosition",
|
169
|
+
"id": 1234,
|
170
|
+
"results": {
|
171
|
+
"position":0
|
172
|
+
},
|
173
|
+
"errors":[]
|
174
|
+
},
|
175
|
+
"mono_moveSlit": {
|
176
|
+
"id": 1234,
|
177
|
+
"command": "mono_moveSlit",
|
178
|
+
"results": {},
|
179
|
+
"errors": []
|
180
|
+
},
|
181
|
+
"mono_enableLaser": {},
|
182
|
+
"mono_getLaserStatus": {},
|
183
|
+
"mono_setLaserPower": {},
|
184
|
+
"mono_getLaserPower": {},
|
185
|
+
"mono_getLidStatus": {},
|
186
|
+
"mono_getSwitchStatus": {}
|
187
|
+
}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
from typing import Any, final
|
2
|
+
|
3
|
+
from loguru import logger
|
4
|
+
from overrides import override
|
5
|
+
|
6
|
+
from horiba_sdk.communication import AbstractCommunicator, Command, Response
|
7
|
+
from horiba_sdk.devices.abstract_device_discovery import AbstractDeviceDiscovery
|
8
|
+
from horiba_sdk.devices.single_devices import Monochromator
|
9
|
+
from horiba_sdk.icl_error import AbstractErrorDB
|
10
|
+
|
11
|
+
|
12
|
+
@final
|
13
|
+
class MonochromatorsDiscovery(AbstractDeviceDiscovery):
|
14
|
+
def __init__(self, communicator: AbstractCommunicator, error_db: AbstractErrorDB):
|
15
|
+
self._communicator: AbstractCommunicator = communicator
|
16
|
+
self._monochromators: list[Monochromator] = []
|
17
|
+
self._error_db: AbstractErrorDB = error_db
|
18
|
+
|
19
|
+
@override
|
20
|
+
async def execute(self, error_on_no_device: bool = False) -> None:
|
21
|
+
"""
|
22
|
+
Discovers the connected Monochromators and saves them internally.
|
23
|
+
"""
|
24
|
+
if not self._communicator.opened():
|
25
|
+
await self._communicator.open()
|
26
|
+
|
27
|
+
response: Response = await self._communicator.request_with_response(Command('mono_discover', {}))
|
28
|
+
if response.results.get('count', 0) == 0 and error_on_no_device:
|
29
|
+
raise Exception('No Monochromators connected')
|
30
|
+
|
31
|
+
response = await self._communicator.request_with_response(Command('mono_list', {}))
|
32
|
+
raw_device_list = response.results['list']
|
33
|
+
self._monochromators = self._parse_monos(raw_device_list)
|
34
|
+
logger.info(f'Found {len(self._monochromators)} Monochromator devices: {self._monochromators}')
|
35
|
+
|
36
|
+
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))
|
44
|
+
|
45
|
+
return detected_monos
|
46
|
+
|
47
|
+
def monochromators(self) -> list[Monochromator]:
|
48
|
+
return self._monochromators
|
@@ -0,0 +1,79 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from horiba_sdk.communication import AbstractCommunicator, Command, Response
|
5
|
+
from horiba_sdk.icl_error import AbstractError, AbstractErrorDB
|
6
|
+
|
7
|
+
|
8
|
+
class AbstractDevice(ABC):
|
9
|
+
"""
|
10
|
+
Abstract base class representing a generic device.
|
11
|
+
|
12
|
+
This class provides an interface for device-specific operations. Concrete implementations should provide specific
|
13
|
+
functionalities for each of the abstract methods.
|
14
|
+
|
15
|
+
Attributes:
|
16
|
+
_id (int):
|
17
|
+
_communicator (WebsocketCommunicator):
|
18
|
+
"""
|
19
|
+
|
20
|
+
def __init__(self, device_id: int, communicator: AbstractCommunicator, error_db: AbstractErrorDB) -> None:
|
21
|
+
self._id: int = device_id
|
22
|
+
self._error_db: AbstractErrorDB = error_db
|
23
|
+
self._communicator: AbstractCommunicator = communicator
|
24
|
+
|
25
|
+
@abstractmethod
|
26
|
+
async def open(self) -> None:
|
27
|
+
"""
|
28
|
+
Open a connection to the device.
|
29
|
+
|
30
|
+
Returns:
|
31
|
+
Result: Result object indicating success or failure.
|
32
|
+
"""
|
33
|
+
if not self._communicator.opened():
|
34
|
+
await self._communicator.open()
|
35
|
+
|
36
|
+
@abstractmethod
|
37
|
+
async def close(self) -> None:
|
38
|
+
"""
|
39
|
+
Close the connection to the device.
|
40
|
+
|
41
|
+
Returns:
|
42
|
+
Result: Result object indicating success or failure.
|
43
|
+
"""
|
44
|
+
pass
|
45
|
+
|
46
|
+
async def _execute_command(self, command_name: str, parameters: dict[Any, Any], timeout: int = 5) -> Response:
|
47
|
+
"""
|
48
|
+
Creates a command from the command name, and it's parameters
|
49
|
+
Executes a command and handles the response.
|
50
|
+
|
51
|
+
Args:
|
52
|
+
command_name (str): The name of the command to execute.
|
53
|
+
parameters (dict): The parameters for the command.
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
Response: The response from the device.
|
57
|
+
|
58
|
+
Raises:
|
59
|
+
Exception: When an error occurred on the device side.
|
60
|
+
"""
|
61
|
+
response: Response = await self._communicator.request_with_response(
|
62
|
+
Command(command_name, parameters), timeout=timeout
|
63
|
+
)
|
64
|
+
if response.errors:
|
65
|
+
self._handle_errors(response.errors)
|
66
|
+
return response
|
67
|
+
|
68
|
+
def _handle_errors(self, errors: list[str]) -> None:
|
69
|
+
"""
|
70
|
+
Handles errors, logs them, and may take corrective actions.
|
71
|
+
|
72
|
+
Args:
|
73
|
+
errors (Exception): The exception or error to handle.
|
74
|
+
"""
|
75
|
+
for error in errors:
|
76
|
+
icl_error: AbstractError = self._error_db.error_from(error)
|
77
|
+
icl_error.log()
|
78
|
+
# TODO: [saga] only throw depending on the log level, tbd
|
79
|
+
raise Exception(f'Error from the ICL: {icl_error.message()}')
|