pymscada 0.2.0rc8__py3-none-any.whl → 0.2.2__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.

@@ -0,0 +1,147 @@
1
+ """Extract history data to CSV files.
2
+
3
+ This tool lists available history tags and extracts their values to CSV files.
4
+ It handles repeating time values as shown in the test_history.py script.
5
+ """
6
+ import argparse
7
+ import csv
8
+ import logging
9
+ import sys
10
+ from pathlib import Path
11
+ from struct import unpack_from
12
+ from typing import Any, Optional
13
+
14
+ from pymscada.config import Config
15
+ from pymscada.history import TagHistory, ITEM_SIZE
16
+
17
+
18
+ def list_history_tags(config_path: str) -> list[str]:
19
+ """List all available history tags from the config path."""
20
+ config = Config(config_path)
21
+ history_path = Path(config['path'])
22
+ if not history_path.exists():
23
+ logging.error(f'History path {history_path} does not exist')
24
+ return []
25
+ tag_names = set()
26
+ for file_path in history_path.glob('*_*.dat'):
27
+ parts = file_path.stem.split('_')
28
+ if len(parts) >= 2 and parts[-1].isdigit():
29
+ tag_name = '_'.join(parts[:-1])
30
+ tag_names.add(tag_name)
31
+ return list(tag_names)
32
+
33
+
34
+ def get_tag_type(tag_name: str, tags_config_path: str) -> Optional[type]:
35
+ """Get the type of a tag from the tags configuration."""
36
+ try:
37
+ tags_config = Config(tags_config_path)
38
+ if tag_name in tags_config:
39
+ tag_info = tags_config[tag_name]
40
+ if 'type' in tag_info:
41
+ tag_type = tag_info['type']
42
+ if tag_type == 'int':
43
+ return int
44
+ elif tag_type == 'float':
45
+ return float
46
+ else:
47
+ return str
48
+ else:
49
+ return float # Default to float
50
+ except Exception as e:
51
+ logging.warning(f'Could not determine type for {tag_name}: {e}')
52
+
53
+
54
+ def extract_tag_history(
55
+ tag_name: str,
56
+ config_path: str,
57
+ tags_config_path: str,
58
+ output_file: Optional[str] = None
59
+ ) -> list[tuple[int, Any]]:
60
+ """Extract history data for a specific tag."""
61
+ config = Config(config_path)
62
+ history_path = Path(config['path'])
63
+ if not history_path.exists():
64
+ logging.error(f'History path {history_path} does not exist')
65
+ return []
66
+ tag_type = get_tag_type(tag_name, tags_config_path)
67
+ if tag_type is None:
68
+ logging.error(f'Could not determine type for tag {tag_name}')
69
+ return []
70
+ tag_history = TagHistory(tag_name, tag_type, str(history_path))
71
+ data_bytes = tag_history.read_bytes()
72
+ records = []
73
+ for i in range(0, len(data_bytes), ITEM_SIZE):
74
+ if i + ITEM_SIZE <= len(data_bytes):
75
+ time_us, value = unpack_from(tag_history.packstr, data_bytes, offset=i)
76
+ records.append((time_us // 1000000, value))
77
+ if output_file:
78
+ with open(output_file, 'w', newline='') as csvfile:
79
+ writer = csv.writer(csvfile)
80
+ writer.writerow(['timestamp_us', 'value'])
81
+ prev_time = 0
82
+ buffer = []
83
+ last_buffer = []
84
+ for time_us, value in records:
85
+ if time_us < prev_time:
86
+ if buffer != last_buffer:
87
+ writer.writerow(buffer)
88
+ last_buffer = buffer.copy()
89
+ buffer = [time_us, value]
90
+ else:
91
+ buffer.extend((time_us, value))
92
+ prev_time = time_us
93
+ if buffer:
94
+ writer.writerow(buffer)
95
+ logging.info(f'Extracted {len(records)} records to {output_file}')
96
+ return records
97
+
98
+
99
+ def main():
100
+ """Main entry point."""
101
+ parser = argparse.ArgumentParser(
102
+ description='Extract history data to CSV files',
103
+ epilog='Example: python get_history.py --config history.yaml --tags tags.yaml --list'
104
+ )
105
+ parser.add_argument('--config', required=True,
106
+ help='History configuration file')
107
+ parser.add_argument('--tags', required=True,
108
+ help='Tags configuration file')
109
+ parser.add_argument('--list', action='store_true',
110
+ help='List available history tags')
111
+ parser.add_argument('--tag',
112
+ help='Extract specific tag to CSV')
113
+ parser.add_argument('--output',
114
+ help='Output CSV file (default: <tag>.csv)')
115
+ parser.add_argument('--verbose', action='store_true',
116
+ help='Verbose logging')
117
+ args = parser.parse_args()
118
+ level = logging.INFO if args.verbose else logging.WARNING
119
+ logging.basicConfig(level=level, format='%(levelname)s: %(message)s')
120
+ if args.list:
121
+ tags = list_history_tags(args.config)
122
+ if tags:
123
+ print('Available history tags:')
124
+ for tag in tags:
125
+ print(f' {tag}')
126
+ else:
127
+ print('No history tags found')
128
+ sys.exit(1)
129
+ elif args.tag:
130
+ if not args.output:
131
+ args.output = f'{args.tag}.csv'
132
+ records = extract_tag_history(args.tag, args.config, args.tags,
133
+ args.output)
134
+ if records:
135
+ print(f'Extracted {len(records)} records for tag "{args.tag}"')
136
+ print(f'Times: {records[0][0]} to {records[-1][0]}')
137
+ print(f'Output file: {args.output}')
138
+ else:
139
+ print(f'No data found for tag "{args.tag}"')
140
+ sys.exit(1)
141
+ else:
142
+ parser.print_help()
143
+ sys.exit(1)
144
+
145
+
146
+ if __name__ == '__main__':
147
+ main()
pymscada/www_server.py CHANGED
@@ -151,7 +151,7 @@ class WSHandler():
151
151
  }
152
152
  }))
