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.
- egauge/ctid/__init__.py +7 -0
- egauge/ctid/bit_stuffer.py +65 -0
- egauge/ctid/ctid.py +967 -0
- egauge/ctid/encoder.py +436 -0
- egauge/ctid/intel_hex_encoder.py +98 -0
- egauge/ctid/waveform.py +299 -0
- egauge/examples/data/test-ctid-decoder.raw +0 -0
- egauge/examples/test_capture.py +77 -0
- egauge/examples/test_common.py +26 -0
- egauge/examples/test_ctid.py +89 -0
- egauge/examples/test_ctid_decoder.py +93 -0
- egauge/examples/test_local.py +201 -0
- egauge/examples/test_register.py +104 -0
- egauge/loggers.py +72 -0
- egauge/pyside/__init__.py +0 -0
- egauge/pyside/ansi2html.py +112 -0
- egauge/pyside/terminal.py +295 -0
- egauge/webapi/__init__.py +34 -0
- egauge/webapi/auth.py +364 -0
- egauge/webapi/cloud/__init__.py +30 -0
- egauge/webapi/cloud/credentials.py +86 -0
- egauge/webapi/cloud/credentials_dialog.py +58 -0
- egauge/webapi/cloud/gui/credentials_dialog.py +100 -0
- egauge/webapi/cloud/serial_number.py +276 -0
- egauge/webapi/device/__init__.py +38 -0
- egauge/webapi/device/capture.py +453 -0
- egauge/webapi/device/ctid_info.py +553 -0
- egauge/webapi/device/device.py +349 -0
- egauge/webapi/device/local.py +268 -0
- egauge/webapi/device/physical_quantity.py +439 -0
- egauge/webapi/device/physical_units.py +473 -0
- egauge/webapi/device/register.py +338 -0
- egauge/webapi/device/register_row.py +145 -0
- egauge/webapi/device/register_type.py +851 -0
- egauge/webapi/device/slop.py +334 -0
- egauge/webapi/device/virtual_register.py +353 -0
- egauge/webapi/error.py +34 -0
- egauge/webapi/json_api.py +332 -0
- egauge_python-0.9.8.dist-info/METADATA +148 -0
- egauge_python-0.9.8.dist-info/RECORD +44 -0
- egauge_python-0.9.8.dist-info/WHEEL +5 -0
- egauge_python-0.9.8.dist-info/entry_points.txt +2 -0
- egauge_python-0.9.8.dist-info/licenses/LICENSE +22 -0
- 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,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
|