pymscada 0.1.11__py3-none-any.whl → 0.1.11b3__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/bus_client.py +23 -22
- pymscada/bus_server.py +28 -25
- pymscada/checkout.py +6 -10
- pymscada/console.py +11 -14
- pymscada/demo/openweather.yaml +25 -0
- pymscada/demo/ping.yaml +0 -3
- pymscada/demo/tags.yaml +2 -148
- pymscada/demo/wwwserver.yaml +6 -461
- pymscada/iodrivers/openweather.py +126 -0
- pymscada/main.py +41 -295
- pymscada/module_config.py +217 -0
- pymscada/protocol_constants.py +29 -39
- pymscada/validate.py +29 -26
- pymscada/www_server.py +4 -4
- {pymscada-0.1.11.dist-info → pymscada-0.1.11b3.dist-info}/METADATA +3 -3
- {pymscada-0.1.11.dist-info → pymscada-0.1.11b3.dist-info}/RECORD +19 -16
- {pymscada-0.1.11.dist-info → pymscada-0.1.11b3.dist-info}/WHEEL +1 -1
- {pymscada-0.1.11.dist-info → pymscada-0.1.11b3.dist-info}/entry_points.txt +0 -0
- {pymscada-0.1.11.dist-info → pymscada-0.1.11b3.dist-info}/licenses/LICENSE +0 -0
pymscada/demo/wwwserver.yaml
CHANGED
|
@@ -2,13 +2,13 @@ bus_ip: 127.0.0.1
|
|
|
2
2
|
bus_port: 1324
|
|
3
3
|
ip: 0.0.0.0
|
|
4
4
|
port: 8324
|
|
5
|
-
get_path:
|
|
6
|
-
serve_path: __HOME__
|
|
5
|
+
get_path:
|
|
6
|
+
serve_path: __HOME__
|
|
7
7
|
pages:
|
|
8
8
|
- name: Notes
|
|
9
9
|
parent:
|
|
10
10
|
items:
|
|
11
|
-
- type:
|
|
11
|
+
- type: opnotes
|
|
12
12
|
site: [Site 1, Site 2]
|
|
13
13
|
by: [B1, B2]
|
|
14
14
|
- name: Default Main
|
|
@@ -41,469 +41,19 @@ pages:
|
|
|
41
41
|
- Four
|
|
42
42
|
- Five
|
|
43
43
|
- {tagname: FloatSelect, type: selectdict, opts: {type: float, dp: 2}}
|
|
44
|
-
- name: Trends
|
|
45
|
-
parent: Dropdown
|
|
46
|
-
items:
|
|
47
|
-
- type: uplot # Do all times in seconds, which uplot uses.
|
|
48
|
-
ms:
|
|
49
|
-
desc: Sample Trend
|
|
50
|
-
age: 172800
|
|
51
|
-
legend_pos: left
|
|
52
|
-
time_pos: left
|
|
53
|
-
time_res: m
|
|
54
|
-
axes:
|
|
55
|
-
- scale: x
|
|
56
|
-
range: [-86400, 0] # 86400 172800 1209600
|
|
57
|
-
- scale: '°C'
|
|
58
|
-
range: [0.0, 100.0]
|
|
59
|
-
dp: 1
|
|
60
|
-
- scale: '%'
|
|
61
|
-
range: [0.0, 100.0]
|
|
62
|
-
dp: 1
|
|
63
|
-
# side: 1
|
|
64
|
-
# bands: # TODO
|
|
65
|
-
# - series: [I_Transpower_Limit_Hi, I_Transpower_Limit_Lo]
|
|
66
|
-
# fill: [red, 0.2]
|
|
67
|
-
# dir: -1
|
|
68
|
-
series:
|
|
69
|
-
- tagname: cpu_load
|
|
70
|
-
label: CPU Load
|
|
71
|
-
scale: '%'
|
|
72
|
-
color: black
|
|
73
|
-
width: 1.5
|
|
74
|
-
dp: 1
|
|
75
|
-
- tagname: disk_use
|
|
76
|
-
label: Disk Use
|
|
77
|
-
scale: '%'
|
|
78
|
-
color: blue
|
|
79
|
-
width: 1
|
|
80
|
-
dp: 1
|
|
81
|
-
- tagname: cpu_temp
|
|
82
|
-
label: CPU Temp
|
|
83
|
-
scale: '°C'
|
|
84
|
-
color: red
|
|
85
|
-
width: 1
|
|
86
|
-
dp: 1
|
|
87
44
|
- name: Files
|
|
88
|
-
parent:
|
|
45
|
+
parent:
|
|
89
46
|
items:
|
|
90
47
|
- type: files
|
|
91
|
-
- name: Temperature
|
|
92
|
-
parent: Weather
|
|
93
|
-
items:
|
|
94
|
-
- type: uplot # Do all times in seconds, which uplot uses.
|
|
95
|
-
ms:
|
|
96
|
-
desc: Temperature
|
|
97
|
-
age: 172800
|
|
98
|
-
legend_pos: left
|
|
99
|
-
time_pos: left
|
|
100
|
-
time_res: m
|
|
101
|
-
axes:
|
|
102
|
-
- scale: x
|
|
103
|
-
range: [-604800, 86400] # 86400 172800 1209600
|
|
104
|
-
- scale: 'C'
|
|
105
|
-
range: [0.0, 35.0]
|
|
106
|
-
dp: 1
|
|
107
|
-
series:
|
|
108
|
-
- tagname: temperature
|
|
109
|
-
label: Current Temperature
|
|
110
|
-
scale: 'C'
|
|
111
|
-
color: black
|
|
112
|
-
width: 2
|
|
113
|
-
dp: 1
|
|
114
|
-
- tagname: temperature_01
|
|
115
|
-
label: 1h Temperature
|
|
116
|
-
scale: 'C'
|
|
117
|
-
color: darkgray
|
|
118
|
-
width: 1.5
|
|
119
|
-
dp: 1
|
|
120
|
-
- tagname: temperature_04
|
|
121
|
-
label: 4h Temperature
|
|
122
|
-
scale: 'C'
|
|
123
|
-
color: green
|
|
124
|
-
width: 1
|
|
125
|
-
dp: 1
|
|
126
|
-
- tagname: temperature_12
|
|
127
|
-
label: 12h Temperature
|
|
128
|
-
scale: 'C'
|
|
129
|
-
color: orange
|
|
130
|
-
width: 0.75
|
|
131
|
-
dp: 1
|
|
132
|
-
- tagname: temperature_24
|
|
133
|
-
label: 24h Temperature
|
|
134
|
-
scale: 'C'
|
|
135
|
-
color: red
|
|
136
|
-
width: 0.5
|
|
137
|
-
dp: 1
|
|
138
|
-
- name: Wind Speed
|
|
139
|
-
parent: Weather
|
|
140
|
-
items:
|
|
141
|
-
- type: uplot # Do all times in seconds, which uplot uses.
|
|
142
|
-
ms:
|
|
143
|
-
desc: Wind Speed
|
|
144
|
-
age: 172800
|
|
145
|
-
legend_pos: left
|
|
146
|
-
time_pos: left
|
|
147
|
-
time_res: m
|
|
148
|
-
axes:
|
|
149
|
-
- scale: x
|
|
150
|
-
range: [-604800, 86400] # 86400 172800 1209600
|
|
151
|
-
- scale: 'm/s'
|
|
152
|
-
range: [0.0, 20.0]
|
|
153
|
-
dp: 1
|
|
154
|
-
series:
|
|
155
|
-
- tagname: windSpeed
|
|
156
|
-
label: Current Wind Speed
|
|
157
|
-
scale: 'm/s'
|
|
158
|
-
color: black
|
|
159
|
-
width: 2
|
|
160
|
-
dp: 1
|
|
161
|
-
- tagname: windSpeed_01
|
|
162
|
-
label: 1h Wind Speed
|
|
163
|
-
scale: 'm/s'
|
|
164
|
-
color: darkgray
|
|
165
|
-
width: 1.5
|
|
166
|
-
dp: 1
|
|
167
|
-
- tagname: windSpeed_04
|
|
168
|
-
label: 4h Wind Speed
|
|
169
|
-
scale: 'm/s'
|
|
170
|
-
color: green
|
|
171
|
-
width: 1
|
|
172
|
-
dp: 1
|
|
173
|
-
- tagname: windSpeed_12
|
|
174
|
-
label: 12h Wind Speed
|
|
175
|
-
scale: 'm/s'
|
|
176
|
-
color: orange
|
|
177
|
-
width: 0.75
|
|
178
|
-
dp: 1
|
|
179
|
-
- tagname: windSpeed_24
|
|
180
|
-
label: 24h Wind Speed
|
|
181
|
-
scale: 'm/s'
|
|
182
|
-
color: red
|
|
183
|
-
width: 0.5
|
|
184
|
-
dp: 1
|
|
185
|
-
- name: Wind Direction
|
|
186
|
-
parent: Weather
|
|
187
|
-
items:
|
|
188
|
-
- type: uplot # Do all times in seconds, which uplot uses.
|
|
189
|
-
ms:
|
|
190
|
-
desc: Wind Direction
|
|
191
|
-
age: 172800
|
|
192
|
-
legend_pos: left
|
|
193
|
-
time_pos: left
|
|
194
|
-
time_res: m
|
|
195
|
-
axes:
|
|
196
|
-
- scale: x
|
|
197
|
-
range: [-604800, 86400] # 86400 172800 1209600
|
|
198
|
-
- scale: 'deg'
|
|
199
|
-
range: [0.0, 360.0]
|
|
200
|
-
dp: 1
|
|
201
|
-
series:
|
|
202
|
-
- tagname: windDirection
|
|
203
|
-
label: Current Wind Direction
|
|
204
|
-
scale: 'deg'
|
|
205
|
-
color: black
|
|
206
|
-
width: 2
|
|
207
|
-
dp: 1
|
|
208
|
-
- tagname: windDirection_01
|
|
209
|
-
label: 1h Wind Direction
|
|
210
|
-
scale: 'deg'
|
|
211
|
-
color: darkgray
|
|
212
|
-
width: 1.5
|
|
213
|
-
dp: 1
|
|
214
|
-
- tagname: windDirection_04
|
|
215
|
-
label: 4h Wind Direction
|
|
216
|
-
scale: 'deg'
|
|
217
|
-
color: green
|
|
218
|
-
width: 1
|
|
219
|
-
dp: 1
|
|
220
|
-
- tagname: windDirection_12
|
|
221
|
-
label: 12h Wind Direction
|
|
222
|
-
scale: 'deg'
|
|
223
|
-
color: orange
|
|
224
|
-
width: 0.75
|
|
225
|
-
dp: 1
|
|
226
|
-
- tagname: windDirection_24
|
|
227
|
-
label: 24h Wind Direction
|
|
228
|
-
scale: 'deg'
|
|
229
|
-
color: red
|
|
230
|
-
width: 0.5
|
|
231
|
-
dp: 1
|
|
232
|
-
- name: Rain Accumulation
|
|
233
|
-
parent: Weather
|
|
234
|
-
items:
|
|
235
|
-
- type: uplot # Do all times in seconds, which uplot uses.
|
|
236
|
-
ms:
|
|
237
|
-
desc: Rain Accumulation
|
|
238
|
-
age: 172800
|
|
239
|
-
legend_pos: left
|
|
240
|
-
time_pos: left
|
|
241
|
-
time_res: m
|
|
242
|
-
axes:
|
|
243
|
-
- scale: x
|
|
244
|
-
range: [-604800, 86400] # 86400 172800 1209600
|
|
245
|
-
- scale: 'mm'
|
|
246
|
-
range: [0.0, 10.0]
|
|
247
|
-
dp: 1
|
|
248
|
-
series:
|
|
249
|
-
- tagname: rainAccumulation
|
|
250
|
-
label: Current Rain Accumulation
|
|
251
|
-
scale: 'mm'
|
|
252
|
-
color: black
|
|
253
|
-
width: 2
|
|
254
|
-
dp: 1
|
|
255
|
-
- tagname: rainAccumulation_01
|
|
256
|
-
label: 1h Rain Accumulation
|
|
257
|
-
scale: 'mm'
|
|
258
|
-
color: darkgray
|
|
259
|
-
width: 1.5
|
|
260
|
-
dp: 1
|
|
261
|
-
- tagname: rainAccumulation_04
|
|
262
|
-
label: 4h Rain Accumulation
|
|
263
|
-
scale: 'mm'
|
|
264
|
-
color: green
|
|
265
|
-
width: 1
|
|
266
|
-
dp: 1
|
|
267
|
-
- tagname: rainAccumulation_12
|
|
268
|
-
label: 12h Rain Accumulation
|
|
269
|
-
scale: 'mm'
|
|
270
|
-
color: orange
|
|
271
|
-
width: 0.75
|
|
272
|
-
dp: 1
|
|
273
|
-
- tagname: rainAccumulation_24
|
|
274
|
-
label: 24h Rain Accumulation
|
|
275
|
-
scale: 'mm'
|
|
276
|
-
color: red
|
|
277
|
-
width: 0.5
|
|
278
|
-
dp: 1
|
|
279
|
-
- name: Humidity
|
|
280
|
-
parent: Weather
|
|
281
|
-
items:
|
|
282
|
-
- type: uplot # Do all times in seconds, which uplot uses.
|
|
283
|
-
ms:
|
|
284
|
-
desc: Humidity
|
|
285
|
-
age: 172800
|
|
286
|
-
legend_pos: left
|
|
287
|
-
time_pos: left
|
|
288
|
-
time_res: m
|
|
289
|
-
axes:
|
|
290
|
-
- scale: x
|
|
291
|
-
range: [-604800, 86400] # 86400 172800 1209600
|
|
292
|
-
- scale: '%'
|
|
293
|
-
range: [0.0, 100.0]
|
|
294
|
-
dp: 1
|
|
295
|
-
series:
|
|
296
|
-
- tagname: humidity
|
|
297
|
-
label: Current Humidity
|
|
298
|
-
scale: '%'
|
|
299
|
-
color: black
|
|
300
|
-
width: 2
|
|
301
|
-
dp: 1
|
|
302
|
-
- tagname: humidity_01
|
|
303
|
-
label: 1h Humidity
|
|
304
|
-
scale: '%'
|
|
305
|
-
color: darkgray
|
|
306
|
-
width: 1.5
|
|
307
|
-
dp: 1
|
|
308
|
-
- tagname: humidity_04
|
|
309
|
-
label: 4h Humidity
|
|
310
|
-
scale: '%'
|
|
311
|
-
color: green
|
|
312
|
-
width: 1
|
|
313
|
-
dp: 1
|
|
314
|
-
- tagname: humidity_12
|
|
315
|
-
label: 12h Humidity
|
|
316
|
-
scale: '%'
|
|
317
|
-
color: orange
|
|
318
|
-
width: 0.75
|
|
319
|
-
dp: 1
|
|
320
|
-
- tagname: humidity_24
|
|
321
|
-
label: 24h Humidity
|
|
322
|
-
scale: '%'
|
|
323
|
-
color: red
|
|
324
|
-
width: 0.5
|
|
325
|
-
dp: 1
|
|
326
|
-
- name: Values
|
|
327
|
-
parent: Weather
|
|
328
|
-
items:
|
|
329
|
-
- {tagname: temperature, type: value}
|
|
330
|
-
- {tagname: temperature_01, type: value}
|
|
331
|
-
- {tagname: temperature_04, type: value}
|
|
332
|
-
- {tagname: temperature_12, type: value}
|
|
333
|
-
- {tagname: temperature_24, type: value}
|
|
334
|
-
- {tagname: windSpeed, type: value}
|
|
335
|
-
- {tagname: windSpeed_01, type: value}
|
|
336
|
-
- {tagname: windSpeed_04, type: value}
|
|
337
|
-
- {tagname: windSpeed_12, type: value}
|
|
338
|
-
- {tagname: windSpeed_24, type: value}
|
|
339
|
-
- {tagname: windDirection, type: value}
|
|
340
|
-
- {tagname: windDirection_01, type: value}
|
|
341
|
-
- {tagname: windDirection_04, type: value}
|
|
342
|
-
- {tagname: windDirection_12, type: value}
|
|
343
|
-
- {tagname: windDirection_24, type: value}
|
|
344
|
-
- {tagname: rainAccumulation, type: value}
|
|
345
|
-
- {tagname: rainAccumulation_01, type: value}
|
|
346
|
-
- {tagname: rainAccumulation_04, type: value}
|
|
347
|
-
- {tagname: rainAccumulation_12, type: value}
|
|
348
|
-
- {tagname: rainAccumulation_24, type: value}
|
|
349
|
-
- {tagname: humidity, type: value}
|
|
350
|
-
- {tagname: humidity_01, type: value}
|
|
351
|
-
- {tagname: humidity_04, type: value}
|
|
352
|
-
- {tagname: humidity_12, type: value}
|
|
353
|
-
- {tagname: humidity_24, type: value}
|
|
354
|
-
- name: Logix
|
|
355
|
-
items:
|
|
356
|
-
- {tagname: Ani_Fin_20, type: setpoint}
|
|
357
|
-
- {tagname: Ani_Fout_20, type: value}
|
|
358
|
-
- {tagname: Ani_Iin_20, type: setpoint}
|
|
359
|
-
- {tagname: Ani_Iout_20, type: value}
|
|
360
|
-
- {tagname: InVar, type: setpoint}
|
|
361
|
-
- {tagname: OutVar, type: value}
|
|
362
|
-
- {tagname: Ani_Iin_21_0, type: setpoint}
|
|
363
|
-
- {tagname: Ani_Iout_21_0, type: value}
|
|
364
|
-
- {tagname: Ani_Iin_21_1, type: setpoint}
|
|
365
|
-
- {tagname: Ani_Iout_21_1, type: value}
|
|
366
|
-
- name: Values
|
|
367
|
-
parent: SNMP
|
|
368
|
-
items:
|
|
369
|
-
- {tagname: Router_eth1_bytes_in, type: value}
|
|
370
|
-
- {tagname: Router_eth1_bytes_out, type: value}
|
|
371
|
-
- {tagname: Router_eth2_bytes_in, type: value}
|
|
372
|
-
- {tagname: Router_eth2_bytes_out, type: value}
|
|
373
|
-
- {tagname: Router_eth3_bytes_in, type: value}
|
|
374
|
-
- {tagname: Router_eth3_bytes_out, type: value}
|
|
375
|
-
- {tagname: Router_eth4_bytes_in, type: value}
|
|
376
|
-
- {tagname: Router_eth4_bytes_out, type: value}
|
|
377
|
-
- {tagname: Router_eth5_bytes_in, type: value}
|
|
378
|
-
- {tagname: Router_eth5_bytes_out, type: value}
|
|
379
|
-
- {tagname: Router_eth6_bytes_in, type: value}
|
|
380
|
-
- {tagname: Router_eth6_bytes_out, type: value}
|
|
381
|
-
- {tagname: Router_eth7_bytes_in, type: value}
|
|
382
|
-
- {tagname: Router_eth7_bytes_out, type: value}
|
|
383
|
-
- {tagname: Router_eth8_bytes_in, type: value}
|
|
384
|
-
- {tagname: Router_eth8_bytes_out, type: value}
|
|
385
|
-
- name: Trend
|
|
386
|
-
parent: SNMP
|
|
387
|
-
items:
|
|
388
|
-
- type: uplot # Do all times in seconds, which uplot uses.
|
|
389
|
-
ms:
|
|
390
|
-
desc: Bytes
|
|
391
|
-
age: 172800
|
|
392
|
-
legend_pos: left
|
|
393
|
-
time_pos: left
|
|
394
|
-
time_res: m
|
|
395
|
-
axes:
|
|
396
|
-
- scale: x
|
|
397
|
-
range: [-86400, 0]
|
|
398
|
-
- scale: 'bytes'
|
|
399
|
-
range: [0, 100000]
|
|
400
|
-
dp: 0
|
|
401
|
-
series:
|
|
402
|
-
- tagname: Router_eth1_bytes_in
|
|
403
|
-
label: eth1 in
|
|
404
|
-
scale: 'bytes'
|
|
405
|
-
color: violet
|
|
406
|
-
width: 1
|
|
407
|
-
dp: 0
|
|
408
|
-
- tagname: Router_eth1_bytes_out
|
|
409
|
-
label: eth1 out
|
|
410
|
-
scale: 'bytes'
|
|
411
|
-
color: violet
|
|
412
|
-
width: 0.5
|
|
413
|
-
dp: 0
|
|
414
|
-
- tagname: Router_eth2_bytes_in
|
|
415
|
-
label: eth2 in
|
|
416
|
-
scale: 'bytes'
|
|
417
|
-
color: blue
|
|
418
|
-
width: 1
|
|
419
|
-
dp: 0
|
|
420
|
-
- tagname: Router_eth2_bytes_out
|
|
421
|
-
label: eth2 out
|
|
422
|
-
scale: 'bytes'
|
|
423
|
-
color: blue
|
|
424
|
-
width: 0.5
|
|
425
|
-
dp: 0
|
|
426
|
-
- tagname: Router_eth3_bytes_in
|
|
427
|
-
label: eth3 in
|
|
428
|
-
scale: 'bytes'
|
|
429
|
-
color: green
|
|
430
|
-
width: 1
|
|
431
|
-
dp: 0
|
|
432
|
-
- tagname: Router_eth3_bytes_out
|
|
433
|
-
label: eth3 out
|
|
434
|
-
scale: 'bytes'
|
|
435
|
-
color: green
|
|
436
|
-
width: 0.5
|
|
437
|
-
dp: 0
|
|
438
|
-
- tagname: Router_eth4_bytes_in
|
|
439
|
-
label: eth4 in
|
|
440
|
-
scale: 'bytes'
|
|
441
|
-
color: gray
|
|
442
|
-
width: 1
|
|
443
|
-
dp: 0
|
|
444
|
-
- tagname: Router_eth4_bytes_out
|
|
445
|
-
label: eth4 out
|
|
446
|
-
scale: 'bytes'
|
|
447
|
-
color: gray
|
|
448
|
-
width: 0.5
|
|
449
|
-
dp: 0
|
|
450
|
-
- tagname: Router_eth5_bytes_in
|
|
451
|
-
label: eth5 in
|
|
452
|
-
scale: 'bytes'
|
|
453
|
-
color: goldenrod
|
|
454
|
-
width: 1
|
|
455
|
-
dp: 0
|
|
456
|
-
- tagname: Router_eth5_bytes_out
|
|
457
|
-
label: eth5 out
|
|
458
|
-
scale: 'bytes'
|
|
459
|
-
color: goldenrod
|
|
460
|
-
width: 0.5
|
|
461
|
-
dp: 0
|
|
462
|
-
- tagname: Router_eth6_bytes_in
|
|
463
|
-
label: eth6 in
|
|
464
|
-
scale: 'bytes'
|
|
465
|
-
color: brown
|
|
466
|
-
width: 1
|
|
467
|
-
dp: 0
|
|
468
|
-
- tagname: Router_eth6_bytes_out
|
|
469
|
-
label: eth6 out
|
|
470
|
-
scale: 'bytes'
|
|
471
|
-
color: brown
|
|
472
|
-
width: 0.5
|
|
473
|
-
dp: 0
|
|
474
|
-
- tagname: Router_eth7_bytes_in
|
|
475
|
-
label: eth7 in
|
|
476
|
-
scale: 'bytes'
|
|
477
|
-
color: orange
|
|
478
|
-
width: 1
|
|
479
|
-
dp: 0
|
|
480
|
-
- tagname: Router_eth7_bytes_out
|
|
481
|
-
label: eth7 out
|
|
482
|
-
scale: 'bytes'
|
|
483
|
-
color: orange
|
|
484
|
-
width: 0.5
|
|
485
|
-
dp: 0
|
|
486
|
-
- tagname: Router_eth8_bytes_in
|
|
487
|
-
label: eth8 in
|
|
488
|
-
scale: 'bytes'
|
|
489
|
-
color: aqua
|
|
490
|
-
width: 1
|
|
491
|
-
dp: 0
|
|
492
|
-
- tagname: Router_eth8_bytes_out
|
|
493
|
-
label: eth8 out
|
|
494
|
-
scale: 'bytes'
|
|
495
|
-
color: aqua
|
|
496
|
-
width: 0.5
|
|
497
|
-
dp: 0
|
|
498
48
|
- name: Ping Values
|
|
499
|
-
parent:
|
|
49
|
+
parent:
|
|
500
50
|
items:
|
|
501
51
|
- {desc: Default tags, type: h1}
|
|
502
52
|
- {tagname: localhost_ping, type: value}
|
|
503
53
|
- {tagname: google_ping, type: value}
|
|
504
54
|
- {tagname: electronet_ping, type: value}
|
|
505
55
|
- name: Ping Trend
|
|
506
|
-
parent:
|
|
56
|
+
parent:
|
|
507
57
|
items:
|
|
508
58
|
- type: uplot # Do all times in seconds, which uplot uses.
|
|
509
59
|
ms:
|
|
@@ -524,11 +74,6 @@ pages:
|
|
|
524
74
|
scale: mS
|
|
525
75
|
color: black
|
|
526
76
|
dp: 1
|
|
527
|
-
- tagname: electronet_ping
|
|
528
|
-
label: electronet
|
|
529
|
-
scale: mS
|
|
530
|
-
color: blue
|
|
531
|
-
dp: 1
|
|
532
77
|
- tagname: google_ping
|
|
533
78
|
label: google
|
|
534
79
|
scale: mS
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Poll OpenWeather current and forecast APIs."""
|
|
2
|
+
import asyncio
|
|
3
|
+
import aiohttp
|
|
4
|
+
import logging
|
|
5
|
+
from time import time
|
|
6
|
+
from pymscada.bus_client import BusClient
|
|
7
|
+
from pymscada.periodic import Periodic
|
|
8
|
+
from pymscada.tag import Tag
|
|
9
|
+
|
|
10
|
+
class OpenWeatherClient:
|
|
11
|
+
"""Get weather data from OpenWeather Current and Forecast APIs."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, bus_ip: str = '127.0.0.1', bus_port: int = 1324,
|
|
14
|
+
proxy: str = None, api: dict = {}, tags: dict = {}) -> None:
|
|
15
|
+
"""
|
|
16
|
+
Connect to bus on bus_ip:bus_port.
|
|
17
|
+
|
|
18
|
+
api dict should contain:
|
|
19
|
+
- api_key: OpenWeatherMap API key
|
|
20
|
+
- locations: dict of location names and coordinates
|
|
21
|
+
- times: list of hours ahead to fetch forecast data for
|
|
22
|
+
- units: optional units (standard, metric, imperial)
|
|
23
|
+
"""
|
|
24
|
+
self.busclient = None
|
|
25
|
+
if bus_ip is not None:
|
|
26
|
+
self.busclient = BusClient(bus_ip, bus_port, module='OpenWeather')
|
|
27
|
+
self.proxy = proxy
|
|
28
|
+
self.map_bus = id(self)
|
|
29
|
+
self.tags = {tagname: Tag(tagname, float) for tagname in tags}
|
|
30
|
+
self.api_key = api['api_key']
|
|
31
|
+
self.units = api.get('units', 'standard')
|
|
32
|
+
self.locations = api.get('locations', {})
|
|
33
|
+
self.parameters = api.get('parameters', {})
|
|
34
|
+
self.times = api.get('times', [3, 6, 12, 24, 48])
|
|
35
|
+
self.current_url = "https://api.openweathermap.org/data/2.5/weather"
|
|
36
|
+
self.forecast_url = "https://api.openweathermap.org/data/2.5/forecast"
|
|
37
|
+
self.queue = asyncio.Queue()
|
|
38
|
+
self.session = None
|
|
39
|
+
self.handle = None
|
|
40
|
+
self.periodic = None
|
|
41
|
+
|
|
42
|
+
def update_tags(self, location, data, suffix):
|
|
43
|
+
"""Update tags for forecast weather."""
|
|
44
|
+
for parameter in self.parameters:
|
|
45
|
+
tagname = f"{location}_{parameter}{suffix}"
|
|
46
|
+
if parameter == 'Temp':
|
|
47
|
+
value = data['main']['temp']
|
|
48
|
+
elif parameter == 'WindSpeed':
|
|
49
|
+
value = data['wind']['speed']
|
|
50
|
+
elif parameter == 'WindDir':
|
|
51
|
+
value = data['wind'].get('deg', 0)
|
|
52
|
+
elif parameter == 'Rain':
|
|
53
|
+
value = data.get('rain', {}).get('1h', 0)
|
|
54
|
+
try:
|
|
55
|
+
self.tags[tagname].value = value
|
|
56
|
+
except KeyError:
|
|
57
|
+
logging.warning(f'{tagname} not found setting weather value')
|
|
58
|
+
|
|
59
|
+
async def handle_response(self):
|
|
60
|
+
"""Handle responses from the API."""
|
|
61
|
+
while True:
|
|
62
|
+
location, data = await self.queue.get()
|
|
63
|
+
now = int(time())
|
|
64
|
+
if 'dt' in data:
|
|
65
|
+
self.update_tags(location, data, '')
|
|
66
|
+
elif 'list' in data:
|
|
67
|
+
for forecast in data['list']:
|
|
68
|
+
hours_ahead = int((forecast['dt'] - now) / 3600)
|
|
69
|
+
if hours_ahead not in self.times:
|
|
70
|
+
continue
|
|
71
|
+
suffix = f'_{hours_ahead:02d}'
|
|
72
|
+
self.update_tags(location, forecast, suffix)
|
|
73
|
+
|
|
74
|
+
async def fetch_current_data(self):
|
|
75
|
+
"""Fetch current weather data for all locations."""
|
|
76
|
+
if self.session is None:
|
|
77
|
+
self.session = aiohttp.ClientSession()
|
|
78
|
+
for location, coords in self.locations.items():
|
|
79
|
+
base_params = {'lat': coords['lat'], 'lon': coords['lon'],
|
|
80
|
+
'appid': self.api_key, 'units': self.units }
|
|
81
|
+
try:
|
|
82
|
+
async with self.session.get(self.current_url,
|
|
83
|
+
params=base_params, proxy=self.proxy) as resp:
|
|
84
|
+
if resp.status == 200:
|
|
85
|
+
self.queue.put_nowait((location, await resp.json()))
|
|
86
|
+
else:
|
|
87
|
+
logging.warning('OpenWeather current API error for '
|
|
88
|
+
f'{location}: {resp.status}')
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logging.warning('OpenWeather current API error for '
|
|
91
|
+
f'{location}: {e}')
|
|
92
|
+
|
|
93
|
+
async def fetch_forecast_data(self):
|
|
94
|
+
"""Fetch forecast weather data for all locations."""
|
|
95
|
+
if self.session is None:
|
|
96
|
+
self.session = aiohttp.ClientSession()
|
|
97
|
+
for location, coords in self.locations.items():
|
|
98
|
+
base_params = {'lat': coords['lat'], 'lon': coords['lon'],
|
|
99
|
+
'appid': self.api_key, 'units': self.units }
|
|
100
|
+
try:
|
|
101
|
+
async with self.session.get(self.forecast_url,
|
|
102
|
+
params=base_params, proxy=self.proxy) as resp:
|
|
103
|
+
if resp.status == 200:
|
|
104
|
+
self.queue.put_nowait((location, await resp.json()))
|
|
105
|
+
else:
|
|
106
|
+
logging.warning('OpenWeather forecast API error '
|
|
107
|
+
f'for {location}: {resp.status}')
|
|
108
|
+
except Exception as e:
|
|
109
|
+
logging.warning('OpenWeather forecast API error for '
|
|
110
|
+
f'{location}: {e}')
|
|
111
|
+
|
|
112
|
+
async def poll(self):
|
|
113
|
+
"""Poll OpenWeather APIs every 10 minutes."""
|
|
114
|
+
now = int(time())
|
|
115
|
+
if now % 600 == 0: # Every 10 minutes
|
|
116
|
+
await self.fetch_current_data()
|
|
117
|
+
if now % 10800 == 60: # Every 3 hours, offset by 1 minute
|
|
118
|
+
await self.fetch_forecast_data()
|
|
119
|
+
|
|
120
|
+
async def start(self):
|
|
121
|
+
"""Start bus connection and API polling."""
|
|
122
|
+
if self.busclient is not None:
|
|
123
|
+
await self.busclient.start()
|
|
124
|
+
self.handle = asyncio.create_task(self.handle_response())
|
|
125
|
+
self.periodic = Periodic(self.poll, 1.0)
|
|
126
|
+
await self.periodic.start()
|