... | ... |
@@ -38,6 +38,8 @@ |
38 | 38 |
# status page and parsed the signal data from the html. |
39 | 39 |
# * v23 released 11 Jun 2021 by J L Owrey; remove unused code. |
40 | 40 |
# * v24 released 14 Jun 2021 by J L Owrey; minor revisions |
41 |
+# * v25 released 9 Jul 2021 by J L Owrey; improved handling of |
|
42 |
+# node status function |
|
41 | 43 |
# |
42 | 44 |
#2345678901234567890123456789012345678901234567890123456789012345678901234567890 |
43 | 45 |
|
... | ... |
@@ -59,7 +61,8 @@ _SERVER_MODE = "primary" |
59 | 61 |
|
60 | 62 |
# set url of the aredn node |
61 | 63 |
|
62 |
-_DEFAULT_AREDN_NODE_URL = "{your AREDN mesh node url" |
|
64 |
+_DEFAULT_AREDN_NODE_URL = \ |
|
65 |
+ "{your node url}" |
|
63 | 66 |
|
64 | 67 |
### FILE AND FOLDER LOCATIONS ### |
65 | 68 |
|
... | ... |
@@ -101,7 +104,7 @@ debugMode = False |
101 | 104 |
# count of failed attempts to get data from aredn node |
102 | 105 |
failedUpdateCount = 0 |
103 | 106 |
# detected status of aredn node device |
104 |
-nodeOnline = True |
|
107 |
+nodeOnline = False |
|
105 | 108 |
|
106 | 109 |
# ip address of aredn node |
107 | 110 |
arednNodeUrl = _DEFAULT_AREDN_NODE_URL |
... | ... |
@@ -165,10 +168,8 @@ def terminateAgentProcess(signal, frame): |
165 | 168 |
signal, frame - dummy parameters |
166 | 169 |
Returns: nothing |
167 | 170 |
""" |
168 |
- # Inform downstream clients by removing output data file. |
|
169 |
- if os.path.exists(_OUTPUT_DATA_FILE): |
|
170 |
- os.remove(_OUTPUT_DATA_FILE) |
|
171 | 171 |
print('%s terminating arednsig agent process' % getTimeStamp()) |
172 |
+ setStatusToOffline() |
|
172 | 173 |
sys.exit(0) |
173 | 174 |
##end def |
174 | 175 |
|
... | ... |
@@ -183,12 +184,8 @@ def getNodeData(dData): |
183 | 184 |
""" |
184 | 185 |
try: |
185 | 186 |
currentTime = time.time() |
186 |
- |
|
187 | 187 |
response = urlopen(arednNodeUrl, timeout=_HTTP_REQUEST_TIMEOUT) |
188 |
- |
|
189 |
- if verboseMode: |
|
190 |
- requestTime = time.time() - currentTime |
|
191 |
- print("http request: %.4f seconds" % requestTime) |
|
188 |
+ requestTime = time.time() - currentTime |
|
192 | 189 |
|
193 | 190 |
content = response.read().decode('utf-8') |
194 | 191 |
content = content.replace('\n', '') |
... | ... |
@@ -206,9 +203,10 @@ def getNodeData(dData): |
206 | 203 |
|
207 | 204 |
if debugMode: |
208 | 205 |
print(content) |
206 |
+ if verboseMode: |
|
207 |
+ print("http request successful: %.4f sec" % requestTime) |
|
209 | 208 |
|
210 | 209 |
dData['content'] = content |
211 |
- |
|
212 | 210 |
return True |
213 | 211 |
##end def |
214 | 212 |
|
... | ... |
@@ -237,14 +235,19 @@ def parseDataString(dData): |
237 | 235 |
snr = snr.replace(' ','') |
238 | 236 |
lsnr = snr.split('/') |
239 | 237 |
|
240 |
- dData['time'] = getEpochSeconds(getTimeStamp()) |
|
241 | 238 |
dData['signal'] = lsnr[0] |
242 | 239 |
dData['noise'] = lsnr[1] |
243 | 240 |
dData['snr'] = lsnr[2] |
244 |
- |
|
245 | 241 |
except Exception as exError: |
246 | 242 |
print("%s parse failed: %s" % (getTimeStamp(), exError)) |
247 | 243 |
return False |
244 |
+ ## end try |
|
245 |
+ |
|
246 |
+ # Add status information to dictionary object. |
|
247 |
+ dData['date'] = getTimeStamp() |
|
248 |
+ dData['chartUpdateInterval'] = chartUpdateInterval |
|
249 |
+ dData['dataRequestInterval'] = dataRequestInterval |
|
250 |
+ dData['serverMode'] = _SERVER_MODE |
|
248 | 251 |
|
249 | 252 |
return True |
250 | 253 |
##end def |
... | ... |
@@ -262,16 +265,12 @@ def writeOutputFile(dData): |
262 | 265 |
# data items are sent to the client file. |
263 | 266 |
# * The last database update date and time |
264 | 267 |
# * The data request interval |
265 |
- lastUpdate = time.strftime( "%m.%d.%Y %T", |
|
266 |
- time.localtime(dData['time']) ) |
|
267 | 268 |
|
268 | 269 |
# Format data into a JSON string. |
269 | 270 |
jsData = json.loads("{}") |
270 | 271 |
try: |
271 |
- jsData.update({"date": lastUpdate}) |
|
272 |
- jsData.update({"chartUpdateInterval": chartUpdateInterval}) |
|
273 |
- jsData.update({"dataRequestInterval": dataRequestInterval}) |
|
274 |
- jsData.update({"serverMode": _SERVER_MODE}) |
|
272 |
+ for key in dData: |
|
273 |
+ jsData.update({key:dData[key]}) |
|
275 | 274 |
sData = "[%s]" % json.dumps(jsData) |
276 | 275 |
except Exception as exError: |
277 | 276 |
print("%s writeOutputFile: %s" % (getTimeStamp(), exError)) |
... | ... |
@@ -291,6 +290,35 @@ def writeOutputFile(dData): |
291 | 290 |
return True |
292 | 291 |
## end def |
293 | 292 |
|
293 |
+def setNodeStatus(updateSuccess): |
|
294 |
+ """Detect if aredn node is offline or not available on |
|
295 |
+ the network. After a set number of attempts to get data |
|
296 |
+ from the node set a flag that the node is offline. |
|
297 |
+ Parameters: |
|
298 |
+ updateSuccess - a boolean that is True if data request |
|
299 |
+ successful, False otherwise |
|
300 |
+ Returns: nothing |
|
301 |
+ """ |
|
302 |
+ global failedUpdateCount, nodeOnline |
|
303 |
+ |
|
304 |
+ if updateSuccess: |
|
305 |
+ failedUpdateCount = 0 |
|
306 |
+ # Set status and send a message to the log if the device |
|
307 |
+ # previously offline and is now online. |
|
308 |
+ if not nodeOnline: |
|
309 |
+ print('%s node online' % getTimeStamp()) |
|
310 |
+ nodeOnline = True |
|
311 |
+ return |
|
312 |
+ elif failedUpdateCount == _MAX_FAILED_DATA_REQUESTS - 1: |
|
313 |
+ # Max number of failed data requests, so set |
|
314 |
+ # device status to offline. |
|
315 |
+ setStatusToOffline() |
|
316 |
+ ## end if |
|
317 |
+ failedUpdateCount += 1 |
|
318 |
+##end def |
|
319 |
+ |
|
320 |
+ ### DATABASE FUNCTIONS ### |
|
321 |
+ |
|
294 | 322 |
def updateDatabase(dData): |
295 | 323 |
""" |
296 | 324 |
Update the rrdtool database by executing an rrdtool system command. |
... | ... |
@@ -300,9 +328,12 @@ def updateDatabase(dData): |
300 | 328 |
written to the rr database file |
301 | 329 |
Returns: True if successful, False otherwise |
302 | 330 |
""" |
331 |
+ |
|
332 |
+ time = getEpochSeconds(dData['date']) |
|
333 |
+ |
|
303 | 334 |
# Format the rrdtool update command. |
304 | 335 |
strFmt = "rrdtool update %s %s:%s:%s:%s:%s:%s:%s:%s" |
305 |
- strCmd = strFmt % (_RRD_FILE, dData['time'], dData['signal'], \ |
|
336 |
+ strCmd = strFmt % (_RRD_FILE, time, dData['signal'], \ |
|
306 | 337 |
dData['noise'], dData['snr'], '0', \ |
307 | 338 |
'0', '0', '0') |
308 | 339 |
|
... | ... |
@@ -319,40 +350,11 @@ def updateDatabase(dData): |
319 | 350 |
return False |
320 | 351 |
|
321 | 352 |
if verboseMode and not debugMode: |
322 |
- print("database updated") |
|
353 |
+ print("database update successful") |
|
323 | 354 |
|
324 | 355 |
return True |
325 | 356 |
##end def |
326 | 357 |
|
327 |
-def setNodeStatus(updateSuccess): |
|
328 |
- """Detect if aredn node is offline or not available on |
|
329 |
- the network. After a set number of attempts to get data |
|
330 |
- from the node set a flag that the node is offline. |
|
331 |
- Parameters: |
|
332 |
- updateSuccess - a boolean that is True if data request |
|
333 |
- successful, False otherwise |
|
334 |
- Returns: nothing |
|
335 |
- """ |
|
336 |
- global failedUpdateCount, nodeOnline |
|
337 |
- |
|
338 |
- if updateSuccess: |
|
339 |
- failedUpdateCount = 0 |
|
340 |
- # Set status and send a message to the log if the node was |
|
341 |
- # previously offline and is now online. |
|
342 |
- if not nodeOnline: |
|
343 |
- print('%s aredn node online' % getTimeStamp()) |
|
344 |
- nodeOnline = True |
|
345 |
- else: |
|
346 |
- # The last attempt failed, so update the failed attempts |
|
347 |
- # count. |
|
348 |
- failedUpdateCount += 1 |
|
349 |
- |
|
350 |
- if failedUpdateCount > _MAX_FAILED_DATA_REQUESTS: |
|
351 |
- # Max number of failed data requests, so set |
|
352 |
- # node status to offline. |
|
353 |
- setStatusToOffline() |
|
354 |
-##end def |
|
355 |
- |
|
356 | 358 |
def createGraph(fileName, dataItem, gLabel, gTitle, gStart, |
357 | 359 |
lower, upper, addTrend, autoScale): |
358 | 360 |
"""Uses rrdtool to create a graph of specified node data item. |
... | ... |
@@ -513,6 +515,7 @@ def main(): |
513 | 515 |
signal.signal(signal.SIGTERM, terminateAgentProcess) |
514 | 516 |
signal.signal(signal.SIGINT, terminateAgentProcess) |
515 | 517 |
|
518 |
+ print('===================') |
|
516 | 519 |
print('%s starting up arednsig agent process' % \ |
517 | 520 |
(getTimeStamp())) |
518 | 521 |
|
... | ... |
@@ -568,7 +571,7 @@ def main(): |
568 | 571 |
if currentTime - lastChartUpdateTime > chartUpdateInterval: |
569 | 572 |
lastChartUpdateTime = currentTime |
570 | 573 |
p = multiprocessing.Process(target=generateGraphs, args=()) |
571 |
- p.start() |
|
574 |
+ #p.start() |
|
572 | 575 |
|
573 | 576 |
# Relinquish processing back to the operating system until |
574 | 577 |
# the next update interval. |
... | ... |
@@ -576,9 +579,9 @@ def main(): |
576 | 579 |
elapsedTime = time.time() - currentTime |
577 | 580 |
if verboseMode: |
578 | 581 |
if result: |
579 |
- print("update successful: %s sec" % elapsedTime) |
|
582 |
+ print("update successful: %s sec\n" % elapsedTime) |
|
580 | 583 |
else: |
581 |
- print("update failed: %s sec" % elapsedTime) |
|
584 |
+ print("update failed: %s sec\n" % elapsedTime) |
|
582 | 585 |
remainingTime = dataRequestInterval - elapsedTime |
583 | 586 |
if remainingTime > 0.0: |
584 | 587 |
time.sleep(remainingTime) |
... | ... |
@@ -231,6 +231,7 @@ function main() { |
231 | 231 |
initializeDateSelector(); |
232 | 232 |
getNodeData(); |
233 | 233 |
getNodeCharts(); |
234 |
+ setInterval(getNodeData, 10000); |
|
234 | 235 |
} |
235 | 236 |
|
236 | 237 |
function getNodeData() { |
... | ... |
@@ -292,23 +293,19 @@ function displayData(dataItem) { |
292 | 293 |
statusElmt.innerHTML = "Online"; |
293 | 294 |
statusElmt.style.color = "green"; |
294 | 295 |
|
295 |
- chartUpdateInterval = dataItem.chartUpdateInterval; |
|
296 |
- dataRequestInterval = dataItem.dataRequestInterval; |
|
296 |
+ chartUpdateInterval = dataItem.chartUpdateInterval; |
|
297 | 297 |
periodElmt.innerHTML = chartUpdateInterval / 60; |
298 |
- setInterval(getNodeData, 1000 * dataRequestInterval); |
|
299 | 298 |
setInterval(getNodeCharts, 1000 * chartUpdateInterval); |
300 | 299 |
} |
301 | 300 |
|
302 | 301 |
function displayOfflineStatus() { |
302 |
+ var localTimeZone; |
|
303 | 303 |
var d = new Date(); |
304 |
- localTimeZone = d.getTimezoneOffset() / 60; |
|
305 |
- dateElmt.innerHTML = (d.getMonth() + 1) + "/" + d.getDate() + "/" + |
|
306 |
- d.getFullYear(); |
|
307 |
- timeElmt.innerHTML = d.getHours() + ":" + d.getMinutes() + |
|
308 |
- " <small>(GMT+" + localTimeZone + ")</small>"; |
|
309 |
- periodElmt.innerHTML = "?"; |
|
304 |
+ |
|
310 | 305 |
statusElmt.innerHTML = "offline"; |
311 | 306 |
statusElmt.style.color = "red"; |
307 |
+ |
|
308 |
+ periodElmt.innerHTML = "?"; |
|
312 | 309 |
} |
313 | 310 |
|
314 | 311 |
function initializeDateSelector() { |