Browse code

support for Aredn FW v3.20.3.0

gandolf authored on 03/31/2020 17:37:45
Showing 10 changed files
... ...
@@ -1,8 +1,8 @@
1 1
 <html>
2 2
 <body>
3
-<h4>Ardensig - Monitor your Node's Performance</h4>
3
+<h4>Arednsig - Monitor your Node's Performance</h4>
4 4
 <p>
5
-Ardensig enables you to view your node's received signal strength and signal to noise ratio for any time period stored in the database.  Ardensig uses a "round-robin" database to store up to years worth of data.  Once you install Arednsig it begins keeping a database.  You can use the web browser to create charts of any time period after installing Arednsig.
5
+Arednsig enables you to view your node's received signal strength and signal to noise ratio for any time period stored in the database.  Arednsig uses a "round-robin" database to store up to years worth of data.  Once you install Arednsig it begins keeping a database.  You can use the web browser to create charts of any time period after installing Arednsig.
6 6
 </p>
7 7
 <p>
8 8
 Installing and using Arednsig will give you an excellent introduction to Linux "devops".  You will learn about Linux server software systems and architecture, scripting for Internet applications, and displaying information in a web page.
... ...
@@ -11,5 +11,13 @@ Installing and using Arednsig will give you an excellent introduction to Linux "
11 11
 You can find all the required software available under open source, GNU license on this project site.  Please read the
12 12
  <a href="docs/Arednsig-Installation.pdf">installation instructions</a> for details on how to install Arednsig.
13 13
 </p>
14
+<p>
15
+Currently two versions of the Aredn firmware are supported by the Arednsig application
16
+<ul>
17
+<li>3.19.3.0</li>
18
+<li>3.20.3.0</li>
19
+</ul>
20
+Please download the software from the appropriate folder.
21
+</p> 
14 22
 </body>
15 23
 </html>
