egauge-python 0.9.8__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 (44) hide show
  1. egauge/ctid/__init__.py +7 -0
  2. egauge/ctid/bit_stuffer.py +65 -0
  3. egauge/ctid/ctid.py +967 -0
  4. egauge/ctid/encoder.py +436 -0
  5. egauge/ctid/intel_hex_encoder.py +98 -0
  6. egauge/ctid/waveform.py +299 -0
  7. egauge/examples/data/test-ctid-decoder.raw +0 -0
  8. egauge/examples/test_capture.py +77 -0
  9. egauge/examples/test_common.py +26 -0
  10. egauge/examples/test_ctid.py +89 -0
  11. egauge/examples/test_ctid_decoder.py +93 -0
  12. egauge/examples/test_local.py +201 -0
  13. egauge/examples/test_register.py +104 -0
  14. egauge/loggers.py +72 -0
  15. egauge/pyside/__init__.py +0 -0
  16. egauge/pyside/ansi2html.py +112 -0
  17. egauge/pyside/terminal.py +295 -0
  18. egauge/webapi/__init__.py +34 -0
  19. egauge/webapi/auth.py +364 -0
  20. egauge/webapi/cloud/__init__.py +30 -0
  21. egauge/webapi/cloud/credentials.py +86 -0
  22. egauge/webapi/cloud/credentials_dialog.py +58 -0
  23. egauge/webapi/cloud/gui/credentials_dialog.py +100 -0
  24. egauge/webapi/cloud/serial_number.py +276 -0
  25. egauge/webapi/device/__init__.py +38 -0
  26. egauge/webapi/device/capture.py +453 -0
  27. egauge/webapi/device/ctid_info.py +553 -0
  28. egauge/webapi/device/device.py +349 -0
  29. egauge/webapi/device/local.py +268 -0
  30. egauge/webapi/device/physical_quantity.py +439 -0
  31. egauge/webapi/device/physical_units.py +473 -0
  32. egauge/webapi/device/register.py +338 -0
  33. egauge/webapi/device/register_row.py +145 -0
  34. egauge/webapi/device/register_type.py +851 -0
  35. egauge/webapi/device/slop.py +334 -0
  36. egauge/webapi/device/virtual_register.py +353 -0
  37. egauge/webapi/error.py +34 -0
  38. egauge/webapi/json_api.py +332 -0
  39. egauge_python-0.9.8.dist-info/METADATA +148 -0
  40. egauge_python-0.9.8.dist-info/RECORD +44 -0
  41. egauge_python-0.9.8.dist-info/WHEEL +5 -0
  42. egauge_python-0.9.8.dist-info/entry_points.txt +2 -0
  43. egauge_python-0.9.8.dist-info/licenses/LICENSE +22 -0
  44. egauge_python-0.9.8.dist-info/top_level.txt +1 -0
