keithley-tempcontrol 0.17.1__py3-none-any.whl → 0.17.3__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.
@@ -1,40 +1,33 @@
1
1
  import logging
2
2
  import re
3
3
  from pathlib import Path
4
- from typing import Dict
4
+ from typing import Dict, Union
5
5
  from typing import List
6
6
  from typing import Tuple
7
7
 
8
- from egse.connect import get_endpoint
9
8
  from egse.decorators import dynamic_interface
10
9
  from egse.device import DeviceConnectionState
11
10
  from egse.device import DeviceInterface
12
- from egse.log import logger
13
- from egse.mixin import CommandType
14
- from egse.mixin import DynamicCommandMixin
11
+ from egse.mixin import DynamicCommandMixin, CommandType
15
12
  from egse.mixin import add_lf
16
13
  from egse.mixin import dynamic_command
17
14
  from egse.proxy import Proxy
18
15
  from egse.settings import Settings
19
- from egse.tempcontrol.keithley.daq6510_dev import DAQ6510
16
+ from egse.tempcontrol.keithley.daq6510_dev import DAQ6510EthernetInterface
17
+ from egse.zmq_ser import connect_address
18
+
19
+ logger = logging.getLogger(__name__)
20
20
 
21
21
  HERE = Path(__file__).parent
22
22
 
23
- cs_settings = Settings.load("Keithley Control Server")
24
- dev_settings = Settings.load("Keithley DAQ6510")
23
+ CTRL_SETTINGS = Settings.load("Keithley Control Server")
24
+ FW_SETTINGS = Settings.load("Keithley DAQ6510")
25
+ DEVICE_SETTINGS = Settings.load(location=HERE, filename="daq6510.yaml")
25
26
 
26
- PROTOCOL = cs_settings.get("PROTOCOL", "tcp")
27
- HOSTNAME = cs_settings.get("HOSTNAME", "localhost")
28
- COMMANDING_PORT = cs_settings.get("COMMANDING_PORT", 0)
29
- TIMEOUT = cs_settings.get("TIMEOUT")
30
- SERVICE_TYPE = cs_settings.get("SERVICE_TYPE", "daq6510")
31
27
 
32
28
  DEFAULT_BUFFER_1 = "defbuffer1"
33
29
  DEFAULT_BUFFER_2 = "defbuffer2"
34
30
 
35
- DEV_HOST = dev_settings.get("HOSTNAME")
36
- DEV_PORT = dev_settings.get("PORT")
37
-
38
31
 
39
32
  class DAQ6510Interface(DeviceInterface):
40
33
  """
@@ -42,7 +35,7 @@ class DAQ6510Interface(DeviceInterface):
42
35
  """
43
36
 
44
37
  @dynamic_interface
45
- def send_command(self, command: str, response: bool) -> str | None:
38
+ def send_command(self, command: str, response: bool) -> Union[None, str]:
46
39
  """Sends the given SCPI command to the device.
47
40
 
48
41
  The valid commands are described in the DAQ6510 Reference Manual [DAQ6510-901-01 Rev. B / September 2019].
@@ -226,12 +219,12 @@ class DAQ6510Controller(DAQ6510Interface, DynamicCommandMixin):
226
219
  through an Ethernet interface.
227
220
  """
228
221
 
229
- def __init__(self, hostname: str = DEV_HOST, port: int = DEV_PORT):
222
+ def __init__(self, hostname: str = FW_SETTINGS.HOSTNAME, port: int = FW_SETTINGS.PORT):
230
223
  """Opens a TCP/IP socket connection with the Keithley DAQ6510 Hardware.
231
224
 
232
225
  Args:
233
- hostname (str): IP address or fully qualified hostname of the DAQ6510 hardware controller.
234
- The default is defined in the ``settings.yaml`` configuration file.
226
+ hostname (str): IP address or fully qualified hostname of the Hexapod hardware controller. The default is
227
+ defined in the ``settings.yaml`` configuration file.
235
228
  port (int): IP port number to connect to, by default set in the ``settings.yaml`` configuration file.
236
229
 
237
230
  Raises:
@@ -242,7 +235,7 @@ class DAQ6510Controller(DAQ6510Interface, DynamicCommandMixin):
242
235
 
243
236
  logger.debug(f"Initializing the DAQ6510 Controller with hostname={hostname} on port={port}")
244
237
 
245
- self.daq = self.transport = DAQ6510(hostname, port)
238
+ self.daq = self.transport = DAQ6510EthernetInterface(hostname, port)
246
239
 
247
240
  # We set the default buffer here, this can be changed with the `create_buffer()` method.
248
241
 
@@ -284,7 +277,7 @@ class DAQ6510Controller(DAQ6510Interface, DynamicCommandMixin):
284
277
 
285
278
  return self.daq.is_connected()
286
279
 
287
- def send_command(self, command: str, response: bool) -> str | None:
280
+ def send_command(self, command: str, response: bool) -> Union[None, str]:
288
281
  """Sends an SCPI command to the device.
289
282
 
290
283
  The valid commands are described in the DAQ6510 Reference Manual [DAQ6510-901-01 Rev. B / September 2019].
@@ -299,7 +292,7 @@ class DAQ6510Controller(DAQ6510Interface, DynamicCommandMixin):
299
292
 
300
293
  return self.daq.trans(command) if response else self.daq.write(command)
301
294
 
302
- def read_buffer(self, start: int, end: int, buffer_name: str = DEFAULT_BUFFER_1, elements: list[str] = None):
295
+ def read_buffer(self, start: int, end: int, buffer_name: str = DEFAULT_BUFFER_1, elements: List[str] = None):
303
296
  """Reads specific data elements (measurements) from the given buffer.
304
297
 
305
298
  Elements that can be specified to read out:
@@ -573,10 +566,10 @@ class DAQ6510Proxy(Proxy, DAQ6510Interface):
573
566
 
574
567
  def __init__(
575
568
  self,
576
- protocol: str = PROTOCOL,
577
- hostname: str = HOSTNAME,
578
- port: int = COMMANDING_PORT,
579
- timeout: float = TIMEOUT, # Timeout [s]: > scan count * interval + (one scan duration)
569
+ protocol: str = CTRL_SETTINGS.PROTOCOL,
570
+ hostname: str = CTRL_SETTINGS.HOSTNAME,
571
+ port: int = CTRL_SETTINGS.COMMANDING_PORT,
572
+ timeout: int = CTRL_SETTINGS.TIMEOUT * 1000, # Timeout [ms]: > scan count * interval + (one scan duration)
580
573
  ):
581
574
  """Initialisation of a DAQ6510Proxy.
582
575
 
@@ -585,12 +578,10 @@ class DAQ6510Proxy(Proxy, DAQ6510Interface):
585
578
  hostname (str): Location of the Control Server (IP address) [default is taken from settings file]
