Browse code

modify charts

Gandolf authored on 06/07/2021 20:50:02
Showing 4 changed files
1 1
old mode 100644
2 2
new mode 100755
... ...
@@ -51,9 +51,10 @@ class ina260:
51 51
         # Initialize INA260 sensor.  See the data sheet for meaning of
52 52
         # each bit.  The following bytes are written to the configuration
53 53
         # register
54
-        #     byte 1: 01100000
54
+        #     byte 1: 11100000
55 55
         #     byte 2: 00100111
56
-        initData = [0x60, 0x27]
56
+        initData = [0b11100000, 0b00100111]
57
+        #initData = [0x60, 0x27]
57 58
         self.bus.write_i2c_block_data(self.sensorAddr, CONFIG_REG, initData)
58 59
     ## end def
59 60
 
... ...
@@ -69,6 +70,15 @@ class ina260:
69 70
         return (mfcidB1, mfcidB2, configB1, configB2)
70 71
     ## end def
71 72
 
73
+    def getCurrentReg(self):
74
+        # Read current register and return raw binary data for test and
75
+        # debug.
76
+        data = self.bus.read_i2c_block_data(self.sensorAddr, CUR_REG, 2)
77
+        dataB1 = format(data[0], "08b")
78
+        dataB2 = format(data[1], "08b")
79
+        return (dataB1, dataB2)
80
+    ## end def
81
+
72 82
     def getCurrent(self):
73 83
         # Get the current data from the sensor.
74 84
         # INA260 returns the data in two bytes formatted as follows
... ...
@@ -86,15 +96,24 @@ class ina260:
86 96
         bdata = data[0] << 8 | data[1]
87 97
         # Convert from two's complement to integer.
88 98
         # If d15 is 1, the the number is a negative two's complement
89
-        # number.  The absolute value is 2^15 - 1 minus the value
99
+        # number.  The absolute value is 2^16 - 1 minus the value
90 100
         # of d14-d0 taken as a positive number.
91 101
         if bdata > 0x7FFF:
92
-            bdata = -(0xFFFF - bdata) # 0xFFFF is 2^15 - 1
102
+            bdata = -(0xFFFF - bdata) # 0xFFFF is 2^16 - 1
93 103
         # Convert integer data to mAmps.
94 104
         mAmps = bdata * 1.25  # LSB is 1.25 mA
95 105
         return mAmps
96 106
     ## end def
97 107
 
108
+    def getVoltageReg(self):
109
+        # Read voltage register and return raw binary data for test
110
+        # and debug.
111
+        data = self.bus.read_i2c_block_data(self.sensorAddr, VOLT_REG, 2)
112
+        dataB1 = format(data[0], "08b")
113
+        dataB2 = format(data[1], "08b")
114
+        return (dataB1, dataB2)
115
+    ## end def
116
+
98 117
     def getVoltage(self):
99 118
         # Get the voltage data from the sensor.
100 119
         # INA260 returns the data in two bytes formatted as follows
... ...
@@ -138,7 +157,9 @@ def test():
138 157
     print "manufacturer ID: %s %s\nconfiguration register: %s %s\n" % data
139 158
     # Print out sensor values.
140 159
     while True:
160
+        print "current register: %s %s" % pwr1.getCurrentReg()
141 161
         print "%6.2f mA" % pwr1.getCurrent()
162
+        print "volt register: %s %s" % pwr1.getVoltageReg()
142 163
         print "%6.2f V" % pwr1.getVoltage()
143 164
         print "%6.2f mW\n" % pwr1.getPower()
144 165
         time.sleep(2)
145 166
old mode 100644
146 167
new mode 100755
... ...
@@ -77,6 +77,8 @@ _CHART_UPDATE_INTERVAL = 600
77 77
 _CHART_WIDTH = 600
78 78
 # standard chart height in pixels
79 79
 _CHART_HEIGHT = 150
80
+# chart average line color
81
+_AVERAGE_LINE_COLOR = '#006600'
80 82
 
