8623d74e |
<!DOCTYPE html>
<!-- Courtesy ruler for editing this file
12345678901234567890123456789012345678901234567890123456789012345678901234567890
-->
<html>
<head>
<title>Node Power</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
background-image: url("static/chalk.jpg");
}
h2 {
font: bold 24px arial, sans-serif;
}
h4 {
font: bold 16px arial, sans-serif;
}
p {
font: normal 14px arial, sans-serif;
}
#mainContainer {
width: 740px;
text-align: center;
margin: auto;
}
#datetime {
padding: 10px;
font: bold 22px arial, sans-serif;
/*border: 1px solid black;*/
}
#notes {
font: 17px arial, sans-serif;
text-align: left;
padding: 10px;
}
|
d65ec281 |
#alert {
font: bold 22px arial, sans-serif;
color: red;
/*border: 1px solid black;*/
}
|
769aeab2 |
#logoBox {
display:inline-block;
width:20%;
/*border:1px solid black;*/
}
#logoInfo {
padding-left: 20px;
padding-top: 10px;
display:inline-block;
width:45%;
font:14px arial,sans-serif;
text-align:left;
vertical-align: top;
/*border:1px solid black;*/
}
|
8623d74e |
.rowContainer {
display: table;
width: 100%;
/*border: 1px solid black;*/
}
.currentDataCell {
width: 50%;
padding: 10px;
font: bold 18px arial, sans-serif;
text-align: center;
display: table-cell;
vertical-align: middle;
/*border: 1px solid black;*/
}
.dataItems {
padding: 2px;
text-align: left;
line-height: 130%;
display: inline-block;
vertical-align: middle;
/*border: 1px solid black;*/
}
.chartContainer {
padding: 2px;
|
769aeab2 |
/*border: 1px solid black;8?
|
8623d74e |
}
img.chart {
width: 100%;
|
769aeab2 |
height: 233px;
/*border: 1px solid black;*/
|
8623d74e |
}
span.chartNav {
margin: auto;
}
ul.chartNav {
list-style-type: none;
margin: 10px;
padding: 0;
overflow: hidden;
background-color: #bbb;
text-align: center;
}
li.chartNav {
display: inline-block;
font: bold 18px arial, sans-serif;
color: black;
}
text.chartNav:hover {
background-color: #333;
cursor: pointer;
color: white;
}
text.chartNav {
display: inline-block;
padding: 8px 12px;
}
|
8d25b7b0 |
#iframe_a {
border:none;
width:100%;
height:1075px;
}
|
8623d74e |
</style>
</head>
<body onload="main()">
<div id="mainContainer">
|
769aeab2 |
<div id="logoBox">
<a href="https://github.com/fractalxaos/ham/tree/master/nodepower"
|
8623d74e |
style="text-decoration:none" target="_new">
|
769aeab2 |
<img src="static/npwlogo.png"></a>
</div>
|
8623d74e |
|
769aeab2 |
<div id="logoInfo">
This web page shows the power consumption of the node installation at the site listed below. The charts provide a historical glimpse for different time periods
of node power consumption, battery and ambient temperatures.
|
8623d74e |
</div>
|
769aeab2 |
<a href="http://wa7abu-pb400-vp-0ccd.local.mesh:8080/cgi-bin/status"
style="text-decoration:none" target="_new">
<h4>WA7ABU Victor Point AREDN Mesh Installation</h4></a>
|
8623d74e |
<div id="datetime">
<text id="date"></text>
<text id="time"></text>
</div>
|
d65ec281 |
<div id="alert">
<text id="alertmsg" style="opacity: 0;">
Warning: Low Battery Voltage</text>
</div>
|
8623d74e |
<div class="rowContainer">
<div class="currentDataCell">
<div class="dataItems">
Current:<br>
Voltage:<br>
Power:
</div>
|
d65ec281 |
<div class="dataItems" style="width: 40%;">
|
8623d74e |
<text id="current"></text> mA<br>
<text id="voltage"></text> V<br>
|
d65ec281 |
<text id="power"></text> W
|
8623d74e |
</div>
</div>
<div class="currentDataCell">
<div class="dataItems">
Battery Temperature:<br>
Ambient Temperature:
</div>
<div class="dataItems" style="width: 30%;">
|
58e58c0d |
<text id="battemp"></text> ℉<br>
<text id="ambtemp"></text> ℉<br>
|
8623d74e |
</div>
</div>
</div>
<div class="rowContainer">
<div class="currentDataCell">
<div class="dataItems">
Charts update every
</div>
<div class="dataItems">
<text id="period"></text> minutes.<br>
</div>
</div>
<div class="currentDataCell">
<div class="dataItems">
Status:
</div>
<div class="dataItems">
<text id="status"></text><br>
</div>
</div>
</div>
<span class="chartNav">
<ul class="chartNav">
<li class="chartNav">Select charts:</li>
<li class="chartNav"><text class="chartNav" onclick="setChartPeriod(1)">
24 hours</text></li>
<li class="chartNav"><text class="chartNav" onclick="setChartPeriod(2)">
4 weeks</text></li>
<li class="chartNav"><text class="chartNav" onclick="setChartPeriod(3)">
12 months</text></li>
|
8d25b7b0 |
<li id="customSelector" class="chartNav">
<text class="chartNav"
onclick="setChartPeriod(0)">Custom…</text></li>
|
8623d74e |
</ul>
</span>
|
8d25b7b0 |
<div class="rowContainer" id="customChartsContainer" style="display:none;">
<div class="currentDataCell">
<form id="fmDateSelector" action="power.php" method="post"
target="iframe_a">
<label for="beginDate">Begin Date: </label>
<input id="beginDate" name="beginDate" type="date" value="mm/dd/yyyy" />
<label for="endDate">End Date: </label>
<input id="endDate" name="endDate" type="date" value="mm/dd/yyyy" />
<br><br>
<input type="button" onclick="getCustomCharts()" value="Get Charts">
</form>
<span id="errorMsg"></span><br>
<iframe id="iframe_a" name="iframe_a"></iframe>
</div>
</div>
|
8623d74e |
<br>
|
8d25b7b0 |
<div class="rowContainer" id="stockChartsContainer">
|
8623d74e |
<div class="chartContainer">
<img class="chart" id="current_g">
</div>
<div class="chartContainer">
<img class="chart" id="voltage_g">
</div>
<div class="chartContainer">
<img class="chart" id="power_g">
</div>
<div class="chartContainer">
<img class="chart" id="battemp_g">
</div>
<div class="chartContainer">
<img class="chart" id="ambtemp_g">
</div>
|
8d25b7b0 |
</div>
|
8623d74e |
<div id="notes">
<b>NOTES:</b>
<ul>
<li>Node sensor project plans and software available at
|
769aeab2 |
<a href="https://github.com/fractalxaos/ham/archive/master.zip" target="_new">
|
8623d74e |
<i>Github.com</i>
</a>.</li>
|
98865bbb |
<li>Project plans and software also available via the mesh
<a href="http://ka7jlo-web.local.mesh/file-manager/files/KA7JLO/Apps/nodepower/nodepower.zip" target="_new">
<i>here</i>
</a>.</li>
|
8623d74e |
<li>Project plans include detailed instructions on how to use a Raspberry
Pi Zero to add power bus and battery temperature monitoring
for your AREDN node.</li>
<li>Displayed data may be delayed by as much as 2 seconds from
time of actual measurement.</li>
<li>Project sponsored by
<a href=https://willamettevalleymesh.net/ TARGET="_NEW">
<i>Willamette Valley Mesh Network</i></a>, Salem, Oregon.</li>
<li>Designed by Jeff Owrey, KA7JLO, 2021.</li>
<li> Released under Creative Commons License.</li>
</ul>
</div><br><br>
</div>
<script>
|
d65ec281 |
"use strict";
|
8623d74e |
/* Global constants */
|
d65ec281 |
var SENSOR_DATA_URL = "dynamic/powerData.js";
var CRITICAL_VOLTAGE = 11.0;
|
8623d74e |
/* Global DOM objects */
// Chart Elements
var current_g = document.getElementById("current_g");
var voltage_g = document.getElementById("voltage_g");
var power_g = document.getElementById("power_g");
var battemp_g = document.getElementById("battemp_g");
var ambtemp_g = document.getElementById("ambtemp_g");
// Text Elements
var date_t = document.getElementById("date");
var time_t = document.getElementById("time");
var current_t = document.getElementById("current");
var voltage_t = document.getElementById("voltage");
var power_t = document.getElementById("power");
var battemp_t = document.getElementById("battemp");
var ambtemp_t = document.getElementById("ambtemp");
var status_t = document.getElementById("status");
|
d65ec281 |
var period_t = document.getElementById("period");
var alertmsg_t = document.getElementById("alertmsg");
|
8623d74e |
|
8d25b7b0 |
var customChartsContainer = document.getElementById("customChartsContainer");
var stockChartsContainer = document.getElementById("stockChartsContainer");
var fmDateSelector = document.getElementById("fmDateSelector");
var errorMsg = document.getElementById("errorMsg");
var customSelector = document.getElementById("customSelector");
|
8623d74e |
/* Global objects */
var httpRequest = new XMLHttpRequest();
/* Global variables */
|
8d25b7b0 |
var chartPeriod = 1;
|
d65ec281 |
var objBlink;
|
8623d74e |
function main() {
|
cd727c58 |
httpRequest.timeout = 3000;
|
8d25b7b0 |
if (location.hostname.match(/.local/g) == null) {
customSelector.style.visibility = "hidden";
}
|
8623d74e |
// Register call back function to process client http requests
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState == 4 && httpRequest.status == 200) {
var dataArray = JSON.parse(httpRequest.responseText);
displayData(dataArray[0]);
} else if (httpRequest.readyState == 4 && httpRequest.status == 404) {
displayOfflineStatus();
}
};
|
cd727c58 |
|
8623d74e |
httpRequest.ontimeout = function(e) {
displayOfflineStatus();
};
|
8d25b7b0 |
initializeDateSelector();
|
8623d74e |
getSensorData();
getSensorGraphs();
setInterval(getSensorData, 2000);
setInterval(getSensorGraphs, 600000);
}
function getSensorData() {
|
cd727c58 |
httpRequest.open("POST", SENSOR_DATA_URL, true);
|
8623d74e |
httpRequest.send();
}
function setChartPeriod(n) {
|
8d25b7b0 |
chartPeriod = n;
if (n == 0) {
customChartsContainer.style.display = "block";
stockChartsContainer.style.display = "none";
} else {
customChartsContainer.style.display = "none";
stockChartsContainer.style.display = "block";
getSensorGraphs();
}
|
8623d74e |
}
function getSensorGraphs() {
var d = new Date;
var pfx;
|
8d25b7b0 |
switch(chartPeriod) {
|
8623d74e |
case 1:
pfx = "24hr_";
break;
case 2:
pfx = "4wk_";
break;
case 3:
pfx = "12m_";
break;
}
current_g.src = "dynamic/" + pfx + "current.png?ver=" + d.getTime();
voltage_g.src = "dynamic/" + pfx + "voltage.png?ver=" + d.getTime();
power_g.src = "dynamic/" + pfx + "power.png?ver=" + d.getTime();
battemp_g.src = "dynamic/" + pfx + "battemp.png?ver=" + d.getTime();
ambtemp_g.src = "dynamic/" + pfx + "ambtemp.png?ver=" + d.getTime();
}
function displayData(dataItem) {
|
d65ec281 |
var voltage, current, power, ambtemp, battemp, powerWatts
voltage = Number(dataItem.voltage);
current = Number(dataItem.current);
power = Number(dataItem.power)/1000.0;
battemp = Number(dataItem.battemp);
ambtemp = Number(dataItem.ambtemp);
if (voltage < CRITICAL_VOLTAGE) {
displayAlert();
} else {
clearAlert();
}
|
8623d74e |
displayTime(dataItem);
|
d65ec281 |
current_t.innerHTML = current.toFixed(2).toString();
voltage_t.innerHTML = voltage.toFixed(2).toString();
power_t.innerHTML = power.toFixed(2).toString();
battemp_t.innerHTML = battemp.toFixed(2).toString();
ambtemp_t.innerHTML = ambtemp.toFixed(2).toString();
|
76a2df75 |
period_t.innerHTML = dataItem.chartUpdateInterval / 60;
|
8623d74e |
status_t.innerHTML = "online";
status_t.style.color = "green";
}
function displayOfflineStatus() {
displayHostTime();
current_t.innerHTML = "";
voltage_t.innerHTML = "";
power_t.innerHTML = "";
battemp_t.innerHTML = "";
ambtemp_t.innerHTML = "";
period_t.innerHTML = " -n/a- ";
status_t.innerHTML = "offline";
status_t.style.color = "red";
}
|
d65ec281 |
function displayAlert() {
if (typeof objBlink == "undefined") {
objBlink = setInterval(function() {
alertmsg_t.style.opacity =
(alertmsg_t.style.opacity == 0 ? 1 : 0);
}, 1000);
}
}
function clearAlert() {
clearInterval(objBlink);
alertmsg_t.style.opacity = 0;
}
|
8623d74e |
function displayTime(dataItem) {
var date, time, hourminute;
var localDateObj, localTimeZone, timeZoneShift;
date = dataItem.time.split(" ")[0];
time = dataItem.time.split(" ")[1];
hourminute = time.split(":")[0] + ":" + time.split(":")[1];
localDateObj = new Date();
localTimeZone = localDateObj.getTimezoneOffset() / 60;
if (Math.sign(localTimeZone)) {
timeZoneShift = "-";
} else {
timeZoneShift = "+"
}
date_t.innerHTML = date;
time_t.innerHTML = hourminute + " <small>(UTC" + timeZoneShift +
localTimeZone + ")</small>";
}
function displayHostTime() {
var d = new Date();
var localTimeZone, timeZoneShift;
localTimeZone = d.getTimezoneOffset() / 60;
if (Math.sign(localTimeZone)) {
timeZoneShift = "-";
} else {
timeZoneShift = "+"
}
date_t.innerHTML = d.getMonth() + "/" + d.getDate() + "/" +
d.getFullYear();
time_t.innerHTML = d.getHours() + ":" + d.getMinutes() +
" <small>(UTC" + timeZoneShift + localTimeZone + ")</small>";
}
|
8d25b7b0 |
function initializeDateSelector() {
var d = new Date();
var dEnd = new Date(d.getFullYear(),
d.getMonth(), d.getDate() - 0);
var dBegin = new Date(d.getFullYear(),
d.getMonth(), d.getDate() - 1);
document.getElementById("beginDate").valueAsDate = dBegin;
document.getElementById("endDate").valueAsDate = dEnd;
}
function getCustomCharts() {
fmDateSelector.submit();
}
|
8623d74e |
</script>
</body>
</html>
|