quantnet-agent 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. quantnet_agent/__init__.py +1 -0
  2. quantnet_agent/cli.py +80 -0
  3. quantnet_agent/common/__init__.py +2 -0
  4. quantnet_agent/common/calibration_status.py +7 -0
  5. quantnet_agent/common/config.py +135 -0
  6. quantnet_agent/common/constants.py +28 -0
  7. quantnet_agent/common/logging.py +60 -0
  8. quantnet_agent/hal/HAL.py +231 -0
  9. quantnet_agent/hal/__init__.py +0 -0
  10. quantnet_agent/hal/driver/OZoptics.py +46 -0
  11. quantnet_agent/hal/driver/Thorlabs.py +39 -0
  12. quantnet_agent/hal/driver/__init__.py +0 -0
  13. quantnet_agent/hal/driver/artiq.py +124 -0
  14. quantnet_agent/hal/driver/dummy.py +373 -0
  15. quantnet_agent/hal/driver/overlayepc.py +27 -0
  16. quantnet_agent/hal/driver/overlayexpframework.py +47 -0
  17. quantnet_agent/hal/driver/overlaylightsrc.py +125 -0
  18. quantnet_agent/hal/driver/overlaymeter.py +58 -0
  19. quantnet_agent/hal/driver/simulator.py +345 -0
  20. quantnet_agent/hal/hwclasses.py +148 -0
  21. quantnet_agent/hal/interpreter/__init__.py +0 -0
  22. quantnet_agent/hal/interpreter/calibration.py +101 -0
  23. quantnet_agent/hal/interpreter/calibration_interpreter.py +43 -0
  24. quantnet_agent/hal/interpreter/dummy_cavity_calibration.py +16 -0
  25. quantnet_agent/hal/interpreter/dummy_lsrc_calibration.py +16 -0
  26. quantnet_agent/hal/interpreter/exp_framework.py +75 -0
  27. quantnet_agent/hal/interpreter/scheduler.py +35 -0
  28. quantnet_agent/hal/local_task_manager.py +249 -0
  29. quantnet_agent/hal/node.py +205 -0
  30. quantnet_agent/interpreter/test_interpreter.py +32 -0
  31. quantnet_agent/scheduler/__init__.py +0 -0
  32. quantnet_agent/scheduler/scheduler.py +483 -0
  33. quantnet_agent/service/__init__.py +1 -0
  34. quantnet_agent/service/agent.py +98 -0
  35. quantnet_agent/service/register.py +77 -0
  36. quantnet_agent-1.0.0.dist-info/METADATA +83 -0
  37. quantnet_agent-1.0.0.dist-info/RECORD +41 -0
  38. quantnet_agent-1.0.0.dist-info/WHEEL +5 -0
  39. quantnet_agent-1.0.0.dist-info/entry_points.txt +2 -0
  40. quantnet_agent-1.0.0.dist-info/licenses/LICENSE +41 -0
  41. quantnet_agent-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