81 83
    ### GLOBAL VARIABLES ###
82 84
 
... ...
@@ -105,7 +107,7 @@ def getTimeStamp():
105 107
     Returns: string containing the time stamp
106 108
     """
107 109
     return time.strftime( "%m/%d/%Y %T", time.localtime() )
108
-##end def
110
+## end def
109 111
 
110 112
 def getEpochSeconds(sTime):
111 113
     """Convert the time stamp supplied in the weather data string
... ...
@@ -122,7 +124,7 @@ def getEpochSeconds(sTime):
122 124
         return None
123 125
     tSeconds = int(time.mktime(t_sTime))
124 126
     return tSeconds
125
-##end def
127
+## end def
126 128
 
127 129
 def terminateAgentProcess(signal, frame):
128 130
     """Send a message to log when the agent process gets killed
... ...
@@ -138,7 +140,7 @@ def terminateAgentProcess(signal, frame):
138 140
     print '%s terminating npw agent process' % \
139 141
               (getTimeStamp())
140 142
     sys.exit(0)
141
-##end def
143
+## end def
142 144
 
143 145
   ###  PUBLIC METHODS  ###
144 146
 
... ...
@@ -161,7 +163,7 @@ def getSensorData(dData):
161 163
         return False
162 164
 
163 165
     return True
164
-##end def
166
+## end def
165 167
 
166 168
 def updateDatabase(dData):
167 169
     """
... ...
@@ -193,7 +195,7 @@ def updateDatabase(dData):
193 195
         return False
194 196
 
195 197
     return True
196
-##end def
198
+## end def
197 199
 
198 200
 def writeOutputDataFile(dData):
199 201
     """Write node data items to the output data file, formatted as 
... ...
@@ -236,7 +238,8 @@ def writeOutputDataFile(dData):
236 238
 ## end def
237 239
 
238 240
 def createGraph(fileName, dataItem, gLabel, gTitle, gStart,
239
-                lower, upper, addTrend, autoScale):
241
+                lower, upper, trendLine, scaleFactor=1, autoScale=True, 
242
+                alertLine=""):
240 243
     """Uses rrdtool to create a graph of specified node data item.
241 244
        Parameters:
242 245
            fileName - name of file containing the graph
