pymscada 0.1.0a6__py3-none-any.whl → 0.1.1a2__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.
Potentially problematic release.
This version of pymscada might be problematic. Click here for more details.
- pymscada/bus_client.py +15 -11
- pymscada/bus_server.py +16 -10
- pymscada/console.py +213 -16
- pymscada/demo/files.yaml +1 -0
- pymscada/demo/opnotes.yaml +5 -0
- pymscada/demo/pymscada-opnotes.service +16 -0
- pymscada/demo/wwwserver.yaml +2 -5
- pymscada/files.py +47 -28
- pymscada/history.py +18 -17
- pymscada/iodrivers/logix_client.py +1 -1
- pymscada/iodrivers/modbus_client.py +2 -1
- pymscada/iodrivers/modbus_map.py +4 -1
- pymscada/iodrivers/modbus_server.py +2 -1
- pymscada/iodrivers/ping_client.py +1 -1
- pymscada/iodrivers/snmp_client.py +3 -3
- pymscada/iodrivers/snmp_map.py +1 -1
- pymscada/main.py +233 -115
- pymscada/opnotes.py +108 -0
- pymscada/protocol_constants.py +11 -8
- pymscada/tag.py +22 -0
- pymscada/www_server.py +47 -52
- {pymscada-0.1.0a6.dist-info → pymscada-0.1.1a2.dist-info}/METADATA +2 -2
- {pymscada-0.1.0a6.dist-info → pymscada-0.1.1a2.dist-info}/RECORD +26 -23
- {pymscada-0.1.0a6.dist-info → pymscada-0.1.1a2.dist-info}/WHEEL +1 -1
- {pymscada-0.1.0a6.dist-info → pymscada-0.1.1a2.dist-info}/entry_points.txt +0 -0
- {pymscada-0.1.0a6.dist-info → pymscada-0.1.1a2.dist-info}/licenses/LICENSE +0 -0
pymscada/www_server.py
CHANGED
|
@@ -7,30 +7,20 @@ from struct import pack, unpack_from
|
|
|
7
7
|
import time
|
|
8
8
|
from pymscada.bus_client import BusClient
|
|
9
9
|
import pymscada.protocol_constants as pc
|
|
10
|
-
from pymscada.tag import Tag, TYPES
|
|
10
|
+
from pymscada.tag import Tag, tag_for_web, TYPES
|
|
11
11
|
from pymscada_html import get_html_file
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
tag
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
tag['type'] = 'float'
|
|
25
|
-
else:
|
|
26
|
-
if tag['type'] not in TYPES:
|
|
27
|
-
tag['type'] = 'str'
|
|
28
|
-
if tag['type'] == 'int':
|
|
29
|
-
tag['dp'] = 0
|
|
30
|
-
elif tag['type'] == 'float' and 'dp' not in tag:
|
|
31
|
-
tag['dp'] = 2
|
|
32
|
-
elif tag['type'] == 'str' and 'dp' in tag:
|
|
33
|
-
del tag['dp']
|
|
14
|
+
class Interface():
|
|
15
|
+
"""Provide an interface between web client rta and the action."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, tagname: str) -> None:
|
|
18
|
+
"""Return path tagname for rta requests."""
|
|
19
|
+
self.tag = Tag(tagname, dict)
|
|
20
|
+
|
|
21
|
+
def ask(self, message):
|
|
22
|
+
"""Process the message."""
|
|
23
|
+
logging.warning(message)
|
|
34
24
|
|
|
35
25
|
|
|
36
26
|
class WSHandler():
|
|
@@ -44,7 +34,7 @@ class WSHandler():
|
|
|
44
34
|
ids = set(range(1, 100))
|
|
45
35
|
|
|
46
36
|
def __init__(self, ws: web.WebSocketResponse, pages: dict,
|
|
47
|
-
tag_info: dict[str, Tag],
|
|
37
|
+
tag_info: dict[str, Tag], do_rta, interface: Interface):
|
|
48
38
|
"""Create callbacks to monitor tag values."""
|
|
49
39
|
self.ws = ws
|
|
50
40
|
self.pages = pages
|
|
@@ -52,13 +42,14 @@ class WSHandler():
|
|
|
52
42
|
self.tag_by_id: dict[int, Tag] = {}
|
|
53
43
|
self.tag_by_name: dict[str, Tag] = {}
|
|
54
44
|
self.queue = asyncio.Queue()
|
|
55
|
-
self.
|
|
56
|
-
self.
|
|
57
|
-
logging.info(f'
|
|
45
|
+
self.do_rta = do_rta
|
|
46
|
+
self.rta_id = self.ids.pop()
|
|
47
|
+
logging.info(f'websocket id {self.rta_id}')
|
|
48
|
+
self.interface = interface
|
|
58
49
|
|
|
59
50
|
def __del__(self):
|
|
60
51
|
"""Depends on garbage collector. Is OK."""
|
|
61
|
-
self.ids.add(self.
|
|
52
|
+
self.ids.add(self.rta_id)
|
|
62
53
|
|
|
63
54
|
async def send_queue(self):
|
|
64
55
|
"""Run forever, write from queue."""
|
|
@@ -70,7 +61,7 @@ class WSHandler():
|
|
|
70
61
|
else:
|
|
71
62
|
await self.ws.send_json(message)
|
|
72
63
|
except asyncio.CancelledError:
|
|
73
|
-
logging.warn(f'{self.
|
|
64
|
+
logging.warn(f'{self.rta_id}: send queue error, close '
|
|
74
65
|
f'{self.ws.exception()}')
|
|
75
66
|
return
|
|
76
67
|
|
|
@@ -91,7 +82,7 @@ class WSHandler():
|
|
|
91
82
|
self.queue.put_nowait((True, pack(
|
|
92
83
|
'!HHQq', # Network big-endian
|
|
93
84
|
tag.id, # Uint16
|
|
94
|
-
pc.TYPE_INT,
|
|
85
|
+
pc.TYPE_INT, # Uint16
|
|
95
86
|
tag.time_us, # Uint64
|
|
96
87
|
tag.value # Int64
|
|
97
88
|
)))
|
|
@@ -99,7 +90,7 @@ class WSHandler():
|
|
|
99
90
|
self.queue.put_nowait((True, pack(
|
|
100
91
|
'!HHQd', # Network big-endian
|
|
101
92
|
tag.id, # Uint16
|
|
102
|
-
pc.TYPE_FLOAT,
|
|
93
|
+
pc.TYPE_FLOAT, # Uint16
|
|
103
94
|
tag.time_us, # Uint64
|
|
104
95
|
tag.value # Float64
|
|
105
96
|
)))
|
|
@@ -113,17 +104,17 @@ class WSHandler():
|
|
|
113
104
|
asbytes # Char as needed
|
|
114
105
|
)))
|
|
115
106
|
elif tag.type == bytes:
|
|
116
|
-
|
|
117
|
-
if
|
|
107
|
+
rta_id = unpack_from('>H', tag.value)[0]
|
|
108
|
+
if rta_id in [0, self.rta_id]:
|
|
118
109
|
self.queue.put_nowait((True, pack(
|
|
119
110
|
f'!HHQ{len(tag.value)}s', # Network big-endian
|
|
120
111
|
tag.id, # Uint16
|
|
121
|
-
pc.TYPE_BYTES,
|
|
112
|
+
pc.TYPE_BYTES, # Uint16
|
|
122
113
|
tag.time_us, # Uint64
|
|
123
114
|
tag.value # Char as needed
|
|
124
115
|
)))
|
|
125
116
|
else:
|
|
126
|
-
logging.info(f'{self.
|
|
117
|
+
logging.info(f'{self.rta_id}: {tag.name} bytes mismatch id')
|
|
127
118
|
elif tag.type in [dict, list]:
|
|
128
119
|
self.queue.put_nowait((False, {
|
|
129
120
|
'type': 'tag',
|
|
@@ -136,7 +127,7 @@ class WSHandler():
|
|
|
136
127
|
|
|
137
128
|
def notify_id(self, tag: Tag):
|
|
138
129
|
"""Must be done here."""
|
|
139
|
-
logging.info(f'{self.
|
|
130
|
+
logging.info(f'{self.rta_id}: send id to webclient for {tag.name}')
|
|
140
131
|
self.tag_info[tag.name]['id'] = tag.id
|
|
141
132
|
self.tag_by_id[tag.id] = tag
|
|
142
133
|
self.tag_by_name[tag.name] = tag
|
|
@@ -151,7 +142,7 @@ class WSHandler():
|
|
|
151
142
|
tag = self.tag_by_name[tagname]
|
|
152
143
|
except KeyError:
|
|
153
144
|
if tagname not in self.tag_info:
|
|
154
|
-
logging.warning(f'{self.
|
|
145
|
+
logging.warning(f'{self.rta_id}: no {tagname} in tag_info')
|
|
155
146
|
return
|
|
156
147
|
tag = Tag(tagname, TYPES[self.tag_info[tagname]['type']])
|
|
157
148
|
if tag.id is None:
|
|
@@ -168,7 +159,7 @@ class WSHandler():
|
|
|
168
159
|
(False, {'type': 'pages', 'payload': self.pages}))
|
|
169
160
|
async for msg in self.ws:
|
|
170
161
|
if msg.type == WSMsgType.TEXT:
|
|
171
|
-
logging.info(f'{self.
|
|
162
|
+
logging.info(f'{self.rta_id}: websocket recv {msg.json()}')
|
|
172
163
|
command = msg.json()
|
|
173
164
|
action = command['type']
|
|
174
165
|
tagname = command['tagname']
|
|
@@ -177,23 +168,25 @@ class WSHandler():
|
|
|
177
168
|
bus = None
|
|
178
169
|
if action == 'set': # pc.CMD_SET
|
|
179
170
|
self.tag_by_name[tagname].value = value, time_us, bus
|
|
180
|
-
elif action == '
|
|
171
|
+
elif action == 'rta': # pc.CMD_RTA
|
|
181
172
|
if 'File' in value:
|
|
182
173
|
file = await anext(self.ws)
|
|
183
174
|
value['_file_data'] = file.data
|
|
184
|
-
value['
|
|
185
|
-
self.
|
|
175
|
+
value['__rta_id__'] = self.rta_id
|
|
176
|
+
self.do_rta(tagname, value)
|
|
177
|
+
elif action == 'request_to_author':
|
|
178
|
+
self.interface.ask(command)
|
|
186
179
|
elif action == 'sub': # pc.CMD_SUB
|
|
187
180
|
self.do_sub(tagname)
|
|
188
181
|
elif action == 'get': # pc.CMD_GET
|
|
189
|
-
logging.warning(f'{self.
|
|
182
|
+
logging.warning(f'{self.rta_id}: CMD_GET not implemented.')
|
|
190
183
|
elif action == 'unsub': # pc.CMD_UNSUB
|
|
191
|
-
logging.warning(f'{self.
|
|
184
|
+
logging.warning(f'{self.rta_id}: CMD_UNSUB not '
|
|
192
185
|
'implemented.')
|
|
193
186
|
elif msg.type == WSMsgType.BINARY:
|
|
194
187
|
logging.info(f'{msg.data}')
|
|
195
188
|
elif msg.type == WSMsgType.ERROR:
|
|
196
|
-
logging.warn(f'{self.
|
|
189
|
+
logging.warn(f'{self.rta_id}: ws closing error '
|
|
197
190
|
f'{self.ws.exception()}')
|
|
198
191
|
send_queue.cancel()
|
|
199
192
|
for tag in self.tag_by_id.values():
|
|
@@ -206,7 +199,8 @@ class WwwServer:
|
|
|
206
199
|
|
|
207
200
|
def __init__(self, bus_ip: str = '127.0.0.1', bus_port: int = 1324,
|
|
208
201
|
ip: str = '127.0.0.1', port: int = 8324, get_path: str = None,
|
|
209
|
-
tag_info: dict = {}, pages: dict = {},
|
|
202
|
+
tag_info: dict = {}, pages: dict = {}, serve_path: str = None,
|
|
203
|
+
www_tag: str = '__wwwserver__'
|
|
210
204
|
) -> None:
|
|
211
205
|
"""
|
|
212
206
|
Connect to bus on bus_ip:bus_port, serve on ip:port for webclient.
|
|
@@ -217,15 +211,17 @@ class WwwServer:
|
|
|
217
211
|
|
|
218
212
|
Event loop must be running.
|
|
219
213
|
"""
|
|
220
|
-
self.busclient = BusClient(bus_ip, bus_port, tag_info
|
|
214
|
+
self.busclient = BusClient(bus_ip, bus_port, tag_info,
|
|
215
|
+
module='WWW Server')
|
|
221
216
|
self.ip = ip
|
|
222
217
|
self.port = port
|
|
223
218
|
self.get_path = get_path
|
|
219
|
+
self.serve_path = Path(serve_path)
|
|
224
220
|
for tagname, tag in tag_info.items():
|
|
225
221
|
tag_for_web(tagname, tag)
|
|
226
222
|
self.tag_info = tag_info
|
|
227
223
|
self.pages = pages
|
|
228
|
-
self.
|
|
224
|
+
self.interface = Interface(www_tag)
|
|
229
225
|
|
|
230
226
|
async def redirect_handler(self, _request: web.Request):
|
|
231
227
|
"""Point an empty request to the index."""
|
|
@@ -247,13 +243,12 @@ class WwwServer:
|
|
|
247
243
|
async def path_handler(self, request: web.Request):
|
|
248
244
|
"""Plain files."""
|
|
249
245
|
logging.info(f"path {request.match_info['path']}")
|
|
250
|
-
path =
|
|
246
|
+
path = self.serve_path.joinpath(request.match_info['path'])
|
|
251
247
|
if path.is_dir():
|
|
252
248
|
return web.HTTPForbidden(reason='folder not permitted')
|
|
253
|
-
if
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
return web.FileResponse(path)
|
|
249
|
+
if not path.exists():
|
|
250
|
+
return web.HTTPNotFound(reason='no such file in path')
|
|
251
|
+
return web.FileResponse(path)
|
|
257
252
|
logging.warning(f"path not configured {request.match_info['path']}")
|
|
258
253
|
return web.HTTPForbidden(reason='path not permitted')
|
|
259
254
|
|
|
@@ -263,8 +258,8 @@ class WwwServer:
|
|
|
263
258
|
logging.info(f"WS from {peer}")
|
|
264
259
|
ws = web.WebSocketResponse(max_msg_size=0) # disables max message size
|
|
265
260
|
await ws.prepare(request)
|
|
266
|
-
await WSHandler(ws, self.pages, self.tag_info, self.busclient.
|
|
267
|
-
).connection_active()
|
|
261
|
+
await WSHandler(ws, self.pages, self.tag_info, self.busclient.rta,
|
|
262
|
+
self.interface).connection_active()
|
|
268
263
|
await ws.close()
|
|
269
264
|
logging.info(f"WS closed {peer}")
|
|
270
265
|
return ws
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pymscada
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1a2
|
|
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
|
|
@@ -13,7 +13,7 @@ Classifier: Development Status :: 1 - Planning
|
|
|
13
13
|
Requires-Python: >=3.9
|
|
14
14
|
Requires-Dist: PyYAML>=6.0.1
|
|
15
15
|
Requires-Dist: aiohttp>=3.8.5
|
|
16
|
-
Requires-Dist: pymscada-html==0.1.
|
|
16
|
+
Requires-Dist: pymscada-html==0.1.0
|
|
17
17
|
Requires-Dist: cerberus>=1.3.5
|
|
18
18
|
Requires-Dist: pycomm3>=1.2.14
|
|
19
19
|
Requires-Dist: pysnmplib>=5.0.24
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
pymscada-0.1.
|
|
2
|
-
pymscada-0.1.
|
|
3
|
-
pymscada-0.1.
|
|
4
|
-
pymscada-0.1.
|
|
1
|
+
pymscada-0.1.1a2.dist-info/METADATA,sha256=dOIdGvZZT4QA4yp4O2v9oYVUNmyDSJb9uOkfq3MkSpw,3214
|
|
2
|
+
pymscada-0.1.1a2.dist-info/WHEEL,sha256=vnE8JVcI2Wz7GRKorsPArnBdnW2SWKWGow5gu5tHlRU,90
|
|
3
|
+
pymscada-0.1.1a2.dist-info/entry_points.txt,sha256=AcZZ7HFj8k1ztP6ge-5bdRinYF8glW2s6lFEQG3esN4,57
|
|
4
|
+
pymscada-0.1.1a2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
5
5
|
pymscada/__init__.py,sha256=D_4aEDWkW6xMVQane3CbehBKPxT3FCaDY_QpFwglCe8,653
|
|
6
6
|
pymscada/__main__.py,sha256=WcyVlrYOoDdktJhOoyubTOycMwpayksFdxwelRU5xpQ,272
|
|
7
|
-
pymscada/bus_client.py,sha256=
|
|
8
|
-
pymscada/bus_server.py,sha256
|
|
7
|
+
pymscada/bus_client.py,sha256=PncKysSCWhcpCPTVq9kkfb4NOjds7bZBwH7jaLHX3nI,8884
|
|
8
|
+
pymscada/bus_server.py,sha256=3ZLT2QFfKMndrTVd1TRWk15rYtaXnW1Ls2dlZe5nsyM,11544
|
|
9
9
|
pymscada/checkout.py,sha256=ISXhwRJbZBRu0cMeVHwgHzMgk9YslhnPtjs7-0lgjRo,3351
|
|
10
10
|
pymscada/config.py,sha256=vwGxieaJBYXiHNQEOYVDFaPuGmnUlCnbNm_W9bugKlc,1851
|
|
11
|
-
pymscada/console.py,sha256=
|
|
11
|
+
pymscada/console.py,sha256=oNsZjGlu16B7_2jCIl8Sw6bVfmJeoDdN-JcmA3LyzUw,8011
|
|
12
12
|
pymscada/demo/README.md,sha256=iNcVbCTkq-d4agLV-979lNRaqf_hbJCn3OFzY-6qfU8,880
|
|
13
13
|
pymscada/demo/__init__.py,sha256=WsDDgkWnZBJbt2-cJCdc2NvRAv_T4a7WOC1Q0k_l0gI,29
|
|
14
14
|
pymscada/demo/bus.yaml,sha256=zde5JDo2Yv5s7NvJ569gAEoTDvsvgBwRPxfrYhsxj3w,26
|
|
15
|
-
pymscada/demo/files.yaml,sha256=
|
|
15
|
+
pymscada/demo/files.yaml,sha256=9jhZ7H5dSUz0oKXUiIB9dVYF8J8nwgt4QaFbvhKRPh0,197
|
|
16
16
|
pymscada/demo/history.yaml,sha256=mn_Xf4h_bK6vwZVQ0Iz9BzJpwWok2gEgSKbDgEM8AOQ,46
|
|
17
17
|
pymscada/demo/logixclient.yaml,sha256=G_NlJhBYwT1a9ceHDgO6fCNKFmBM2pVO_t9Xa1NqlRY,912
|
|
18
18
|
pymscada/demo/modbus_plc.py,sha256=3zZHHbyrdxyryEHBeNIw-fpcDGcS1MaJiqEwQDr6zWI,2397
|
|
19
19
|
pymscada/demo/modbusclient.yaml,sha256=geeCsUJZkkEj7jjXR_Yk6R5zA5Ta9IczrHsARz7ZgXY,1099
|
|
20
20
|
pymscada/demo/modbusserver.yaml,sha256=67_mED6jXgtnzlDIky9Cg4j-nXur06iz9ve3JUwSyG8,1133
|
|
21
|
+
pymscada/demo/opnotes.yaml,sha256=1uxAdimPiWlckkRqszh-I3NEi47BNtGraBGLgq8C4L4,111
|
|
21
22
|
pymscada/demo/ping.yaml,sha256=r_VBGTLU5r4cZi9bIGL3M4eNw70KnoBptOUoNrSbnFY,210
|
|
22
23
|
pymscada/demo/pymscada-bus.service,sha256=rRTFwHaS8XWd9YAIB3cET4QvASaIO9emmxFiUAbl14g,257
|
|
23
24
|
pymscada/demo/pymscada-demo-modbus_plc.service,sha256=jmgk_peoxwKVXe-LbyK2VluMS1JMmoTud4JZHi9Tgec,316
|
|
@@ -28,33 +29,35 @@ pymscada/demo/pymscada-io-modbusclient.service,sha256=4tenKcrfRi0iMdv8-k2gtMQA4O
|
|
|
28
29
|
pymscada/demo/pymscada-io-modbusserver.service,sha256=FqCMD3EJKoiq6EbYnoijRLX5UeUWbZrNzDs50eQj7iE,344
|
|
29
30
|
pymscada/demo/pymscada-io-ping.service,sha256=d1n32srVKGd8qo8JWeBYEEznCRZWRWaBQLOYzdqEXWg,327
|
|
30
31
|
pymscada/demo/pymscada-io-snmpclient.service,sha256=wrA2kDR3bgO30lP_lNJrIsVXNQiXmWKnphoqUj3QTRI,339
|
|
32
|
+
pymscada/demo/pymscada-opnotes.service,sha256=5CyKOBlToqyjbyeBE6A68IEov7Y0sPdC_uC1TEJDPRw,350
|
|
31
33
|
pymscada/demo/pymscada-wwwserver.service,sha256=uDnqzfvAdAnTrqOCqDm1PN7SmeMSuOdmAhorHPJdEVI,366
|
|
32
34
|
pymscada/demo/snmpclient.yaml,sha256=z8iACrFvMftYUtqGrRjPZYZTpn7aOXI-Kp675NAM8cU,2013
|
|
33
35
|
pymscada/demo/tags.yaml,sha256=GH90X3QRBANUhvd2E9OuyIoiZD25OBihHHlDBw1uzlw,4231
|
|
34
|
-
pymscada/demo/wwwserver.yaml,sha256=
|
|
35
|
-
pymscada/files.py,sha256=
|
|
36
|
-
pymscada/history.py,sha256=
|
|
36
|
+
pymscada/demo/wwwserver.yaml,sha256=vkRbnZLCf3HXMXmgG_3q0aSShEVzxpGCJLJeWa9REmM,12543
|
|
37
|
+
pymscada/files.py,sha256=FSEvFs6gNgErx_B7mtWkt6EsGNSc-TlxEbDW59NxIZs,2439
|
|
38
|
+
pymscada/history.py,sha256=G079gHfzasmGtI5ANS8MdETD4bdZg5vHE_yTKk7atHw,9504
|
|
37
39
|
pymscada/iodrivers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
-
pymscada/iodrivers/logix_client.py,sha256=
|
|
40
|
+
pymscada/iodrivers/logix_client.py,sha256=eqmiYLYUBHbr7wTljomGIZVNvXe-5WleGKfzwcHXO8w,2829
|
|
39
41
|
pymscada/iodrivers/logix_map.py,sha256=ljjBAMJcw199v1V5u0Yfl38U6zbZzba5mdY4I3ZvdIM,5401
|
|
40
|
-
pymscada/iodrivers/modbus_client.py,sha256=
|
|
41
|
-
pymscada/iodrivers/modbus_map.py,sha256=
|
|
42
|
-
pymscada/iodrivers/modbus_server.py,sha256=
|
|
43
|
-
pymscada/iodrivers/ping_client.py,sha256=
|
|
42
|
+
pymscada/iodrivers/modbus_client.py,sha256=DIGrEPz_Bwwj9CEeog5fQqiAu1UMV7xVL6KxlKgXNPs,9592
|
|
43
|
+
pymscada/iodrivers/modbus_map.py,sha256=af2J3CGSeYQ4mSy8rNsERp9z7fRgRUYk3it5Mrc_IQA,7255
|
|
44
|
+
pymscada/iodrivers/modbus_server.py,sha256=VqvjOJ4-LOVaD1jOK22raXhrCshJEaWlMxLvn5xMnFc,6570
|
|
45
|
+
pymscada/iodrivers/ping_client.py,sha256=UOQgUfoIcYqy5VvKyJ8XGHHjeSRTfjmrhyWEojhIZQk,4188
|
|
44
46
|
pymscada/iodrivers/ping_map.py,sha256=EbOteqfEYKIOMqPymROJ4now2If-ekEj6jnM5hthoSA,1403
|
|
45
|
-
pymscada/iodrivers/snmp_client.py,sha256=
|
|
46
|
-
pymscada/iodrivers/snmp_map.py,sha256=
|
|
47
|
-
pymscada/main.py,sha256=
|
|
47
|
+
pymscada/iodrivers/snmp_client.py,sha256=GykrHqKhT-TRIEowLlt90pNQrbm4SXeMBFscflSHtCw,2623
|
|
48
|
+
pymscada/iodrivers/snmp_map.py,sha256=sDdIR5ZPAETpozDfBt_XQiZ-f4t99UCPlzj7BxFxQyM,2369
|
|
49
|
+
pymscada/main.py,sha256=ifu6DuQcI6QpK8w28QAKpbf8gWiaG-zzPoRVorxjFpY,8097
|
|
48
50
|
pymscada/misc.py,sha256=0Cj6OFhQonyhyk9x0BG5MiS-6EPk_w6zvavt8o_Hlf0,622
|
|
51
|
+
pymscada/opnotes.py,sha256=jo9E0if2dcv1ziGjrLqyzaf-eZvBihtLizP9GmWt5ok,4377
|
|
49
52
|
pymscada/pdf/__init__.py,sha256=WsDDgkWnZBJbt2-cJCdc2NvRAv_T4a7WOC1Q0k_l0gI,29
|
|
50
53
|
pymscada/pdf/one.pdf,sha256=eoJ45DrAjVZrwmwdA_EAz1fwmT44eRnt_tkc2pmMrKY,1488
|
|
51
54
|
pymscada/pdf/two.pdf,sha256=TAuW5yLU1_wfmTH_I5ezHwY0pxhCVuZh3ixu0kwmJwE,1516
|
|
52
55
|
pymscada/periodic.py,sha256=MLlL93VLvFqBBgjO1Us1t0aLHTZ5BFdW0B__G02T1nQ,1235
|
|
53
|
-
pymscada/protocol_constants.py,sha256=
|
|
56
|
+
pymscada/protocol_constants.py,sha256=scqu_vecB4U8WxbFbn3mdIhKuZWgNO7fyd-RMP5O_14,2094
|
|
54
57
|
pymscada/samplers.py,sha256=t0IscgsCm5YByioOZ6aOKMO_guDFS_wxnJSiOGKI4Nw,2583
|
|
55
|
-
pymscada/tag.py,sha256=
|
|
58
|
+
pymscada/tag.py,sha256=E9xQkf3b0trDRshhsaz_2baa4CAvTCgcZQXqWd3oHEM,10095
|
|
56
59
|
pymscada/tools/snmp_client2.py,sha256=pdn5dYyEv4q-ubA0zQ8X-3tQDYxGC7f7Xexa7QPaL40,1675
|
|
57
60
|
pymscada/tools/walk.py,sha256=OgpprUbKLhEWMvJGfU1ckUt_PFEpwZVOD8HucCgzmOc,1625
|
|
58
61
|
pymscada/validate.py,sha256=VPpAVEwfgori5OREEwWlbPoPxz5Tfqr6dw-O5pINHyI,13125
|
|
59
|
-
pymscada/www_server.py,sha256=
|
|
60
|
-
pymscada-0.1.
|
|
62
|
+
pymscada/www_server.py,sha256=ToTddnrnmcLdL2JDviBZ1nflw8wi8bBIk8uSxE6jvWk,11465
|
|
63
|
+
pymscada-0.1.1a2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|