egauge/webapi/error.py ADDED
@@ -0,0 +1,34 @@
1
+ #
2
+ # Copyright (c) 2020 eGauge Systems LLC
3
+ # 1644 Conestoga St, Suite 2
4
+ # Boulder, CO 80301
5
+ # voice: 720-545-9767
6
+ # email: davidm@egauge.net
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # MIT License
11
+ #
12
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ # of this software and associated documentation files (the "Software"), to deal
14
+ # in the Software without restriction, including without limitation the rights
15
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ # copies of the Software, and to permit persons to whom the Software is
17
+ # furnished to do so, subject to the following conditions:
18
+ #
19
+ # The above copyright notice and this permission notice shall be included in
20
+ # all copies or substantial portions of the Software.
21
+ #
22
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28
+ # THE SOFTWARE.
29
+ #
30
+ """All WebAPI exceptions derive from the exception defined here."""
31
+
32
+
33
+ class Error(Exception):
34
+ """Base class of all WebAPI exceptions."""
@@ -0,0 +1,332 @@
1
+ #
2
+ # Copyright (c) 2020-2025 eGauge Systems LLC
3
+ # 4805 Sterling Dr, Suite 1
4
+ # Boulder, CO 80301
5
+ # voice: 720-545-9767
6
+ # email: davidm@egauge.net
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # MIT License
11
+ #
12
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ # of this software and associated documentation files (the "Software"), to deal
14
+ # in the Software without restriction, including without limitation the rights
15
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ # copies of the Software, and to permit persons to whom the Software is
17
+ # furnished to do so, subject to the following conditions:
18
+ #
19
+ # The above copyright notice and this permission notice shall be included in
20
+ # all copies or substantial portions of the Software.
21
+ #
22
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28
+ # THE SOFTWARE.
29
+ #
30
+ """This module provides helper methods for accessing JSON web services."""
31
+
32
+ import logging
33
+ import socket
34
+ from typing import Any
35
+
36
+ import requests
37
+
38
+ from egauge.loggers import ModuleLogger
39
+
40
+ from .error import Error
41
+
42
+ log = ModuleLogger.get(__name__)
43
+
44
+ JSONObject = dict[str, "JSONValue"]
45
+ JSONArray = list[Any]
46
+ JSONValue = None | bool | int | float | str | JSONArray | JSONObject
47
+
48
+
49
+ class JSONAPIError(Error):
50
+ """Raised if for any JSON API errors. The first argument to this
51
+ exception is a textual description of the error which occurred.
52
+ Additional arguments are dependent on the source of the error.
53
+
54
+ """
55
+
56
+
57
+ class UnauthenticatedError(Error):
58
+ """Raised when a request fails with HTTP status code 401."""
59
+
60
+
61
+ def _raw_response(kwargs: dict[Any, Any]) -> bool:
62
+ """Check if `raw_response` in kwargs is present and, if so, return
63
+ whether its value is True.
64
+
65
+ Required arguments:
66
+
67
+ kwargs -- The keyword arguments to be checked.
68
+
69
+ """
70
+ if "raw_response" in kwargs:
71
+ raw_response = kwargs["raw_response"]
72
+ del kwargs["raw_response"]
73
+ return raw_response is True
74
+ return False
75
+
76
+
77
+ def _check_status(
78
+ resource: str,
79
+ reply: requests.Response,
80
+ method: str,
81
+ data=None,
82
+ kwargs=None,
83
+ ):
84
+ """Check status code of the reply. Raises UnauthenticatedError if
85
+ 401 or JSONAPIError if any other status code outside the range of
86
+ 200..299.
87
+
88
+ Required arguments:
89
+
90
+ resource -- The URL the request was issued for.
91
+
92
+ reply -- A requests.Response object.
93
+
94
+ method -- The name of the HTTP method that resulted in the reply
95
+ ("GET", "POUT", etc.).
96
+
97
+ data -- The data passed in the request body.
98
+
99
+ kwargs -- The keyword arguments passed to the requests method.
100
+
101
+ """
102
+ if reply.status_code == 401:
103
+ raise UnauthenticatedError(reply)
104
+ if reply.status_code < 200 or reply.status_code > 299:
105
+ if log.getEffectiveLevel() <= logging.DEBUG:
106
+ data_str = f", data: {data}. " if data else ""
107
+ kwargs_str = f", kwargs: {kwargs}" if kwargs else ""
108
+ log.debug(
109
+ "HTTP %s %s => %s%s%s",
110
+ method,
111
+ resource,
112
+ reply.status_code,
113
+ data_str,
114
+ kwargs_str,
115
+ )
116
+ raise JSONAPIError(
117
+ "Unexpected HTTP status code.", reply.status_code, reply.content
118
+ )
119
+
120
+
121
+ def _json(reply: requests.Response) -> JSONValue:
122
+ """Convert a response body to a JSONValue. If there is no
123
+ response body, the response body is empty, or the response body is
124
+ the string "null", None is returned.
125
+
126
+ If the body cannot be JSON-decoded, exception JSONAPIError is
127
+ raised with "Invalid JSON data." as the first argument and the
128
+ reply.content as the second argument.
129
+
130
+ In all other cases, the JSON-decoded value of the body is
131
+ returned.
132
+
133
+ Required arguments:
134
+
135
+ reply -- The response object to convert to a JSON value.
136
+
137
+ """
138
+ if not reply.text:
139
+ return None
140
+
141
+ try:
142
+ return reply.json()
143
+ except requests.JSONDecodeError as e:
144
+ raise JSONAPIError("Invalid JSON data.", reply.content) from e
145
+
146
+
147
+ def get(resource: str, **kwargs) -> JSONValue | requests.Response:
148
+ """Issue an HTTP GET request and return the parsed JSON reply or
149
+ None if there is no response body or the response body is empty
150
+ (note that this is indistinguishable from a body containing the
151
+ string "null", which also returns None). If keyword argument
152
+ `raw_response` is True, a requests.Response object is returned
153
+ instead.
154
+
155
+ Raises UnauthenticatedError if the reply has a status code of 401.
156
+
157
+ Raises JSONAPIError if the request fails for any reason or if the
158
+ reply does not have a status code in the range from 200 to 299 or
159
+ 401.
160
+
161
+ Required arguments:
162
+
163
+ resource -- The URL of the resource to issue the request to.
164
+
165
+ Keyword arguments:
166
+
167
+ raw_response -- If True, return a requests.Response object.
168
+
169
+ All other keyword arguments are passed on to requests.get().
170
+
171
+ """
172
+ raw = _raw_response(kwargs)
173
+ try:
174
+ r = requests.get(resource, **kwargs)
175
+ except (requests.exceptions.RequestException, socket.error) as e:
176
+ raise JSONAPIError("requests.get exception.", e) from e
177
+ _check_status(resource, r, "GET", kwargs)
178
+ return r if raw else _json(r)
179
+
180
+
181
+ def patch(resource: str, json_data, **kwargs) -> JSONValue | requests.Response:
182
+ """Issue an HTTP PATCH request and return the parsed JSON reply or
183
+ None if there is no response body or the response body is empty
184
+ (note that this is indistinguishable from a body containing the
185
+ string "null", which also returns None). If keyword argument
186
+ `raw_response` is True, a requests.Response object is returned
187
+ instead.
188
+
189
+ Raises UnauthenticatedError if the reply has a status code of 401.
190
+
191
+ Raises JSONAPIError if the request fails for any reason or if the
192
+ reply does not have a status code in the range from 200 to 299 or
193
+ 401.
194
+
195
+ Required arguments:
196
+
197
+ resource -- The URL of the resource to issue the request to.
198
+
199
+ json_data -- The data to JSON-encode and include in the request
200
+ body.
201
+
202
+ Keyword arguments:
203
+
204
+ raw_response -- If True, return a requests.Response object.
205
+
206
+ All other keyword arguments are passed on to requests.patch().
207
+
208
+ """
209
+ headers = kwargs.get("headers", {})
210
+ headers["Content-Type"] = "application/json"
211
+ kwargs["headers"] = headers
212
+ raw = _raw_response(kwargs)
213
+ try:
214
+ r = requests.patch(resource, json=json_data, **kwargs)
215
+ except (requests.exceptions.RequestException, socket.error) as e:
216
+ raise JSONAPIError("requests.patch exception.", e) from e
217
+ _check_status(resource, r, "PATCH", json_data, kwargs)
218
+ return r if raw else _json(r)
219
+
220
+
221
+ def put(resource: str, json_data, **kwargs) -> JSONValue | requests.Response:
222
+ """Issue an HTTP PUT request and return the parsed JSON reply or
223
+ None if there is no response body or the response body is empty
224
+ (note that this is indistinguishable from a body containing the
225
+ string "null", which also returns None). If keyword argument
226
+ `raw_response` is True, a requests.Response object is returned
227
+ instead.
228
+
229
+ Raises UnauthenticatedError if the reply has a status code of 401.
230
+
231
+ Raises JSONAPIError if the request fails for any reason or if the
232
+ reply does not have a status code in the range from 200 to 299 or
233
+ 401.
234
+
235
+ Required arguments:
236
+
237
+ resource -- The URL of the resource to issue the request to.
238
+
239
+ json_data -- The data to JSON-encode and include in the request
240
+ body.
241
+
242
+ Keyword arguments:
243
+
244
+ raw_response -- If True, return a requests.Response object.
245
+
246
+ All other keyword arguments are passed on to requests.put().
247
+
248
+ """
249
+ headers = kwargs.get("headers", {})
250
+ headers["Content-Type"] = "application/json"
251
+ kwargs["headers"] = headers
252
+ raw = _raw_response(kwargs)
253
+ try:
254
+ r = requests.put(resource, json=json_data, **kwargs)
255
+ except (requests.exceptions.RequestException, socket.error) as e:
256
+ raise JSONAPIError("requests.put exception.", e) from e
257
+ _check_status(resource, r, "PUT", json_data, kwargs)
258
+ return r if raw else _json(r)
259
+
260
+
261
+ def post(resource: str, json_data, **kwargs) -> JSONValue | requests.Response:
262
+ """Issue an HTTP POST request and return the parsed JSON reply or
263
+ None if there is no response body or the response body is empty
264
+ (note that this is indistinguishable from a body containing the
265
+ string "null", which also returns None). If keyword argument
266
+ `raw_response` is True, a requests.Response object is returned
267
+ instead.
268
+
269
+ Raises UnauthenticatedError if the reply has a status code of 401.
270
+
271
+ Raises JSONAPIError if the request fails for any reason or if the
272
+ reply does not have a status code in the range from 200 to 299 or
273
+ 401.
274
+
275
+ Required arguments:
276
+
277
+ resource -- The URL of the resource to issue the request to.
278
+
279
+ json_data -- The data to JSON-encode and include in the request
280
+ body.
281
+
282
+ Keyword arguments:
283
+
284
+ raw_response -- If True, return a requests.Response object.
285
+
286
+ All other keyword arguments are passed on to requests.post().
287
+
288
+ """
289
+ headers = kwargs.get("headers", {})
290
+ headers["Content-Type"] = "application/json"
291
+ kwargs["headers"] = headers
292
+ raw = _raw_response(kwargs)
293
+ try:
294
+ r = requests.post(resource, json=json_data, **kwargs)
295
+ except (requests.exceptions.RequestException, socket.error) as e:
296
+ raise JSONAPIError("requests.post exception.", e) from e
297
+ _check_status(resource, r, "POST", json_data, kwargs)
298
+ return r if raw else _json(r)
299
+
300
+
301
+ def delete(resource: str, **kwargs) -> JSONValue | requests.Response:
302
+ """Issue an HTTP DELETE request and return the parsed JSON reply
303
+ or None if there is no response body or the response body is empty
304
+ (note that this is indistinguishable from a body containing the
305
+ string "null", which also returns None). If keyword argument
306
+ `raw_response` is True, a requests.Response object is returned
307
+ instead.
308
+
309
+ Raises UnauthenticatedError if the reply has a status code of 401.
310
+
311
+ Raises JSONAPIError if the request fails for any reason or if the
312
+ reply does not have a status code in the range from 200 to 299 or
313
+ 401.
314
+
315
+ Required arguments:
316
+
317
+ resource -- The URL of the resource to issue the request to.
318
+
319
+ Keyword arguments:
320
+
321
+ raw_response -- If True, return a requests.Response object.
322
+
323
+ All other keyword arguments are passed on to requests.delete().
324
+
325
+ """
326
+ raw = _raw_response(kwargs)
327
+ try:
328
+ r = requests.delete(resource, **kwargs)
329
+ except (requests.exceptions.RequestException, socket.error) as e:
330
+ raise JSONAPIError("requests.delete exception.", e) from e
331
+ _check_status(resource, r, "DELETE", kwargs=kwargs)
332
+ return r if raw else _json(r)
@@ -0,0 +1,148 @@
1
+ Metadata-Version: 2.4
2
+ Name: egauge-python
3
+ Version: 0.9.8
4
+ Summary: Support code for communicating with eGauge hardware.
5
+ Home-page: https://bitbucket.org/egauge/python/
6
+ Author: David Mosberger-Tang
7
+ Author-email: davidm@egauge.net
8
+ License: MIT License
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.6
16
+ Requires-Python: >=3.11
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: crcmod
20
+ Requires-Dist: deprecated
21
+ Requires-Dist: intelhex
22
+ Requires-Dist: requests>=2.4.2
23
+ Provides-Extra: examples
24
+ Requires-Dist: matplotlib; extra == "examples"
25
+ Requires-Dist: readchar; extra == "examples"
26
+ Provides-Extra: pyside
27
+ Requires-Dist: PySide6; extra == "pyside"
28
+ Dynamic: author
29
+ Dynamic: author-email
30
+ Dynamic: classifier
31
+ Dynamic: description
32
+ Dynamic: description-content-type
33
+ Dynamic: home-page
34
+ Dynamic: license
35
+ Dynamic: license-file
36
+ Dynamic: provides-extra
37
+ Dynamic: requires-dist
38
+ Dynamic: requires-python
39
+ Dynamic: summary
40
+
41
+ # eGauge open source Python code
42
+
43
+ This repository is a collection of Python packages that have been
44
+ released by eGauge Systems LLC as open source (MIT license). These
45
+ are released in the hope that they may be useful for other developers.
46
+ Please see LICENSE for details. eGauge Systems LLC reserves the
47
+ rights to add, modify, or remove code from this repository or the
48
+ entire repository without notice.
49
+
50
+ ## egauge.pyside.terminal Support
51
+
52
+ To use module `egauge.pyside.terminal`, be sure to install the package
53
+ with the `pyside` extra dependencies:
54
+
55
+ ```sh
56
+ pip install egauge-python[pyside]
57
+ ```
58
+
59
+ ## Example Programs
60
+
61
+ Example programs can be found in the `egauge.examples` module. If you
62
+ want to run these programs, ensure that all dependencies are installed
63
+ by running the command:
64
+
65
+ ```sh
66
+ pip install egauge-python[examples]
67
+ ```
68
+
69
+ The following examples are available:
70
+
71
+ * `test_capture`: Illustrates the use of the
72
+ `egauge.webapi.device.Capture` class to capture waveform data.
73
+
74
+ * `test_ctid_decoder`: Illustrates how the `egauge.ctid.Decoder` can be
75
+ used to decode CTid information from a waveform.
76
+
77
+ * `test_ctid`: Illustrates how the `egauge.webapi.device.CTidInfo`
78
+ class can be used to control a meter to scan CTid information from
79
+ a sensor, make the sensor blink the indicator LED, and so on.
80
+
81
+ * `test_local`: Illustrates how the `egauge.webapi.device.Local`
82
+ class can be used to fetch and display the locally acquired
83
+ measurements of a meter.
84
+
85
+ * `test_register`: Illustrates how the `egauge.webapi.device.Register`
86
+ class can be used to fetch and display the register data of a
87
+ meter.
88
+
89
+ Before running these programs, set the following environment variables
90
+ for your preferred test device:
91
+
92
+ * `EGDEV`: URL of the test device (e.g., "http://eGaugeXXXXX.local" or
93
+ "http://eGaugeXXXX.d.egauge.net")
94
+ * `EGUSR`: Username to authenticate with (e.g., "owner")
95
+ * `EGPWD`: Password to authenticate with (e.g., "super-secret-pw")
96
+
97
+ For example, the test program that illustrates the use of the register
98
+ data interface can be run with the command:
99
+
100
+ ```
101
+ python -m egauge.examples.test_register
102
+ ```
103
+
104
+ ## Overview of available modules
105
+
106
+ ### egauge.webapi
107
+
108
+ The classes in this module provide access to eGauge web services. The
109
+ APIs may be available on eGauge devices and/or as cloud-based web
110
+ services.
111
+
112
+ ### egauge.webapi.device
113
+
114
+ The classes in this module provide access to APIs implemented on
115
+ eGauge devices.
116
+
117
+ ### egauge.webapi.cloud
118
+
119
+ The classes in this module provide access to APIs implemented by
120
+ eGauge cloud services.
121
+
122
+ ### egauge.ctid
123
+
124
+ The classes in this module support manufacturing CTid® sensors. CTid®
125
+ is patented technology and shall be used in accordance with the
126
+ licensing agreements governing its use.
127
+
128
+ ### egauge.pyside
129
+
130
+ The classes in this module support QT6-based graphical
131
+ user-interfaces.
132
+
133
+ ## Source Code Conventions
134
+
135
+ Source code should be formatted with `ruff format` using a maximum
136
+ line-length of 79 characters. The formatter can be installed with
137
+ `pip install ruff`.
138
+
139
+ Source code should be validated with `ruff check` and `pyright`. The
140
+ latter can be installed with `pip install pyright`.
141
+
142
+ To do these things automatically before committing a change, install
143
+ the pre-commit hooks with:
144
+
145
+ ```sh
146
+ pip install pre-commit
147
+ pre-commit install
148
+ ```
@@ -0,0 +1,44 @@
1
+ egauge/loggers.py,sha256=r7H6GxH-Np_IZJiD29G7zFUZuAPTsWk_9GDySNTJ8j8,2740
2
+ egauge/ctid/__init__.py,sha256=Q2SjjoGOof814JCjDrNTIHQfL3DiMpz6zXQIKcz6VXw,212
3
+ egauge/ctid/bit_stuffer.py,sha256=wKli916sgCf4KuiebtyL5fdBG9nVWaJ2xW08pV2RHkM,2254
4
+ egauge/ctid/ctid.py,sha256=_TMWWKWIkpWnZnO6pqv6WW7t537b0ReQi8wZIhVGwGM,32637
5
+ egauge/ctid/encoder.py,sha256=_6HUryqPKp8_2kuCHYZW4mdKPYaBS2R2RxQsOPq9UdM,12055
6
+ egauge/ctid/intel_hex_encoder.py,sha256=Eei_bXBTZCpJ1yb1bqNNk-yIxU7uks5VtlD39EcjOmQ,3228
7
+ egauge/ctid/waveform.py,sha256=lpSMj-QQ-22YQQzKkj9-pcTUXdPQJO5FsEwlHvCu0SY,9651
8
+ egauge/examples/test_capture.py,sha256=dzCAd7MRa6Td9ZtR1FQ4O0MoMd5Qr0_tcl0l3mdbtXk,2287
9
+ egauge/examples/test_common.py,sha256=UG-i1rWbsad0xfXGlfWv2DaNbiMBZj0BU_vqCjQksks,716
10
+ egauge/examples/test_ctid.py,sha256=3F2uwS1t8_Cn0X2KfbQi8uEARJU8RLxQTRnt8Xtulj8,2289
11
+ egauge/examples/test_ctid_decoder.py,sha256=yV8N0ue3G-8L-o1VUt5r_FMVZlcLo_QHZsrCfrLjQJ4,2628
12
+ egauge/examples/test_local.py,sha256=e5LyDFKsA4S2bOHk3wDamslp5ug5g9C8QinHEWLWM6Q,6027
13
+ egauge/examples/test_register.py,sha256=kjt18LuBbb7kwMrf9DlwEODVjUy0Yy6OBlOesrGaBzA,3367
14
+ egauge/examples/data/test-ctid-decoder.raw,sha256=FRWUwduRYpBwwUwr9gkOZbmuFRmRLbakVFxUfPvd8ZU,127012
15
+ egauge/pyside/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ egauge/pyside/ansi2html.py,sha256=V1Cu2ZAO5IihrygtCXQVEuPKU4IYoKv2TPcGA1xX13Q,3625
17
+ egauge/pyside/terminal.py,sha256=3OIshPfCyd2_tZtZ27EjarQuNzAdHmGz7805vMpVP-Y,11005
18
+ egauge/webapi/__init__.py,sha256=-hIICb-1w10vQW2lxqrrH85VJEwdDAXBGyKfPlv1WKw,1410
19
+ egauge/webapi/auth.py,sha256=mBM6eQ62H_DLm0IBsAjHWvK0pCckKzxgexIJPESnMho,11795
20
+ egauge/webapi/error.py,sha256=EGR2DVCg7bvA5M1_ISHPK5uObMbVjMowQ2CwpHMkKKg,1405
21
+ egauge/webapi/json_api.py,sha256=pGHzkLGEcIcVarVgv9NdzC-R9rd7YrXGM6nm2O0qqqc,11186
22
+ egauge/webapi/cloud/__init__.py,sha256=1LHd4WysO5xGan7pAjcrtXUeLzRwgHwl3D-igfRkFZM,1307
23
+ egauge/webapi/cloud/credentials.py,sha256=mZjNFsh5yZVjw863I1z-DdBgcxrNJVclnad78EJr8qQ,2854
24
+ egauge/webapi/cloud/credentials_dialog.py,sha256=SxdpxrfoDra98apvs3LQI54pe4RfOAKD61vjqPO-eGk,1739
25
+ egauge/webapi/cloud/serial_number.py,sha256=W_3W6oyKNy3jfoe5D5WaDX2l1N47OybDdhYUOLDBv5I,9219
26
+ egauge/webapi/cloud/gui/credentials_dialog.py,sha256=z1BxsGxYelISNWQ5KoYy_gERw5_HHHK9vuRH_loSrcw,4384
27
+ egauge/webapi/device/__init__.py,sha256=_zH1zqinig1XJE-30WbpDA7VTeVy2O8_kv0BaFAa4z4,1574
28
+ egauge/webapi/device/capture.py,sha256=QnF18eQeK5iofotSJ8lEAVlQftKfvRwM9Lv2ET4MXko,15265
29
+ egauge/webapi/device/ctid_info.py,sha256=xtKbeZbkHE7HOUaMNiJ1ZAMWx04qQ6EucQOIFAEv2hA,19048
30
+ egauge/webapi/device/device.py,sha256=T00oww8d-x-aeJ8KFwBrjmqDUFNcTigEbRLksVo-8Po,11239
31
+ egauge/webapi/device/local.py,sha256=PfuJpYywy0eW_x5LWURQlsfJqu8HbfGhB7rXXtbxrzE,8631
32
+ egauge/webapi/device/physical_quantity.py,sha256=9EpgRaw5erhj8bc5HMMXLYXB56rVBLobWYft3Du0Y0A,15088
33
+ egauge/webapi/device/physical_units.py,sha256=dPK5IS3RLnPrN3jzPMiGcKPViTTTW8eigfPyeIBJ6qQ,15528
34
+ egauge/webapi/device/register.py,sha256=m40vHKfNCMX-Z1gHtTHrQHHnYJQdO90lkK3likEJHWw,10792
35
+ egauge/webapi/device/register_row.py,sha256=kmp-J-1UCmIADsWzVuUh8UoNGGxPEFJ-6ctODwTkpjg,5356
36
+ egauge/webapi/device/register_type.py,sha256=Vib1yB7NVvU2V_dmynn5XmP-GGLJEeyMrxGe_CFGscI,31862
37
+ egauge/webapi/device/slop.py,sha256=Qd8SMW8nNj-9tOPyo5q2mIiJOCujSdhTziOsg6B7PGc,11119
38
+ egauge/webapi/device/virtual_register.py,sha256=5kHCRjlll3TVzV-rUN4mN77ji4bxcVcnmKbphXPpWuU,11225
39
+ egauge_python-0.9.8.dist-info/licenses/LICENSE,sha256=ag5WNF_k9HwPpEsSE01bSKehdey_oZXHk4eG2vt6jPo,1090
40
+ egauge_python-0.9.8.dist-info/METADATA,sha256=Wr4ZrF2zQsZ31JMyIv_Oq6NCDkTt8ftpjPh6BSNoBrY,4509
41
+ egauge_python-0.9.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
42
+ egauge_python-0.9.8.dist-info/entry_points.txt,sha256=0L36-f8EWCWIGTz5LvaxRN5YXpeyZyQiooC-yJkvvtQ,58
43
+ egauge_python-0.9.8.dist-info/top_level.txt,sha256=VRgtqeml4GfDfXUzv7cdHTfiW_XVIM9G4js8ubDxlWc,7
44
+ egauge_python-0.9.8.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ctid-encoder = egauge.ctid.encoder:main
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015-2023 eGauge Systems LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
1
+ egauge