...
|
...
|
@@ -11,7 +11,7 @@
|
11
|
11
|
# - conversion of data items
|
12
|
12
|
# - update a round robin (rrdtool) database with the radiation data
|
13
|
13
|
# - periodically generate graphic charts for display in html documents
|
14
|
|
-# - write the processed weather data to a JSON file for use by html
|
|
14
|
+# - write the processed radmon data to a JSON file for use by html
|
15
|
15
|
# documents
|
16
|
16
|
#
|
17
|
17
|
# Copyright 2015 Jeff Owrey
|
...
|
...
|
@@ -35,6 +35,7 @@
|
35
|
35
|
# improved radmon device offline status handling
|
36
|
36
|
# * v23 released 16 Nov 2018 by J L Owrey: improved fault handling
|
37
|
37
|
# and data conversion
|
|
38
|
+#2345678901234567890123456789012345678901234567890123456789012345678901234567890
|
38
|
39
|
|
39
|
40
|
import os
|
40
|
41
|
import urllib2
|
...
|
...
|
@@ -50,7 +51,7 @@ _USER = os.environ['USER']
|
50
|
51
|
### DEFAULT RADIATION MONITOR URL ###
|
51
|
52
|
|
52
|
53
|
# ip address of radiation monitoring device
|
53
|
|
-_DEFAULT_RADIATION_MONITOR_URL = "{your radiation monitor url}"
|
|
54
|
+_DEFAULT_RADIATION_MONITOR_URL = "http://192.168.1.24"
|
54
|
55
|
|
55
|
56
|
### FILE AND FOLDER LOCATIONS ###
|
56
|
57
|
|
...
|
...
|
@@ -58,11 +59,9 @@ _DEFAULT_RADIATION_MONITOR_URL = "{your radiation monitor url}"
|
58
|
59
|
_DOCROOT_PATH = "/home/%s/public_html/radmon/" % _USER
|
59
|
60
|
# folder for charts and output data file
|
60
|
61
|
_CHARTS_DIRECTORY = _DOCROOT_PATH + "dynamic/"
|
61
|
|
-# location of data input file
|
62
|
|
-_INPUT_DATA_FILE = _DOCROOT_PATH + "dynamic/radmonInputData.dat"
|
63
|
62
|
# location of data output file
|
64
|
63
|
_OUTPUT_DATA_FILE = _DOCROOT_PATH + "dynamic/radmonOutputData.js"
|
65
|
|
-# database that stores weather data
|
|
64
|
+# database that stores radmon data
|
66
|
65
|
_RRD_FILE = "/home/%s/database/radmonData.rrd" % _USER
|
67
|
66
|
|
68
|
67
|
### GLOBAL CONSTANTS ###
|
...
|
...
|
@@ -81,6 +80,8 @@ _HTTP_REQUEST_TIMEOUT = 3
|
81
|
80
|
_CHART_WIDTH = 600
|
82
|
81
|
# standard chart height in pixels
|
83
|
82
|
_CHART_HEIGHT = 150
|
|
83
|
+# source of time stamp attached to output data file
|
|
84
|
+_USE_RADMON_TIMESTAMP = True
|
84
|
85
|
|
85
|
86
|
### GLOBAL VARIABLES ###
|
86
|
87
|
|
...
|
...
|
@@ -123,13 +124,9 @@ def setStatusToOffline():
|
123
|
124
|
"""
|
124
|
125
|
global stationOnline
|
125
|
126
|
|
126
|
|
- # Inform downstream clients by removing input and output
|
127
|
|
- # data files.
|
128
|
|
- if os.path.exists(_INPUT_DATA_FILE):
|
129
|
|
- os.remove(_INPUT_DATA_FILE)
|
|
127
|
+ # Inform downstream clients by removing output data file.
|
130
|
128
|
if os.path.exists(_OUTPUT_DATA_FILE):
|
131
|
129
|
os.remove(_OUTPUT_DATA_FILE)
|
132
|
|
-
|
133
|
130
|
# If the radiation monitor was previously online, then send
|
134
|
131
|
# a message that we are now offline.
|
135
|
132
|
if stationOnline:
|
...
|
...
|
@@ -145,15 +142,11 @@ def terminateAgentProcess(signal, frame):
|
145
|
142
|
signal, frame - dummy parameters
|
146
|
143
|
Returns: nothing
|
147
|
144
|
"""
|
|
145
|
+ # Inform downstream clients by removing output data file.
|
|
146
|
+ if os.path.exists(_OUTPUT_DATA_FILE):
|
|
147
|
+ os.remove(_OUTPUT_DATA_FILE)
|
148
|
148
|
print '%s terminating radmon agent process' % \
|
149
|
149
|
(getTimeStamp())
|
150
|
|
-
|
151
|
|
- # Inform downstream clients by removing input and output
|
152
|
|
- # data files.
|
153
|
|
- if os.path.exists(_OUTPUT_DATA_FILE):
|
154
|
|
- os.remove(_OUTPUT_DATA_FILE)
|
155
|
|
- if os.path.exists(_INPUT_DATA_FILE):
|
156
|
|
- os.remove(_INPUT_DATA_FILE)
|
157
|
150
|
sys.exit(0)
|
158
|
151
|
##end def
|
159
|
152
|
|
...
|
...
|
@@ -232,18 +225,19 @@ def convertData(dData):
|
232
|
225
|
Returns: True if successful, False otherwise
|
233
|
226
|
"""
|
234
|
227
|
try:
|
235
|
|
- # Convert the UTC timestamp provided by the radiation monitoring
|
236
|
|
- # device to epoch local time in seconds.
|
237
|
|
- ts_utc = time.strptime(dData['UTC'], "%H:%M:%S %m/%d/%Y")
|
238
|
|
- epoch_local_sec = calendar.timegm(ts_utc)
|
239
|
|
- dData['ELT'] = epoch_local_sec
|
240
|
|
-
|
241
|
|
- # Uncomment the code line below to use a timestamp generated by the
|
242
|
|
- # requesting server (this) instead of the timestamp provided by the
|
243
|
|
- # radiation monitoring device. Using the server generated timestamp
|
244
|
|
- # prevents errors that occur when the radiation monitoring device
|
245
|
|
- # fails to synchronize with a valid NTP time server.
|
246
|
|
- #dData['ELT'] = time.time()
|
|
228
|
+ if _USE_RADMON_TIMESTAMP:
|
|
229
|
+ # Convert the UTC timestamp provided by the radiation monitoring
|
|
230
|
+ # device to epoch local time in seconds.
|
|
231
|
+ ts_utc = time.strptime(dData['UTC'], "%H:%M:%S %m/%d/%Y")
|
|
232
|
+ epoch_local_sec = calendar.timegm(ts_utc)
|
|
233
|
+ dData['ELT'] = epoch_local_sec
|
|
234
|
+ else:
|
|
235
|
+ # Use a timestamp generated by the requesting server (this)
|
|
236
|
+ # instead of the timestamp provided by the radiation monitoring
|
|
237
|
+ # device. Using the server generated timestamp prevents errors
|
|
238
|
+ # that occur when the radiation monitoring device fails to
|
|
239
|
+ # synchronize with a valid NTP time server.
|
|
240
|
+ dData['ELT'] = time.time()
|
247
|
241
|
|
248
|
242
|
dData['Mode'] = dData['Mode'].lower()
|
249
|
243
|
dData['uSvPerHr'] = '%.2f' % float(dData.pop('uSv/hr'))
|
...
|
...
|
@@ -264,22 +258,22 @@ def writeOutputDataFile(dData):
|
264
|
258
|
to the output data file
|
265
|
259
|
Returns: True if successful, False otherwise
|
266
|
260
|
"""
|
|
261
|
+ # Create temporary copy of output data items.
|
|
262
|
+ dTemp = dict(dData)
|
267
|
263
|
# Set date to current time and data
|
268
|
|
- dData['date'] = time.strftime("%m/%d/%Y %T", time.localtime(dData['ELT']))
|
269
|
|
-
|
|
264
|
+ dTemp['date'] = time.strftime("%m/%d/%Y %T", time.localtime(dData['ELT']))
|
270
|
265
|
# Remove unnecessary data items.
|
271
|
|
- dTemp = dict(dData)
|
272
|
266
|
dTemp.pop('ELT')
|
273
|
267
|
dTemp.pop('UTC')
|
274
|
|
-
|
275
|
|
- # Format the weather data as string using java script object notation.
|
|
268
|
+
|
|
269
|
+ # Format the radmon data as string using java script object notation.
|
276
|
270
|
sData = '[{'
|
277
|
271
|
for key in dTemp:
|
278
|
|
- sData += '\"%s\":\"%s\",' % (key, dData[key])
|
|
272
|
+ sData += '\"%s\":\"%s\",' % (key, dTemp[key])
|
279
|
273
|
sData = sData[:-1] + '}]\n'
|
280
|
274
|
|
281
|
275
|
if verboseDebug:
|
282
|
|
- print sData
|
|
276
|
+ print sData,
|
283
|
277
|
|
284
|
278
|
# Write the string to the output data file for use by html documents.
|
285
|
279
|
try:
|
...
|
...
|
@@ -293,26 +287,6 @@ def writeOutputDataFile(dData):
|
293
|
287
|
return True
|
294
|
288
|
## end def
|
295
|
289
|
|
296
|
|
-def writeInputDataFile(sData):
|
297
|
|
- """Write raw data from radiation monitor to the input data file.
|
298
|
|
- This file may then be accessed by downstream mirror servers.
|
299
|
|
- Parameters:
|
300
|
|
- sData - a string object containing the raw data from
|
301
|
|
- the radiation monitor
|
302
|
|
- Returns: True if successful, False otherwise
|
303
|
|
- """
|
304
|
|
- sData += "\n"
|
305
|
|
- try:
|
306
|
|
- fc = open(_INPUT_DATA_FILE, "w")
|
307
|
|
- fc.write(sData)
|
308
|
|
- fc.close()
|
309
|
|
- except Exception, exError:
|
310
|
|
- print "%s writeInputDataFile: %s" % (getTimeStamp(), exError)
|
311
|
|
- return False
|
312
|
|
-
|
313
|
|
- return True
|
314
|
|
-##end def
|
315
|
|
-
|
316
|
290
|
def setStationStatus(updateSuccess):
|
317
|
291
|
"""Detect if radiation monitor is offline or not available on
|
318
|
292
|
the network. After a set number of attempts to get data
|
...
|
...
|
@@ -332,13 +306,13 @@ def setStationStatus(updateSuccess):
|
332
|
306
|
print '%s radiation monitor online' % getTimeStamp()
|
333
|
307
|
stationOnline = True
|
334
|
308
|
if debugOption:
|
335
|
|
- print 'radiation update successful'
|
|
309
|
+ print 'data request successful'
|
336
|
310
|
else:
|
337
|
311
|
# The last attempt failed, so update the failed attempts
|
338
|
312
|
# count.
|
339
|
313
|
failedUpdateCount += 1
|
340
|
314
|
if debugOption:
|
341
|
|
- print 'radiation update failed'
|
|
315
|
+ print 'data request failed'
|
342
|
316
|
|
343
|
317
|
if failedUpdateCount >= _MAX_FAILED_DATA_REQUESTS:
|
344
|
318
|
# Max number of failed data requests, so set
|
...
|
...
|
@@ -346,7 +320,6 @@ def setStationStatus(updateSuccess):
|
346
|
320
|
setStatusToOffline()
|
347
|
321
|
##end def
|
348
|
322
|
|
349
|
|
-
|
350
|
323
|
def updateDatabase(dData):
|
351
|
324
|
"""
|
352
|
325
|
Update the rrdtool database by executing an rrdtool system command.
|
...
|
...
|
@@ -386,7 +359,7 @@ def updateDatabase(dData):
|
386
|
359
|
|
387
|
360
|
def createGraph(fileName, dataItem, gLabel, gTitle, gStart,
|
388
|
361
|
lower, upper, addTrend, autoScale):
|
389
|
|
- """Uses rrdtool to create a graph of specified weather data item.
|
|
362
|
+ """Uses rrdtool to create a graph of specified radmon data item.
|
390
|
363
|
Parameters:
|
391
|
364
|
fileName - name of file containing the graph
|
392
|
365
|
dataItem - data item to be graphed
|
...
|
...
|
@@ -438,7 +411,7 @@ def createGraph(fileName, dataItem, gLabel, gTitle, gStart,
|
438
|
411
|
% trendWindow[gStart]
|
439
|
412
|
|
440
|
413
|
if verboseDebug:
|
441
|
|
- print "%s\n" % strCmd # DEBUG
|
|
414
|
+ print "\n%s" % strCmd # DEBUG
|
442
|
415
|
|
443
|
416
|
# Run the formatted rrdtool command as a subprocess.
|
444
|
417
|
try:
|
...
|
...
|
@@ -450,7 +423,7 @@ def createGraph(fileName, dataItem, gLabel, gTitle, gStart,
|
450
|
423
|
return False
|
451
|
424
|
|
452
|
425
|
if debugOption:
|
453
|
|
- print "rrdtool graph: %s" % result
|
|
426
|
+ print "rrdtool graph: %s" % result,
|
454
|
427
|
return True
|
455
|
428
|
|
456
|
429
|
##end def
|
...
|
...
|
@@ -535,7 +508,7 @@ def main():
|
535
|
508
|
## Exit with error if rrdtool database does not exist.
|
536
|
509
|
if not os.path.exists(_RRD_FILE):
|
537
|
510
|
print 'rrdtool database does not exist\n' \
|
538
|
|
- 'use createWeatherRrd script to ' \
|
|
511
|
+ 'use createRadmonRrd script to ' \
|
539
|
512
|
'create rrdtool database\n'
|
540
|
513
|
exit(1)
|
541
|
514
|
|
...
|
...
|
@@ -566,7 +539,6 @@ def main():
|
566
|
539
|
|
567
|
540
|
# If conversion successful, write data to data files.
|
568
|
541
|
if result:
|
569
|
|
- writeInputDataFile(sData)
|
570
|
542
|
writeOutputDataFile(dData)
|
571
|
543
|
|
572
|
544
|
# At the rrdtool database update interval, update the database.
|
...
|
...
|
@@ -592,7 +564,7 @@ def main():
|
592
|
564
|
|
593
|
565
|
elapsedTime = time.time() - currentTime
|
594
|
566
|
if debugOption and not verboseDebug:
|
595
|
|
- print
|
|
567
|
+ pass #print
|
596
|
568
|
if verboseDebug:
|
597
|
569
|
print "processing time: %6f sec\n" % elapsedTime
|
598
|
570
|
remainingTime = dataRequestInterval - elapsedTime
|