Many changes - not yet "controlled" updates.
21
Firmware/Resources/Button.css
Normal file
@@ -0,0 +1,21 @@
|
||||
input.BigButton {
|
||||
width: 150px;
|
||||
padding: 20px;
|
||||
white-space: normal;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
font-size: 120%;
|
||||
background: #3366cc;
|
||||
color: #fff;
|
||||
border: 5px solid #112233;
|
||||
border-radius: 10px;
|
||||
-moz-box-shadow: 6px 6px 5px #999;
|
||||
-webkit-box-shadow: 6px 6px 5px #999;
|
||||
box-shadow: 6px 6px 5px #999;
|
||||
}
|
||||
|
||||
input.BigButton:hover {
|
||||
color: #ffff00;
|
||||
background: #000;
|
||||
border: 5px solid #fff;
|
||||
}
|
||||
BIN
Firmware/Resources/Green1x1.png
Normal file
|
After Width: | Height: | Size: 119 B |
BIN
Firmware/Resources/Heater.png
Normal file
|
After Width: | Height: | Size: 443 B |
BIN
Firmware/Resources/Open.png
Normal file
|
After Width: | Height: | Size: 655 B |
BIN
Firmware/Resources/PlantModel.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
Firmware/Resources/Water.png
Normal file
|
After Width: | Height: | Size: 869 B |
55
Firmware/Resources/about.htm
Normal file
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Grow Controller</title>
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, width=device-width">
|
||||
<script type='text/javascript' src='myip.js'></script>
|
||||
<script type='text/javascript' src='about.js'></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Grow Controller</h1>
|
||||
by Smartware Computing
|
||||
<blockquote>
|
||||
<table cellpadding="5">
|
||||
<tr valign="top">
|
||||
<td><img src="/icon.jpg" /></td>
|
||||
<td>
|
||||
This Grow Controller is an IOT device based on an ESP8266-12 module. The software for it has been
|
||||
derived from various sources and where copyrights have been identified, they are listed below.<br />
|
||||
<ul>
|
||||
<li>The composite work is Copyright © 2018-2021 by Smartware Computing, all rights reserved.</li>
|
||||
<li>Library for WEMO emulation, Copyright © 2016 by Xose Pérez</li>
|
||||
<li>Libraries; Copyright © 2001-2013 Free Software Foundation, Inc.</li>
|
||||
<li>Libraries; Copyright (c) 1997 Silicon Graphics Computer Systems, Inc.</li>
|
||||
</ul>
|
||||
<dl>
|
||||
<dt>Toggle Button</dt>
|
||||
<dd>Each press will toggle the circuit between on and off.</dd>
|
||||
<dt>Reset Button</dt>
|
||||
<dd>Momentary press resets unit. Very Long press causes Factory reset back to Access Point mode.</dd>
|
||||
</dl>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Mode:
|
||||
Uptime:
|
||||
|
||||
</blockquote>
|
||||
|
||||
<table>
|
||||
<tr valign="top">
|
||||
<td>NAV:</td>
|
||||
<td>
|
||||
<a href='/'>Home</a> |
|
||||
<a href='/config'>Config</a> |
|
||||
<a href='/scan'>Scan</a> |
|
||||
<a href='/rssi'>RSSI</a> |
|
||||
<a href='/curr'>Current</a> |
|
||||
<a href='/config?ssid=reset&pass=reset' onclick=\"return confirm('Are you sure?')\">Factory Reset</a> |
|
||||
<a href='/about'>About</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
30
Firmware/Resources/about.js
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// rssi script
|
||||
//
|
||||
// var mySite = 'http://192.168.1.23' from myip.js
|
||||
var url = mySite + '/state';
|
||||
setInterval(RefreshStatus, 5000);
|
||||
|
||||
getIt = function(aUrl, callback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', aUrl, true);
|
||||
xhr.responseType = 'text';
|
||||
xhr.onload = function(e) {
|
||||
if (this.status === 200) {
|
||||
callback(this.response);
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function RefreshStatus() {
|
||||
getIt(url,
|
||||
function(data) {
|
||||
obj = JSON.parse(data);
|
||||
var elms = document.querySelectorAll('.' + 'ip'), i;
|
||||
for (i = 0; i < elms.length; ++i) {
|
||||
elms[i].textContent = obj.ip;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
43
Firmware/Resources/curr.htm
Normal file
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Grow Controller</title>
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, width=device-width">
|
||||
<script type='text/javascript' src='myip.js'></script>
|
||||
<script type='text/javascript' src='curr.js'></script>
|
||||
</head>
|
||||
<body onload='CurrInit();'>
|
||||
<h1>Grow Controller - Current Sense</h1>
|
||||
<blockquote>
|
||||
<table width='800' border='0'>
|
||||
<tr>
|
||||
<td colspan='3' align='center'>
|
||||
<canvas id='curr' width='790' height='400'></canvas>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width='*' align='left'>
|
||||
<div id='uptime'>x:xx:xx</div>
|
||||
</td>
|
||||
<td width='20%' align='right'>
|
||||
<div id='currText'>xx</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</blockquote>
|
||||
<table>
|
||||
<tr valign="top">
|
||||
<td>NAV:</td>
|
||||
<td>
|
||||
<a href='/'>Home</a> |
|
||||
<a href='/config'>Config</a> |
|
||||
<a href='/scan'>Scan</a> |
|
||||
<a href='/rssi'>RSSI</a> |
|
||||
<a href='/curr'>Current</a> |
|
||||
<a href='/config?ssid=reset&pass=reset' onclick=\"return confirm('Are you sure?')\">Factory Reset</a> |
|
||||
<a href='/about'>About</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
141
Firmware/Resources/curr.js
Normal file
@@ -0,0 +1,141 @@
|
||||
//
|
||||
// curr script
|
||||
//
|
||||
// var mySite = 'http://192.168.1.23' from myip.js
|
||||
var url = mySite + '/state';
|
||||
var rawData = [];
|
||||
var avgData = [];
|
||||
var currIndex = 0;
|
||||
var axes = {};
|
||||
var totalSamples = 400; // Width of the graph
|
||||
for (var i = 0; i < totalSamples; i++)
|
||||
rawData[i] = avgData[i] = 0;
|
||||
setInterval(RefreshStatus, 250);
|
||||
|
||||
// -------------------------
|
||||
|
||||
getIt = function (aUrl, callback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', aUrl, true);
|
||||
xhr.responseType = 'text';
|
||||
xhr.onload = function (e) {
|
||||
if (this.status === 200) {
|
||||
callback(this.response);
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
};
|
||||
|
||||
function RefreshStatus() {
|
||||
getIt(url,
|
||||
function (data) {
|
||||
obj = JSON.parse(data);
|
||||
UpdateGraph(obj.raw, obj.sense); // raw and averaged
|
||||
document.getElementById('uptime').innerHTML = 'Uptime: ' + obj.uptime;
|
||||
document.getElementById('currText').innerHTML = 'raw: ' + obj.raw + ', avg: ' + obj.sense;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function CurrInit() {
|
||||
var canvas = document.getElementById('curr');
|
||||
if (null === canvas || !canvas.getContext)
|
||||
return;
|
||||
ctx = canvas.getContext('2d');
|
||||
axes.w = 0.9 * canvas.width;
|
||||
axes.h = 0.8 * canvas.height;
|
||||
axes.x0 = 0.07 * canvas.width; // x0 pixels from left to x=0
|
||||
axes.y0 = 0.10 * canvas.height; // y0 pixels from top to y=0
|
||||
axes.scaleX = totalSamples; // # pixels from x=0 to x=1
|
||||
axes.scaleY = 1024;
|
||||
axes.doNegativeX = false;
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.rect(0, 0, canvas.width - 1, canvas.height - 1);
|
||||
ctx.strokeStyle = 'black';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
showAxes(ctx, axes);
|
||||
}
|
||||
|
||||
function UpdateGraph(rawCurr, avgCurr) {
|
||||
var xx, yy;
|
||||
var i;
|
||||
|
||||
if (rawCurr > axes.scaleY) // safety limit
|
||||
rawCurr = axes.scaleY;
|
||||
else if (rawCurr < 0)
|
||||
rawCurr = 0;
|
||||
if (avgCurr > axes.scaleY) // safety limit
|
||||
avgCurr = axes.scaleY;
|
||||
else if (avgCurr < 0)
|
||||
avgCurr = 0;
|
||||
rawData[currIndex] = rawCurr;
|
||||
avgData[currIndex] = avgCurr;
|
||||
console.log('UpdateGraph(-' + rawCurr + ')');
|
||||
CurrInit();
|
||||
|
||||
// Draw Raw
|
||||
x0 = axes.x0;
|
||||
y0 = axes.y0;
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = '#FF8080';
|
||||
ctx.lineWidth = 3;
|
||||
for (i = 0; i < totalSamples; i++) {
|
||||
pi = (currIndex + 1 + i) % totalSamples;
|
||||
xx = x0 + i / axes.scaleX * axes.w;
|
||||
yy = y0 + axes.h - rawData[pi] / axes.scaleY * axes.h;
|
||||
ctx.lineTo(xx, yy);
|
||||
}
|
||||
ctx.stroke();
|
||||
// Circle
|
||||
ctx.beginPath();
|
||||
ctx.arc(xx, yy, 7, 0, 2 * Math.PI, false);
|
||||
ctx.fillstyle = '#FF8080';
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#FF0000';
|
||||
ctx.stroke();
|
||||
|
||||
// Draw Average
|
||||
x0 = axes.x0;
|
||||
y0 = axes.y0;
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = '#8080FF';
|
||||
ctx.lineWidth = 3;
|
||||
for (i = 0; i < totalSamples; i++) {
|
||||
pi = (currIndex + 1 + i) % totalSamples;
|
||||
xx = x0 + i / axes.scaleX * axes.w;
|
||||
yy = y0 + axes.h - avgData[pi] / axes.scaleY * axes.h;
|
||||
ctx.lineTo(xx, yy);
|
||||
}
|
||||
ctx.stroke();
|
||||
// Circle
|
||||
ctx.beginPath();
|
||||
ctx.arc(xx, yy, 7, 0, 2 * Math.PI, false);
|
||||
ctx.fillstyle = '#8080FF';
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#0000FF';
|
||||
ctx.stroke();
|
||||
currIndex++;
|
||||
currIndex %= totalSamples;
|
||||
}
|
||||
|
||||
function showAxes(ctx, axes) {
|
||||
var x0 = axes.x0, w = axes.w;
|
||||
var y0 = axes.y0, h = axes.h;
|
||||
var xmin = axes.doNegativeX ? 0 : x0;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.font = '12px Arial';
|
||||
ctx.textAlign = 'end';
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = 'rgb(128,128,128)';
|
||||
ctx.moveTo(x0, y0); ctx.lineTo(x0, y0 + h); // Y axis
|
||||
for (var y = 0; y <= axes.scaleY; y += 100) {
|
||||
yy = axes.y0 + axes.h - y / axes.scaleY * axes.h;
|
||||
ctx.moveTo(xmin, yy); ctx.lineTo(x0 + w, yy); // X axis
|
||||
ctx.fillText(y, x0 - 3, yy + 3);
|
||||
}
|
||||
ctx.font = '18px Arial';
|
||||
ctx.textAlign = 'start';
|
||||
ctx.fillText('Current Graph', axes.x0, axes.y0 - 6);
|
||||
ctx.stroke();
|
||||
}
|
||||
BIN
Firmware/Resources/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
Firmware/Resources/icon.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
208
Firmware/Resources/index.htm
Normal file
@@ -0,0 +1,208 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Grow Controller</title>
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, width=device-width">
|
||||
<style>
|
||||
input.SmallButton {
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
padding: 10px;
|
||||
white-space: normal;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
font-size: 100%;
|
||||
background: #3366cc;
|
||||
color: #fff;
|
||||
border: 5px solid #112233;
|
||||
border-radius: 10px;
|
||||
-moz-box-shadow: 6px 6px 5px #999;
|
||||
-webkit-box-shadow: 6px 6px 5px #999;
|
||||
box-shadow: 6px 6px 5px #999;
|
||||
}
|
||||
|
||||
input.SmallButton:hover {
|
||||
color: #ffff00;
|
||||
background: #000;
|
||||
border: 5px solid #fff;
|
||||
}
|
||||
|
||||
input.BigButton {
|
||||
width: 150px;
|
||||
height: 100px;
|
||||
padding: 10px;
|
||||
white-space: normal;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
font-size: 120%;
|
||||
background: #3366cc;
|
||||
color: #fff;
|
||||
border: 5px solid #112233;
|
||||
border-radius: 10px;
|
||||
-moz-box-shadow: 6px 6px 5px #999;
|
||||
-webkit-box-shadow: 6px 6px 5px #999;
|
||||
box-shadow: 6px 6px 5px #999;
|
||||
}
|
||||
|
||||
input.BigButton:hover {
|
||||
color: #ffff00;
|
||||
background: #000;
|
||||
border: 5px solid #fff;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
.box {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
div.airtemp {
|
||||
position: absolute;
|
||||
left: 170px;
|
||||
top: 50px;
|
||||
//border: 2px solid lightgray;
|
||||
}
|
||||
div.soilmoisture {
|
||||
position: absolute;
|
||||
left: 140px;
|
||||
top: 75px;
|
||||
//border: 2px solid lightgray;
|
||||
}
|
||||
div.soiltemp {
|
||||
position: absolute;
|
||||
left: 150px;
|
||||
top: 120px;
|
||||
color: white;
|
||||
//border: 2px solid lightgray;
|
||||
}
|
||||
div.heater {
|
||||
position: absolute;
|
||||
left: 105px;
|
||||
top: 156px;
|
||||
color: white;
|
||||
//border: 2px solid lightgray;
|
||||
}
|
||||
div.ambtemp {
|
||||
position: absolute;
|
||||
left: 205px;
|
||||
top: 205px;
|
||||
//border: 2px solid lightgray;
|
||||
}
|
||||
div.drumMotorV {
|
||||
position: absolute;
|
||||
left: 190px;
|
||||
top: 290px;
|
||||
//border: 2px solid lightgray;
|
||||
}
|
||||
div.drumMotorI {
|
||||
position: absolute;
|
||||
left: 180px;
|
||||
top: 320px;
|
||||
//border: 2px solid lightgray;
|
||||
}
|
||||
div.waterMotorV {
|
||||
position: absolute;
|
||||
left: 210px;
|
||||
top: 390px;
|
||||
//border: 2px solid lightgray;
|
||||
}
|
||||
div.waterLevel {
|
||||
position: absolute;
|
||||
left: 85px;
|
||||
top: 395px;
|
||||
//border: 2px solid lightgray;
|
||||
}
|
||||
div.heaterCoil {
|
||||
position: absolute;
|
||||
left: 78px;
|
||||
top: 177px;
|
||||
}
|
||||
div.water {
|
||||
position: absolute;
|
||||
left: 52px;
|
||||
top: 420px;
|
||||
z-index: -55;
|
||||
}
|
||||
</style>
|
||||
<script type='text/javascript' src='myip.js'></script>
|
||||
<script type='text/javascript' src='index.js'></script>
|
||||
</head>
|
||||
<body onload="RefreshStatus();">
|
||||
<h1><span id='name'>Grow Controller</span></h1>
|
||||
<form>
|
||||
<table border='0'>
|
||||
<tr>
|
||||
<td width='45%' align='center'>
|
||||
<div class="box">
|
||||
<div style="position: relative; z-index: -10;">
|
||||
<!-- 243 x 488 -->
|
||||
<img src='PlantModel.png' />
|
||||
</div>
|
||||
<div class="airtemp">92°F</div>
|
||||
<div class="soilmoisture">8%</div>
|
||||
<div class="soiltemp">74°F</div>
|
||||
<div class="heater">ON</div>
|
||||
<div class="ambtemp">65°F</div>
|
||||
<div class="drumMotorV">12.3V</div>
|
||||
<div class="drumMotorI">1.2A</div>
|
||||
<div class="waterMotorV">0.0V</div>
|
||||
<div class="waterLevel">OK</div>
|
||||
<div class="heaterCoil"><img src="Heater.png" /></div>
|
||||
<div class="water"><img src="Water.png" /></div>
|
||||
</div>
|
||||
</td>
|
||||
<td width='10%' align='center'>
|
||||
</td>
|
||||
<td width='45%' align='center'>
|
||||
<input class='BigButton' type='button' value='Automatic' onclick="window.location.href='/?SW=1'" />
|
||||
<br />
|
||||
<input class='BigButton' type='button' value='Manual [Open|Close]' onclick="window.location.href='/?SW=0'" />
|
||||
<br />
|
||||
<br />
|
||||
<input class='BigButton' type='button' value='Grow Settings' onclick="window.location.href='/?SW=2'" />
|
||||
<br />
|
||||
<input class='SmallButton' type='button' value='Load Monitor' onclick="window.location.href='/curr'" />
|
||||
<br />
|
||||
<input class='SmallButton' type='button' value='Wi-Fi Config.' onclick="window.location.href='/config'" />
|
||||
<br />
|
||||
<input class='SmallButton' type='button' value='RSSI Monitor' onclick="window.location.href='/rssi'" />
|
||||
<br />
|
||||
<input class='SmallButton' type='button' value='Scan for APs' onclick="window.location.href='/scan'" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<p></p>
|
||||
<table border='0'>
|
||||
<tr valign="top">
|
||||
<td>NAV:</td>
|
||||
<td>
|
||||
<a href='/'>Home</a> |
|
||||
<a href='/config'>Config</a> |
|
||||
<a href='/scan'>Scan</a> |
|
||||
<a href='/rssi'>RSSI</a> |
|
||||
<a href='/curr'>Current</a> |
|
||||
<a href='/config?ssid=reset&pass=reset' onclick=\"return confirm('Are you sure?')\">Factory Reset</a> |
|
||||
<a href='/about'>About</a>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- tr valign="top">
|
||||
<td>M2M:</td>
|
||||
<td>
|
||||
<a href='/on'>http://<span class='ip'></span>/on</a> |
|
||||
<a href='/off'>http://<span class='ip'></span>/off</a> |
|
||||
<a href='/toggle'>http://<span class='ip'></span>/toggle</a> |
|
||||
<a href='/state'>http://<span class='ip'></span>/state</a>
|
||||
</td>
|
||||
</tr!-->
|
||||
</table>
|
||||
<hr>
|
||||
<table border='0'>
|
||||
<tr>
|
||||
<td>GrowController by Origin Technologies</td>
|
||||
<td align="right"><a href="/swupdatecheck">Firmware</a>: <span id='version'>v0.00.00</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
44
Firmware/Resources/index.js
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// rssi script
|
||||
//
|
||||
// var mySite = 'http://192.168.1.23' from myip.js
|
||||
var url = mySite + '/state';
|
||||
setInterval(RefreshStatus, 250);
|
||||
|
||||
getIt = function (aUrl, callback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', aUrl, true);
|
||||
xhr.responseType = 'text';
|
||||
xhr.onload = function (e) {
|
||||
if (this.status === 200) {
|
||||
callback(this.response);
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
};
|
||||
|
||||
function RefreshStatus() {
|
||||
getIt(url,
|
||||
function(data) {
|
||||
obj = JSON.parse(data);
|
||||
if (obj.state === 1)
|
||||
state = "On";
|
||||
else
|
||||
state = "Off";
|
||||
document.getElementById('version').innerHTML = obj.version;
|
||||
document.getElementById('name').innerHTML = obj.name;
|
||||
document.getElementById('state').innerHTML = 'Output: ' + state;
|
||||
document.getElementById('raw').innerHTML = 'raw: ' + obj.raw;
|
||||
document.getElementById('sense').innerHTML = 'Sense: ' + obj.sense;
|
||||
document.getElementById('toggle').innerHTML = 'Toggle: ' + obj.toggle;
|
||||
document.getElementById('reset').innerHTML = 'Reset: ' + obj.reset;
|
||||
document.getElementById('countdown').innerHTML = obj.countdown;
|
||||
document.getElementById('uptime').innerHTML = 'Uptime: ' + obj.uptime;
|
||||
document.getElementById('wifimode').innerHTML = 'Mode: ' + obj.wifimode;
|
||||
var elms = document.querySelectorAll('.' + 'ip'), i;
|
||||
for (i = 0; i < elms.length; ++i) {
|
||||
elms[i].textContent = obj.ip;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
43
Firmware/Resources/rssi.htm
Normal file
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Grow Controller RSSI</title>
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, width=device-width">
|
||||
<script type='text/javascript' src='myip.js'></script>
|
||||
<script type='text/javascript' src='rssi.js'></script>
|
||||
</head>
|
||||
<body onload='RSSIInit();'>
|
||||
<h1>Grow Controller - RSSI</h1>
|
||||
<blockquote>
|
||||
<table width='800' border='0'>
|
||||
<tr>
|
||||
<td colspan='3' align='center'>
|
||||
<canvas id='RSSIGraph' width='790' height='400'></canvas>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width='*' align='left'>
|
||||
<div id='uptime'>x:xx:xx</div>
|
||||
</td>
|
||||
<td width='20%' align='right'>
|
||||
<div id='rssi'>-xx</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</blockquote>
|
||||
<table>
|
||||
<tr valign="top">
|
||||
<td>NAV:</td>
|
||||
<td>
|
||||
<a href='/'>Home</a> |
|
||||
<a href='/config'>Config</a> |
|
||||
<a href='/scan'>Scan</a> |
|
||||
<a href='/rssi'>RSSI</a> |
|
||||
<a href='/curr'>Current</a> |
|
||||
<a href='/config?ssid=reset&pass=reset' onclick=\"return confirm('Are you sure?')\">Factory Reset</a> |
|
||||
<a href='/about'>About</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
109
Firmware/Resources/rssi.js
Normal file
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// rssi script
|
||||
//
|
||||
// var mySite = 'http://192.168.1.23' from myip.js
|
||||
var url = mySite + '/state';
|
||||
var rssiData = [];
|
||||
var rssiIndex = 0;
|
||||
var axes = {};
|
||||
for (var i = 0; i<100; i++)
|
||||
rssiData[i] = 0;
|
||||
setInterval(RefreshStatus, 250);
|
||||
|
||||
// -------------------------
|
||||
|
||||
getIt = function (aUrl, callback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', aUrl, true);
|
||||
xhr.responseType = 'text';
|
||||
xhr.onload = function (e) {
|
||||
if (this.status === 200) {
|
||||
callback(this.response);
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
};
|
||||
|
||||
function RefreshStatus() {
|
||||
getIt(url,
|
||||
function(data) {
|
||||
obj = JSON.parse(data);
|
||||
UpdateGraph(obj.rssi);
|
||||
document.getElementById('rssi').innerHTML = 'RSSI: ' + obj.rssi;
|
||||
document.getElementById('uptime').innerHTML = 'Uptime: ' + obj.uptime;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function RSSIInit() {
|
||||
var canvas = document.getElementById('RSSIGraph');
|
||||
if (null === canvas || !canvas.getContext)
|
||||
return;
|
||||
ctx = canvas.getContext('2d');
|
||||
axes.w = 0.9 * canvas.width;
|
||||
axes.h = 0.8 * canvas.height;
|
||||
axes.x0 = 0.07 * canvas.width; // x0 pixels from left to x=0
|
||||
axes.y0 = 0.10 * canvas.height; // y0 pixels from top to y=0
|
||||
axes.scaleX = 100; // # pixels from x=0 to x=1
|
||||
axes.scaleY = 100;
|
||||
axes.doNegativeX = false;
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.rect(0, 0, canvas.width - 1, canvas.height - 1);
|
||||
ctx.strokeStyle = 'black';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
showAxes(ctx, axes);
|
||||
}
|
||||
|
||||
function UpdateGraph(rssi) {
|
||||
var xx, yy;
|
||||
rssi = -rssi; // invert for convenience
|
||||
if (rssi > axes.scaleY) // safety limit
|
||||
rssi = axes.scaleY;
|
||||
else if (rssi < 0)
|
||||
rssi = 0;
|
||||
rssiData[rssiIndex] = rssi;
|
||||
console.log('UpdateGraph(-' + rssi + ')');
|
||||
RSSIInit();
|
||||
x0 = axes.x0;
|
||||
y0 = axes.y0;
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = 'rgb(250,128,128)';
|
||||
ctx.lineWidth = 5;
|
||||
for (var i = 0; i<100; i++) {
|
||||
pi = (rssiIndex + 1 + i) % 100;
|
||||
xx = x0 + i / axes.scaleX * axes.w;
|
||||
yy = y0 + rssiData[pi] / axes.scaleY * axes.h;
|
||||
ctx.lineTo(xx, yy);
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.arc(xx, yy, 7, 0, 2 * Math.PI, false);
|
||||
ctx.fillstyle = 'green';
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#003300';
|
||||
ctx.stroke();
|
||||
rssiIndex++;
|
||||
rssiIndex %= 100;
|
||||
}
|
||||
|
||||
function showAxes(ctx, axes) {
|
||||
var x0 = axes.x0, w = axes.w;
|
||||
var y0 = axes.y0, h = axes.h;
|
||||
var xmin = axes.doNegativeX ? 0 : x0;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.font = '12px Arial';
|
||||
ctx.textAlign = 'end';
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = 'rgb(128,128,128)';
|
||||
ctx.moveTo(x0, y0); ctx.lineTo(x0, y0 + h); // Y axis
|
||||
for (var y = 0; y <= axes.scaleY; y += 10) {
|
||||
yy = axes.y0 + y / axes.scaleY * axes.h;
|
||||
ctx.moveTo(xmin, yy); ctx.lineTo(x0 + w, yy); // X axis
|
||||
ctx.fillText(-y, x0 - 3, yy + 3);
|
||||
}
|
||||
ctx.font = '18px Arial';
|
||||
ctx.textAlign = 'start';
|
||||
ctx.fillText('RSSI Graph', axes.x0, axes.y0 - 6);
|
||||
ctx.stroke();
|
||||
}
|
||||