586
579
  port (int): TCP port on which the Control Server is listening for commands [default is taken from settings
587
580
  file]
588
- timeout (float): Timeout by which to establish the connection [s]
581
+ timeout (int): Timeout by which to establish the connection [ms]
589
582
  """
590
583
 
591
- endpoint = get_endpoint(SERVICE_TYPE, protocol, hostname, port)
592
-
593
- super().__init__(endpoint, timeout=timeout)
584
+ super().__init__(connect_address(protocol, hostname, port), timeout=timeout)
594
585
 
595
586
 
596
587
  def create_channel_list(*args) -> str:
@@ -1,28 +1,18 @@
1
- __all__ = [
2
- "DAQ6510",
3
- ]
4
-
5
1
  import asyncio
2
+ import logging
6
3
  from typing import Any
7
4
  from typing import Dict
8
5
  from typing import Optional
9
6
 
10
- from egse.log import logger
11
7
  from egse.scpi import AsyncSCPIInterface
12
- from egse.settings import Settings
13
-
14
- dev_settings = Settings.load("Keithley DAQ6510")
15
8
 
16
- DEV_HOST = dev_settings.get("HOSTNAME")
17
- DEV_PORT = dev_settings.get("PORT")
18
- DEVICE_NAME = dev_settings.get("DEVICE_NAME", "DAQ6510")
19
- DEV_ID_VALIDATION = "DAQ6510"
9
+ logger = logging.getLogger(__name__)
20
10
 
21
11
 
22
12
  class DAQ6510(AsyncSCPIInterface):
23
13
  """Keithley DAQ6510 specific implementation."""
24
14
 
25
- def __init__(self, hostname: str = DEV_HOST, port: int = DEV_PORT, settings: Optional[Dict[str, Any]] = None):
15
+ def __init__(self, hostname: str, port: int = 5025, settings: Optional[Dict[str, Any]] = None):
26
16
  """Initialize a Keithley DAQ6510 interface.
27
17
 
28
18
  Args:
@@ -31,15 +21,45 @@ class DAQ6510(AsyncSCPIInterface):
31
21
  settings: Additional device settings
32
22
  """
33
23
  super().__init__(
34
- device_name=DEVICE_NAME,
24
+ device_name="DAQ6510",
35
25
  hostname=hostname,
36
26
  port=port,
37
27
  settings=settings,
38
- id_validation=DEV_ID_VALIDATION, # String that must appear in IDN? response
28
+ id_validation="DAQ6510", # String that must appear in IDN? response
39
29
  )
40
30
 
41
31
  self._measurement_lock = asyncio.Lock()
42
32
 
33
+ async def initialize(self):
34
+ # Initialize
35
+
36
+ await self.write("*RST") # this also the user-defined buffer "test1"
37
+
38
+ for cmd, response in [
39
+ ('TRAC:MAKE "test1", 1000', False), # create a new buffer
40
+ # settings for channel 1 and 2 of slot 1
41
+ ('SENS:FUNC "TEMP", (@101:102)', False), # set the function to temperature
42
+ ("SENS:TEMP:TRAN FRTD, (@101)", False), # set the transducer to 4-wire RTD
43
+ ("SENS:TEMP:RTD:FOUR PT100, (@101)", False), # set the type of the 4-wire RTD
44
+ ("SENS:TEMP:TRAN RTD, (@102)", False), # set the transducer to 2-wire RTD
45
+ ("SENS:TEMP:RTD:TWO PT100, (@102)", False), # set the type of the 2-wire RTD
46
+ ('ROUT:SCAN:BUFF "test1"', False),
47
+ ("ROUT:SCAN:CRE (@101:102)", False),
48
+ ("ROUT:CHAN:OPEN (@101:102)", False),
49
+ ("ROUT:STAT? (@101:102)", True),
50
+ ("ROUT:SCAN:STAR:STIM NONE", False),
51
+ # ("ROUT:SCAN:ADD:SING (@101, 102)", False), # not sure what this does, not really needed
52
+ ("ROUT:SCAN:COUN:SCAN 1", False), # not sure if this is needed in this setting
53
+ # ("ROUT:SCAN:INT 1", False),
54
+ ]:
55
+ if response:
56
+ logger.info(f"Sending {cmd}...")
57
+ response = (await self.trans(cmd)).decode().strip()
58
+ logger.info(f"{response = }")
59
+ else:
60
+ logger.info(f"Sending {cmd}...")
61
+ await self.write(cmd)
62
+
43
63
  async def get_measurement(self, channel: str) -> float:
44
64
  """Get a measurement from a specific channel.
45
65
 
@@ -1,29 +1,22 @@
1
+ import logging
1
2
  import multiprocessing
2
3
  import sys
3
4
 
5
+ import click
6
+ import invoke
4
7
  import rich
5
- import typer
6
8
  import zmq
7
-
8
- from egse.connect import get_endpoint
9
9
  from egse.control import ControlServer
10
10
  from egse.control import is_control_server_active
11
- from egse.log import logger
12
- from egse.logger import remote_logging
13
- from egse.registry.client import RegistryClient
14
11
  from egse.settings import Settings
15
- from egse.storage import store_housekeeping_information
16
12
  from egse.tempcontrol.keithley.daq6510 import DAQ6510Proxy
17
13
  from egse.tempcontrol.keithley.daq6510_protocol import DAQ6510Protocol
18
14
  from egse.zmq_ser import connect_address
15
+ from prometheus_client import start_http_server
19
16
 
20
- cs_settings = Settings.load("Keithley Control Server")
17
+ logger = logging.getLogger(__name__)
21
18
 
22
- PROTOCOL = cs_settings.get("PROTOCOL", "tcp")
23
- HOSTNAME = cs_settings.get("HOSTNAME", "localhost")
24
- COMMANDING_PORT = cs_settings.get("COMMANDING_PORT", 0)
25
- STORAGE_MNEMONIC = cs_settings.get("STORAGE_MNEMONIC", "DAQ6510")
26
- SERVICE_TYPE = cs_settings.get("SERVICE_TYPE", "daq6510")
19
+ CTRL_SETTINGS = Settings.load("Keithley Control Server")
27
20
 
28
21
 
29
22
  def is_daq6510_cs_active(timeout: float = 0.5) -> bool:
@@ -35,14 +28,7 @@ def is_daq6510_cs_active(timeout: float = 0.5) -> bool:
35
28
  Returns: True if the Control Server is running and replied with the expected answer; False otherwise.
