pymscada 0.1.11b10__py3-none-any.whl → 0.2.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.
- pymscada/alarms.py +353 -0
- pymscada/bus_client.py +6 -5
- pymscada/bus_server.py +14 -2
- pymscada/callout.py +206 -0
- pymscada/checkout.py +87 -89
- pymscada/console.py +4 -3
- pymscada/demo/__pycache__/__init__.cpython-311.pyc +0 -0
- pymscada/demo/alarms.yaml +5 -0
- pymscada/demo/callout.yaml +17 -0
- pymscada/demo/openweather.yaml +1 -1
- pymscada/demo/pymscada-alarms.service +16 -0
- pymscada/demo/pymscada-callout.service +16 -0
- pymscada/demo/pymscada-io-openweather.service +15 -0
- pymscada/demo/{pymscada-io-accuweather.service → pymscada-io-witsapi.service} +2 -2
- pymscada/demo/tags.yaml +4 -0
- pymscada/demo/witsapi.yaml +17 -0
- pymscada/files.py +3 -3
- pymscada/history.py +64 -8
- pymscada/iodrivers/openweather.py +131 -50
- pymscada/iodrivers/witsapi.py +217 -0
- pymscada/iodrivers/witsapi_POC.py +246 -0
- pymscada/main.py +1 -1
- pymscada/module_config.py +40 -14
- pymscada/opnotes.py +81 -16
- pymscada/pdf/__pycache__/__init__.cpython-311.pyc +0 -0
- pymscada/protocol_constants.py +51 -33
- pymscada/tag.py +0 -22
- pymscada/www_server.py +72 -17
- {pymscada-0.1.11b10.dist-info → pymscada-0.2.0.dist-info}/METADATA +9 -7
- {pymscada-0.1.11b10.dist-info → pymscada-0.2.0.dist-info}/RECORD +38 -25
- {pymscada-0.1.11b10.dist-info → pymscada-0.2.0.dist-info}/WHEEL +2 -1
- {pymscada-0.1.11b10.dist-info → pymscada-0.2.0.dist-info}/entry_points.txt +0 -3
- pymscada-0.2.0.dist-info/top_level.txt +1 -0
- {pymscada-0.1.11b10.dist-info → pymscada-0.2.0.dist-info}/licenses/LICENSE +0 -0
pymscada/www_server.py
CHANGED
|
@@ -4,13 +4,36 @@ from aiohttp import web, WSMsgType
|
|
|
4
4
|
import logging
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from struct import pack, unpack_from
|
|
7
|
+
import socket
|
|
7
8
|
import time
|
|
8
9
|
from pymscada.bus_client import BusClient
|
|
9
10
|
import pymscada.protocol_constants as pc
|
|
10
|
-
from pymscada.tag import Tag,
|
|
11
|
+
from pymscada.tag import Tag, TYPES
|
|
11
12
|
from pymscada_html import get_html_file
|
|
12
13
|
|
|
13
14
|
|
|
15
|
+
def standardise_tag_info(tagname: str, tag: dict):
|
|
16
|
+
"""Correct tag dictionary in place to be suitable for web client."""
|
|
17
|
+
tag['name'] = tagname
|
|
18
|
+
tag['id'] = None
|
|
19
|
+
if 'desc' not in tag:
|
|
20
|
+
tag['desc'] = tagname
|
|
21
|
+
if 'multi' in tag:
|
|
22
|
+
tag['type'] = 'int'
|
|
23
|
+
else:
|
|
24
|
+
if 'type' not in tag:
|
|
25
|
+
tag['type'] = 'float'
|
|
26
|
+
else:
|
|
27
|
+
if tag['type'] not in TYPES:
|
|
28
|
+
tag['type'] = 'str'
|
|
29
|
+
if tag['type'] == 'int':
|
|
30
|
+
tag['dp'] = 0
|
|
31
|
+
elif tag['type'] == 'float' and 'dp' not in tag:
|
|
32
|
+
tag['dp'] = 2
|
|
33
|
+
elif tag['type'] == 'str' and 'dp' in tag:
|
|
34
|
+
del tag['dp']
|
|
35
|
+
|
|
36
|
+
|
|
14
37
|
class Interface():
|
|
15
38
|
"""Provide an interface between web client rta and the action."""
|
|
16
39
|
|
|
@@ -34,11 +57,13 @@ class WSHandler():
|
|
|
34
57
|
ids = set(range(1, 1000))
|
|
35
58
|
|
|
36
59
|
def __init__(self, ws: web.WebSocketResponse, pages: dict,
|
|
37
|
-
tag_info: dict[str, Tag], do_rta, interface: Interface
|
|
60
|
+
tag_info: dict[str, Tag], do_rta, interface: Interface,
|
|
61
|
+
config: dict):
|
|
38
62
|
"""Create callbacks to monitor tag values."""
|
|
39
63
|
self.ws = ws
|
|
40
64
|
self.pages = pages
|
|
41
65
|
self.tag_info = tag_info
|
|
66
|
+
self.config = config
|
|
42
67
|
self.tag_by_id: dict[int, Tag] = {}
|
|
43
68
|
self.tag_by_name: dict[str, Tag] = {}
|
|
44
69
|
self.queue = asyncio.Queue()
|
|
@@ -140,7 +165,7 @@ class WSHandler():
|
|
|
140
165
|
|
|
141
166
|
def notify_id(self, tag: Tag):
|
|
142
167
|
"""Must be done here."""
|
|
143
|
-
logging.info(f'{self.rta_id}: send id to
|
|
168
|
+
logging.info(f'{self.rta_id}: send id to browser for {tag.name}')
|
|
144
169
|
self.tag_info[tag.name]['id'] = tag.id
|
|
145
170
|
self.tag_by_id[tag.id] = tag
|
|
146
171
|
self.tag_by_name[tag.name] = tag
|
|
@@ -168,6 +193,8 @@ class WSHandler():
|
|
|
168
193
|
async def connection_active(self):
|
|
169
194
|
"""Run while the connection is active and don't return."""
|
|
170
195
|
send_queue = asyncio.create_task(self.send_queue())
|
|
196
|
+
self.queue.put_nowait(
|
|
197
|
+
(False, {'type': 'config', 'payload': self.config}))
|
|
171
198
|
self.queue.put_nowait(
|
|
172
199
|
(False, {'type': 'pages', 'payload': self.pages}))
|
|
173
200
|
async for msg in self.ws:
|
|
@@ -208,32 +235,60 @@ class WSHandler():
|
|
|
208
235
|
|
|
209
236
|
|
|
210
237
|
class WwwServer:
|
|
211
|
-
"""Connect to bus on bus_ip:bus_port, serve on ip:port for
|
|
238
|
+
"""Connect to bus on bus_ip:bus_port, serve on ip:port for webserver."""
|
|
212
239
|
|
|
213
|
-
def __init__(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
240
|
+
def __init__(
|
|
241
|
+
self,
|
|
242
|
+
bus_ip: str = '127.0.0.1',
|
|
243
|
+
bus_port: int = 1324,
|
|
244
|
+
ip: str = '127.0.0.1',
|
|
245
|
+
port: int = 8324,
|
|
246
|
+
get_path: str | None = None,
|
|
247
|
+
tag_info: dict = {},
|
|
248
|
+
pages: dict = {},
|
|
249
|
+
config: dict = {},
|
|
250
|
+
serve_path: str | None = None,
|
|
251
|
+
www_tag: str = '__wwwserver__'
|
|
252
|
+
) -> None:
|
|
218
253
|
"""
|
|
219
|
-
Connect to bus on bus_ip:bus_port, serve on ip:port for
|
|
254
|
+
Connect to bus on bus_ip:bus_port, serve on ip:port for webserver.
|
|
220
255
|
|
|
221
|
-
Serves the
|
|
222
|
-
|
|
256
|
+
Serves the files at /, as a relative path. The browser uses a
|
|
257
|
+
websocket connection to request and set tag values and subscribe to
|
|
223
258
|
changes.
|
|
224
259
|
|
|
225
260
|
Event loop must be running.
|
|
226
261
|
"""
|
|
262
|
+
try:
|
|
263
|
+
socket.gethostbyname(bus_ip)
|
|
264
|
+
except socket.gaierror as e:
|
|
265
|
+
raise ValueError(f'Cannot resolve bus IP/hostname: {e}')
|
|
266
|
+
if not isinstance(bus_port, int):
|
|
267
|
+
raise TypeError('bus_port must be an integer')
|
|
268
|
+
if not 1024 <= bus_port <= 65535:
|
|
269
|
+
raise ValueError('bus_port must be between 1024 and 65535')
|
|
270
|
+
try:
|
|
271
|
+
socket.gethostbyname(ip)
|
|
272
|
+
except socket.gaierror as e:
|
|
273
|
+
raise ValueError(f'Cannot resolve IP/hostname: {e}')
|
|
274
|
+
if not isinstance(port, int):
|
|
275
|
+
raise TypeError('port must be an integer')
|
|
276
|
+
if not 1024 <= port <= 65535:
|
|
277
|
+
raise ValueError('port must be between 1024 and 65535')
|
|
278
|
+
if not isinstance(www_tag, str) or not www_tag:
|
|
279
|
+
raise ValueError('www_tag must be a non-empty string')
|
|
280
|
+
|
|
227
281
|
self.busclient = BusClient(bus_ip, bus_port, tag_info,
|
|
228
282
|
module='WWW Server')
|
|
229
283
|
self.ip = ip
|
|
230
284
|
self.port = port
|
|
231
285
|
self.get_path = get_path
|
|
232
|
-
self.serve_path = Path(serve_path)
|
|
286
|
+
self.serve_path = Path(serve_path) if serve_path else None
|
|
233
287
|
for tagname, tag in tag_info.items():
|
|
234
|
-
|
|
288
|
+
standardise_tag_info(tagname, tag)
|
|
235
289
|
self.tag_info = tag_info
|
|
236
290
|
self.pages = pages
|
|
291
|
+
self.config = config
|
|
237
292
|
self.interface = Interface(www_tag)
|
|
238
293
|
|
|
239
294
|
async def redirect_handler(self, _request: web.Request):
|
|
@@ -256,14 +311,14 @@ class WwwServer:
|
|
|
256
311
|
async def path_handler(self, request: web.Request):
|
|
257
312
|
"""Plain files."""
|
|
258
313
|
logging.info(f"path {request.match_info['path']}")
|
|
314
|
+
if self.serve_path is None:
|
|
315
|
+
return web.HTTPForbidden(reason='path not configured')
|
|
259
316
|
path = self.serve_path.joinpath(request.match_info['path'])
|
|
260
317
|
if path.is_dir():
|
|
261
318
|
return web.HTTPForbidden(reason='folder not permitted')
|
|
262
319
|
if not path.exists():
|
|
263
320
|
return web.HTTPNotFound(reason='no such file in path')
|
|
264
321
|
return web.FileResponse(path)
|
|
265
|
-
# logging.warning(f"path not configured {request.match_info['path']}")
|
|
266
|
-
# return web.HTTPForbidden(reason='path not permitted')
|
|
267
322
|
|
|
268
323
|
async def websocket_handler(self, request: web.Request):
|
|
269
324
|
"""Wait for connections. Create a new one each time."""
|
|
@@ -272,7 +327,7 @@ class WwwServer:
|
|
|
272
327
|
ws = web.WebSocketResponse(max_msg_size=0) # disables max message size
|
|
273
328
|
await ws.prepare(request)
|
|
274
329
|
await WSHandler(ws, self.pages, self.tag_info, self.busclient.rta,
|
|
275
|
-
self.interface).connection_active()
|
|
330
|
+
self.interface, self.config).connection_active()
|
|
276
331
|
await ws.close()
|
|
277
332
|
logging.info(f"WS closed {peer}")
|
|
278
333
|
return ws
|
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pymscada
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Shared tag value SCADA with python backup and Angular UI
|
|
5
|
-
Author-
|
|
5
|
+
Author-email: Jamie Walton <jamie@walton.net.nz>
|
|
6
6
|
License: GPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://github.com/jamie0walton/pymscada
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/jamie0walton/pymscada/issues
|
|
7
9
|
Classifier: Programming Language :: Python :: 3
|
|
8
10
|
Classifier: Programming Language :: JavaScript
|
|
9
11
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
10
12
|
Classifier: Operating System :: OS Independent
|
|
11
13
|
Classifier: Environment :: Console
|
|
12
14
|
Classifier: Development Status :: 1 - Planning
|
|
13
|
-
Project-URL: Homepage, https://github.com/jamie0walton/pymscada
|
|
14
|
-
Project-URL: Bug Tracker, https://github.com/jamie0walton/pymscada/issues
|
|
15
15
|
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
16
18
|
Requires-Dist: PyYAML>=6.0.1
|
|
17
19
|
Requires-Dist: aiohttp>=3.8.5
|
|
18
|
-
Requires-Dist: pymscada-html
|
|
20
|
+
Requires-Dist: pymscada-html==0.2.0rc4
|
|
19
21
|
Requires-Dist: cerberus>=1.3.5
|
|
20
22
|
Requires-Dist: pycomm3>=1.2.14
|
|
21
23
|
Requires-Dist: pysnmplib>=5.0.24
|
|
22
|
-
|
|
24
|
+
Dynamic: license-file
|
|
23
25
|
|
|
24
26
|
# pymscada
|
|
25
27
|
#### [Docs](https://github.com/jamie0walton/pymscada/blob/main/docs/README.md)
|
|
@@ -1,44 +1,59 @@
|
|
|
1
|
-
pymscada-0.1.11b10.dist-info/METADATA,sha256=eBGZjmCSP1HPBnfBlpacMN1Q2VdGFm0_52G2FU-TlLg,2350
|
|
2
|
-
pymscada-0.1.11b10.dist-info/WHEEL,sha256=thaaA2w1JzcGC48WYufAs8nrYZjJm8LqNfnXFOFyCC4,90
|
|
3
|
-
pymscada-0.1.11b10.dist-info/entry_points.txt,sha256=j_UgZmqFhNquuFC2M8g5-8X9FCpp2RaDb7NrExzkj1c,72
|
|
4
|
-
pymscada-0.1.11b10.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
5
1
|
pymscada/__init__.py,sha256=NV_cIIwe66Ugp8ns426rtfJIIyskWbqwImD9p_5p0bQ,739
|
|
6
2
|
pymscada/__main__.py,sha256=WcyVlrYOoDdktJhOoyubTOycMwpayksFdxwelRU5xpQ,272
|
|
7
|
-
pymscada/
|
|
8
|
-
pymscada/
|
|
9
|
-
pymscada/
|
|
3
|
+
pymscada/alarms.py,sha256=eo-9-DSwV825ihuHApaYkADPpLouKbNLHyh0z4bdPoU,12936
|
|
4
|
+
pymscada/bus_client.py,sha256=eRGvHQ4sFM_n3rKvKDWZQJPQJqvKMWvxbH3MjtT2WBo,9131
|
|
5
|
+
pymscada/bus_server.py,sha256=k7ht2SAr24Oab0hBOPeW4NRDF_RK-F46iE0cMzh7K4w,12323
|
|
6
|
+
pymscada/callout.py,sha256=egY-zQmb7Np46qbAxOck_5JbCHgF2x6OLIFunsIU6mc,7435
|
|
7
|
+
pymscada/checkout.py,sha256=RLuCMTEuUI7pp1hIRAUPbo8xYFta8TjArelx0SD4gOY,3897
|
|
10
8
|
pymscada/config.py,sha256=vwGxieaJBYXiHNQEOYVDFaPuGmnUlCnbNm_W9bugKlc,1851
|
|
11
|
-
pymscada/console.py,sha256=
|
|
9
|
+
pymscada/console.py,sha256=EEsJLCvn8AFimN8qGNilX0ks6t3OFcGW5nw6OVAXfac,8850
|
|
10
|
+
pymscada/files.py,sha256=iouEOPfEkVI0Qbbf1p-L324Y04zSrynVypLW0-1MThA,2499
|
|
11
|
+
pymscada/history.py,sha256=7UEOeMnlSMv0LoWTqLWx7QwOW1FZZ4wAvzH6v6b0_vI,11592
|
|
12
|
+
pymscada/main.py,sha256=d6EnK4-tEcvM5AqMHYhvqlnSh-E_wd0Tuxk-kXYSiDw,1854
|
|
13
|
+
pymscada/misc.py,sha256=0Cj6OFhQonyhyk9x0BG5MiS-6EPk_w6zvavt8o_Hlf0,622
|
|
14
|
+
pymscada/module_config.py,sha256=K-ZBO-2rZTdlDbVkeQ3_4uI75EUxVMmanVzDuuDNsao,9564
|
|
15
|
+
pymscada/opnotes.py,sha256=MKM51IrB93B2-kgoTzlpOLpaMYs-7rPQHWmRLME-hQQ,7952
|
|
16
|
+
pymscada/periodic.py,sha256=MLlL93VLvFqBBgjO1Us1t0aLHTZ5BFdW0B__G02T1nQ,1235
|
|
17
|
+
pymscada/protocol_constants.py,sha256=lPJ4JEgFJ_puJjTym83EJIOw3UTUFbuFMwg3ohyUAGY,2414
|
|
18
|
+
pymscada/samplers.py,sha256=t0IscgsCm5YByioOZ6aOKMO_guDFS_wxnJSiOGKI4Nw,2583
|
|
19
|
+
pymscada/tag.py,sha256=hTRxogw8BXAi1OJpM1Lhx4KKMqZ53y7D5KcCycO7fRQ,9471
|
|
20
|
+
pymscada/validate.py,sha256=fPMlP6RscYuTIgdEJjJ0ZZI0OyVSat1lpqg254wqpdE,13140
|
|
21
|
+
pymscada/www_server.py,sha256=NfvX9jbVWY2qxWM6TfWUcwsCY7lR-dkty1nCOXyoWTA,13747
|
|
12
22
|
pymscada/demo/README.md,sha256=iNcVbCTkq-d4agLV-979lNRaqf_hbJCn3OFzY-6qfU8,880
|
|
13
23
|
pymscada/demo/__init__.py,sha256=WsDDgkWnZBJbt2-cJCdc2NvRAv_T4a7WOC1Q0k_l0gI,29
|
|
14
24
|
pymscada/demo/accuweather.yaml,sha256=Fk4rV0S8jCau0173QCzKW8TdUbc4crYVi0aD8fPLNgU,322
|
|
25
|
+
pymscada/demo/alarms.yaml,sha256=Ea8tLZ0aEiyKM_m5MN1TF6xS-lI5ReXiz2oUPO8GvmQ,110
|
|
15
26
|
pymscada/demo/bus.yaml,sha256=zde5JDo2Yv5s7NvJ569gAEoTDvsvgBwRPxfrYhsxj3w,26
|
|
27
|
+
pymscada/demo/callout.yaml,sha256=I0nFWEXu1J48tJjKolyeCqvOVnds4FOp3dYBf8cSpcA,298
|
|
16
28
|
pymscada/demo/files.yaml,sha256=XWtmGDJxtD4qdl2h7miUfJYkDKsvwNTgQjlGpR6LQNs,163
|
|
17
29
|
pymscada/demo/history.yaml,sha256=c0OuYe8LbTeZqJGU2WKGgTEkOA0IYAjO3e046ddQB8E,55
|
|
18
30
|
pymscada/demo/logixclient.yaml,sha256=G_NlJhBYwT1a9ceHDgO6fCNKFmBM2pVO_t9Xa1NqlRY,912
|
|
19
31
|
pymscada/demo/modbus_plc.py,sha256=3zZHHbyrdxyryEHBeNIw-fpcDGcS1MaJiqEwQDr6zWI,2397
|
|
20
32
|
pymscada/demo/modbusclient.yaml,sha256=geeCsUJZkkEj7jjXR_Yk6R5zA5Ta9IczrHsARz7ZgXY,1099
|
|
21
33
|
pymscada/demo/modbusserver.yaml,sha256=67_mED6jXgtnzlDIky9Cg4j-nXur06iz9ve3JUwSyG8,1133
|
|
22
|
-
pymscada/demo/openweather.yaml,sha256=
|
|
34
|
+
pymscada/demo/openweather.yaml,sha256=n8aPc_Ar6uiM-XbrEbBydABxFYm2uv_49dGo8u7DI8Q,433
|
|
23
35
|
pymscada/demo/opnotes.yaml,sha256=gdT8DKaAV4F6u9trLCPyBgf449wYaP_FF8GCbjXm9-k,105
|
|
24
36
|
pymscada/demo/ping.yaml,sha256=fm3eUdR2BwnPI_lU_V07qgmDxjSoPP6lPazYB6ZgpVg,149
|
|
37
|
+
pymscada/demo/pymscada-alarms.service,sha256=nHjEMsonat-3ny0QJoY6KTZoPIt2HZiarKgW5uasY8k,383
|
|
25
38
|
pymscada/demo/pymscada-bus.service,sha256=F3ViriRXyMKdCY3tHa3wXAnv2Fo2_16-EScTLsYnSOA,261
|
|
39
|
+
pymscada/demo/pymscada-callout.service,sha256=XpG20TVofjEuoRnBxH1f5DQEBdGbj2tORs60IjiuQw4,386
|
|
26
40
|
pymscada/demo/pymscada-demo-modbus_plc.service,sha256=EtbWDwqAs4nLNLKScUiHcUWU1b6_tRBeAAVGi9q95hY,320
|
|
27
41
|
pymscada/demo/pymscada-files.service,sha256=iLOfbl4SCxAwYHT20XCGHU0BJsUVicNHjHzKS8xIdgA,326
|
|
28
42
|
pymscada/demo/pymscada-history.service,sha256=61c5RqOmJ13Dl1yyRfsChKOdXp2W-xfYyCOYoJHLkh8,386
|
|
29
|
-
pymscada/demo/pymscada-io-accuweather.service,sha256=M_dnPYwmvTpYGF5AbMStbYL6VCWgOFR50nRRpfqvpBo,358
|
|
30
43
|
pymscada/demo/pymscada-io-logixclient.service,sha256=mn4UzkiOfYqHvgfTFSkUeoPFQQXZboet5I0m7-L5SAY,348
|
|
31
44
|
pymscada/demo/pymscada-io-modbusclient.service,sha256=eTgNdK10dJCs2lLPhmHBh-3j6Ltx2oyU_MNl2f3xnhg,348
|
|
32
45
|
pymscada/demo/pymscada-io-modbusserver.service,sha256=g7Rzm6zGLq_qvTJRL_pcLl4Ps7CNIa2toeGhPNp_oEc,348
|
|
46
|
+
pymscada/demo/pymscada-io-openweather.service,sha256=SQnZ-cq1V3qvZY7EgR_Vx36vCOw1ipfGoLoutHsxtNk,359
|
|
33
47
|
pymscada/demo/pymscada-io-ping.service,sha256=Fm8qR4IVq0NupEvHLGONXGwjjQsx5VqaBYPewhg7-k4,329
|
|
34
48
|
pymscada/demo/pymscada-io-snmpclient.service,sha256=Rsm8uiwnoGx-1MkXqYgtj4UP9-r7AEEeB9yoR0y0oVA,343
|
|
49
|
+
pymscada/demo/pymscada-io-witsapi.service,sha256=ZjNwUnZg7WZsCaBFk8aNibnCbwqtbhl1i9D8tdUGXiQ,343
|
|
35
50
|
pymscada/demo/pymscada-opnotes.service,sha256=TlrTRgP3rzrlXT8isAGT_Wy38ScDjT1VvnlgW84XiS8,354
|
|
36
51
|
pymscada/demo/pymscada-wwwserver.service,sha256=7Qy2wsMmFEsQn-b5mgAcsrAQZgXynkv8SpHD6hLvRGc,370
|
|
37
52
|
pymscada/demo/snmpclient.yaml,sha256=z8iACrFvMftYUtqGrRjPZYZTpn7aOXI-Kp675NAM8cU,2013
|
|
38
|
-
pymscada/demo/tags.yaml,sha256=
|
|
53
|
+
pymscada/demo/tags.yaml,sha256=1HH9SqevBE0P0NXHK0Slfu68gwx5iKpgyirClmAcXGY,2814
|
|
54
|
+
pymscada/demo/witsapi.yaml,sha256=B8F136jvLIYU8t-pOdsEU_j97qMo3RgGQ1Rs4ExhmeE,289
|
|
39
55
|
pymscada/demo/wwwserver.yaml,sha256=mmwvSLUXUDCIPaHeCJdCETAp9Cc4wb5CuK_aGv01KWk,2759
|
|
40
|
-
pymscada/
|
|
41
|
-
pymscada/history.py,sha256=G079gHfzasmGtI5ANS8MdETD4bdZg5vHE_yTKk7atHw,9504
|
|
56
|
+
pymscada/demo/__pycache__/__init__.cpython-311.pyc,sha256=TC7eGWRbKH4Ym3_tWYBtysWg3sgiWQ19zy81aJLriKQ,195
|
|
42
57
|
pymscada/iodrivers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
58
|
pymscada/iodrivers/accuweather.py,sha256=p_OYJtCrtbSQYjgf06Yk3Qc9wGpkx8ogn81XNGd19fE,3842
|
|
44
59
|
pymscada/iodrivers/logix_client.py,sha256=eqmiYLYUBHbr7wTljomGIZVNvXe-5WleGKfzwcHXO8w,2829
|
|
@@ -46,24 +61,22 @@ pymscada/iodrivers/logix_map.py,sha256=ljjBAMJcw199v1V5u0Yfl38U6zbZzba5mdY4I3Zvd
|
|
|
46
61
|
pymscada/iodrivers/modbus_client.py,sha256=DIGrEPz_Bwwj9CEeog5fQqiAu1UMV7xVL6KxlKgXNPs,9592
|
|
47
62
|
pymscada/iodrivers/modbus_map.py,sha256=af2J3CGSeYQ4mSy8rNsERp9z7fRgRUYk3it5Mrc_IQA,7255
|
|
48
63
|
pymscada/iodrivers/modbus_server.py,sha256=VqvjOJ4-LOVaD1jOK22raXhrCshJEaWlMxLvn5xMnFc,6570
|
|
49
|
-
pymscada/iodrivers/openweather.py,sha256=
|
|
64
|
+
pymscada/iodrivers/openweather.py,sha256=IVzmaEjdwm1NDhsOYpEV5vzB8HFaQEpWsnm6fhpsPCQ,8926
|
|
50
65
|
pymscada/iodrivers/ping_client.py,sha256=UOQgUfoIcYqy5VvKyJ8XGHHjeSRTfjmrhyWEojhIZQk,4188
|
|
51
66
|
pymscada/iodrivers/ping_map.py,sha256=EbOteqfEYKIOMqPymROJ4now2If-ekEj6jnM5hthoSA,1403
|
|
52
67
|
pymscada/iodrivers/snmp_client.py,sha256=66-IDzddeKcSnqOzNXIZ8wuuAqhIxZjyLNrDwDvHCvw,2708
|
|
53
68
|
pymscada/iodrivers/snmp_map.py,sha256=sDdIR5ZPAETpozDfBt_XQiZ-f4t99UCPlzj7BxFxQyM,2369
|
|
54
|
-
pymscada/
|
|
55
|
-
pymscada/
|
|
56
|
-
pymscada/module_config.py,sha256=Sq9DDND0WotxwdY7mRHG8G-WNPYqWp9fxvx38--kwr0,8462
|
|
57
|
-
pymscada/opnotes.py,sha256=pxjFgy4uMnAmJcfrk8BX4Gl5j0z4fFb5waXcqI6UJ_M,5133
|
|
69
|
+
pymscada/iodrivers/witsapi.py,sha256=Ga6JpEQRUciT_LxWW36LsVGkUeWjModtzPoWYIzyzHs,8381
|
|
70
|
+
pymscada/iodrivers/witsapi_POC.py,sha256=dQcR2k1wsLb_cnNqvAB4kJ7FdY0BlcnxiMoepr28Ars,10132
|
|
58
71
|
pymscada/pdf/__init__.py,sha256=WsDDgkWnZBJbt2-cJCdc2NvRAv_T4a7WOC1Q0k_l0gI,29
|
|
59
72
|
pymscada/pdf/one.pdf,sha256=eoJ45DrAjVZrwmwdA_EAz1fwmT44eRnt_tkc2pmMrKY,1488
|
|
60
73
|
pymscada/pdf/two.pdf,sha256=TAuW5yLU1_wfmTH_I5ezHwY0pxhCVuZh3ixu0kwmJwE,1516
|
|
61
|
-
pymscada/
|
|
62
|
-
pymscada/protocol_constants.py,sha256=ooGmBM7WGWWdN10FObdjzcYieK8WN7Zy6qVxtD93LMk,1963
|
|
63
|
-
pymscada/samplers.py,sha256=t0IscgsCm5YByioOZ6aOKMO_guDFS_wxnJSiOGKI4Nw,2583
|
|
64
|
-
pymscada/tag.py,sha256=Oxh70q2MrPAEI94v4QsWt4gD8QP6BlfzNv9xXeeUFys,10103
|
|
74
|
+
pymscada/pdf/__pycache__/__init__.cpython-311.pyc,sha256=5Mad2aaeayIDH_0G1eLDNTLHN14smUPFz7K4D4szoRI,194
|
|
65
75
|
pymscada/tools/snmp_client2.py,sha256=pdn5dYyEv4q-ubA0zQ8X-3tQDYxGC7f7Xexa7QPaL40,1675
|
|
66
76
|
pymscada/tools/walk.py,sha256=OgpprUbKLhEWMvJGfU1ckUt_PFEpwZVOD8HucCgzmOc,1625
|
|
67
|
-
pymscada/
|
|
68
|
-
pymscada/
|
|
69
|
-
pymscada-0.
|
|
77
|
+
pymscada-0.2.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
78
|
+
pymscada-0.2.0.dist-info/METADATA,sha256=us-TxGOsrM-izAAvIzc48J1uwRDQ4-ulToU_jYdm40I,2390
|
|
79
|
+
pymscada-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
80
|
+
pymscada-0.2.0.dist-info/entry_points.txt,sha256=2UJBi8jrqujnerrcXcq4F8GHJYVDt26sacXl94t3sd8,56
|
|
81
|
+
pymscada-0.2.0.dist-info/top_level.txt,sha256=LxIB-zrtgObJg0fgdGZXBkmNKLDYHfaH1Hw2YP2ZMms,9
|
|
82
|
+
pymscada-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pymscada
|
|
File without changes
|