... ...
@@ -246,12 +249,17 @@ def createGraph(fileName, dataItem, gLabel, gTitle, gStart,
246 249
            gStart - beginning time of the graphed data
247 250
            lower - lower bound for graph ordinate #NOT USED
248 251
            upper - upper bound for graph ordinate #NOT USED
249
-           addTrend - 0, show only graph data
250
-                      1, show only a trend line
251
-                      2, show a trend line and the graph data
252
+           trendLine 
253
+                0, show only graph data
254
+                1, show only a trend line
255
+                2, show a trend line and the graph data
256
+           scaleFactor - amount to pre-scale the data before charting
257
+                the data [default=1]
252 258
            autoScale - if True, then use vertical axis auto scaling
253
-               (lower and upper parameters are ignored), otherwise use
254
-               lower and upper parameters to set vertical axis scale
259
+                (lower and upper parameters must be zero)
260
+           alertLine - value for which to print a critical
261
+                low voltage alert line on the chart. If not provided
262
+                alert line will not be printed.
255 263
        Returns: True if successful, False otherwise
256 264
     """
257 265
     gPath = _CHARTS_DIRECTORY + fileName + ".png"
... ...
@@ -277,16 +285,21 @@ def createGraph(fileName, dataItem, gLabel, gTitle, gStart,
277 285
  
278 286
     # Show the data, or a moving average trend line over
279 287
     # the data, or both.
280
-    strCmd += "DEF:dSeries=%s:%s:LAST " % (_RRD_FILE, dataItem)
281
-    if addTrend == 0:
288
+    strCmd += "DEF:rSeries=%s:%s:LAST " % (_RRD_FILE, dataItem)
289
+    strCmd += "CDEF:dSeries=rSeries,%s,/ " % (scaleFactor)
290
+
291
+    if trendLine == 0:
282 292
         strCmd += "LINE1:dSeries#0400ff "
283
-    elif addTrend == 1:
284
-        strCmd += "CDEF:smoothed=dSeries,%s,TREND LINE2:smoothed#000000 " \
285
-                  % trendWindow[gStart]
286
-    elif addTrend == 2:
293
+    elif trendLine == 1:
294
+        strCmd += "CDEF:smoothed=dSeries,%s,TREND LINE2:smoothed%s " \
295
+                  % (trendWindow[gStart], _AVERAGE_LINE_COLOR)
296
+    elif trendLine == 2:
287 297
         strCmd += "LINE1:dSeries#0400ff "
288
-        strCmd += "CDEF:smoothed=dSeries,%s,TREND LINE2:smoothed#000000 " \
289
-                  % trendWindow[gStart]
298
+        strCmd += "CDEF:smoothed=dSeries,%s,TREND LINE2:smoothed%s " \
299
+                  % (trendWindow[gStart], _AVERAGE_LINE_COLOR)
300
+
301
+    if alertLine != "":
302
+        strCmd += "HRULE:%s#FF0000:Critical\ Low\ Voltage " % (alertLine)
290 303
      
291 304
     if verboseDebug:
292 305
         print "%s" % strCmd # DEBUG
... ...
@@ -304,60 +317,68 @@ def createGraph(fileName, dataItem, gLabel, gTitle, gStart,
304 317
         print "rrdtool graph: %s\n" % result,
305 318
     return True
306 319
 
307
-##end def
320
+## end def
308 321
 
309 322
 def generateGraphs():
310 323
     """Generate graphs for display in html documents.
311 324
        Parameters: none
312 325
        Returns: nothing
313 326
     """
314
-    autoScale = False
315 327
 
316 328
     # 24 hour stock charts
317 329
 
318
-    createGraph('24hr_current', 'CUR', 'mA', 
319
-                'Current\ -\ Last\ 24\ Hours', 'end-1day', 0, 0, 0, autoScale)
320
-    createGraph('24hr_voltage', 'VOLT', 'V', 
321
-                'Voltage\ -\ Last\ 24\ Hours', 'end-1day', 0, 0, 0, autoScale)
322
-    createGraph('24hr_power', 'PWR', 'mW', 
323
-                'Power\ -\ Last\ 24\ Hours', 'end-1day', 0, 0, 0, autoScale)
330
+    createGraph('24hr_current', 'CUR', 'Amps',
331
+                'Current\ -\ Last\ 24\ Hours', 'end-1day', \
332
+                0, 0, 2, 1000)
333
+    createGraph('24hr_voltage', 'VOLT', 'Volts',
334
+                'Voltage\ -\ Last\ 24\ Hours', 'end-1day', \
335
+                9, 15, 0, 1, True, 11)
336
+    createGraph('24hr_power', 'PWR', 'Watts', 
337
+                'Power\ -\ Last\ 24\ Hours', 'end-1day', \
338
+                0, 0, 2, 1000)
324 339
     createGraph('24hr_battemp', 'BTMP', 'deg\ F', 
325 340
                 'Battery\ Temperature\ -\ Last\ 24\ Hours', 'end-1day', \
326
-                 0, 0, 0, autoScale)
341
+                0, 0, 0)
327 342
     createGraph('24hr_ambtemp', 'ATMP', 'deg\ F', 
328 343
                 'Ambient\ Temperature\ -\ Last\ 24\ Hours', 'end-1day', \
329
-                 0, 0, 0, autoScale)
344
+                0, 0, 0)
330 345
 
331 346
     # 4 week stock charts
332 347
 
333
-    createGraph('4wk_current', 'CUR', 'mA', 
334
-                'Current\ -\ Last\ 4\ Weeks', 'end-4weeks', 0, 0, 0, autoScale)
335
-    createGraph('4wk_voltage', 'VOLT', 'V', 
336
-                'Voltage\ -\ Last\ 4\ Weeks', 'end-4weeks', 0, 0, 0, autoScale)
337
-    createGraph('4wk_power', 'PWR', 'mW', 
338
-                'Power\ -\ Last\ 4\ Weeks', 'end-4weeks', 0, 0, 0, autoScale)
348
+    createGraph('4wk_current', 'CUR', 'Amps',
349
+                'Current\ -\ Last\ 4\ Weeks', 'end-4weeks', \
350
+                0, 0, 2, 1000)
351
+    createGraph('4wk_voltage', 'VOLT', 'Volts',
352
+                'Voltage\ -\ Last\ 4\ Weeks', 'end-4weeks', \
353
+                9, 15, 0, 1, True, 11)
354
+    createGraph('4wk_power', 'PWR', 'Watts', 
355
+                'Power\ -\ Last\ 4\ Weeks', 'end-4weeks', \
356
+                0, 0, 2, 1000)
339 357
     createGraph('4wk_battemp', 'BTMP', 'deg\ F', 
340 358
                 'Battery\ Temperature\ -\ Last\ 4\ Weeks', 'end-4weeks', \
341
-                 0, 0, 2, autoScale)
359
+                0, 0, 2)
342 360
     createGraph('4wk_ambtemp', 'ATMP', 'deg\ F', 
343 361
                 'Ambient\ Temperature\ -\ Last\ 4\ Weeks', 'end-4weeks', \
344
-                 0, 0, 0, autoScale)
362
+                0, 0, 2)
345 363
 
346 364
     # 12 month stock charts
347 365
 
348
-    createGraph('12m_current', 'CUR', 'mA', 
349
-                'Current\ -\ Past\ Year', 'end-12months', 0, 0, 0, autoScale)
350
-    createGraph('12m_voltage', 'VOLT', 'V', 
351
-                'Voltage\ -\ Past\ Year', 'end-12months', 0, 0, 0, autoScale)
352
-    createGraph('12m_power', 'PWR', 'mW', 
353
-                'Power\ -\ Past\ Year', 'end-12months', 0, 0, 0, autoScale)
366
+    createGraph('12m_current', 'CUR', 'Amps',
367
+                'Current\ -\ Past\ Year', 'end-12months', \
368
+                0, 0, 2, 1000)
369
+    createGraph('12m_voltage', 'VOLT', 'Volts',
370
+                'Voltage\ -\ Past\ Year', 'end-12months', \
371
+                9, 15, 0, 1, True, 11)
372
+    createGraph('12m_power', 'PWR', 'Watts', 
373
+                'Power\ -\ Past\ Year', 'end-12months', \
374
+                0, 0, 2, 1000)
354 375
     createGraph('12m_battemp', 'BTMP', 'deg\ F', 
355 376
                 'Battery\ Temperature\ -\ Past\ Year', 'end-12months', \
356
-                 0, 0, 0, autoScale)
377
+                0, 0, 2)
357 378
     createGraph('12m_ambtemp', 'ATMP', 'deg\ F', 
358 379
                 'Ambient\ Temperature\ -\ Past\ Year', 'end-12months', \
359
-                 0, 0, 0, autoScale)
360
-##end def
380
+                0, 0, 2)
381
+## end def
361 382
 
362 383
 def getCLarguments():
363 384
     """Get command line arguments.  There are three possible arguments
... ...
@@ -437,6 +458,7 @@ def main():
437 458
             # If get data successful, write data to data files.
438 459
             if result:
439 460
                 result = writeOutputDataFile(dData)
461
+                pass
440 462
 
441 463
             # At the rrdtool database update interval, update the database.
442 464
             if currentTime - lastDatabaseUpdateTime > \
... ...
@@ -445,13 +467,14 @@ def main():
445 467
                 ## Update the round robin database with the parsed data.
446 468
                 if result:
447 469
                     updateDatabase(dData)
470
+                    pass
448 471
 
449 472
         # At the chart generation interval, generate charts.
450 473
         if currentTime - lastChartUpdateTime > chartUpdateInterval:
451 474
             lastChartUpdateTime = currentTime
452 475
             p = multiprocessing.Process(target=generateGraphs, args=())
453 476
             p.start()
454
-
477
+            
455 478
         # Relinquish processing back to the operating system until
456 479
         # the next update interval.
457 480
 
458 481
old mode 100644
459 482
new mode 100755
... ...
@@ -66,6 +66,15 @@ class tmp102:
66 66
         return (configB1, configB2)
67 67
     ## end def
68 68
 
69
+    def getTempReg(self):
70
+        # Read temperature register and return raw binary data for test
71
+        # and debug.
72
+        data = self.bus.read_i2c_block_data(self.sensorAddr, TEMP_REG, 2)
73
+        dataB1 = format(data[0], "08b")
74
+        dataB2 = format(data[1], "08b")
75
+        return (dataB1, dataB2)
76
+    ## end def
77
+
69 78
     # Gets the temperature in binary format and converts to degrees
70 79
     # Celsius.
71 80
     def getTempC(self):
... ...
@@ -110,14 +119,17 @@ def testclass():
110 119
     # Print out sensor values.
111 120
     bAl = False
112 121
     while True:
122
+        regdata = ts1.getTempReg()
113 123
         tempC = ts1.getTempC()
114 124
         tempF = ts1.getTempF()
115 125
         if bAl:
116 126
             bAl = False
117
-            print "\033[42;30m%6.2f%sC  %6.2f%sF\033[m" % \
127
+            print "\033[42;30mTemperature Reg: %s %s\033[m" % regdata
128
+            print "\033[42;30m%6.2f%sC  %6.2f%s                 \033[m" % \
118 129
                   (tempC, DEGSYM, tempF, DEGSYM)
119 130
         else:
120 131
             bAl = True
132
+            print "Temperature Reg: %s %s" % regdata
121 133
             print "%6.2f%sC  %6.2f%sF" % \
122 134
                   (tempC, DEGSYM, tempF, DEGSYM)
123 135
         time.sleep(2)
... ...
@@ -36,6 +36,11 @@ p {
36 36
     text-align: left;
37 37
     padding: 10px;
38 38
 }
39
+#alert {
40
+    font: bold 22px arial, sans-serif;
41
+    color: red;
42
+    /*border: 1px solid black;*/
43
+}
39 44
 .rowContainer {
40 45
     display: table;
41 46
     width: 100%;
... ...
@@ -60,7 +65,7 @@ p {
60 65
 }
61 66
 .chartContainer {
62 67
     padding: 2px;
63
-    /*border: 1px solid black;*/
68
+    border: 1px solid black;
64 69
 }
65 70
 img.chart {
66 71
     width: 100%;
... ...
@@ -114,6 +119,11 @@ temperatures.
114 119
 <text id="time"></text>
115 120
 </div>
116 121
 
122
+<div id="alert">
123
+<text id="alertmsg" style="opacity: 0;">
124
+Warning: Low Battery Voltage</text>
125
+</div>
126
+
117 127
 <div class="rowContainer">
118 128
 
119 129
 <div class="currentDataCell">
... ...
@@ -122,10 +132,10 @@ Current:<br>
122 132
 Voltage:<br>
123 133
 Power:
124 134
 </div>
125
-<div class="dataItems" style="width: 30%;">
135
+<div class="dataItems" style="width: 40%;">
126 136
 <text id="current"></text> mA<br>
127 137
 <text id="voltage"></text> V<br>
128
-<text id="power"></text> mW
138
+<text id="power"></text> W
129 139
 </div>
130 140
 </div>
131 141
 
... ...
@@ -215,10 +225,12 @@ Status:
215 225
 </div>
216 226
 
217 227
 <script>
228
+"use strict";
218 229
 
219 230
 /* Global constants */
220 231
 
221
-var sensorDataUrl = "dynamic/powerData.js";
232
+var SENSOR_DATA_URL = "dynamic/powerData.js";
233
+var CRITICAL_VOLTAGE = 11.0;
222 234
 
223 235
 /* Global DOM objects */
224 236
 
... ...
@@ -238,7 +250,8 @@ var power_t = document.getElementById("power");
238 250
 var battemp_t = document.getElementById("battemp");    
239 251
 var ambtemp_t = document.getElementById("ambtemp");    
240 252
 var status_t = document.getElementById("status");
241
-var period_t = document.getElementById("period");    
253
+var period_t = document.getElementById("period");
254
+var alertmsg_t = document.getElementById("alertmsg");   
242 255
 
243 256
 /* Global objects */
244 257
 
... ...
@@ -247,6 +260,7 @@ var httpRequest = new XMLHttpRequest();
247 260
 /* Global variables */
248 261
 
249 262
 var graphPeriod;
263
+var objBlink;
250 264
 
251 265
 function main() {
252 266
     // Register call back function to process client http requests
... ...
@@ -270,7 +284,7 @@ function main() {
270 284
 }
271 285
 
272 286
 function getSensorData() {
273
-    httpRequest.open("GET", sensorDataUrl, true);
287
+    httpRequest.open("GET", SENSOR_DATA_URL, true);
274 288
     httpRequest.timeout = 3000;
275 289
     httpRequest.send();
276 290
 }
... ...
@@ -303,17 +317,27 @@ function getSensorGraphs() {
303 317
 }
304 318
 
305 319
 function displayData(dataItem) {
320
+    var voltage, current, power, ambtemp, battemp, powerWatts
321
+
322
+    voltage = Number(dataItem.voltage);
323
+    current = Number(dataItem.current);
324
+    power = Number(dataItem.power)/1000.0;
325
+    battemp = Number(dataItem.battemp);
326
+    ambtemp = Number(dataItem.ambtemp);
327
+
328
+    if (voltage < CRITICAL_VOLTAGE) {
329
+        displayAlert();
330
+    } else {
331
+        clearAlert();
332
+    }
333
+
306 334
     displayTime(dataItem);
307
-    current_t.innerHTML = 
308
-        (Number(dataItem.current).toFixed(2)).toString();
309
-    voltage_t.innerHTML = 
310
-        (Number(dataItem.voltage).toFixed(2)).toString();
311
-    power_t.innerHTML = 
312
-        (Number(dataItem.power).toFixed(2)).toString();
313
-    battemp_t.innerHTML = 
314
-        (Number(dataItem.battemp).toFixed(2)).toString();
315
-    ambtemp_t.innerHTML = 
316
-        (Number(dataItem.ambtemp).toFixed(2)).toString();
335
+    current_t.innerHTML = current.toFixed(2).toString(); 
336
+    voltage_t.innerHTML = voltage.toFixed(2).toString();
337
+    power_t.innerHTML = power.toFixed(2).toString();
338
+    battemp_t.innerHTML = battemp.toFixed(2).toString();
339
+    ambtemp_t.innerHTML = ambtemp.toFixed(2).toString();
340
+
317 341
     period_t.innerHTML = dataItem.period / 60;
318 342
     status_t.innerHTML = "online";
319 343
     status_t.style.color = "green";
... ...
@@ -331,6 +355,20 @@ function displayOfflineStatus() {
331 355
     status_t.style.color = "red";
332 356
 }
333 357
 
358
+function displayAlert() {
359
+    if (typeof objBlink == "undefined") {
360
+    objBlink = setInterval(function() {
361
+            alertmsg_t.style.opacity = 
362
+                (alertmsg_t.style.opacity == 0 ? 1 : 0);
363
+    }, 1000);
364
+    }
365
+}
366
+
367
+function clearAlert() {
368
+    clearInterval(objBlink);
369
+    alertmsg_t.style.opacity = 0;
370
+}
371
+
334 372
 function displayTime(dataItem) {
335 373
     var date, time, hourminute;
336 374
     var localDateObj, localTimeZone, timeZoneShift;