36
29
  """
37
30
 
38
- if COMMANDING_PORT == 0:
39
- with RegistryClient() as client:
40
- endpoint = client.get_endpoint(SERVICE_TYPE)
41
- if endpoint is None:
42
- logger.debug(f"No endpoint for {SERVICE_TYPE}")
43
- return False
44
- else:
45
- endpoint = connect_address(PROTOCOL, HOSTNAME, COMMANDING_PORT)
31
+ endpoint = connect_address(CTRL_SETTINGS.PROTOCOL, CTRL_SETTINGS.HOSTNAME, CTRL_SETTINGS.COMMANDING_PORT)
46
32
 
47
33
  return is_control_server_active(endpoint, timeout)
48
34
 
@@ -76,15 +62,13 @@ class DAQ6510ControlServer(ControlServer):
76
62
 
77
63
  self.poller.register(self.dev_ctrl_cmd_sock, zmq.POLLIN)
78
64
 
79
- self.register_service(service_type=cs_settings.SERVICE_TYPE)
80
-
81
65
  def get_communication_protocol(self) -> str:
82
66
  """Returns the communication protocol used by the Control Server.
83
67
 
84
68
  Returns: Communication protocol used by the Control Server, as specified in the settings.
85
69
  """
86
70
 
87
- return cs_settings.PROTOCOL
71
+ return CTRL_SETTINGS.PROTOCOL
88
72
 
89
73
  def get_commanding_port(self) -> int:
90
74
  """Returns the commanding port used by the Control Server.
@@ -92,7 +76,7 @@ class DAQ6510ControlServer(ControlServer):
92
76
  Returns: Commanding port used by the Control Server, as specified in the settings.
93
77
  """
94
78
 
95
- return cs_settings.COMMANDING_PORT
79
+ return CTRL_SETTINGS.COMMANDING_PORT
96
80
 
97
81
  def get_service_port(self):
98
82
  """Returns the service port used by the Control Server.
@@ -100,7 +84,7 @@ class DAQ6510ControlServer(ControlServer):
100
84
  Returns: Service port used by the Control Server, as specified in the settings.
101
85
  """
102
86
 
103
- return cs_settings.SERVICE_PORT
87
+ return CTRL_SETTINGS.SERVICE_PORT
104
88
 
105
89
  def get_monitoring_port(self):
106
90
  """Returns the monitoring port used by the Control Server.
@@ -108,7 +92,7 @@ class DAQ6510ControlServer(ControlServer):
108
92
  Returns: Monitoring port used by the Control Server, as specified in the settings.
109
93
  """
110
94
 
111
- return cs_settings.MONITORING_PORT
95
+ return CTRL_SETTINGS.MONITORING_PORT
112
96
 
113
97
  def get_storage_mnemonic(self):
114
98
  """Returns the storage mnemonics used by the Control Server.
@@ -120,88 +104,57 @@ class DAQ6510ControlServer(ControlServer):
120
104
  settings, "DAQ6510" will be used.
121
105
  """
122
106
 
123
- return STORAGE_MNEMONIC
124
-
125
- def is_storage_manager_active(self):
126
- from egse.storage import is_storage_manager_active
127
-
128
- return is_storage_manager_active()
129
-
130
- def store_housekeeping_information(self, data):
131
- """Send housekeeping information to the Storage manager."""
132
-
133
- origin = self.get_storage_mnemonic()
134
- store_housekeeping_information(origin, data)
135
-
136
- def register_to_storage_manager(self):
137
- from egse.storage import register_to_storage_manager
138
- from egse.storage.persistence import TYPES
139
-
140
- register_to_storage_manager(
141
- origin=self.get_storage_mnemonic(),
142
- persistence_class=TYPES["CSV"],
143
- prep={
144
- "column_names": list(self.device_protocol.get_housekeeping().keys()),
145
- "mode": "a",
146
- },
147
- )
148
-
149
- def unregister_from_storage_manager(self):
150
- from egse.storage import unregister_from_storage_manager
151
-
152
- unregister_from_storage_manager(origin=self.get_storage_mnemonic())
107
+ try:
108
+ return CTRL_SETTINGS.STORAGE_MNEMONIC
109
+ except AttributeError:
110
+ return "DAQ6510"
153
111
 
154
112
  def before_serve(self):
155
113
  """Steps to take before the Control Server is activated."""
156
114
 
115
+ start_http_server(CTRL_SETTINGS.METRICS_PORT)
116
+
157
117
 
158
- app = typer.Typer(name="daq6510_cs")
118
+ @click.group()
119
+ def cli():
120
+ pass
159
121
 
160
122
 
161
- @app.command()
123
+ @cli.command()
162
124
  def start():
163
125
  """Starts the Keithley DAQ6510 Control Server."""
164
126
 
165
127
  multiprocessing.current_process().name = "daq6510_cs (start)"
166
128
 
167
- with remote_logging():
168
- from egse.env import setup_env
169
-
170
- setup_env()
171
-
172
- try:
173
- control_server = DAQ6510ControlServer()
174
- control_server.serve()
175
- except KeyboardInterrupt:
176
- logger.debug("Shutdown requested...exiting")
177
- except SystemExit as exit_code:
178
- logger.debug("System Exit with code {}.".format(exit_code))
179
- sys.exit(exit_code.code)
180
- except Exception:
181
- msg = "Cannot start the DAQ6510 Control Server"
182
- logger.exception(msg)
183
- rich.print(f"[red]{msg}.")
129
+ try:
130
+ control_server = DAQ6510ControlServer()
131
+ control_server.serve()
132
+ except KeyboardInterrupt:
133
+ logger.debug("Shutdown requested...exiting")
134
+ except SystemExit as exit_code:
135
+ logger.debug("System Exit with code {}.".format(exit_code))
136
+ sys.exit(exit_code)
137
+ except Exception:
138
+ msg = "Cannot start the DAQ6510 Control Server"
139
+ logger.exception(msg)
140
+ rich.print(f"[red]{msg}.")
184
141
 
185
142
  return 0
186
143
 
187
144
 
188
- @app.command()
145
+ @cli.command()
189
146
  def start_bg():
190
147
  """Starts the DAQ6510 Control Server in the background."""
191
148
 
192
- print("Starting the DAQ6510 in the background is not implemented.")
149
+ invoke.run("daq6510_cs start", disown=True)
193
150
 
194
151
 
195
- @app.command()
152
+ @cli.command()
196
153
  def stop():
197
154
  """Sends a 'quit_server' command to the Keithley DAQ6510 Control Server."""
198
155
 
199
156
  multiprocessing.current_process().name = "daq6510_cs (stop)"
200
157
 
201
- from egse.env import setup_env
202
-
203
- setup_env()
204
-
205
158
  try:
206
159
  with DAQ6510Proxy() as daq:
207
160
  sp = daq.get_service_proxy()
@@ -212,17 +165,17 @@ def stop():
212
165
  rich.print(f"[red]{msg}, could not send the Quit command. [black]Check log messages.")
213
166
 
214
167
 
215
- @app.command()
168
+ @cli.command()
216
169
  def status():
217
170
  """Requests status information from the Control Server."""
218
171
 
219
172
  multiprocessing.current_process().name = "daq6510_cs (status)"
220
173
 
221
- from egse.env import setup_env
174
+ protocol = CTRL_SETTINGS.PROTOCOL
175
+ hostname = CTRL_SETTINGS.HOSTNAME
176
+ port = CTRL_SETTINGS.COMMANDING_PORT
222
177
 
223
- setup_env()
224
-
225
- endpoint = get_endpoint(SERVICE_TYPE, PROTOCOL, HOSTNAME, COMMANDING_PORT)
178
+ endpoint = connect_address(protocol, hostname, port)
226
179
 
227
180
  if is_control_server_active(endpoint):
228
181
  rich.print("DAQ6510 CS: [green]active")
@@ -237,4 +190,6 @@ def status():
237
190
 
238
191
 
239
192
  if __name__ == "__main__":
240
- sys.exit(app())
193
+ logging.basicConfig(level=logging.DEBUG, format=Settings.LOG_FORMAT_FULL)
194
+
195
+ sys.exit(cli())
@@ -1,30 +1,23 @@
1
- __all__ = [
2
- "DAQ6510",
3
- "DAQ6510Command",
4
- ]
1
+ import logging
5
2
  import socket
6
3
  import time
7
4
 
8
5
  from egse.command import ClientServerCommand
9
6
  from egse.device import DeviceConnectionError
7
+ from egse.device import DeviceConnectionInterface
10
8
  from egse.device import DeviceError
11
- from egse.device import DeviceInterface
12
9
  from egse.device import DeviceTimeoutError
13
10
  from egse.device import DeviceTransport
14
- from egse.log import logger
15
11
  from egse.settings import Settings
12
+ from egse.system import Timer
16
13
 
17
- IDENTIFICATION_QUERY = "*IDN?"
18
-
19
- dev_settings = Settings.load("Keithley DAQ6510")
14
+ logger = logging.getLogger(__name__)
20
15
 
21
- DEVICE_NAME = dev_settings.get("DEVICE_NAME", "DAQ6510")
22
- DEV_HOST = dev_settings.get("HOSTNAME")
23
- DEV_PORT = dev_settings.get("PORT")
24
- READ_TIMEOUT = dev_settings.get("TIMEOUT") # [s], can be smaller than timeout (for DAQ6510Proxy) (e.g. 1s)
16
+ IDENTIFICATION_QUERY = "*IDN?"
25
17
 
26
- SEPARATOR = b"\n"
27
- SEPARATOR_STR = SEPARATOR.decode()
18
+ DEVICE_SETTINGS = Settings.load("Keithley DAQ6510")
19
+ DEVICE_NAME = "DAQ6510"
20
+ READ_TIMEOUT = DEVICE_SETTINGS.TIMEOUT # [s], can be smaller than timeout (for DAQ6510Proxy) (e.g. 1s)
28
21
 
29
22
 
30
23
  class DAQ6510Command(ClientServerCommand):
@@ -39,13 +32,13 @@ class DAQ6510Command(ClientServerCommand):
39
32
  """