16 24
deleted file mode 100755
... ...
@@ -1,27 +0,0 @@
1
-#!/bin/bash
2
-#
3
-# The monitor url can look something like http://192.168.1.155, or
4
-# something linke http://radiationMonitor.domain.com depending on
5
-# whether your local network uses a domain name server.
6
-#
7
-
8
-APP_PATH="/home/$USER/bin"
9
-LOG_PATH="/home/$USER/log"
10
-
11
-AGENT_NAME="[a]rednsigAgent.py"
12
-NODE_URL="http://localnode:8080/cgi-bin/signal.json"
13
-
14
-POLLING_INTERVAL="60"
15
-
16
-PROCESS_ID="$(ps x | awk -v a=$AGENT_NAME '$7 ~ a {print $1}')"
17
-
18
-if [ -n "$PROCESS_ID" ]; then
19
-  if [ "$1" != "-q" ]; then
20
-    printf "arednsig agent running [%s]\n" $PROCESS_ID
21
-  fi
22
-else
23
-  printf "starting up arednsig agent\n"
24
-  cd $APP_PATH
25
-  $(./$AGENT_NAME -u $NODE_URL -p $POLLING_INTERVAL >> \
26
- $LOG_PATH/arednsigAgent.log 2>&1 &)
27
-fi
28 0
deleted file mode 100755
... ...
@@ -1,14 +0,0 @@
1
-#!/bin/bash
2
-# Stop the radmon agent process and clean up environment.
3
-
4
-
5
-AGENT_NAME="[a]rednsigAgent.py"
6
-
7
-PROCESS_ID="$(ps x | awk -v a=$AGENT_NAME '$7 ~ a {print $1}')"
8
-
9
-if [ -n "$PROCESS_ID" ]; then
10
-  printf "killing arednsig agent [%s]\n" $PROCESS_ID
11
-  kill $PROCESS_ID
12
-else
13
-  echo arednsig agent not running
14
-fi
15 0
deleted file mode 100755
... ...
@@ -1,704 +0,0 @@
1
-#!/usr/bin/python -u
2
-# The -u option above turns off block buffering of python output. This 
3
-# assures that each error message gets individually printed to the log file.
4
-#
5
-# Module: arednsigAgent.py
6
-#
7
-# Description: This module acts as an agent between the aredn node
8
-# and aredn mest services.  The agent periodically sends an http
9
-# request to the aredn node, processes the response from
10
-# the node, and performs a number of operations:
11
-#     - conversion of data items
12
-#     - update a round robin (rrdtool) database with the node data
13
-#     - periodically generate graphic charts for display in html documents
14
-#     - write the processed node status to a JSON file for use by html
15
-#       documents
16
-#
17
-# Copyright 2020 Jeff Owrey
18
-#    This program is free software: you can redistribute it and/or modify
19
-#    it under the terms of the GNU General Public License as published by
20
-#    the Free Software Foundation, either version 3 of the License, or
21
-#    (at your option) any later version.
22
-#
23
-#    This program is distributed in the hope that it will be useful,
24
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
25
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
-#    GNU General Public License for more details.
27
-#
28
-#    You should have received a copy of the GNU General Public License
29
-#    along with this program.  If not, see http://www.gnu.org/license.
30
-#
31
-# Revision History
32
-#   * v20 released 11 Jan 2020 by J L Owrey; first release
33
-#   * v21 released 13 Feb 2020 by J L Owrey; fixed bug occuring when node
34
-#     powers on and signal data memory is empty.  Data points with N/A data
35
-#     are discarded.
36
-#
37
-#2345678901234567890123456789012345678901234567890123456789012345678901234567890
38
-
39
-import os
40
-import urllib2
41
-import sys
42
-import signal
43
-import subprocess
44
-import multiprocessing
45
-import time
46
-import json
47
-
48
-_USER = os.environ['USER']
49
-_HOSTNAME = os.uname()[1]
50
-
51
-   ### DEFAULT AREDN NODE URL ###
52
-
53
-# set url of the aredn node
54
-
55
-_DEFAULT_AREDN_NODE_URL = "http://localnode:8080/cgi-bin/signal.json"
56
-
57
-if _HOSTNAME == "raspi2": 
58
-    _DEFAULT_AREDN_NODE_URL = "http://192.168.1.30:8080/cgi-bin/signal.json"
59
-
60
-    ### FILE AND FOLDER LOCATIONS ###
61
-
62
-# folder for containing dynamic data objects
63
-_DOCROOT_PATH = "/home/%s/public_html/arednsig/" % _USER
64
-# folder for charts and output data file
65
-_CHARTS_DIRECTORY = _DOCROOT_PATH + "dynamic/"
66
-# location of data output file
67
-_OUTPUT_DATA_FILE = _DOCROOT_PATH + "dynamic/arednsigOutputData.js"
68
-# dummy output data file
69
-_DUMMY_OUTPUT_FILE = _DOCROOT_PATH + "dynamic/nodeOnline.js"
70
-# database that stores node data
71
-_RRD_FILE = "/home/%s/database/arednsigData.rrd" % _USER
72
-
73
-    ### GLOBAL CONSTANTS ###
74
-
75
-# max number of failed data requests allowed
76
-_MAX_FAILED_DATA_REQUESTS = 0
77
-# interval in minutes between data requests to the aredn node
78
-_DEFAULT_DATA_REQUEST_INTERVAL = 60
79
-# number seconds to wait for a response to HTTP request
80
-_HTTP_REQUEST_TIMEOUT = 10
81
-# standard chart width in pixels
82
-_CHART_WIDTH = 600
83
-# standard chart height in pixels
84
-_CHART_HEIGHT = 150
85
-# Set this to True only if this server is intended to relay raw
86
-# node data to a mirror server.
87
-_RELAY_SERVER = False
88
-
89
-   ### GLOBAL VARIABLES ###
90
-
91
-# turn on or off of verbose debugging information
92
-debugOption = False
93
-verboseDebug = False
94
-
95
-# The following two items are used for detecting system faults
96
-# and aredn node online or offline status.
97
-
98
-# count of failed attempts to get data from aredn node
99
-failedUpdateCount = 0
100
-# detected status of aredn node device
101
-nodeOnline = True
102
-
103
-# ip address of aredn node
104
-arednNodeUrl = _DEFAULT_AREDN_NODE_URL
105
-# frequency of data requests to aredn node
106
-dataRequestInterval = _DEFAULT_DATA_REQUEST_INTERVAL
107
-# last node request time
108
-lastDataPointTime = -1
109
-
110
-  ###  PRIVATE METHODS  ###
111
-
112
-def getTimeStamp():
113
-    """
114
-    Set the error message time stamp to the local system time.
115
-    Parameters: none
116
-    Returns: string containing the time stamp
117
-    """
118
-    return time.strftime( "%m/%d/%Y %T", time.localtime() )
119
-##end def
120
-
121
-def getLastDataPointTime():
122
-    """
123
-    Get the timestamp of the most recent update to the round robin
124
-    database.
125
-    Parameters: none
126
-    Returns: string epoch time stamp of the last rrd update
127
-    """
128
-    strCmd = "rrdtool lastupdate %s" % \
129
-             (_RRD_FILE)
130
-
131
-    # Run the command as a subprocess.
132
-    try:
133
-        result = subprocess.check_output(strCmd, shell=True,  \
134
-                             stderr=subprocess.STDOUT)
135
-    except subprocess.CalledProcessError, exError:
136
-        print "%s: rrdtool update failed: %s" % \
137
-                    (getTimeStamp(), exError.output)
138
-        return None
139
-
140
-    # Return just the epoch time stamp of the last rrd update
141
-    return int((result.split('\n')[-2]).split(':')[0])
142
-##end def
143
-
144
-def setStatusToOffline():
145
-    """Set the detected status of the aredn node to
146
-       "offline" and inform downstream clients by removing input
147
-       and output data files.
148
-       Parameters: none
149
-       Returns: nothing
150
-    """
151
-    global nodeOnline
152
-
153
-    # Inform downstream clients by removing output data file.
154
-    if os.path.exists(_OUTPUT_DATA_FILE):
155
-       os.remove(_OUTPUT_DATA_FILE)
156
-    if os.path.exists(_DUMMY_OUTPUT_FILE):
157
-       os.remove(_DUMMY_OUTPUT_FILE)
158
-    # If the aredn node was previously online, then send
159
-    # a message that we are now offline.
160
-    if nodeOnline:
161
-        print '%s aredn node offline' % getTimeStamp()
162
-    nodeOnline = False
163
-##end def
164
-
165
-def terminateAgentProcess(signal, frame):
166
-    """Send a message to log when the agent process gets killed
167
-       by the operating system.  Inform downstream clients
168
-       by removing input and output data files.
169
-       Parameters:
170
-           signal, frame - dummy parameters
171
-       Returns: nothing
172
-    """
173
-    # Inform downstream clients by removing output data file.
174
-    if os.path.exists(_OUTPUT_DATA_FILE):
175
-       os.remove(_OUTPUT_DATA_FILE)
176
-    if os.path.exists(_DUMMY_OUTPUT_FILE):
177
-       os.remove(_DUMMY_OUTPUT_FILE)
178
-    print '%s terminating arednsig agent process' % \
179
-              (getTimeStamp())
180
-    sys.exit(0)
181
-##end def
182
-
183
-  ###  PUBLIC METHODS  ###
184
-
185
-def getArednNodeData():
186
-    """Send http request to aredn node.  The response from the
187
-       node contains the node signal data as unformatted ascii text.
188
-       Parameters: none
189
-       Returns: a string containing the node signal data if successful,
190
-                or None if not successful
191
-    """
192
-    try:
193
-        conn = urllib2.urlopen(arednNodeUrl, timeout=_HTTP_REQUEST_TIMEOUT)
194
-
195
-        # Format received data into a single string.
196
-        content = ""
197
-        for line in conn:
198
-            content += line.strip()
199
-        del conn
200
-
201
-    except Exception, exError:
202
-        # If no response is received from the device, then assume that
203
-        # the device is down or unavailable over the network.  In
204
-        # that case return None to the calling function.
205
-        print "%s http error: %s" % (getTimeStamp(), exError)
206
-        return None
207
-
208
-    if verboseDebug:
209
-        print "http request successful: %d bytes" % len(content)
210
-
211
-    return content
212
-##end def
213
-
214
-def parseNodeData(sData, ldData):
215
-    """Parse the node  signal data JSON string from the aredn node
216
-       into its component parts.  
217
-       Parameters:
218
-           sData - the string containing the data to be parsed
219
-           dData - a dictionary object to contain the parsed data items
220
-       Returns: True if successful, False otherwise
221
-    """
222
-    iTrail = int(dataRequestInterval)
223
-
224
-    try:
225
-        ldTmp = json.loads(sData[1:-1])
226
-        ldTmp = ldTmp[-iTrail:]
227
-        if len(ldTmp) != iTrail:
228
-            #raise Exception("truncated list")
229
-            pass
230
-    except Exception, exError:
231
-        print "%s parse failed: %s" % (getTimeStamp(), exError)
232
-        return False
233
-    
234
-    del ldData[:]
235
-    for item in ldTmp:
236
-        ldData.append(item)
237
-
238
-    if verboseDebug:
239
-        print "parse successful: %d data points" % len(ldData)
240
-    return True
241
-##end def
242
-
243
-def convertData(ldData):
244
-    """Convert individual node signal data items as necessary.
245
-       Parameters:
246
-           dData - a dictionary object containing the node signal data
247
-       Returns: True if successful, False otherwise
248
-    """
249
-    # parse example string
250
-    # {u'tx_mcs': u'15', u'rx_mcs': u'15', u'm': 47,
251
-    #  u'label': u'01/10/2020 22:17:01', u'rx_rate': u'130',
252
-    #  u'y': [-48, -95], u'x': 1578694621000, u'tx_rate': u'130'}
253
-    #
254
-    index = 0
255
-    while index < len(ldData):
256
-        item = ldData[index]
257
-        try:
258
-            item['time'] = int(item.pop('x')) / 1000
259
-            item['signal'] = int(item['y'][0])
260
-            item['noise'] = int(item['y'][1])
261
-            item['snr'] = int(item.pop('m'))
262
-            item['rx_mcs'] = int(item.pop('rx_mcs'))
263
-            item['tx_mcs'] = int(item.pop('tx_mcs'))
264
-            item['rx_rate'] = int(item.pop('rx_rate'))
265
-            item['tx_rate'] = int(item.pop('tx_rate'))
266
-            item.pop('y')
267
-            item.pop('label')
268
-        except Exception, exError:
269
-            print "%s convert data item failed: %s" % (getTimeStamp(), exError)
270
-            print "discarding %s" % item
271
-            #return False
272
-            ldData.pop(index)
273
-        else:
274
-            index += 1
275
-    ##end for
276
-
277
-    if len(ldData) > 0:
278
-        if verboseDebug:
279
-            print "convert data successful"
280
-        return True
281
-    else:
282
-        print "convert data failed"
283
-        return False
284
-##end def
285
-
286
-def updateDatabase(ldData):
287
-    """
288
-    Update the rrdtool database by executing an rrdtool system command.
289
-    Format the command using the data extracted from the aredn node
290
-    response.   
291
-    Parameters: dData - dictionary object containing data items to be
292
-                        written to the rr database file
293
-    Returns: True if successful, False otherwise
294
-    """
295
-    updateCount = 0
296
-    lastDataPointTime = getLastDataPointTime()
297
-
298
-    if verboseDebug:
299
-         print "updating database..."
300
-
301
-    for item in ldData:
302
-
303
-        if item['time'] <= lastDataPointTime:
304
-            if verboseDebug:
305
-                print "%s invalid timestamp: discarding data" % \
306
-                      (getTimeStamp())
307
-            continue
308
-
309
-        # Format the rrdtool update command.
310
-        strFmt = "rrdtool update %s %s:%s:%s:%s:%s:%s:%s:%s"
311
-        strCmd = strFmt % (_RRD_FILE, item['time'], item['signal'], \
312
-                 item['noise'], item['snr'], item['rx_mcs'], \
313
-                 item['tx_mcs'], item['rx_rate'], item['tx_rate'])
314
-
315
-        if verboseDebug:
316
-            print "%s" % strCmd # DEBUG
317
-
318
-        # Run the command as a subprocess.
319
-        try:
320
-            subprocess.check_output(strCmd, shell=True,  \
321
-                                 stderr=subprocess.STDOUT)
322
-        except subprocess.CalledProcessError, exError:
323
-            print "%s: rrdtool update failed: %s" % \
324
-                        (getTimeStamp(), exError.output)
325
-            return False
326
-        updateCount += 1
327
-    ##end for
328
-
329
-    if debugOption:
330
-        print '%s added %d data points to database' % \
331
-              (getTimeStamp(), updateCount)
332
-    return True
333
-##end def
334
-
335
-def writeOutputDataFile(sData, ldData):
336
-    """Write node data items to the output data file, formatted as 
337
-       a Javascript file.  This file may then be accessed and used by
338
-       by downstream clients, for instance, in HTML documents.
339
-       Parameters:
340
-           sData - a string object containing the data to be written
341
-                   to the output data file
342
-       Returns: True if successful, False otherwise
343
-    """
344
-    # Write file for use by html clients.  The following two
345
-    # data items are sent to the client file.
346
-    #    * The last database update date and time
347
-    #    * The data request interval
348
-    lastUpdate = time.strftime( "%m.%d.%Y %T", 
349
-                                time.localtime(ldData[-1]['time']) )
350
-    sDate = "[{\"date\":\"%s\",\"period\":\"%s\"}]" % \
351
-           (lastUpdate, dataRequestInterval)
352
-    try:
353
-        fc = open(_DUMMY_OUTPUT_FILE, "w")
354
-        fc.write(sDate)
355
-        fc.close()
356
-    except Exception, exError:
357
-        print "%s write node file failed: %s" % (getTimeStamp(), exError)
358
-        return False
359
-
360
-    if _RELAY_SERVER:
361
-        # Write the entire node data response to the output data file.
362
-        try:
363
-            fc = open(_OUTPUT_DATA_FILE, "w")
364
-            fc.write(sData)
365
-            fc.close()
366
-        except Exception, exError:
367
-            print "%s write output file failed: %s" % \
368
-                  (getTimeStamp(), exError)
369
-            return False
370
-        if verboseDebug:
371
-            print "write output data file: %d bytes" % len(sData)
372
-
373
-    return True
374
-## end def
375
-
376
-def setNodeStatus(updateSuccess):
377
-    """Detect if aredn node is offline or not available on
378
-       the network. After a set number of attempts to get data
379
-       from the node set a flag that the node is offline.
380
-       Parameters:
381
-           updateSuccess - a boolean that is True if data request
382
-                           successful, False otherwise
383
-       Returns: nothing
384
-    """
385
-    global failedUpdateCount, nodeOnline
386
-
387
-    if updateSuccess:
388
-        failedUpdateCount = 0
389
-        # Set status and send a message to the log if the node was
390
-        # previously offline and is now online.
391
-        if not nodeOnline:
392
-            print '%s aredn node online' % getTimeStamp()
393
-            nodeOnline = True
394
-    else:
395
-        # The last attempt failed, so update the failed attempts
396
-        # count.
397
-        failedUpdateCount += 1
398
-
399
-    if failedUpdateCount > _MAX_FAILED_DATA_REQUESTS:
400
-        # Max number of failed data requests, so set
401
-        # node status to offline.
402
-        setStatusToOffline()
403
-##end def
404
-
405
-def createGraph(fileName, dataItem, gLabel, gTitle, gStart,
406
-                lower, upper, addTrend, autoScale):
407
-    """Uses rrdtool to create a graph of specified node data item.
408
-       Parameters:
409
-           fileName - name of file containing the graph
410
-           dataItem - data item to be graphed
411
-           gLabel - string containing a graph label for the data item
412
-           gTitle - string containing a title for the graph
413
-           gStart - beginning time of the graphed data
414
-           lower - lower bound for graph ordinate #NOT USED
415
-           upper - upper bound for graph ordinate #NOT USED
416
-           addTrend - 0, show only graph data
417
-                      1, show only a trend line
418
-                      2, show a trend line and the graph data
419
-           autoScale - if True, then use vertical axis auto scaling
420
-               (lower and upper parameters are ignored), otherwise use
421
-               lower and upper parameters to set vertical axis scale
422
-       Returns: True if successful, False otherwise
423
-    """
424
-    gPath = _CHARTS_DIRECTORY + fileName + ".png"
425
-    trendWindow = { 'end-1day': 7200,
426
-                    'end-4weeks': 172800,
427
-                    'end-12months': 604800 }
428
- 
429
-    # Format the rrdtool graph command.
430
-
431
-    # Set chart start time, height, and width.
432
-    strCmd = "rrdtool graph %s -a PNG -s %s -e now -w %s -h %s " \
433
-             % (gPath, gStart, _CHART_WIDTH, _CHART_HEIGHT)
434
-   
435
-    # Set the range and scaling of the chart y-axis.
436
-    if lower < upper:
437
-        strCmd  +=  "-l %s -u %s -r " % (lower, upper)
438
-    elif autoScale:
439
-        strCmd += "-A "
440
-    strCmd += "-Y "
441
-
442
-    # Set the chart ordinate label and chart title. 
443
-    strCmd += "-v %s -t %s " % (gLabel, gTitle)
444
- 
445
-    # Show the data, or a moving average trend line over
446
-    # the data, or both.
447
-    strCmd += "DEF:dSeries=%s:%s:LAST " % (_RRD_FILE, dataItem)
448
-    if addTrend == 0:
449
-        strCmd += "LINE1:dSeries#0400ff "
450
-    elif addTrend == 1:
451
-        strCmd += "CDEF:smoothed=dSeries,%s,TREND LINE3:smoothed#ff0000 " \
452
-                  % trendWindow[gStart]
453
-    elif addTrend == 2:
454
-        strCmd += "LINE1:dSeries#0400ff "
455
-        strCmd += "CDEF:smoothed=dSeries,%s,TREND LINE3:smoothed#ff0000 " \
456
-                  % trendWindow[gStart]
457
-     
458
-    if verboseDebug:
459
-        print "%s" % strCmd # DEBUG
460
-    
461
-    # Run the formatted rrdtool command as a subprocess.
462
-    try:
463
-        result = subprocess.check_output(strCmd, \
464
-                     stderr=subprocess.STDOUT,   \
465
-                     shell=True)
466
-    except subprocess.CalledProcessError, exError:
467
-        print "rrdtool graph failed: %s" % (exError.output)
468
-        return False
469
-
470
-    if debugOption:
471
-        print "rrdtool graph: %s\n" % result,
472
-    return True
473
-
474
-##end def
475
-
476
-def generateGraphs():
477
-    """Generate graphs for display in html documents.
478
-       Parameters: none
479
-       Returns: nothing
480
-    """
481
-    autoScale = False
482
-
483
-    # The following will force creation of charts
484
-    # of only signal strength and S/N charts.  Note that the following
485
-    # data items appear constant and do not show variation with time:
486
-    # noise level, rx mcs, rx rate, tx mcs, tx rate.  Therefore, until
487
-    # these parameters are demonstrated to vary in time, there is no point
488
-    # in creating the charts for these data items.
489
-    createAllCharts = False
490
-
491
-    # 24 hour stock charts
492
-
493
-    createGraph('24hr_signal', 'S', 'dBm', 
494
-                'RSSI\ -\ Last\ 24\ Hours', 'end-1day', 0, 0, 2, autoScale)
495
-    createGraph('24hr_snr', 'SNR', 'dB', 
496
-                'SNR\ -\ Last\ 24\ Hours', 'end-1day', 0, 0, 2, autoScale)
497
-
498
-    if createAllCharts:
499
-        createGraph('24hr_noise', 'N', 'dBm', 
500
-                    'Noise\ -\ Last\ 24\ Hours', 'end-1day', 0, 0, 2,
501
-                    autoScale)
502
-        createGraph('24hr_rx_rate', 'RX_RATE', 'Mbps',
503
-                    'Rx\ Rate\ -\ Last\ 24\ Hours', 'end-1day', 0, 0, 2,
504
-                    autoScale)
505
-        createGraph('24hr_tx_rate', 'TX_RATE', 'Mbps',
506
-                    'Tx\ Rate\ -\ Last\ 24\ Hours', 'end-1day', 0, 0, 2,
507
-                    autoScale)
508
-        createGraph('24hr_rx_mcs', 'RX_MCS', 'Index',
509
-                    'Rx\ MCS\ -\ Last\ 24\ Hours', 'end-1day', 0, 0, 2,
510
-                     autoScale)
511
-        createGraph('24hr_tx_mcs', 'TX_MCS', 'Index',
512
-                    'Tx\ MCS\ -\ Last\ 24\ Hours', 'end-1day', 0, 0, 2,
513
-                     autoScale)
514
-
515
-    # 4 week stock charts
516
-
517
-    createGraph('4wk_signal', 'S', 'dBm', 
518
-                'RSSI\ -\ Last\ 4\ Weeks', 'end-4weeks', 0, 0, 2, autoScale)
519
-    createGraph('4wk_snr', 'SNR', 'dB', 
520
-                'SNR\ -\ Last\ 4\ Weeks', 'end-4weeks', 0, 0, 2, autoScale)
521
-
522
-    if createAllCharts:
523
-        createGraph('4wk_noise', 'N', 'dBm', 
524
-                    'Noise\ -\ Last\ 4\ Weeks', 'end-4weeks', 0, 0, 2,
525
-                    autoScale)
526
-        createGraph('4wk_rx_rate', 'RX_RATE', 'Mbps',
527
-                    'Rx\ Rate\ -\ Last\ 4\ Weeks', 'end-4weeks', 0, 0, 2,
528
-                    autoScale)
529
-        createGraph('4wk_tx_rate', 'TX_RATE', 'Mbps',
530
-                    'Tx\ Rate\ -\ Last\ 4\ Weeks', 'end-4weeks', 0, 0, 2,
531
-                    autoScale)
532
-        createGraph('4wk_rx_mcs', 'RX_MCS', 'Index',
533
-                    'Rx\ MCS\ -\ Last\ 4\ Weeks', 'end-4weeks', 0, 0, 2,
534
-                    autoScale)
535
-        createGraph('4wk_tx_mcs', 'TX_MCS', 'Index',
536
-                    'Tx\ MCS\ -\ Last\ 4\ Weeks', 'end-4weeks', 0, 0, 2,
537
-                    autoScale)
538
-
539
-    # 12 month stock charts
540
-
541
-    createGraph('12m_signal', 'S', 'dBm', 
542
-                'RSSI\ -\ Past\ Year', 'end-12months', 0, 0, 2, autoScale)
543
-    createGraph('12m_snr', 'SNR', 'dB', 
544
-                'SNR\ -\ Past\ Year', 'end-12months', 0, 0, 2, autoScale)
545
-
546
-    if createAllCharts:
547
-        createGraph('12m_noise', 'N', 'dBm', 
548
-                    'Noise\ -\ Past\ Year', 'end-12months', 0, 0, 2,
549
-                    autoScale)
550
-        createGraph('12m_rx_rate', 'RX_RATE', 'Mbps',
551
-                    'Rx\ Rate\ -\ Past\ Year', 'end-12months', 0, 0, 2,
552
-                    autoScale)
553
-        createGraph('12m_tx_rate', 'TX_RATE', 'Mbps',
554
-                    'Tx\ Rate\ -\ Past\ Year', 'end-12months', 0, 0, 2,
555
-                    autoScale)
556
-        createGraph('12m_rx_mcs', 'RX_MCS', 'Index',
557
-                    'Rx\ MCS\ -\ Past\ Year', 'end-12months', 0, 0, 2,
558
-                    autoScale)
559
-        createGraph('12m_tx_mcs', 'TX_MCS', 'Index',
560
-                    'Tx\ MCS\ -\ Past\ Year', 'end-12months', 0, 0, 2,
561
-                    autoScale)
562
-    if debugOption:
563
-        #print # print a blank line to improve readability when in debug mode
564
-        pass
565
-##end def
566
-
567
-def getCLarguments():
568
-    """Get command line arguments.  There are four possible arguments
569
-          -d turns on debug mode
570
-          -v turns on verbose debug mode
571
-          -t sets the aredn node query interval
572
-          -u sets the url of the aredn nodeing device
573
-       Returns: nothing
574
-    """
575
-    global debugOption, verboseDebug, dataRequestInterval, \
576
-           arednNodeUrl
577
-
578
-    index = 1
579
-    while index < len(sys.argv):
580
-        if sys.argv[index] == '-d':
581
-            debugOption = True
582
-        elif sys.argv[index] == '-v':
583
-            debugOption = True
584
-            verboseDebug = True
585
-        elif sys.argv[index] == '-p':
586
-            try:
587
-                dataRequestInterval = abs(int(sys.argv[index + 1]))
588
-            except:
589
-                print "invalid polling period"
590
-                exit(-1)
591
-            index += 1
592
-        elif sys.argv[index] == '-u':
593
-            arednNodeUrl = sys.argv[index + 1]
594
-            index += 1
595
-        else:
596
-            cmd_name = sys.argv[0].split('/')
597
-            print "Usage: %s [-d] [-v] [-p seconds] [-u url]" % cmd_name[-1]
598
-            exit(-1)
599
-        index += 1
600
-##end def
601
-
602
-def main():
603
-    """Handles timing of events and acts as executive routine managing
604
-       all other functions.
605
-       Parameters: none
606
-       Returns: nothing
607
-    """
608
-    global dataRequestInterval
609
-
610
-    signal.signal(signal.SIGTERM, terminateAgentProcess)
611
-
612
-    print '%s starting up arednsig agent process' % \
613
-                  (getTimeStamp())
614
-
615
-    # last time output JSON file updated
616
-    lastDataRequestTime = -1
617
-    # last time charts generated
618
-    lastChartUpdateTime = - 1
619
-    # last time the rrdtool database updated
620
-    lastDatabaseUpdateTime = -1
621
-
622
-    ## Get command line arguments.
623
-    getCLarguments()
624
-
625
-    requestIntervalSeconds = dataRequestInterval * 60 # convert to seconds
626
-    chartUpdateInterval = dataRequestInterval # get charts interval
627
-
628
-    ## Exit with error if rrdtool database does not exist.
629
-    if not os.path.exists(_RRD_FILE):
630
-        print 'rrdtool database does not exist\n' \
631
-              'use createArednsigRrd script to ' \
632
-              'create rrdtool database\n'
633
-        exit(1)
634
- 
635
-    ## main loop
636
-    while True:
637
-
638
-        currentTime = time.time() # get current time in seconds
639
-
640
-        # Every web update interval request data from the aredn
641
-        # node and process the received data.
642
-        if currentTime - lastDataRequestTime > requestIntervalSeconds:
643
-            lastDataRequestTime = currentTime
644
-            ldData = []
645
-            result = True
646
-
647
-            # Get the data string from the device.
648
-            sData = getArednNodeData()
649
-            # If the first http request fails, try one more time.
650
-            if sData == None:
651
-                time.sleep(5)
652
-                sData = getArednNodeData()
653
-                if sData == None:
654
-                    result = False
655
-
656
-            # If successful parse the data.
657
-            if result:
658
-                result = parseNodeData(sData, ldData)
659
-           
660
-            # If parsing successful, convert the data.
661
-            if result:
662
-                result = convertData(ldData)
663
-
664
-            # If conversion successful, write data to data files.
665
-            if result:
666
-                result = updateDatabase(ldData)
667
-
668
-            if result:
669
-                writeOutputDataFile(sData, ldData)
670
-
671
-            # Set the node status to online or offline depending on the
672
-            # success or failure of the above operations.
673
-            setNodeStatus(result)
674
-
675
-
676
-        # At the chart generation interval, generate charts.
677
-        if currentTime - lastChartUpdateTime > chartUpdateInterval:
678
-            lastChartUpdateTime = currentTime
679
-            p = multiprocessing.Process(target=generateGraphs, args=())
680
-            p.start()
681
-
682
-        # Relinquish processing back to the operating system until
683
-        # the next update interval.
684
-
685
-        elapsedTime = time.time() - currentTime
686
-        if debugOption:
687
-            if result:
688
-                print "%s update successful:" % getTimeStamp(),
689
-            else:
690
-                print "%s update failed:" % getTimeStamp(),
691
-            print "%6f seconds processing time\n" % elapsedTime 
692
-        remainingTime = requestIntervalSeconds - elapsedTime
693
-        if remainingTime > 0.0:
694
-            time.sleep(remainingTime)
695
-    ## end while
696
-    return
697
-## end def
698
-
699
-if __name__ == '__main__':
700
-    try:
701
-        main()
702
-    except KeyboardInterrupt:
703
-        print '\n',
704
-        terminateAgentProcess('KeyboardInterrupt','Module')
705 0
deleted file mode 100755
... ...
@@ -1,89 +0,0 @@
1
-#!/usr/bin/python -u
2
-## The -u option above turns off block buffering of python output. This assures
3
-## that each error message gets individually printed to the log file.
4
-#
5
-# Module: createArednsigRrd.py
6
-#
7
-# Description: Creates a rrdtool database for use by the weather agent to
8
-# store the data from the weather station.  The agent uses the data in the
9
-# database to generate graphic charts for display in the weather station
10
-# web page.
11
-#
12
-# Copyright 2020 Jeff Owrey
13
-#    This program is free software: you can redistribute it and/or modify
14
-#    it under the terms of the GNU General Public License as published by
15
-#    the Free Software Foundation, either version 3 of the License, or
16
-#    (at your option) any later version.
17
-#
18
-#    This program is distributed in the hope that it will be useful,
19
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
20
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
-#    GNU General Public License for more details.
22
-#
23
-#    You should have received a copy of the GNU General Public License
24
-#    along with this program.  If not, see http://www.gnu.org/license.
25
-#
26
-# Revision History
27
-#   * v10 released 11 Jan 2020 by J L Owrey
28
-#
29
-import os
30
-import time
31
-import subprocess
32
-
33
-    ### DEFINE FILE LOCATIONS ###
34
-
35
-_USER = os.environ['USER']
36
-# the file that stores the data
37
-_RRD_FILE = "/home/%s/database/arednsigData.rrd" % _USER
38
-_RRD_SIZE_IN_DAYS = 370 # days
39
-_1YR_RRA_STEPS_PER_DAY = 96
40
-_DATABASE_UPDATE_INTERVAL = 60
41
-
42
-def createRrdFile():
43
-    """Create the rrd file if it does not exist.
44
-       Parameters: none
45
-       Returns: True, if successful
46
-    """
47
-
48
-    if os.path.exists(_RRD_FILE):
49
-        print "aredn node database already exists"
50
-        return True
51
-
52
-     ## Calculate database size
53
- 
54
-    heartBeat = 2 * _DATABASE_UPDATE_INTERVAL
55
-    rra1yrNumPDP =  int(round(86400 / (_1YR_RRA_STEPS_PER_DAY * \
56
-                    _DATABASE_UPDATE_INTERVAL)))
57
-    rrd24hrNumRows = int(round(86400 / _DATABASE_UPDATE_INTERVAL))
58
-    rrd1yearNumRows = _1YR_RRA_STEPS_PER_DAY * _RRD_SIZE_IN_DAYS
59
-       
60
-    strFmt = ("rrdtool create %s --start now-1day --step %s "
61
-              "DS:S:GAUGE:%s:U:U DS:N:GAUGE:%s:U:U DS:SNR:GAUGE:%s:U:U "
62
-              "DS:RX_MCS:GAUGE:%s:U:U DS:TX_MCS:GAUGE:%s:U:U "
63
-              "DS:RX_RATE:GAUGE:%s:U:U DS:TX_RATE:GAUGE:%s:U:U "
64
-              "RRA:LAST:0.5:1:%s RRA:LAST:0.5:%s:%s")
65
-
66
-    strCmd = strFmt % (_RRD_FILE, _DATABASE_UPDATE_INTERVAL, \
67
-                heartBeat, heartBeat, heartBeat, heartBeat,  \
68
-                heartBeat,  heartBeat, heartBeat,            \
69
-                rrd24hrNumRows, rra1yrNumPDP, rrd1yearNumRows)
70
-
71
-    print "creating aredn node database...\n\n%s\n" % strCmd
72
-
73
-    # Spawn a sub-shell and run the command
74
-    try:
75
-        subprocess.check_output(strCmd, stderr=subprocess.STDOUT, \
76
-                                shell=True)
77
-    except subprocess.CalledProcessError, exError:
78
-        print "rrdtool create failed: %s" % (exError.output)
79
-        return False
80
-    return True
81
-##end def
82
-
83
-def main():
84
-    createRrdFile()
85
-## end def
86
-
87
-if __name__ == '__main__':
88
-    main()
89
-        
90 0
deleted file mode 100755
... ...
@@ -1,16 +0,0 @@
1
-#!/bin/sh
2
-#
3
-# Create a directory in the temporary file system for arednsig dynamic
4
-# data.  Set ownership and permissions to allow the Apache www-data user
5
-# read and write access to this folder.
6
-mkdir /tmp/arednsig
7
-sudo chown :www-data /tmp/arednsig
8
-chmod g+w /tmp/arednsig
9
-
10
-# Uncomment the following line if you choose to mount the dynamic
11
-# folder to the folder created above.
12
-#sudo mount --bind /tmp/arednsig  /home/pi/public_html/arednsig/dynamic
13
-
14
-# Start arednsig agent
15
-(sleep 5; /home/pi/bin/ardstart;) &
16
-
17 0
deleted file mode 100644
... ...
@@ -1,323 +0,0 @@
1
-<!DOCTYPE html>
2
-<!-- Courtesy ruler for editing this file
3
-12345678901234567890123456789012345678901234567890123456789012345678901234567890
4
-<html>
5
-<head>
6
-<title>Node Signal</title>
7
-<meta charset="UTF-8">
8
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
9
-<style>
10
-body {
11
-    background-image: url("static/chalk.jpg");
12
-}
13
-h2 {
14
-    font: bold 24px arial, sans-serif;
15
-}
16
-h3 {
17
-    font: bold 18px arial, sans-serif;
18
-}
19
-h4 {
20
-    font: bold 16px arial, sans-serif;
21
-}
22
-.mainContainer {
23
-    width: 750px;
24
-    text-align: center;
25
-    margin: auto;
26
-    /*border: 1px solid black;*/
27
-}
28
-.datetime {
29
-    font: bold 22px arial, sans-serif;
30
-    padding: 0px;
31
-}
32
-.rowContainer {
33
-    display: table;
34
-    width: 100%;
35
-}
36
-.currentDataCell {
37
-    width: 50%;
38
-    padding: 10px;
39
-    font: bold 20px arial, sans-serif;
40
-    text-align: center;
41
-    display: table-cell;
42
-    vertical-align: middle;
43
-}
44
-.dataItems {
45
-    padding: 2px;
46
-    text-align: left;
47
-    line-height: 130%;
48
-    display: inline-block;
49
-    vertical-align: middle;
50
-}
51
-.chartContainer {
52
-    padding: 2px;
53
-}
54
-img.chart {
55
-    width:100%;
56
-}
57
-.notes {
58
-    font: 17px arial, sans-serif;
59
-    text-align: left;
60
-    padding: 10px;
61
-}
62
-span.chartSelector {
63
-    margin: auto;
64
-}
65
-ul.selectorElement {
66
-    list-style-type: none;
67
-    margin: 10px;
68
-    padding: 0;
69
-    overflow: hidden;
70
-    background-color: #bbb;
71
-    text-align: center;
72
-}
73
-li.selectorElement {
74
-    display: inline-block;
75
-    font: bold 18px arial, sans-serif;
76
-    color: black;
77
-}
78
-span.selectorElement:hover {
79
-    background-color: #333;
80
-    cursor: pointer;
81
-    color: white;
82
-}
83
-span.selectorElement {
84
-    display: inline-block;
85
-    padding: 8px 12px;
86
-}
87
-#iframe_a {
88
-    border:none;
89
-    width:100%;
90
-    height:450px;
91
-}
92
-</style>
93
-</head>
94
-
95
-<body onload="main()">
96
-
97
-<div class="mainContainer">
98
-<h2><a href="https://github.com/fractalxaos/ham/tree/master/arednsig" 
99
-  style="text-decoration:none" target="_new">
100
-KA7JLO AREDN<sup>&#174;</sup> Node Signal</a></h2>
101
-<h3>Last Updated</h3>
102
-<div class="datetime">
103
-<span id="date"></span>
104
-&nbsp;&nbsp;
105
-<span id="time"></span>
106
-</div>
107
-
108
-<div class="rowContainer">
109
-<div class="currentDataCell">
110
-<div class="dataItems" style="text-align: center;">
111
-Status: <span id="status"></span><br>
112
-Data updates every: <span id="period"></span> minutes
113
-</div>
114
-
115
-</div>
116
-</div>
117
-
118
-<span class="chartSelectors">
119
-<ul class="selectorElement">
120
-<li class="selectorElement">Select charts:</li>
121
-<li class="selectorElement"><span class="selectorElement"
122
- onclick="setChartPeriod(1)">24 hours</span></li>
123
-<li class="selectorElement"><span class="selectorElement"
124
- onclick="setChartPeriod(2)">4 weeks</span></li>
125
-<li class="selectorElement"><span class="selectorElement"
126
- onclick="setChartPeriod(3)">12 months</span></li>
127
-<li class="selectorElement"><span class="selectorElement"
128
- onclick="setChartPeriod(0)">Custom…</span></li>
129
-</ul>
130
-</span>
131
-
132
-<div class="rowContainer" id="customChartsContainer" style="display:none;">
133
-<div class="currentDataCell">
134
-<form id="fmDateSelector" action="arednsig.php" method="post"
135
- target="iframe_a">
136
-<label for="beginDate">Begin Date: </label>
137
-<input id="beginDate" name="beginDate" type="date" value="mm/dd/yyyy" />
138
-<label for="endDate">End Date: </label>
139
-<input id="endDate" name="endDate" type="date" value="mm/dd/yyyy" />
140
-<br><br>
141
-<input type="button" onclick="getCustomCharts()" value="Get Charts">
142
-</form>
143
-<span id="errorMsg"></span><br>
144
-<iframe id="iframe_a" name="iframe_a"></iframe>
145
-</div>
146
-</div>
147
-
148
-<br>
149
-
150
-<div class="rowContainer" id="stockChartsContainer">
151
-<div class="chartContainer">
152
-<img class="chart" id="signalChart">
153
-</div>
154
-<div class="chartContainer">
155
-<img class="chart" id="snrChart">
156
-</div>
157
-</div>
158
-
159
-<div class="notes">
160
-<b>NOTES:</b>
161
-<ul>
162
-<li>Aredn Node Signal software available at
163
-<a href="https://github.com/fractalxaos/ham/tree/master/arednsig"
164
- target="_new">
165
-<i>Github.com</i></a>.</li>
166
-<li>Project sponsored by 
167
-<a href="https://willamettevalleymesh.net" TARGET="_NEW">
168
-<i>Willamette Valley Mesh Network</i></a>, Salem, Oregon.</li>
169
-<li>For more information about the amateur radio emergency
170
- data network (AREDN) see official web site at
171
- <a href="http://www.arednmesh.org" target="_blank">
172
-www.arednmesh.org</a>.</li>
173
-</ul>
174
-</div>
175
-</div>
176
-<br>
177
-
178
-<script>
179
-
180
-/* Global constants */
181
-
182
-var nodeDataUrl = "dynamic/nodeOnline.js";
183
-
184
-/* Global DOM objects */
185
-
186
-// Chart elements
187
-var signalChart = document.getElementById("signalChart");
188
-var snrChart = document.getElementById("snrChart");
189
-
190
-// Text elements
191
-var dateElmt = document.getElementById("date");    
192
-var timeElmt = document.getElementById("time"); 
193
-var statusElmt = document.getElementById("status");
194
-var periodElmt = document.getElementById("period");
195
-
196
-// Document elements
197
-var customChartsContainer = document.getElementById("customChartsContainer");
198
-var stockChartsContainer = document.getElementById("stockChartsContainer");
199
-var fmDateSelector = document.getElementById("fmDateSelector");
200
-var errorMsg = document.getElementById("errorMsg");
201
-
202
-/* Global objects */
203
-
204
-var httpRequest = new XMLHttpRequest();
205
-
206
-/* Global variables */
207
-
208
-var chartPeriod = 1;
209
-var chartRefreshRate = 0; // chart refresh rate in minutes
210
-
211
-function main() {
212
-    /* Register call back function to process http requests */
213
-    httpRequest.onreadystatechange = function() {
214
-        if (httpRequest.readyState == 4 && httpRequest.status == 200) {
215
-            var dataArray = JSON.parse(httpRequest.responseText);
216
-            displayData(dataArray[0]);
217
-        } else if (httpRequest.readyState == 4 && httpRequest.status == 404) {
218
-            displayOfflineStatus();
219
-        }
220
-    };
221
-    httpRequest.ontimeout = function(e) {
222
-        displayOfflineStatus();
223
-    };
224
-
225
-    initializeDateSelector();
226
-    getNodeData();
227
-    getNodeCharts();
228
-}
229
-
230
-function getNodeData() {
231
-    httpRequest.open("GET", nodeDataUrl, true);
232
-    httpRequest.timeout = 3000;
233
-    httpRequest.send();
234
-}
235
-
236
-function setChartPeriod(n) {
237
-    chartPeriod = n;
238
-    if (n == 0) {
239
-        customChartsContainer.style.display = "block";
240
-        stockChartsContainer.style.display = "none";
241
-    } else {
242
-        customChartsContainer.style.display = "none";
243
-        stockChartsContainer.style.display = "block";
244
-    getNodeCharts();   
245
-    }
246
-}
247
-
248
-function getNodeCharts() {
249
-    var d = new Date;
250
-    var pfx;
251
-
252
-    switch(chartPeriod) {
253
-        case 1:
254
-            pfx = "24hr_";
255
-            break;
256
-        case 2:
257
-            pfx = "4wk_";
258
-            break;
259
-       case 3:
260
-            pfx = "12m_";
261
-            break;
262
-    }
263
-    signalChart.src = "dynamic/" + pfx + "signal.png?ver=" + d.getTime();
264
-    snrChart.src = "dynamic/" + pfx + "snr.png?ver=" + d.getTime();
265
-}
266
-
267
-function displayData(dataItem) {
268
-    var timeStamp, date, time, hourminute;
269
-    var localDateObj,localTimeZone;
270
-
271
-    timeStamp = dataItem.date;
272
-    date = timeStamp.split(" ")[0];
273
-    time = timeStamp.split(" ")[1];
274
-    hourminute = time.split(":")[0] + ":" + time.split(":")[1];
275
-    localDate = new Date();
276
-    localTimeZone = localDate.getTimezoneOffset() / 60;
277
-    dateElmt.innerHTML = date;    
278
-    timeElmt.innerHTML = hourminute +
279
-                         "  <small>(GMT+" + localTimeZone + ")</small>";    
280
-     
281
-    statusElmt.innerHTML = "Online";
282
-    statusElmt.style.color = "green";
283
-
284
-    chartRefreshRate = dataItem.period;
285
-    periodElmt.innerHTML = chartRefreshRate;
286
-    setInterval(getNodeData, 60000 * chartRefreshRate);
287
-    setInterval(getNodeCharts, 60000 * chartRefreshRate);
288
-}
289
-
290
-function displayOfflineStatus() {
291
-    var d = new Date();
292
-    localTimeZone = d.getTimezoneOffset() / 60;
293
-    dateElmt.innerHTML = (d.getMonth() + 1) + "/" + d.getDate() + "/" +
294
-                          d.getFullYear();    
295
-    timeElmt.innerHTML = d.getHours() + ":" + d.getMinutes() +
296
-                         "  <small>(GMT+" + localTimeZone + ")</small>";
297
-    periodElmt.innerHTML = "?";    
298
-    statusElmt.innerHTML = "offline";    
299
-    statusElmt.style.color = "red";
300
-}
301
-
302
-function initializeDateSelector() {
303
-    var d = new Date();
304
-
305
-    var dEnd = new Date(d.getFullYear(),
306
-               d.getMonth(), d.getDate() - 0);
307
-
308
-    var dBegin = new Date(d.getFullYear(),
309
-               d.getMonth(), d.getDate() - 1);
310
-
311
-    document.getElementById("beginDate").valueAsDate = dBegin;
312
-    document.getElementById("endDate").valueAsDate = dEnd;
313
-}
314
-
315
-function getCustomCharts() {
316
-    fmDateSelector.submit();
317
-}
318
-</script>
319
-
320
-</body>
321
-</html>
322
-
323 0
deleted file mode 100644
... ...
@@ -1,205 +0,0 @@
1
-<html>
2
-<!-- Courtsey ruler
3
-12345678901234567890123456789012345678901234567890123456789012345678901234567890
4
-<head>
5
-<style>
6
-p {
7
-    font: 14px ariel, sans serif;
8
-}
9
-#errorMsg {
10
-    font:bold 18px arial,sans-serif;
11
-    color:red;
12
-    text-align:center;
13
-}
14
-.chartContainer {
15
-    padding: 2px;
16
-}
17
-img.chart {
18
-    width:100%;
19
-}
20
-</style>
21
-</head>
22
-<body>
23
-
24
-<?php
25
-/*
26
- Script: arednsig.php
27
-
28
- Description: This scripts generates on the server charts showing
29
- signal data spanning the period supplied by the user.  The script
30
- does the following:
31
-    - converts user supplied dates to  epoch time
32
-    - gets the times of the first and last data point in the round
33
-      robin database (RRD)
34
-    - from above validates user supplied begin and end dates
35
-    - creates charts of the specified period
36
-
37
- Copyright 2020 Jeff Owrey
38
-    This program is free software: you can redistribute it and/or modify
39
-    it under the terms of the GNU General Public License as published by
40
-    the Free Software Foundation, either version 3 of the License, or
41
-    (at your option) any later version.
42
-
43
-    This program is distributed in the hope that it will be useful,
44
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
45
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
46
-    GNU General Public License for more details.
47
-
48
-    You should have received a copy of the GNU General Public License
49
-    along with this program.  If not, see http://www.gnu.org/license.
50
-
51
- Revision History
52
-   * v20 released 18 Jan 2020 by J L Owrey; first release
53
-*/
54
-
55
-# Define global constants
56
-
57
-# round robin database file
58
-define("_RRD_FILE", str_replace("public_html/arednsig/arednsig.php",
59
-                                "database/arednsigData.rrd",
60
-                                $_SERVER["SCRIPT_FILENAME"]));
61
-# charts html directory
62
-define("_CHART_DIRECTORY", str_replace("arednsig.php",
63
-                                       "dynamic/",
64
-                                       $_SERVER["SCRIPT_FILENAME"]));
65
-# standard chart width in pixels
66
-define("_CHART_WIDTH", 600);
67
-# standard chart height in pixels
68
-define("_CHART_HEIGHT", 150);
69
-# debug mode
70
-define("_DEBUG", false);
71
-
72
-# Set error handling modes.
73
-error_reporting(E_ALL);
74
-
75
-# Get user supplied chart begin and end dates.
76
-$beginDate = $_POST["beginDate"];
77
-$endDate =  $_POST["endDate"];
78
-
79
-# Convert the user supplied dates to epoch time stamps.
80
-$beginDateEp = strtotime($beginDate);
81
-$endDateEp = strtotime($endDate);
82
-
83
-# Get the time stamp of the earliest data point in the RRD file.
84
-$cmd = sprintf("rrdtool first %s --rraindex 1", _RRD_FILE);
85
-$firstDP = shell_exec($cmd);
86
-
87
-# Get the time stamp of the latest data point in the RRD file.
88
-$cmd = sprintf("rrdtool last %s", _RRD_FILE);
89
-$lastDP = shell_exec($cmd);
90
-
91
-# Determine validity of user supplied dates.  User supplied begin
92
-# date must be less than user supplied end date.  Furthermore both
93
-# dates must be within the range of dates stored in the RRD.
94
-if ($beginDateEp > $endDateEp) {
95
-    echo "<p id=\"errorMsg\">" .
96
-         "End date must be after begin date.</p>";
97
-} elseif ($beginDateEp < $firstDP || $endDateEp > $lastDP) {
98
-    echo "<p id=\"errorMsg\">" .
99
-          "Date range must be between " .
100
-          date('m / d / Y', $firstDP) . " and " . 
101
-          date('m / d / Y', $lastDP) . ".</p>";
102
-} else {
103
-    # Generate charts from validated user supplied dates.
104
-    if (_DEBUG) {
105
-        echo "<p>Date range: " . $beginDateEp . " thru " .
106
-              $endDateEp . "</p>";
107
-    }
108
-    createChart('custom_signal', 'S', 'dBm', 
109
-                'RSSI', $beginDateEp, $endDateEp,
110
-                 0, 0, 2, false);
111
-    createChart('custom_snr', 'SNR', 'dBm', 
112
-                'S/N', $beginDateEp, $endDateEp,
113
-                 0, 0, 2, false);
114
-    # Send html commands to client browser.
115
-    echo "<div class=\"chartContainer\">" .
116
-         "<img class=\"chart\" src=\"dynamic/custom_signal.png\">" .
117
-         "</div>";
118
-    echo "<div class=\"chartContainer\">" .
119
-         "<img class=\"chart\" src=\"dynamic/custom_snr.png\">" .
120
-         "</div>";
121
-}
122
-
123
-function createChart($chartFile, $dataItem, $label, $title, $begin,
124
-                     $end, $lower, $upper, $addTrend, $autoScale) {
125
-    /*
126
-    Uses rrdtool to create a chart of specified aredn node data item.
127
-    Parameters:
128
-       fileName - name of the created chart file
129
-       dataItem - data item to be charted
130
-       label - string containing a label for the item to be charted
131
-       title - string containing a title for the chart
132
-       begin - beginning time of the chart data
133
-       end   - ending time of the data to be charted
134
-       lower - lower bound for chart ordinate #NOT USED
135
-       upper - upper bound for chart ordinate #NOT USED
136
-       addTrend - 0, show only chart data
137
-                  1, show only a trend line
138
-                  2, show a trend line and the chart data
139
-       autoScale - if True, then use vertical axis auto scaling
140
-           (lower and upper parameters are ignored), otherwise use
141
-           lower and upper parameters to set vertical axis scale
142
-    Returns: True if successful, False otherwise
143
-    */
144
-
145
-    # Define path on server to chart files.
146
-    $chartPath = _CHART_DIRECTORY . $chartFile . ".png";
147
-
148
-    # Format the rrdtool chart command.
149
-
150
-    # Set chart file name, start time, end time, height, and width.
151
-    $cmdfmt = "rrdtool graph %s -a PNG -s %s -e %s -w %s -h %s ";
152
-    $cmd = sprintf($cmdfmt, $chartPath, $begin, $end, _CHART_WIDTH,
153
-                   _CHART_HEIGHT);
154
-    $cmdfmt = "-l %s -u %s -r ";
155
-
156
-    # Set upper and lower ordinate bounds.
157
-    if ($lower < $upper) {
158
-        $cmd .= sprintf($cmdfmt, $lower, $upper);
159
-    } elseif ($autoScale) {
160
-        $cmd .= "-A ";
161
-    }
162
-    $cmd .= "-Y ";
163
-
164
-    # Set the chart ordinate label and chart title. 
165
-    $cmdfmt = "-v %s -t %s ";
166
-    $cmd .= sprintf($cmdfmt, $label, $title);
167
-   
168
-    # Define moving average window width.
169
-    $trendWindow = floor(($end - $begin) / 12);
170
-        
171
-    # Show the data, or a moving average trend line over
172
-    # the data, or both.
173
-    $cmdfmt = "DEF:dSeries=%s:%s:LAST ";
174
-    $cmd .= sprintf($cmdfmt, _RRD_FILE, $dataItem);
175
-    if ($addTrend == 0) {
176
-        $cmd .= "LINE1:dSeries#0400ff ";
177
-    } elseif ($addTrend == 1) {
178
-        $cmdfmt = "CDEF:smoothed=dSeries,%s,TREND LINE3:smoothed#ff0000 ";
179
-        $cmd .= sprintf($cmdfmt, $trendWindow);
180
-    } elseif ($addTrend == 2) {
181
-        $cmd .= "LINE1:dSeries#0400ff ";
182
-        $cmdfmt = "CDEF:smoothed=dSeries,%s,TREND LINE3:smoothed#ff0000 ";
183
-        #$cmdfmt = "CDEF:smoothed=dSeries,%s,XYZZY LINE3:smoothed#ff0000 ";
184
-        $cmd .=  sprintf($cmdfmt, $trendWindow);
185
-    }
186
-     
187
-    # Execute the formatted rrdtool command in the shell. The rrdtool
188
-    # command will complete execution before the html image tags get
189
-    # sent to the browser.  This assures that the charts are available
190
-    # when the client browser executes the html code that loads the
191
-    # charts into the document displayed by the client browser.
192
-    if (_DEBUG) {
193
-        echo "<p>chart command:<br>" . $cmd . "</p>";
194
-    }
195
-    $result = shell_exec($cmd . " 2>&1");
196
-    if (_DEBUG) {
197
-        echo "<p>result:<br>" . $result . "</p>";
198
-    }
199
-}
200
-
201
-?>
202
-
203
-</body>
204
-</html>
205 0
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-<!DOCTYPE html>
2
-<html>
3
-<head>
4
-  <meta http-equiv="refresh" content="0; url=./arednsig.html">
5
-  <!--<meta http-equiv="refresh" content="0; url=https://github.com/fractalxaos/radmon">-->
6
-</head>
7
-</html>
8 0
deleted file mode 100644
9 1
Binary files a/arednsig/html/static/chalk.jpg and /dev/null differ