153
153
  elif tag.type is dict:
154
- if '__rta_id__' in tag.value:
154
+ if '__rta_id__' in tag.value and tag.value['__rta_id__'] != 0:
155
155
  if tag.value['__rta_id__'] != self.rta_id:
156
156
  return
157
157
  self.queue.put_nowait((False, {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymscada
3
- Version: 0.2.0rc8
3
+ Version: 0.2.2
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
@@ -17,7 +17,7 @@ Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
18
  Requires-Dist: PyYAML>=6.0.1
19
19
  Requires-Dist: aiohttp>=3.8.5
20
- Requires-Dist: pymscada-html==0.2.0rc4
20
+ Requires-Dist: pymscada-html==0.2.0
21
21
  Requires-Dist: cerberus>=1.3.5
22
22
  Requires-Dist: pycomm3>=1.2.14
23
23
  Requires-Dist: pysnmplib>=5.0.24
@@ -1,41 +1,42 @@
1
- pymscada/__init__.py,sha256=NV_cIIwe66Ugp8ns426rtfJIIyskWbqwImD9p_5p0bQ,739
1
+ pymscada/__init__.py,sha256=dtn2kaj1q9cYaldrian16dWbvl17mus8-nz2WnWfdyc,882
2
2
  pymscada/__main__.py,sha256=WcyVlrYOoDdktJhOoyubTOycMwpayksFdxwelRU5xpQ,272
3
- pymscada/alarms.py,sha256=eo-9-DSwV825ihuHApaYkADPpLouKbNLHyh0z4bdPoU,12936
3
+ pymscada/alarms.py,sha256=W-SsltXGZn-uZT-iFdOlLVdlp2j3SkhJYlQcueWoEQs,13055
4
4
  pymscada/bus_client.py,sha256=eRGvHQ4sFM_n3rKvKDWZQJPQJqvKMWvxbH3MjtT2WBo,9131
5
5
  pymscada/bus_server.py,sha256=k7ht2SAr24Oab0hBOPeW4NRDF_RK-F46iE0cMzh7K4w,12323
6
- pymscada/callout.py,sha256=o_GCB-3IFG-QIcHfrmW-N9CTTlsIu9nMLC-F1jQu1hQ,7274
6
+ pymscada/callout.py,sha256=hHSkUE0pJjlyexJI52H_lbZjfud4QFzbIdlNyv6VtWs,9848
7
7
  pymscada/checkout.py,sha256=RLuCMTEuUI7pp1hIRAUPbo8xYFta8TjArelx0SD4gOY,3897
8
- pymscada/config.py,sha256=vwGxieaJBYXiHNQEOYVDFaPuGmnUlCnbNm_W9bugKlc,1851
8
+ pymscada/config.py,sha256=yRENJPGDPLNPOn4zSCE576UO0QWx2Q0VDsaLDEehRmU,2539
9
9
  pymscada/console.py,sha256=EEsJLCvn8AFimN8qGNilX0ks6t3OFcGW5nw6OVAXfac,8850
10
10
  pymscada/files.py,sha256=iouEOPfEkVI0Qbbf1p-L324Y04zSrynVypLW0-1MThA,2499
11
- pymscada/history.py,sha256=7UEOeMnlSMv0LoWTqLWx7QwOW1FZZ4wAvzH6v6b0_vI,11592
11
+ pymscada/history.py,sha256=q5hKNTcvLLl_o4FWHily-d1bKZq6j_kqtuONzRDPZCQ,11563
12
12
  pymscada/main.py,sha256=d6EnK4-tEcvM5AqMHYhvqlnSh-E_wd0Tuxk-kXYSiDw,1854
13
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
14
+ pymscada/module_config.py,sha256=QfLI6aOB1H5Xo6P_qaaLUKdOzXSfNBXtdHo1dFelCkA,9999
15
+ pymscada/opnotes.py,sha256=cDqsbsT5JTTxQWPlai9EvXgJJwi1oex14URGqdtmDq8,8066
16
16
  pymscada/periodic.py,sha256=MLlL93VLvFqBBgjO1Us1t0aLHTZ5BFdW0B__G02T1nQ,1235
17
17
  pymscada/protocol_constants.py,sha256=lPJ4JEgFJ_puJjTym83EJIOw3UTUFbuFMwg3ohyUAGY,2414
18
18
  pymscada/samplers.py,sha256=t0IscgsCm5YByioOZ6aOKMO_guDFS_wxnJSiOGKI4Nw,2583
19
19
  pymscada/tag.py,sha256=hTRxogw8BXAi1OJpM1Lhx4KKMqZ53y7D5KcCycO7fRQ,9471
20
- pymscada/validate.py,sha256=fPMlP6RscYuTIgdEJjJ0ZZI0OyVSat1lpqg254wqpdE,13140
21
- pymscada/www_server.py,sha256=NfvX9jbVWY2qxWM6TfWUcwsCY7lR-dkty1nCOXyoWTA,13747
20
+ pymscada/www_server.py,sha256=WeLGRhseXVTns5PKlA0w--byatxpEQ4PcE60qMghLuM,13780
22
21
  pymscada/demo/README.md,sha256=iNcVbCTkq-d4agLV-979lNRaqf_hbJCn3OFzY-6qfU8,880
23
22
  pymscada/demo/__init__.py,sha256=WsDDgkWnZBJbt2-cJCdc2NvRAv_T4a7WOC1Q0k_l0gI,29
24
23
  pymscada/demo/accuweather.yaml,sha256=Fk4rV0S8jCau0173QCzKW8TdUbc4crYVi0aD8fPLNgU,322
25
24
  pymscada/demo/alarms.yaml,sha256=Ea8tLZ0aEiyKM_m5MN1TF6xS-lI5ReXiz2oUPO8GvmQ,110
26
25
  pymscada/demo/bus.yaml,sha256=zde5JDo2Yv5s7NvJ569gAEoTDvsvgBwRPxfrYhsxj3w,26
27
- pymscada/demo/callout.yaml,sha256=ze2UfAymU05lzVp-t8wSa9hYJMGSkhT4FwL4rVJQG4o,270
26
+ pymscada/demo/callout.yaml,sha256=WwrdY-d7k7RxCyI6oatEgP9hDY8MoSoHgmIeYASC6SM,464
28
27
  pymscada/demo/files.yaml,sha256=XWtmGDJxtD4qdl2h7miUfJYkDKsvwNTgQjlGpR6LQNs,163
29
28
  pymscada/demo/history.yaml,sha256=c0OuYe8LbTeZqJGU2WKGgTEkOA0IYAjO3e046ddQB8E,55
30
29
  pymscada/demo/logixclient.yaml,sha256=G_NlJhBYwT1a9ceHDgO6fCNKFmBM2pVO_t9Xa1NqlRY,912
31
30
  pymscada/demo/modbus_plc.py,sha256=3zZHHbyrdxyryEHBeNIw-fpcDGcS1MaJiqEwQDr6zWI,2397
32
31
  pymscada/demo/modbusclient.yaml,sha256=geeCsUJZkkEj7jjXR_Yk6R5zA5Ta9IczrHsARz7ZgXY,1099
33
32
  pymscada/demo/modbusserver.yaml,sha256=67_mED6jXgtnzlDIky9Cg4j-nXur06iz9ve3JUwSyG8,1133
34
- pymscada/demo/openweather.yaml,sha256=n8aPc_Ar6uiM-XbrEbBydABxFYm2uv_49dGo8u7DI8Q,433
33
+ pymscada/demo/openweather.yaml,sha256=_xHb3xmf8e2BfNvwupxacXNNKLAlV5HaaMg3wuK3Za4,440
35
34
  pymscada/demo/opnotes.yaml,sha256=gdT8DKaAV4F6u9trLCPyBgf449wYaP_FF8GCbjXm9-k,105
35
+ pymscada/demo/piapi.yaml,sha256=1Rpwx7fD-uhA8IgMuKAX6Pxc5Ma-hosMiR9F4JSq3vs,320
36
36
  pymscada/demo/ping.yaml,sha256=fm3eUdR2BwnPI_lU_V07qgmDxjSoPP6lPazYB6ZgpVg,149
37
37
  pymscada/demo/pymscada-alarms.service,sha256=nHjEMsonat-3ny0QJoY6KTZoPIt2HZiarKgW5uasY8k,383
38
38
  pymscada/demo/pymscada-bus.service,sha256=F3ViriRXyMKdCY3tHa3wXAnv2Fo2_16-EScTLsYnSOA,261
39
+ pymscada/demo/pymscada-callout.service,sha256=XpG20TVofjEuoRnBxH1f5DQEBdGbj2tORs60IjiuQw4,386
39
40
  pymscada/demo/pymscada-demo-modbus_plc.service,sha256=EtbWDwqAs4nLNLKScUiHcUWU1b6_tRBeAAVGi9q95hY,320
40
41
  pymscada/demo/pymscada-files.service,sha256=iLOfbl4SCxAwYHT20XCGHU0BJsUVicNHjHzKS8xIdgA,326
41
42
  pymscada/demo/pymscada-history.service,sha256=61c5RqOmJ13Dl1yyRfsChKOdXp2W-xfYyCOYoJHLkh8,386
@@ -43,15 +44,18 @@ pymscada/demo/pymscada-io-logixclient.service,sha256=mn4UzkiOfYqHvgfTFSkUeoPFQQX
43
44
  pymscada/demo/pymscada-io-modbusclient.service,sha256=eTgNdK10dJCs2lLPhmHBh-3j6Ltx2oyU_MNl2f3xnhg,348
44
45
  pymscada/demo/pymscada-io-modbusserver.service,sha256=g7Rzm6zGLq_qvTJRL_pcLl4Ps7CNIa2toeGhPNp_oEc,348
45
46
  pymscada/demo/pymscada-io-openweather.service,sha256=SQnZ-cq1V3qvZY7EgR_Vx36vCOw1ipfGoLoutHsxtNk,359
47
+ pymscada/demo/pymscada-io-piapi.service,sha256=82-azz0JBAHnv8nGwJx545Nj13rwsa62c4-ntbjbzw0,343
46
48
  pymscada/demo/pymscada-io-ping.service,sha256=Fm8qR4IVq0NupEvHLGONXGwjjQsx5VqaBYPewhg7-k4,329
49
+ pymscada/demo/pymscada-io-sms.service,sha256=QKa7DEEmxhJWR2EuTIfQeqR4conMeeZS37oZGSWhbO8,460
47
50
  pymscada/demo/pymscada-io-snmpclient.service,sha256=Rsm8uiwnoGx-1MkXqYgtj4UP9-r7AEEeB9yoR0y0oVA,343
48
51
  pymscada/demo/pymscada-io-witsapi.service,sha256=ZjNwUnZg7WZsCaBFk8aNibnCbwqtbhl1i9D8tdUGXiQ,343
49
52
  pymscada/demo/pymscada-opnotes.service,sha256=TlrTRgP3rzrlXT8isAGT_Wy38ScDjT1VvnlgW84XiS8,354
50
53
  pymscada/demo/pymscada-wwwserver.service,sha256=7Qy2wsMmFEsQn-b5mgAcsrAQZgXynkv8SpHD6hLvRGc,370
54
+ pymscada/demo/sms.yaml,sha256=nvY2d95NLWByHF2uy4STQbq4jwcZdX_q8m2FzO7CaQU,238
51
55
  pymscada/demo/snmpclient.yaml,sha256=z8iACrFvMftYUtqGrRjPZYZTpn7aOXI-Kp675NAM8cU,2013
52
- pymscada/demo/tags.yaml,sha256=1HH9SqevBE0P0NXHK0Slfu68gwx5iKpgyirClmAcXGY,2814
53
- pymscada/demo/witsapi.yaml,sha256=B8F136jvLIYU8t-pOdsEU_j97qMo3RgGQ1Rs4ExhmeE,289
54
- pymscada/demo/wwwserver.yaml,sha256=mmwvSLUXUDCIPaHeCJdCETAp9Cc4wb5CuK_aGv01KWk,2759
56
+ pymscada/demo/tags.yaml,sha256=DZrMDyHVlS-zuiI_eaeSMrLl5Cz9AMMtYs5oEd7B7nE,2845
57
+ pymscada/demo/witsapi.yaml,sha256=6nWboDmHLJOqPzZWkLoI0cCxXWxijqdH6CBy4ZnLiE4,303
58
+ pymscada/demo/wwwserver.yaml,sha256=SBEKh5YPLO5DqTvI7xUcHn8tHwtdNkPAeFSX6ZFVI-I,3119
55
59
  pymscada/demo/__pycache__/__init__.cpython-311.pyc,sha256=tpxZoW429YA-2mbwzOlhBmbSTcbvTJqgKCfDRMrhEJE,195
56
60
  pymscada/iodrivers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
61
  pymscada/iodrivers/accuweather.py,sha256=p_OYJtCrtbSQYjgf06Yk3Qc9wGpkx8ogn81XNGd19fE,3842
@@ -61,21 +65,24 @@ pymscada/iodrivers/modbus_client.py,sha256=DIGrEPz_Bwwj9CEeog5fQqiAu1UMV7xVL6Kxl
61
65
  pymscada/iodrivers/modbus_map.py,sha256=af2J3CGSeYQ4mSy8rNsERp9z7fRgRUYk3it5Mrc_IQA,7255
62
66
  pymscada/iodrivers/modbus_server.py,sha256=VqvjOJ4-LOVaD1jOK22raXhrCshJEaWlMxLvn5xMnFc,6570
63
67
  pymscada/iodrivers/openweather.py,sha256=IVzmaEjdwm1NDhsOYpEV5vzB8HFaQEpWsnm6fhpsPCQ,8926
68
+ pymscada/iodrivers/piapi.py,sha256=00f9gcPM6OXSldbPvBFqMk4Lt2fyPCvNUpNodVCWXhc,4933
64
69
  pymscada/iodrivers/ping_client.py,sha256=UOQgUfoIcYqy5VvKyJ8XGHHjeSRTfjmrhyWEojhIZQk,4188
65
70
  pymscada/iodrivers/ping_map.py,sha256=EbOteqfEYKIOMqPymROJ4now2If-ekEj6jnM5hthoSA,1403
71
+ pymscada/iodrivers/sms.py,sha256=ltBZ1uz6-KBxomhtTP3I_YT5-n9s0DCSBUmBONL3HNQ,8309
66
72
  pymscada/iodrivers/snmp_client.py,sha256=66-IDzddeKcSnqOzNXIZ8wuuAqhIxZjyLNrDwDvHCvw,2708
67
73
  pymscada/iodrivers/snmp_map.py,sha256=sDdIR5ZPAETpozDfBt_XQiZ-f4t99UCPlzj7BxFxQyM,2369
68
- pymscada/iodrivers/witsapi.py,sha256=Ga6JpEQRUciT_LxWW36LsVGkUeWjModtzPoWYIzyzHs,8381
74
+ pymscada/iodrivers/witsapi.py,sha256=soclRYQLVZpNGmxPQgxDa3xORF67p6DwGFYDaSNkRoU,7995
69
75
  pymscada/iodrivers/witsapi_POC.py,sha256=dQcR2k1wsLb_cnNqvAB4kJ7FdY0BlcnxiMoepr28Ars,10132
70
76
  pymscada/pdf/__init__.py,sha256=WsDDgkWnZBJbt2-cJCdc2NvRAv_T4a7WOC1Q0k_l0gI,29
71
77
  pymscada/pdf/one.pdf,sha256=eoJ45DrAjVZrwmwdA_EAz1fwmT44eRnt_tkc2pmMrKY,1488
72
78
  pymscada/pdf/two.pdf,sha256=TAuW5yLU1_wfmTH_I5ezHwY0pxhCVuZh3ixu0kwmJwE,1516
73
79
  pymscada/pdf/__pycache__/__init__.cpython-311.pyc,sha256=4KTfXrV9bGDbTIEv-zgIj_LvzLbVTj77lEC1wzMh9e0,194
80
+ pymscada/tools/get_history.py,sha256=LfUB7i0qne4lE0lk-bWRmK1B0xpex-AfIOh2paxSDCk,5409
74
81
  pymscada/tools/snmp_client2.py,sha256=pdn5dYyEv4q-ubA0zQ8X-3tQDYxGC7f7Xexa7QPaL40,1675
75
82
  pymscada/tools/walk.py,sha256=OgpprUbKLhEWMvJGfU1ckUt_PFEpwZVOD8HucCgzmOc,1625
76
- pymscada-0.2.0rc8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
77
- pymscada-0.2.0rc8.dist-info/METADATA,sha256=vL-9rZ1w6VfZfJe6AHLdxIzQmu5ncN9q10k-GE1DfVE,2393
78
- pymscada-0.2.0rc8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
79
- pymscada-0.2.0rc8.dist-info/entry_points.txt,sha256=2UJBi8jrqujnerrcXcq4F8GHJYVDt26sacXl94t3sd8,56
80
- pymscada-0.2.0rc8.dist-info/top_level.txt,sha256=LxIB-zrtgObJg0fgdGZXBkmNKLDYHfaH1Hw2YP2ZMms,9
81
- pymscada-0.2.0rc8.dist-info/RECORD,,
83
+ pymscada-0.2.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
84
+ pymscada-0.2.2.dist-info/METADATA,sha256=yO9K8mwxTWL8Qpl-QckvC4s3A8XrVN974YmspyFQKoE,2387
85
+ pymscada-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
86
+ pymscada-0.2.2.dist-info/entry_points.txt,sha256=2UJBi8jrqujnerrcXcq4F8GHJYVDt26sacXl94t3sd8,56
87
+ pymscada-0.2.2.dist-info/top_level.txt,sha256=LxIB-zrtgObJg0fgdGZXBkmNKLDYHfaH1Hw2YP2ZMms,9
88
+ pymscada-0.2.2.dist-info/RECORD,,