40
33
 
41
34
  out = super().get_cmd_string(*args, **kwargs)
42
- return out + SEPARATOR_STR
35
+ return out + "\n"
43
36
 
44
37
 
45
- class DAQ6510(DeviceInterface, DeviceTransport):
38
+ class DAQ6510EthernetInterface(DeviceConnectionInterface, DeviceTransport):
46
39
  """Defines the low-level interface to the Keithley DAQ6510 Controller."""
47
40
 
48
- def __init__(self, hostname: str = DEV_HOST, port: int = DEV_PORT):
41
+ def __init__(self, hostname: str = None, port: int = None):
49
42
  """Initialisation of an Ethernet interface for the DAQ6510.
50
43
 
51
44
  Args:
@@ -55,66 +48,12 @@ class DAQ6510(DeviceInterface, DeviceTransport):
55
48
 
56
49
  super().__init__()
57
50
 
58
- self.device_name = DEVICE_NAME
59
- self.hostname = hostname
60
- self.port = port
51
+ self.hostname = DEVICE_SETTINGS.HOSTNAME if hostname is None else hostname
52
+ self.port = DEVICE_SETTINGS.PORT if port is None else port
61
53
  self._sock = None
62
54
 
63
55
  self._is_connection_open = False
64
56
 
65
- def initialize(self, commands: list[tuple[str, bool]] = None, reset_device: bool = False) -> list[str | None]:
66
- """Initialize the device with optional reset and command sequence.
67
-
68
- Performs device initialization by optionally resetting the device and then
69
- executing a sequence of commands. Each command can optionally expect a
70
- response that will be logged for debugging purposes.
71
-
72
- Args:
73
- commands: List of tuples containing (command_string, expects_response).
74
- Each tuple specifies a command to send and whether to wait for and
75
- log the response. Defaults to None (no commands executed).
76
- reset_device: Whether to send a reset command (*RST) before executing
77
- the command sequence. Defaults to False.
78
-
79
- Returns:
80
- Response for each of the commands, or None when no response was expected.
81
-
82
- Raises:
83
- Any exceptions raised by the underlying write() or trans() methods,
84
- typically communication errors or device timeouts.
85
-
86
- Example:
87
- responses = device.initialize(
88
- [
89
- ("*IDN?", True), # Query device ID, expect response
90
- ("SYST:ERR?", True), # Check for errors, expect response
91
- ("OUTP ON", False) # Enable output, no response expected
92
- ],
93
- reset_device=True
94
- )
95
- """
96
-
97
- commands = commands or []
98
- responses = []
99
-
100
- if reset_device:
101
- logger.info(f"Resetting the {self.device_name}...")
102
- self.write("*RST") # this also resets the user-defined buffer
103
-
104
- for cmd, expects_response in commands:
105
- if expects_response:
106
- logger.debug(f"Sending {cmd}...")
107
- response = self.trans(cmd).decode().strip()
108
- logger.debug(f"{response = }")
109
- else:
110
- logger.debug(f"Sending {cmd}...")
111
- self.write(cmd)
112
-
113
- return responses
114
-
115
- def is_simulator(self) -> bool:
116
- return False
117
-
118
57
  def connect(self) -> None:
119
58
  """Connects the device.
120
59
 
@@ -248,7 +187,7 @@ class DAQ6510(DeviceInterface, DeviceTransport):
248
187
  """
249
188
 
250
189
  try:
251
- command += SEPARATOR_STR if not command.endswith(SEPARATOR_STR) else ""
190
+ command += "\n" if not command.endswith("\n") else ""
252
191
 
253
192
  self._sock.sendall(command.encode())
254
193
 
@@ -263,7 +202,7 @@ class DAQ6510(DeviceInterface, DeviceTransport):
263
202
  raise DeviceConnectionError(DEVICE_NAME, msg)
264
203
  raise
265
204
 
266
- def trans(self, command: str) -> bytes:
205
+ def trans(self, command: str) -> str:
267
206
  """Sends a single command to the device controller and block until a response from the controller.