quantnet_agent/cli.py ADDED
@@ -0,0 +1,80 @@
1
+ import socket
2
+ import click
3
+ import sys
4
+ from quantnet_agent.service import QuantnetAgent
5
+ from quantnet_agent.common import Constants, Config
6
+ from quantnet_agent.common.logging import setup_logging
7
+
8
+
9
+ @click.command("Quantnet Agent")
10
+ @click.option("-c",
11
+ "--config",
12
+ default=Constants.DEFAULT_CONFIG_FILE,
13
+ help="Main configuration file",
14
+ show_default=True)
15
+ @click.option("-n",
16
+ "--node-config",
17
+ default=None,
18
+ help="Node configuration file",
19
+ show_default=True)
20
+ @click.option("-a",
21
+ "--agent_id",
22
+ default=socket.getfqdn(),
23
+ help="Specify an agent identifier",
24
+ show_default=True)
25
+ @click.option("--mq-broker-host",
26
+ "mq_broker_host",
27
+ type=str,
28
+ help="Message queue broker host",
29
+ show_default=True)
30
+ @click.option("--mq-broker-port",
31
+ "mq_broker_port",
32
+ type=int,
33
+ help="Message queue broker port",
34
+ show_default=True)
35
+ @click.option("-d",
36
+ "--debug",
37
+ is_flag=True,
38
+ show_default=True,
39
+ default=False,
40
+ help="Enable debug logging")
41
+ @click.option("--interpreter-path",
42
+ "interpreter_path",
43
+ type=str,
44
+ help="Location of additional command interpreters",
45
+ show_default=True)
46
+ @click.option("--schema-path",
47
+ "schema_path",
48
+ type=str,
49
+ help="Specify a path containing additional schema files",
50
+ show_default=True
51
+ )
52
+ def main(config,
53
+ agent_id,
54
+ node_config,
55
+ mq_broker_host,
56
+ mq_broker_port,
57
+ debug,
58
+ interpreter_path,
59
+ schema_path):
60
+ cobj = Config(config,
61
+ node_config,
62
+ debug,
63
+ agent_id,
64
+ mq_broker_host,
65
+ mq_broker_port,
66
+ interpreter_path,
67
+ schema_path)
68
+
69
+ if cobj.node_file is None:
70
+ print("No node configuration file specified. Use --node-config (-n) to provide one.")
71
+ sys.exit(1)
72
+
73
+ setup_logging(cobj)
74
+
75
+ agent = QuantnetAgent(cobj)
76
+ agent.run()
77
+
78
+
79
+ if __name__ == "__main__":
80
+ sys.exit(main()) # pragma: no cover
@@ -0,0 +1,2 @@
1
+ from .constants import Constants
2
+ from .config import Config
@@ -0,0 +1,7 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Calibration_status(Enum):
5
+ FULL = "Full_scale_calibration"
6
+ LIGHT = "Lightweight_calibration"
7
+ CHECK = "Status_check"
@@ -0,0 +1,135 @@
1
+ import os
2
+ import logging
3
+ import configobj
4
+ import json
5
+ from quantnet_agent.common.constants import Constants
6
+
7
+ log = logging.getLogger(__name__)
8
+
9
+
10
+ def get_config(config_file):
11
+ config_files = []
12
+ if config_file:
13
+ config_files.append(config_file)
14
+ if "QUANTNET_HOME" in os.environ:
15
+ config_files.append(f"{os.environ['QUANTNET_HOME']}/etc/agent.cfg")
16
+ else:
17
+ config_files.append("/etc/quantnet/agent.cfg")
18
+
19
+ for cf in config_files:
20
+ try:
21
+ config = configobj.ConfigObj(cf)
22
+ except IOError:
23
+ continue
24
+ return config
25
+
26
+
27
+ class Config:
28
+ def __init__(
29
+ self,
30
+ config_file: str = None,
31
+ node_file: str = None,
32
+ debug: bool = False,
33
+ agent_id: str = None,
34
+ mq_broker_host: str = None,
35
+ mq_broker_port: int = None,
36
+ interpreter_path: str = None,
37
+ schema_path: str = None,
38
+ ):
39
+ self._config = None
40
+ self.devices = {}
41
+
42
+ self._config = get_config(config_file)
43
+
44
+ if not self._config:
45
+ log.warning("No configuration file found, continuing with defaults")
46
+
47
+ if node_file:
48
+ self.node_file = node_file
49
+ else:
50
+ self.node_file = self.config_get("agent", "node_file", raise_exception=False)
51
+
52
+ if mq_broker_host:
53
+ self.mq_broker_host = mq_broker_host
54
+ else:
55
+ self.mq_broker_host = self.config_get("mq", "host", default="127.0.0.1")
56
+
57
+ if mq_broker_port:
58
+ self.mq_broker_port = mq_broker_port
59
+ else:
60
+ self.mq_broker_port = self.config_get("mq", "port", default="1883")
61
+
62
+ self.threads = int(self.config_get("agent", "threads", default=8))
63
+
64
+ if debug:
65
+ self.debug = debug
66
+ else:
67
+ self.config_get("agent", "debug", default=False)
68
+
69
+ if agent_id:
70
+ self.cid = agent_id
71
+ else:
72
+ try:
73
+ self.cid = self.config_get("agent", "agent_id")
74
+ except Exception:
75
+ self.cid = None
76
+
77
+ if interpreter_path:
78
+ self.interpreter_path = interpreter_path
79
+ else:
80
+ self.interpreter_path = self.config_get("interpreters", "path", raise_exception=False)
81
+
82
+ if "protocols" in self._config and len(self._config["protocols"]) > 0:
83
+ if self.interpreter_path is None:
84
+ raise Exception("Interpreter location for protocols is not found")
85
+ self.proto_plugins = self._config["protocols"]
86
+ else:
87
+ self.proto_plugins = {}
88
+
89
+ if schema_path:
90
+ self.schema_path = schema_path
91
+ else:
92
+ self.schema_path = self.config_get("schemas", "path", raise_exception=False)
93
+
94
+ if "devices" in self._config:
95
+ self.devices = self._config["devices"]
96
+
97
+ self.tasks = []
98
+ self.task_properties = {}
99
+
100
+ if "tasks" in self._config:
101
+ for task, property in self._config["tasks"].items():
102
+ try:
103
+ if type(property) is configobj.Section:
104
+ with open(os.path.join(Constants.DEFAULT_TASK_PATH, property["path"]), "r") as file:
105
+ calibration_task = json.load(file)
106
+ if float(calibration_task["Periodicity"]) <= Constants.SLOTSIZE.total_seconds():
107
+ raise Exception(
108
+ f"Task {task} interval is too short."
109
+ "It should be larger than the TDMA slot size "
110
+ f"{Constants.SLOTSIZE.total_seconds() * 1e3 }"
111
+ )
112
+ self.tasks.append(calibration_task)
113
+ else:
114
+ self.task_properties[task] = property
115
+ except Exception as e:
116
+ log.error(f"Cannot load local task {task} : {e}")
117
+
118
+ def config_get(self, section, option, raise_exception=True, default=None, check_config_table=True):
119
+ """
120
+ Return the string value for a given option in a section
121
+
122
+ :param section: the named section.
123
+ :param option: the named option.
124
+ :param raise_exception: Boolean to raise or not NoOptionError or NoSectionError.
125
+ :param default: the default value if not found.
126
+ :param check_config_table: if not set, avoid looking at config table
127
+ .
128
+ :returns: the configuration value.
129
+ """
130
+ try:
131
+ return self._config[section][option]
132
+ except (configobj.ConfigObjError, KeyError) as err:
133
+ if raise_exception and default is None:
134
+ raise err
135
+ return default
@@ -0,0 +1,28 @@
1
+ import os
2
+ from datetime import timedelta
3
+ import quantnet_agent
4
+
5
+
6
+ class Constants:
7
+ DEFAULT_CONFIG_FILE = "./config/agent.cfg"
8
+ DEFAULT_NODE_CONFIG_FILE = "./config/conf-alice.json"
9
+ DEFAULT_LOGGING_CONFIG_FILE = "./config/logging.conf"
10
+ DEFAULT_INTERPRETERS = {
11
+ "scheduler": "scheduler.py",
12
+ "calibration": "calibration.py",
13
+ "experiment": "exp_framework.py",
14
+ }
15
+ DEFAULT_TASK_PATH = os.path.join(os.path.dirname(os.path.dirname(quantnet_agent.__file__)), "config/")
16
+ DEFAULT_TASK_INTERPRETER = os.path.join(
17
+ os.path.dirname(quantnet_agent.__file__), "hal/interpreter/calibration_interpreter.py"
18
+ )
19
+ DEFAULT_TASK_NS = "quantnet_agent.task"
20
+ HEARTBEAT_INTERVAL = 10
21
+ REGISTRATION_RETRY_INTERVAL = 10
22
+ MAX_TIMESLOTS = 20000
23
+ SLOTSIZE = timedelta(milliseconds=100)
24
+ SCHEDULER_GRACE_PERIOD = timedelta(milliseconds=50)
25
+ # TODO: Check SCHEDULER_GRACE_PERIOD < SLOTSIZE * MAX_TIMESLOTS
26
+ UPDATE_INTERVAL = SLOTSIZE * MAX_TIMESLOTS / 2
27
+ # TODO: Check if update_interval is appropriate
28
+ DAG_CHECK_INTERVAL = timedelta(milliseconds=1000)
@@ -0,0 +1,60 @@
1
+ import os
2
+ import sys
3
+ import logging
4
+ import logging.config
5
+
6
+
7
+ def quantnet_log_formatter(cobj=None):
8
+ config_logformat = cobj.config_get(
9
+ "common",
10
+ "logformat",
11
+ raise_exception=False,
12
+ default="{asctime} {name:<29} {process} {levelname:>8} {message}",
13
+ )
14
+ return logging.Formatter(fmt=config_logformat, style='{')
15
+
16
+
17
+ def setup_default_logging(cobj=None):
18
+ """
19
+ Configures the logging by setting the output stream to stdout and
20
+ configures log level and log format.
21
+ """
22
+ config_loglevel = getattr(logging, cobj.config_get("common", "loglevel",
23
+ raise_exception=False, default="INFO").upper())
24
+
25
+ stdouthandler = logging.StreamHandler(stream=sys.stdout)
26
+ stdouthandler.setFormatter(quantnet_log_formatter(cobj))
27
+ stdouthandler.setLevel(config_loglevel)
28
+ logging.basicConfig(level=config_loglevel, handlers=[stdouthandler])
29
+
30
+
31
+ def setup_logging(cobj=None):
32
+ """
33
+ Configures the logging by setting the output stream to stdout and
34
+ configures log level and log format.
35
+ """
36
+
37
+ configfiles = list()
38
+
39
+ if cobj:
40
+ logging_config_path = cobj.config_get("common", "logging_config", raise_exception=False, default=None)
41
+ if logging_config_path:
42
+ configfiles.append(logging_config_path)
43
+
44
+ for i in ["QUANTNET_HOME", "VIRTUAL_ENV"]:
45
+ if i in os.environ:
46
+ configfiles.append(f"{os.environ[i]}/etc/logging.conf")
47
+ configfiles.append("/opt/quantnet/etc/logging.conf")
48
+
49
+ has_config = False
50
+ for configfile in configfiles:
51
+ try:
52
+ logging.config.fileConfig(configfile, disable_existing_loggers=False)
53
+ has_config = True
54
+ except Exception:
55
+ has_config = False
56
+ if has_config:
57
+ break
58
+
59
+ if not has_config and cobj:
60
+ setup_default_logging(cobj)
@@ -0,0 +1,231 @@
1
+ import logging
2
+ import ast
3
+ import os
4
+ import importlib
5
+ import sys
6
+ from abc import ABC, abstractmethod
7
+ import traceback
8
+ from pydantic import TypeAdapter
9
+
10
+ log = logging.getLogger(__name__)
11
+ driver_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "driver")
12
+
13
+
14
+ def get_driver_module(classname):
15
+ for filename in os.listdir(driver_path):
16
+ f_path = os.path.join(driver_path, filename)
17
+ if not os.path.isfile(f_path):
18
+ continue
19
+ with open(f_path) as file:
20
+ node = ast.parse(file.read())
21
+ classes = [n for n in node.body if isinstance(n, ast.ClassDef)]
22
+ for class_ in classes:
23
+ if classname == class_.name:
24
+ try:
25
+ spec = importlib.util.spec_from_file_location(
26
+ os.path.splitext(filename)[0], os.path.join(driver_path, filename)
27
+ )
28
+ module = importlib.util.module_from_spec(spec)
29
+ sys.modules["module.name"] = module
30
+ spec.loader.exec_module(module)
31
+ mod = getattr(module, classname)
32
+ return mod
33
+ except Exception:
34
+ log.error(f"Cannot load driver class {class_.name}")
35
+ log.error(traceback.format_exc())
36
+ return
37
+ log.error(f"Cannot find class {classname} from plugin dir")
38
+
39
+
40
+ class HardwareAbstractionLayer:
41
+ def __init__(self, config, msgclient):
42
+
43
+ self.devs = {}
44
+ self._msgclient = msgclient
45
+ self._config = config
46
+
47
+ for device, property in config.devices.items():
48
+ enabled = property.get("enabled")
49
+ if enabled and not TypeAdapter(bool).validate_python(enabled):
50
+ continue
51
+ if device in self.devs:
52
+ log.error(f"Duplicated Device {device}")
53
+ continue
54
+ dev_cls = get_driver_module(property["driver"])
55
+ if dev_cls is None:
56
+ continue
57
+ try:
58
+ dev = dev_cls(property,
59
+ config.node_file,
60
+ config.mq_broker_host,
61
+ config.mq_broker_port)
62
+ except Exception as e:
63
+ log.error(f"Cannot instantiate driver class {dev_cls}: {e}")
64
+ continue
65
+ self.devs[device] = dev
66
+
67
+
68
+ class Interpreter(ABC):
69
+ """Abstract base class for the Agent Interpreter module.
70
+
71
+ Example::
72
+
73
+ i = Interpreter(hal)
74
+
75
+ :param hal: :doc:`HAL </hal>` object created by :class:`~quantnet_agent.hal.node`.
76
+ """
77
+
78
+ def __init__(self, hal):
79
+ self.hal = hal
80
+
81
+
82
+ class CoreInterpreter(Interpreter):
83
+ """Abstract base class for the built-in Agent Interpreter module (e.g.,
84
+ :class:`~quantnet_agent.hal.interpreter.scheduler`).
85
+
86
+ Example::
87
+
88
+ i = CoreInterpreter(node)
89
+
90
+ :param node: :class:`~quantnet_agent.hal.node` object created by :class:`~quantnet_agent.service.node`.
91
+ """
92
+
93
+ def __init__(self, node) -> None:
94
+ self.node = node
95
+
96
+ @abstractmethod
97
+ def get_commands(self):
98
+ """Returns a dictionary of RPC handlers for a built-in interpreter to register with the RPC server
99
+ in the controller. The dictionary keys are the names of RPC endpoints, and the values are lists composed
100
+ of an RPC handler pointer and a schema model corresponding to the RPC.
101
+
102
+ Example::
103
+
104
+ def get_commands(self):
105
+ commands = {
106
+ "scheduler.getSchedule": [self.get_schedule, "quantnet_mq.schema.models.scheduler.getSchedule"]
107
+ }
108
+ return commands
109
+ """
110
+ pass
111
+
112
+
113
+ class CMDInterpreter(Interpreter):
114
+ """Abstract base class for the Agent command Interpreter module (e.g., Link calibration module
115
+ :class:`~quantnet_agent.hal.interpreter.calibration`).
116
+
117
+ Example::
118
+
119
+ i = CMDInterpreter(hal)
120
+
121
+ :param hal: :doc:`HAL </hal>` object created by :class:`~quantnet_agent.hal.node`.
122
+ """
123
+
124
+ def __init__(self, hal) -> None:
125
+ super().__init__(hal)
126
+
127
+ @abstractmethod
128
+ def get_commands(self):
129
+ """Returns a dictionary of RPC handlers for a command interpreter to register with the RPC server
130
+ in the controller. The dictionary keys are the names of RPC endpoints, and the values are lists
131
+ composed of an RPC handler pointer and a schema model corresponding to the RPC.
132
+
133
+ Example::
134
+
135
+ def get_commands(self):
136
+ commands = {
137
+ "calibration.calibration": [self.measure, "quantnet_mq.schema.models.calibration.calibration"]
138
+ }
139
+ return commands
140
+ """
141
+ pass
142
+
143
+
144
+ class ScheduleableInterpreter(CMDInterpreter):
145
+ """Abstract base class for a schedulable Agent command Interpreter module (e.g.,
146
+ :class:`~quantnet_agent.hal.interpreter.ExperimentFramework`).
147
+
148
+ Example::
149
+
150
+ i = ScheduleableInterpreter(hal)
151
+
152
+ :param hal: :doc:`HAL </hal>` object created by :class:`~quantnet_agent.hal.node`.
153
+ """
154
+
155
+ def __init__(self, hal) -> None:
156
+ super().__init__(hal)
157
+
158
+ @abstractmethod
159
+ def get_commands(self):
160
+ """Returns a dictionary of RPC handlers for a schedulable command interpreter to register with the RPC server
161
+ in the controller. The dictionary keys are the names of RPC endpoints, and the values are lists composed
162
+ of an RPC handler pointer and a schema model corresponding to the RPC.
163
+
164
+ Example::
165
+
166
+ def get_commands(self):
167
+ commands = {
168
+ "experiment.getState": [self.get_state, "quantnet_mq.schema.models.experiment.getState"]
169
+ }
170
+ return commands
171
+ """
172
+ pass
173
+
174
+ @abstractmethod
175
+ def get_schedulable_commands(self):
176
+ """Returns a dictionary of RPC handlers for a schedulable command interpreter to register with the RPC server
177
+ in the two-level scheduler. The RPC endpoints returned by this function are used by the agent scheduler
178
+ instead of the agent node, enabling the scheduler to allocate a handler to an available timeslot when
179
+ requested by the global scheduler.
180
+
181
+ Keys in the dictionary are the names of the RPC endpoints, and the values are lists composed of
182
+ an RPC handler pointer, a schema model corresponding to the RPC, and a schema model for the response.
183
+
184
+ Example::
185
+
186
+ def get_schedulable_commands(self):
187
+ commands = {
188
+ "experiment.submit": [
189
+ self.submit,
190
+ "quantnet_mq.schema.models.experiment.submit",
191
+ experiment.submitResponse,
192
+ ]
193
+ }
194
+ return commands
195
+ """
196
+ pass
197
+
198
+
199
+ class LocalTaskInterpreter(Interpreter):
200
+ """Abstract base class for a local Agent command Interpreter module (e.g., local device calibration).
201
+
202
+ Example::
203
+
204
+ i = LocalTaskInterpreter(hal)
205
+
206
+ :param hal: :doc:`HAL </hal>` object created by :class:`~quantnet_agent.hal.node`.
207
+ """
208
+
209
+ def __init__(self, hal):
210
+ super().__init__(hal)
211
+
212
+ @abstractmethod
213
+ def run(self, *args, **kwargs):
214
+ """Execute a local task (e.g., device calibration).
215
+
216
+ :param args: Parameters to use for running the local task.
217
+ :type args: list
218
+ :param kwargs: Keyword parameter to use for running the local task.
219
+ :type kwargs: dict
220
+ """
221
+ pass
222
+
223
+ @abstractmethod
224
+ def stop(self):
225
+ """Stops a local task started with the `run` method."""
226
+ pass
227
+
228
+ @abstractmethod
229
+ async def receive(self, *args, **kwargs):
230
+ """Receive result of the `run` method."""
231
+ pass
File without changes
@@ -0,0 +1,46 @@
1
+ import serial
2
+ from quantnet_agent.hal.hwclasses import Filter
3
+ import logging
4
+
5
+ log = logging.getLogger(__name__)
6
+
7
+
8
+ class OZOptics(Filter):
9
+ def __init__(self, config):
10
+ self.ser = serial.Serial(
11
+ port=config["port"],
12
+ baudrate=config["baudrate"],
13
+ timeout=1,
14
+ bytesize=serial.EIGHTBITS,
15
+ stopbits=serial.STOPBITS_ONE,
16
+ )
17
+
18
+ log.info(f"Initialized OZOptics EPC with port={config['port']}")
19
+ self.buflen = 2048
20
+
21
+ @property
22
+ def okay(self):
23
+ return True if self.ser else False
24
+
25
+ def __ask(self, cmd):
26
+ if self.ser:
27
+ self.ser.write(f"{cmd}\r\n".encode())
28
+ return self.ser.read(self.buflen).decode()
29
+
30
+ @property
31
+ def help(self):
32
+ return self.__ask("?")
33
+
34
+ def _mode_ac(self):
35
+ self.__ask("MAC")
36
+
37
+ def _mode_dc(self):
38
+ self.__ask("MDC")
39
+
40
+ def dst_init(self, request):
41
+ log.info("Initializing for Calibration")
42
+ return 0
43
+
44
+ def calibrate(self, request):
45
+ log.info("Starting Calibration")
46
+ return 0
@@ -0,0 +1,39 @@
1
+ from ThorlabsPM100 import ThorlabsPM100, USBTMC
2
+ import numpy as np
3
+ from quantnet_agent.hal.hwclasses import LightMeasurement
4
+ import logging
5
+
6
+ log = logging.getLogger(__name__)
7
+
8
+
9
+ class PM100D(LightMeasurement):
10
+ def __init__(self, config):
11
+ inst = USBTMC(device=config["device"])
12
+ self.dev = ThorlabsPM100(inst=inst)
13
+ self.pd_bandwidth = self.dev.input.pdiode.filter.lpass.state
14
+ self.avg_count = self.dev.sense.average.count
15
+ log.info(f"Initialized PM100D with bw={self.pd_bandwidth} avr={self.avg_count} wavelength={self.wavelength}")
16
+ log.info(f"Configuration: {self.getconfigure}")
17
+
18
+ @property
19
+ def read(self):
20
+ return self.dev.read
21
+
22
+ @property
23
+ def wavelength(self):
24
+ return self.dev.sense.correction.wavelength
25
+
26
+ @property
27
+ def power(self, count=10):
28
+ request = type('', (), {})()
29
+ request.count = count
30
+ self.measure(request)
31
+
32
+ @property
33
+ def getconfigure(self):
34
+ return self.dev.getconfigure
35
+
36
+ def measure(self, request):
37
+ log.info(f"Reading: {request.count} measurements")
38
+ power = np.array([self.dev.read for _ in range(request.count)])
39
+ return power
File without changes