pymscada 0.1.9__tar.gz → 0.1.11__tar.gz
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-0.1.9 → pymscada-0.1.11}/PKG-INFO +3 -1
- {pymscada-0.1.9 → pymscada-0.1.11}/pyproject.toml +5 -1
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/files.py +12 -17
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/iodrivers/accuweather.py +4 -2
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/www_server.py +6 -7
- {pymscada-0.1.9 → pymscada-0.1.11}/LICENSE +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/README.md +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/__init__.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/__main__.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/bus_client.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/bus_server.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/checkout.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/config.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/console.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/README.md +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/__init__.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/accuweather.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/bus.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/files.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/history.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/logixclient.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/modbus_plc.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/modbusclient.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/modbusserver.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/opnotes.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/ping.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/pymscada-bus.service +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/pymscada-demo-modbus_plc.service +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/pymscada-files.service +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/pymscada-history.service +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/pymscada-io-accuweather.service +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/pymscada-io-logixclient.service +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/pymscada-io-modbusclient.service +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/pymscada-io-modbusserver.service +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/pymscada-io-ping.service +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/pymscada-io-snmpclient.service +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/pymscada-opnotes.service +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/pymscada-wwwserver.service +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/snmpclient.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/tags.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/demo/wwwserver.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/history.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/iodrivers/__init__.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/iodrivers/logix_client.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/iodrivers/logix_map.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/iodrivers/modbus_client.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/iodrivers/modbus_map.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/iodrivers/modbus_server.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/iodrivers/ping_client.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/iodrivers/ping_map.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/iodrivers/snmp_client.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/iodrivers/snmp_map.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/main.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/misc.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/opnotes.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/pdf/__init__.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/pdf/one.pdf +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/pdf/two.pdf +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/periodic.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/protocol_constants.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/samplers.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/tag.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/tools/snmp_client2.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/tools/walk.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/src/pymscada/validate.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/__init__.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/bus_echo.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/iodrivers/test_logix.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/iodrivers/test_modbus.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_assets/busserver.yaml +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_assets/db.sqlite +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_assets/hist_tag_0_0.dat +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_assets/hist_tag_0_10_2.dat +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_assets/hist_tag_0_15.dat +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_assets/hist_tag_0_26.dat +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_assets/hist_tag_0_50.dat +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_bus_server.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_config.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_history.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_misc.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_opnotes.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_periodic.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_samplers.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_tag.py +0 -0
- {pymscada-0.1.9 → pymscada-0.1.11}/tests/test_validate.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pymscada
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.11
|
|
4
4
|
Summary: Shared tag value SCADA with python backup and Angular UI
|
|
5
5
|
Author-Email: Jamie Walton <jamie@walton.net.nz>
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -10,6 +10,8 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Classifier: Environment :: Console
|
|
12
12
|
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
|
|
13
15
|
Requires-Python: >=3.9
|
|
14
16
|
Requires-Dist: PyYAML>=6.0.1
|
|
15
17
|
Requires-Dist: aiohttp>=3.8.5
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pymscada"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.11"
|
|
4
4
|
description = "Shared tag value SCADA with python backup and Angular UI"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Jamie Walton", email = "jamie@walton.net.nz" },
|
|
@@ -30,6 +30,10 @@ text = "GPL-3.0-or-later"
|
|
|
30
30
|
[project.scripts]
|
|
31
31
|
pymscada = "pymscada.__main__:cmd_line"
|
|
32
32
|
|
|
33
|
+
[project.urls]
|
|
34
|
+
Homepage = "https://github.com/jamie0walton/pymscada"
|
|
35
|
+
"Bug Tracker" = "https://github.com/jamie0walton/pymscada/issues"
|
|
36
|
+
|
|
33
37
|
[build-system]
|
|
34
38
|
requires = [
|
|
35
39
|
"pdm-backend",
|
|
@@ -6,9 +6,6 @@ from pymscada.periodic import Periodic
|
|
|
6
6
|
from pymscada.tag import Tag
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
RATE = 10
|
|
10
|
-
|
|
11
|
-
|
|
12
9
|
class Files():
|
|
13
10
|
"""Connect to bus_ip:bus_port, store and provide a value history."""
|
|
14
11
|
|
|
@@ -23,7 +20,6 @@ class Files():
|
|
|
23
20
|
|
|
24
21
|
Event loop must be running.
|
|
25
22
|
"""
|
|
26
|
-
self.busclient = BusClient(bus_ip, bus_port, module='Files')
|
|
27
23
|
self.path = Path(path)
|
|
28
24
|
self.files = files
|
|
29
25
|
for file in self.files:
|
|
@@ -33,11 +29,19 @@ class Files():
|
|
|
33
29
|
file['mode'] = 'ro'
|
|
34
30
|
file['_path'] = self.path.joinpath(file['path'])
|
|
35
31
|
file['st_mtime_ns'] = 0
|
|
32
|
+
self.busclient = BusClient(bus_ip, bus_port, module='Files')
|
|
36
33
|
self.rta = Tag(rta_tag, dict)
|
|
34
|
+
self.rta.value = {}
|
|
37
35
|
self.busclient.add_callback_rta(rta_tag, self.rta_cb)
|
|
38
|
-
self.scan_files()
|
|
39
36
|
|
|
40
|
-
def
|
|
37
|
+
def rta_cb(self, request):
|
|
38
|
+
"""Respond to Request to Author and publish on rta_tag as needed."""
|
|
39
|
+
if 'action' not in request:
|
|
40
|
+
logging.warning(f'rta_cb malformed {request}')
|
|
41
|
+
logging.info(f'files rta_cb {request}')
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
async def scan_files(self):
|
|
41
45
|
"""Scan folders for files."""
|
|
42
46
|
update = False
|
|
43
47
|
for file in self.files:
|
|
@@ -57,19 +61,10 @@ class Files():
|
|
|
57
61
|
'name': fn.name,
|
|
58
62
|
'desc': file['desc'],
|
|
59
63
|
'mode': file['mode']})
|
|
60
|
-
self.rta.value = {'
|
|
61
|
-
|
|
62
|
-
def rta_cb(self, tag):
|
|
63
|
-
"""Respond to bus requests for data to publish on rta."""
|
|
64
|
-
logging.info(f'files rta_cb {tag.name} {tag.value}')
|
|
65
|
-
pass
|
|
66
|
-
|
|
67
|
-
async def check_files(self):
|
|
68
|
-
"""Check to see if any files have changed."""
|
|
69
|
-
self.scan_files()
|
|
64
|
+
self.rta.value = {'dat': info}
|
|
70
65
|
|
|
71
66
|
async def start(self):
|
|
72
67
|
"""Async startup."""
|
|
73
68
|
await self.busclient.start()
|
|
74
|
-
self.periodic = Periodic(self.
|
|
69
|
+
self.periodic = Periodic(self.scan_files, 10.0)
|
|
75
70
|
await self.periodic.start()
|
|
@@ -42,7 +42,7 @@ class AccuWeatherClient:
|
|
|
42
42
|
for record in json:
|
|
43
43
|
epoch = record['EpochDateTime']
|
|
44
44
|
hour = int((epoch - time_mod) / 3600)
|
|
45
|
-
logging.
|
|
45
|
+
logging.info(f'epoch {epoch} time_s {time_s} hour {hour}')
|
|
46
46
|
if hour not in self.api['times']:
|
|
47
47
|
continue
|
|
48
48
|
suffix = ''
|
|
@@ -55,11 +55,13 @@ class AccuWeatherClient:
|
|
|
55
55
|
['Rain', 'Rain', None, 'Value'],
|
|
56
56
|
['Snow', 'Snow', None, 'Value']
|
|
57
57
|
]:
|
|
58
|
-
|
|
58
|
+
tagname = f'{site}{parm}{suffix}'
|
|
59
|
+
tag = self.tags[tagname]
|
|
59
60
|
if key2 is None:
|
|
60
61
|
value = record[key1][key]
|
|
61
62
|
else:
|
|
62
63
|
value = record[key1][key2][key]
|
|
64
|
+
logging.info(f'{tagname} was {tag.value} new {value}')
|
|
63
65
|
if tag.value != value:
|
|
64
66
|
tag.value = value, int(epoch * 1e6), self.map_bus
|
|
65
67
|
|
|
@@ -63,9 +63,8 @@ class WSHandler():
|
|
|
63
63
|
# logging.debug(f'{self.rta_id} as json {message}')
|
|
64
64
|
await self.ws.send_json(message)
|
|
65
65
|
except asyncio.CancelledError:
|
|
66
|
-
logging.
|
|
67
|
-
|
|
68
|
-
return
|
|
66
|
+
logging.warning(f'{self.rta_id}: send queue error, close '
|
|
67
|
+
f'{self.ws.exception()}')
|
|
69
68
|
|
|
70
69
|
def publish(self, tag: Tag):
|
|
71
70
|
"""
|
|
@@ -200,8 +199,8 @@ class WSHandler():
|
|
|
200
199
|
elif msg.type == WSMsgType.BINARY:
|
|
201
200
|
logging.info(f'{msg.data}')
|
|
202
201
|
elif msg.type == WSMsgType.ERROR:
|
|
203
|
-
logging.
|
|
204
|
-
|
|
202
|
+
logging.warning(f'{self.rta_id}: ws closing error '
|
|
203
|
+
f'{self.ws.exception()}')
|
|
205
204
|
send_queue.cancel()
|
|
206
205
|
for tag in self.tag_by_id.values():
|
|
207
206
|
tag.del_callback_id(self.notify_id)
|
|
@@ -263,8 +262,8 @@ class WwwServer:
|
|
|
263
262
|
if not path.exists():
|
|
264
263
|
return web.HTTPNotFound(reason='no such file in path')
|
|
265
264
|
return web.FileResponse(path)
|
|
266
|
-
logging.warning(f"path not configured {request.match_info['path']}")
|
|
267
|
-
return web.HTTPForbidden(reason='path not permitted')
|
|
265
|
+
# logging.warning(f"path not configured {request.match_info['path']}")
|
|
266
|
+
# return web.HTTPForbidden(reason='path not permitted')
|
|
268
267
|
|
|
269
268
|
async def websocket_handler(self, request: web.Request):
|
|
270
269
|
"""Wait for connections. Create a new one each time."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|