Many changes - not yet "controlled" updates.

This commit is contained in:
David
2021-10-04 13:45:39 +00:00
parent 8c1a403008
commit 74543a99f8
42 changed files with 7718 additions and 0 deletions

View 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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

BIN
Firmware/Resources/Open.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 B

View 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 &copy; 2018-2021 by Smartware Computing, all rights reserved.</li>
<li>Library for WEMO emulation, Copyright &copy; 2016 by Xose Pérez</li>
<li>Libraries; Copyright &copy; 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>

View 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;
}
}
);
}

View 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
View 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();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
Firmware/Resources/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View 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&deg;F</div>
<div class="soilmoisture">8%</div>
<div class="soiltemp">74&deg;F</div>
<div class="heater">ON</div>
<div class="ambtemp">65&deg;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>

View 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;
}
}
);
}

View 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
View 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();
}