268
207
 
269
208
  This is seen as a transaction.
@@ -282,7 +221,7 @@ class DAQ6510(DeviceInterface, DeviceTransport):
282
221
  try:
283
222
  # Attempt to send the complete command
284
223
 
285
- command += SEPARATOR_STR if not command.endswith(SEPARATOR_STR) else ""
224
+ command += "\n" if not command.endswith("\n") else ""
286
225
 
287
226
  self._sock.sendall(command.encode())
288
227
 
@@ -328,7 +267,10 @@ class DAQ6510(DeviceInterface, DeviceTransport):
328
267
  break
329
268
  except socket.timeout:
330
269
  logger.warning(f"Socket timeout error for {self.hostname}:{self.port}")
331
- return SEPARATOR
270
+ return b"\r\n"
271
+ except TimeoutError as exc:
272
+ logger.warning(f"Socket timeout error: {exc}")
273
+ return b"\r\n"
332
274
  finally:
333
275
  self._sock.settimeout(saved_timeout)
334
276
 
@@ -1,31 +1,22 @@
1
1
  import asyncio
2
2
  import datetime
3
3
  import json
4
+ import logging
4
5
  import signal
5
6
  import time
6
7
  from asyncio import Task
7
8
  from pathlib import Path
8
9
  from typing import Any
9
- from typing import Callable
10
10
  from typing import Optional
11
11
 
12
- import typer
13
12
  import zmq
14
13
  import zmq.asyncio
15
14
 
16
15
  from egse.device import DeviceConnectionError
17
16
  from egse.device import DeviceTimeoutError
18
- from egse.log import logger
19
- from egse.settings import Settings
20
- from egse.system import TyperAsyncCommand
21
17
  from egse.tempcontrol.keithley.daq6510_adev import DAQ6510
22
18
 
23
- settings = Settings.load("Keithley DAQ6510")
24
-
25
- DAQ_DEV_HOST = settings.get("HOSTNAME")
26
- DAQ_DEV_PORT = settings.get("PORT")
27
-
28
- DAQ_MON_CMD_PORT = 5556
19
+ logger = logging.getLogger("daq6510-mon")
29
20
 
30
21
 
31
22
  class DAQ6510Monitor:
@@ -37,8 +28,8 @@ class DAQ6510Monitor:
37
28
  def __init__(
38
29
  self,
39
30
  daq_hostname: str,
40
- daq_port: int = DAQ_DEV_PORT,
41
- zmq_port: int = DAQ_MON_CMD_PORT,
31
+ daq_port: int = 5025,
32
+ zmq_port: int = 5556,
42
33
  log_file: str = "temperature_readings.log",
43
34
  channels: list[str] = None,
44
35
  poll_interval: float = 60.0,
@@ -69,7 +60,7 @@ class DAQ6510Monitor:
69
60
  self.running = False
70
61
  self.polling_active = False
71
62
  self.daq_interface = None
72
- self.command_handlers: dict[str, Callable] = {
63
+ self.command_handlers = {
73
64
  "START_POLLING": self._handle_start_polling,
74
65
  "STOP_POLLING": self._handle_stop_polling,
75
66
  "SET_INTERVAL": self._handle_set_interval,
@@ -87,8 +78,6 @@ class DAQ6510Monitor:
87
78
  self.log_file.parent.mkdir(exist_ok=True, parents=True)
88
79
 
89
80
  # Create DAQ interface
90
- # In this case we use the device itself, no control server. That means
91
- # the monitoring must be the only service connecting to the device.
92
81
  self.daq_interface = DAQ6510(hostname=daq_hostname, port=daq_port)
93
82
 
94
83
  async def start(self):
@@ -96,12 +85,9 @@ class DAQ6510Monitor:
96
85
  logger.info(f"Starting DAQ6510 Monitoring Service on ZMQ port {self.zmq_port}")
97
86
  self.running = True
98
87
 
99
- def handle_shutdown():
100
- asyncio.create_task(self.shutdown())
101
-
102
88
  # Register signal handlers for graceful shutdown
103
89
  for sig in (signal.SIGINT, signal.SIGTERM):
104
- asyncio.get_event_loop().add_signal_handler(sig, handle_shutdown)
90
+ asyncio.get_event_loop().add_signal_handler(sig, lambda: asyncio.create_task(self.shutdown()))
105
91
 
106
92
  # Start the main service tasks
107
93
  await asyncio.gather(self.command_listener(), self.connect_daq(), return_exceptions=True)
@@ -115,29 +101,11 @@ class DAQ6510Monitor:
115
101
  async def connect_daq(self):
116
102
  """Establish connection to the DAQ6510."""
117
103
  while self.running:
118
- init_commands = [
119
- ('TRAC:MAKE "test1", 1000', False), # create a new buffer
120
- # settings for channel 1 and 2 of slot 1
121
- ('SENS:FUNC "TEMP", (@101:102)', False), # set the function to temperature
122
- ("SENS:TEMP:TRAN FRTD, (@101)", False), # set the transducer to 4-wire RTD
123
- ("SENS:TEMP:RTD:FOUR PT100, (@101)", False), # set the type of the 4-wire RTD
124
- ("SENS:TEMP:TRAN RTD, (@102)", False), # set the transducer to 2-wire RTD
125
- ("SENS:TEMP:RTD:TWO PT100, (@102)", False), # set the type of the 2-wire RTD
126
- ('ROUT:SCAN:BUFF "test1"', False),
127
- ("ROUT:SCAN:CRE (@101:102)", False),
128
- ("ROUT:CHAN:OPEN (@101:102)", False),
129
- ("ROUT:STAT? (@101:102)", True),
130
- ("ROUT:SCAN:STAR:STIM NONE", False),
131
- # ("ROUT:SCAN:ADD:SING (@101, 102)", False), # not sure what this does, not really needed
132
- ("ROUT:SCAN:COUN:SCAN 1", False), # not sure if this is needed in this setting
133
- # ("ROUT:SCAN:INT 1", False),
134
- ]
135
-
136
104
  try:
137
105
  logger.info(f"Connecting to DAQ6510 at {self.daq_hostname}:{self.daq_port}")
138
106
  await self.daq_interface.connect()
139
107
  logger.info("Successfully connected to DAQ6510.")
140
- await self.daq_interface.initialize(commands=init_commands, reset_device=True)
108
+ await self.daq_interface.initialize()
141
109
  logger.info("Successfully initialized DAQ6510 for measurements.")
142
110
 
143
111
  # If we were polling before, restart it.
@@ -399,9 +367,9 @@ class DAQ6510Monitor:
399
367
 
400
368
 
401
369
  class DAQMonitorClient:
402
- """A simple client for interacting with the DAQ Monitor Service."""
370
+ """Simple client for interacting with the DAQ Monitor Service."""
403
371
 
404
- def __init__(self, server_address: str = "localhost", port: int = DAQ_MON_CMD_PORT, timeout: float = 5.0):
372
+ def __init__(self, server_address: str = "localhost", port: int = 5556, timeout: float = 5.0):
405
373
  """Initialize the client.
406
374
 
407
375
  Args:
@@ -444,7 +412,7 @@ class DAQMonitorClient:
444
412
  params: Optional command parameters
445
413
 
446
414
  Returns:
447
- Response from the service as a dictionary.
415
+ Response from the service
448
416
  """
449
417
  params = params or {}
450
418
  message = {"command": command, "params": params}
@@ -520,10 +488,8 @@ class DAQMonitorClient:
520
488
  def get_status(self) -> dict[str, Any]:
521
489
  """Get current service status.
522
490
 
523
- To confirm the status is 'ok', check the response for the key 'status'.
524
-
525
491
  Returns:
526
- Status information as dictionary.
492
+ Status information
527
493
  """
528
494
  return self._send_command("GET_STATUS")
529
495
 
@@ -536,19 +502,12 @@ class DAQMonitorClient:
536
502
  return self._send_command("SHUTDOWN")
537
503
 
538
504
 
539
- app = typer.Typer(name="daq6510_mon")
540
-
541
-
542
- @app.command(cls=TyperAsyncCommand, name="monitor")
543
- async def main(log_file: str = "temperature_readings.log"):
544
- """
545
- Start the DAQ6510 monitoring app in the background.
546
- """
505
+ async def main():
547
506
  monitor = DAQ6510Monitor(
548
- daq_hostname=DAQ_DEV_HOST,
549
- daq_port=DAQ_DEV_PORT,
550
- zmq_port=DAQ_MON_CMD_PORT,
551
- log_file=log_file,
507
+ daq_hostname="192.168.68.77",
508
+ daq_port=5025,
509
+ zmq_port=5556,
510
+ log_file="temperature_readings.log",
552
511
  channels=["101", "102"],
553
512
  poll_interval=10.0,
554
513
  )
@@ -557,4 +516,9 @@ async def main(log_file: str = "temperature_readings.log"):
557
516
 
558
517
 
559
518
  if __name__ == "__main__":
560
- asyncio.run(app())
519
+ logging.basicConfig(
520
+ level=logging.DEBUG,
521
+ format="[%(asctime)s] %(threadName)-12s %(levelname)-8s %(name)-12s %(lineno)5d:%(module)-20s %(message)s",
522
+ )
523
+
524
+ asyncio.run(main())
@@ -1,20 +1,21 @@
1
1
  import logging
2
- from pathlib import Path
3
2
 
4
3
  from egse.control import ControlServer
5
4
  from egse.device import DeviceTimeoutError
5
+ from egse.hk import read_conversion_dict
6
+ from egse.metrics import define_metrics
6
7
  from egse.protocol import CommandProtocol
7
8
  from egse.settings import Settings
8
9
  from egse.setup import load_setup
10
+ from egse.synoptics import SynopticsManagerProxy
9
11
  from egse.system import format_datetime
10
12
  from egse.tempcontrol.keithley.daq6510 import DAQ6510Controller
11
13
  from egse.tempcontrol.keithley.daq6510 import DAQ6510Interface
14
+ from egse.tempcontrol.keithley.daq6510 import DAQ6510Simulator
12
15
  from egse.tempcontrol.keithley.daq6510_dev import DAQ6510Command
13
16
  from egse.zmq_ser import bind_address
14
17
 
15
- HERE = Path(__file__).parent
16
-
17
- COMMAND_SETTINGS = Settings.load(location=HERE, filename="daq6510.yaml")
18
+ COMMAND_SETTINGS = Settings.load(filename="daq6510.yaml")
18
19
 
19
20
  MODULE_LOGGER = logging.getLogger(__name__)
20
21
 
@@ -27,9 +28,13 @@ class DAQ6510Protocol(CommandProtocol):
27
28
  control_server: Control Server for which to send out status and monitoring information
28
29
  """
29
30
 
30
- super().__init__(control_server)
31
+ super().__init__()
32
+ self.control_server = control_server
31
33
 
32
- self.daq = DAQ6510Controller()
34
+ if Settings.simulation_mode():
35
+ self.daq = DAQ6510Simulator()
36
+ else:
37
+ self.daq = DAQ6510Controller()
33
38
 
34
39
  try:
35
40
  self.daq.connect()
@@ -42,12 +47,16 @@ class DAQ6510Protocol(CommandProtocol):
42
47
  setup = load_setup()
43
48
  self.channels = setup.gse.DAQ6510.channels
44
49
 
50
+ self.hk_conversion_table = read_conversion_dict(self.control_server.get_storage_mnemonic(), setup=setup)
51
+
52
+ self.synoptics = SynopticsManagerProxy()
53
+ self.metrics = define_metrics(origin="DAS-DAQ6510", use_site=True, setup=setup)
54
+
45
55
  def get_bind_address(self) -> str:
46
- """
47
- Returns a string with the bind address, the endpoint, for accepting connections and bind a socket to.
56
+ """Returns a string with the bind address, the endpoint, for accepting connections and bind a socket to.
48
57
 
49
- Returns:
50
- String with the protocol and port to bind a socket to.
58
+
59
+ Returns: String with the protocol and port to bind a socket to.
51
60
  """
52
61
 
53
62
  return bind_address(
@@ -56,26 +65,34 @@ class DAQ6510Protocol(CommandProtocol):
56
65
  )
57
66
 
58
67
  def get_status(self) -> dict:
59
- """
60
- Returns a dictionary with status information for the Control Server and the DAQ6510.
68
+ """Returns a dictionary with status information for the Control Server and the DAQ6510.
61
69
 
62
- Returns:
63
- Dictionary with status information for the Control Server and the DAQ6510.
70
+ Returns: Dictionary with status information for the Control Server and the DAQ6510.
64
71
  """
65
72
 
66
73
  return super().get_status()
67
74
 
68
75
  def get_housekeeping(self) -> dict:
69
- """
70
- Returns a dictionary with housekeeping information about the DAQ6510.
76
+ """Returns a dictionary with housekeeping information about the DAQ6510.
71
77
 
72
- Returns:
73
- Dictionary with housekeeping information about the DAQ6510.
78
+ Returns: Dictionary with housekeeping information about the DAQ6510.
74
79
  """
75
80
 
76
81
  hk_dict = dict()
77
82
  hk_dict["timestamp"] = format_datetime()
78
83
 
84
+ # # TODO I guess we have to do something along those lines
85
+ # # (We'll have to increase the HK delay, cfr. Agilents)
86
+ # measurement = self.daq.perform_measurement(channel_list=self.channels)
87
+ # temperatures = convert_hk_names(measurement, self.hk_conversion_table)
88
+ # hk_dict.update(temperatures)
89
+ #
90
+ # self.synoptics.store_th_synoptics(hk_dict)
91
+ #
92
+ # for key, value in hk_dict.items():
93
+ # if key != "timestamp":
94
+ # self.metrics[key].set(value)
95
+
79
96
  return hk_dict
80
97
 
81
98
  def quit(self) -> None:
@@ -1,23 +1,21 @@
1
+ from __future__ import annotations
2
+
1
3
  import contextlib
2
4
  import datetime
5
+ import logging
3
6
  import re
4
7
  import socket
5
8
  import time
6
- from typing import Annotated
7
9
 
8
10
  import typer
9
-
10
- from egse.log import logging
11
11
  from egse.settings import Settings
12
12
  from egse.system import SignalCatcher
13
13
 
14
- logger = logging.getLogger("egse.daq6510-sim")
14
+ logger = logging.getLogger("daq6510-sim")
15
15
 
16
16
  HOST = "localhost"
17
17
  DAQ_SETTINGS = Settings.load("Keithley DAQ6510")
18
18
 
19
- SEPARATOR = b"\n"
20
- SEPARATOR_STR = SEPARATOR.decode()
21
19
 
22
20
  device_time = datetime.datetime.now(datetime.timezone.utc)
23
21
  reference_time = device_time
@@ -81,7 +79,7 @@ COMMAND_PATTERNS_ACTIONS_RESPONSES = {
81
79
 
82
80
 
83
81
  def write(conn, response: str):
84
- response = f"{response}{SEPARATOR_STR}".encode()
82
+ response = f"{response}\n".encode()
85
83
  logger.debug(f"write: {response = }")
86
84
  conn.sendall(response)
87
85
 
@@ -198,20 +196,20 @@ def run_simulator():
198
196
  logger.info(f"{exc.__class__.__name__} caught: {exc.args}")
199
197
 
200
198
 
201
- def send_request(cmd: str, cmd_type: str = "query") -> str | None:
202
- from egse.tempcontrol.keithley.daq6510_dev import DAQ6510
199
+ def send_request(cmd: str, type_: str = "query"):
200
+ from egse.tempcontrol.keithley.daq6510_dev import DAQ6510EthernetInterface
203
201
 
204
202
  response = None
205
203
 
206
- daq_dev = DAQ6510(hostname="localhost", port=5025)
204
+ daq_dev = DAQ6510EthernetInterface(hostname="localhost", port=5025)
207
205
  daq_dev.connect()
208
206
 
209
- if cmd_type.lower().strip() == "query":
207
+ if type_.lower().strip() == "query":
210
208
  response = daq_dev.query(cmd)
211
- elif cmd_type.lower().strip() == "write":
209
+ elif type_.lower().strip() == "write":
212
210
  daq_dev.write(cmd)
213
211
  else:
214
- logger.info(f"Unknown command type {cmd_type} for send_request.")
212
+ logger.info(f"Unknown type {type_} for send_request.")
215
213
 
216
214
  daq_dev.disconnect()
217
215
 
@@ -236,14 +234,15 @@ def stop():
236
234
 
237
235
 
238
236
  @app.command()
239
- def command(
240
- cmd: str,
241
- cmd_type: Annotated[str, typer.Argument(help="either 'write', 'query'")] = "query",
242
- ):
243
- """Send an SCPI command directly to the simulator. The response will be in the log info."""
244
- response = send_request(cmd, cmd_type)
237
+ def command(type_: str, cmd: str):
238
+ response = send_request(cmd, type_)
245
239
  logger.info(f"{response}")
246
240
 
247
241
 
248
242
  if __name__ == "__main__":
243
+ logging.basicConfig(
244
+ level=logging.DEBUG,
245
+ format="%(asctime)s %(threadName)-12s %(levelname)-8s %(name)-12s %(module)-20s %(message)s",
246
+ )
247
+
249
248
  app()
@@ -2,13 +2,14 @@
2
2
  #
3
3
  import subprocess
4
4
  import sys
5
+ from pathlib import Path
5
6
 
6
7
  import rich
7
8
  import typer
8
9
 
9
- from egse.system import redirect_output_to_log
10
-
11
- daq6510 = typer.Typer(name="daq6510", help="DAQ6510 Data Acquisition Unit, Keithley, temperature monitoring")
10
+ daq6510 = typer.Typer(
11
+ name="daq6510", help="DAQ6510 Data Acquisition Unit, Keithley, temperature monitoring", no_args_is_help=True
12
+ )
12
13
 
13
14
 
14
15
  @daq6510.command(name="start")
@@ -16,39 +17,19 @@ def start_daq6510():
16
17
  """Start the daq6510 service."""
17
18
  rich.print("Starting service daq6510")
18
19
 
19
- out = redirect_output_to_log("daq6510_cs.start.log")
20
-
21
- subprocess.Popen(
22
- [sys.executable, "-m", "egse.tempcontrol.keithley.daq6510_cs", "start"],
23
- stdout=out,
24
- stderr=out,
25
- stdin=subprocess.DEVNULL,
26
- close_fds=True,
27
- )
28
-
29
20
 
30
21
  @daq6510.command(name="stop")
31
22
  def stop_daq6510():
32
23
  """Stop the daq6510 service."""
33
24
  rich.print("Terminating service daq6510")
34
25
 
35
- out = redirect_output_to_log("daq6510_cs.stop.log")
36
-
37
- subprocess.Popen(
38
- [sys.executable, "-m", "egse.tempcontrol.keithley.daq6510_cs", "stop"],
39
- stdout=out,
40
- stderr=out,
41
- stdin=subprocess.DEVNULL,
42
- close_fds=True,
43
- )
44
-
45
26
 
46
27
  @daq6510.command(name="status")
47
28
  def status_daq6510():
48
29
  """Print status information on the daq6510 service."""
49
30
 
50
31
  proc = subprocess.Popen(
51
- [sys.executable, "-m", "egse.tempcontrol.keithley.daq6510_cs", "status"],
32
+ [sys.executable, "-m", "egse.tempcontrol.keithley.daq6510_sim", "status"],
52
33
  stdout=subprocess.PIPE,
53
34
  stderr=subprocess.PIPE,
54
35
  stdin=subprocess.DEVNULL,
@@ -66,7 +47,7 @@ def start_daq6510_sim():
66
47
  """Start the DAQ6510 Simulator."""
67
48
  rich.print("Starting service DAQ6510 Simulator")
68
49
 
69
- out = redirect_output_to_log("daq6510_sim.start.log")
50
+ out = open(Path("~/.daq6510_sim.start.out").expanduser(), "w")
70
51
 
71
52
  subprocess.Popen(
72
53
  [sys.executable, "-m", "egse.tempcontrol.keithley.daq6510_sim", "start"],
@@ -82,7 +63,7 @@ def stop_daq6510_sim():
82
63
  """Stop the DAQ6510 Simulator."""
83
64
  rich.print("Terminating the DAQ6510 simulator.")
84
65
 
85
- out = redirect_output_to_log("daq6510_sim.stop.log")
66
+ out = open(Path("~/.daq6510_sim.stop.out").expanduser(), "w")
86
67
 
87
68
  subprocess.Popen(
88
69
  [sys.executable, "-m", "egse.tempcontrol.keithley.daq6510_sim", "stop"],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: keithley-tempcontrol
3
- Version: 0.17.1
3
+ Version: 0.17.3
4
4
  Summary: Keithley Temperature Control for CGSE
5
5
  Author: IvS KU Leuven
6
6
  Maintainer-email: Rik Huygen <rik.huygen@kuleuven.be>, Sara Regibo <sara.regibo@kuleuven.be>
@@ -0,0 +1,17 @@
1
+ egse/tempcontrol/keithley/__init__.py,sha256=QMm0vy6OMqzWmJZ1K6IwKSOpgYeCmUdbcRhv75LH9ZY,130
2
+ egse/tempcontrol/keithley/daq6510.py,sha256=QA3K0xJ_-bsY6D4jzOyeDHz1uYSrgf8Z8O-9RynCB5E,24711
3
+ egse/tempcontrol/keithley/daq6510.yaml,sha256=dHHVNyUpOQpdrZpnxPbT6slsl-8Gbnhifj4Q8QOfOYg,4400
4
+ egse/tempcontrol/keithley/daq6510_adev.py,sha256=kodJGonsy_whr15XbVC5CA94mMqm1036FGK0DXmZtxo,3482
5
+ egse/tempcontrol/keithley/daq6510_cs.py,sha256=YVmUtEkGZ0ZKQ7BtvloL_da_fSy_rVr0EB1V2SjLdq0,6089
6
+ egse/tempcontrol/keithley/daq6510_dev.py,sha256=ZjzDU3x7XYRLRoNK9lcqE-t32XDMt0IHW26GO87xt98,10780
7
+ egse/tempcontrol/keithley/daq6510_mon.py,sha256=uox4IaHKwC_hXDQpj4sGEnZyK-dKXjqQdZ2yiaCbt_c,19103
8
+ egse/tempcontrol/keithley/daq6510_protocol.py,sha256=fdcJxsOFYaEDVIY4XzLVC4PSIAL20gKj8os8f0nsSh4,3655
9
+ egse/tempcontrol/keithley/daq6510_sim.py,sha256=GHC7NY2NZ5fm20AjMx7glSGWY1OOynndHUnCPcs5MZM,7568
10
+ keithley_tempcontrol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ keithley_tempcontrol/cgse_explore.py,sha256=y_FkFxJW0vdqGNp9yTU0ELBKxby74-ev3fTuf99Vl1s,400
12
+ keithley_tempcontrol/cgse_services.py,sha256=H62jEzwRQMvKjkefFw9mSQTYRnT8ga_-SdJ26gPaUE8,1960
13
+ keithley_tempcontrol/settings.yaml,sha256=wbrgSZQAdqFl6AxiLJIN36UsdiVHQCzdsgi7Hs7dv7o,1467
14
+ keithley_tempcontrol-0.17.3.dist-info/METADATA,sha256=JhlNFJaYoCoFBeh8A3boUq3XSNPLxJs72_0NrW7BgcY,962
15
+ keithley_tempcontrol-0.17.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
16
+ keithley_tempcontrol-0.17.3.dist-info/entry_points.txt,sha256=_0j2BwcwPi4LlRrhvEWfp9GO9KT8WhCkJe2gFgMzOPs,491
17
+ keithley_tempcontrol-0.17.3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,3 +0,0 @@
1
- """
2
- The asynchronous control server for the DAQ6510 device.
3
- """
@@ -1,18 +0,0 @@
1
- egse/tempcontrol/keithley/__init__.py,sha256=QMm0vy6OMqzWmJZ1K6IwKSOpgYeCmUdbcRhv75LH9ZY,130
2
- egse/tempcontrol/keithley/daq6510.py,sha256=pe12HIC2Yav5ZCGYecoQzhypYcCwecEaJpWZn-OHi8A,24867
3
- egse/tempcontrol/keithley/daq6510.yaml,sha256=dHHVNyUpOQpdrZpnxPbT6slsl-8Gbnhifj4Q8QOfOYg,4400
4
- egse/tempcontrol/keithley/daq6510_acs.py,sha256=6sGc2E8gg67ZwkNmHtNSsunC6cN0IYNwtJXC3yMYcpM,64
5
- egse/tempcontrol/keithley/daq6510_adev.py,sha256=WjBuQvhpeXr2WHVB54mACM5WQwnecSY6I3iG2Cajs5c,2247
6
- egse/tempcontrol/keithley/daq6510_cs.py,sha256=Ga7z8S6z0oTxL_qQP8FXPaNKlJ6o9RrsPFOXeIJ2TT4,7700
7
- egse/tempcontrol/keithley/daq6510_dev.py,sha256=EKFFDhP8-FdIPBPosc1DfzE3h4DQmNU1d0Fi7Yhx4I4,12906
8
- egse/tempcontrol/keithley/daq6510_mon.py,sha256=Xbn2U-l9uxPwNN1-aYW72oJodL2sx13suCiPPbDSti0,20932
9
- egse/tempcontrol/keithley/daq6510_protocol.py,sha256=v8FUrxEm7bnRzM_iQzW0mMCHTgAMZw4f2Ronl8fdKIE,2676
10
- egse/tempcontrol/keithley/daq6510_sim.py,sha256=RGjdbNmK2khflc53f4egOJ0dGJBght6TN8kpQDi9hfs,7665
11
- keithley_tempcontrol/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- keithley_tempcontrol/cgse_explore.py,sha256=y_FkFxJW0vdqGNp9yTU0ELBKxby74-ev3fTuf99Vl1s,400
13
- keithley_tempcontrol/cgse_services.py,sha256=tndviv2rvygkNSsGy1oA43VfFpyVkdB9If-9sVlLbK4,2466
14
- keithley_tempcontrol/settings.yaml,sha256=wbrgSZQAdqFl6AxiLJIN36UsdiVHQCzdsgi7Hs7dv7o,1467
15
- keithley_tempcontrol-0.17.1.dist-info/METADATA,sha256=qVuytSXOrdXx9yy3TuFYkhMifush-gJQxFgKVG7Tbao,962
16
- keithley_tempcontrol-0.17.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
17
- keithley_tempcontrol-0.17.1.dist-info/entry_points.txt,sha256=_0j2BwcwPi4LlRrhvEWfp9GO9KT8WhCkJe2gFgMzOPs,491
18
- keithley_tempcontrol-0.17.1.dist-info/RECORD,,