Browse Source

Major overhaul

refactored frontend source files
added frontend build script
minor code optimizations
development
Rohan Sircar 4 years ago
parent
commit
068703999a
  1. 3
      .gitignore
  2. BIN
      data/NotoSansBold15.vlw
  3. BIN
      data/NotoSansBold36.vlw
  4. BIN
      data/Nunito-Light20.vlw
  5. BIN
      data/Nunito-Light28.vlw
  6. BIN
      data/Nunito-Light32.vlw
  7. BIN
      data/Nunito-Regular20.vlw
  8. BIN
      data/WebSocket.js.gz
  9. BIN
      data/colors.css.gz
  10. BIN
      data/edit.html.gz
  11. BIN
      data/favicon.ico.gz
  12. BIN
      data/index.html.gz
  13. BIN
      data/ledcontrol.html.gz
  14. BIN
      data/loadMenu.js.gz
  15. BIN
      data/main.css.gz
  16. BIN
      data/main.js.gz
  17. BIN
      data/manifest.json.gz
  18. BIN
      data/manualMode-ajax.html.gz
  19. BIN
      data/manualMode.html.gz
  20. BIN
      data/menu.html.gz
  21. BIN
      data/nunito-regular-webfont.woff
  22. BIN
      data/nunito-regular-webfont.woff2
  23. BIN
      data/settings-ajax.html.gz
  24. BIN
      data/settings-success.html.gz
  25. BIN
      data/settings.html.gz
  26. BIN
      data/settings.js.gz
  27. 7
      data/settingsFile1.txt
  28. 7
      data/settingsFile2.txt
  29. 7
      data/settingsFile3.txt
  30. BIN
      data/success.html.gz
  31. BIN
      data/temperatures.txt.gz
  32. BIN
      data/uploadButtonStyle.js.gz
  33. 19
      frontend-build.sh
  34. 159
      frontend/src/colors.css
  35. 0
      frontend/src/combinedSettingsFile.txt
  36. 61
      frontend/src/edit.html
  37. 109
      frontend/src/index.html
  38. 39
      frontend/src/ledcontrol.html
  39. 3
      frontend/src/loadMenu.js
  40. 29
      frontend/src/main.css
  41. 177
      frontend/src/main.js
  42. 186
      frontend/src/main_bak.css
  43. 11
      frontend/src/manifest.json
  44. 122
      frontend/src/manualMode-ajax.html
  45. 78
      frontend/src/manualMode.html
  46. 0
      frontend/src/manualMode.txt
  47. 26
      frontend/src/menu.html
  48. 88
      frontend/src/settings-ajax.html
  49. 23
      frontend/src/settings-success.html
  50. 88
      frontend/src/settings.html
  51. 39
      frontend/src/settings.js
  52. 7
      frontend/src/settingsFile1.txt
  53. 7
      frontend/src/settingsFile2.txt
  54. 7
      frontend/src/settingsFile3.txt
  55. 23
      frontend/src/success.html
  56. 6
      frontend/src/temperatures.txt
  57. 8
      frontend/src/uploadButtonStyle.js
  58. 10
      include.js
  59. 6
      platformio.ini
  60. 21
      src/main.cpp
  61. BIN
      website-zipped_bak/index.html.gz
  62. BIN
      website-zipped_bak/ledcontrol.html.gz
  63. BIN
      website-zipped_bak/main.css.gz
  64. BIN
      website-zipped_bak/manifest.json.gz
  65. BIN
      website-zipped_bak/manualMode-ajax.html.gz
  66. BIN
      website-zipped_bak/manualMode.html.gz
  67. BIN
      website-zipped_bak/menu.html.gz
  68. BIN
      website-zipped_bak/nunito-regular-webfont.woff.gz
  69. BIN
      website-zipped_bak/nunito-regular-webfont.woff2.gz
  70. BIN
      website-zipped_bak/settings-ajax.html.gz
  71. BIN
      website-zipped_bak/settings-success.html.gz
  72. BIN
      website-zipped_bak/settings.html.gz
  73. BIN
      website-zipped_bak/success.html.gz

3
.gitignore

@ -6,3 +6,6 @@ website-source-copy
website-zipped
website-zipped_bak
.vscode
target
/data/
/data2/

BIN
data/NotoSansBold15.vlw

BIN
data/NotoSansBold36.vlw

BIN
data/Nunito-Light20.vlw

BIN
data/Nunito-Light28.vlw

BIN
data/Nunito-Light32.vlw

BIN
data/Nunito-Regular20.vlw

BIN
data/WebSocket.js.gz

BIN
data/colors.css.gz

BIN
data/edit.html.gz

BIN
data/favicon.ico.gz

BIN
data/index.html.gz

BIN
data/ledcontrol.html.gz

BIN
data/loadMenu.js.gz

BIN
data/main.css.gz

BIN
data/main.js.gz

BIN
data/manifest.json.gz

BIN
data/manualMode-ajax.html.gz

BIN
data/manualMode.html.gz

BIN
data/menu.html.gz

BIN
data/nunito-regular-webfont.woff

BIN
data/nunito-regular-webfont.woff2

BIN
data/settings-ajax.html.gz

BIN
data/settings-success.html.gz

BIN
data/settings.html.gz

BIN
data/settings.js.gz

7
data/settingsFile1.txt

@ -1,7 +0,0 @@
{
"shour1": 16,
"fadePeriod1": 30,
"smin1": 0,
"ehour": 22,
"emin": 0
}

7
data/settingsFile2.txt

@ -1,7 +0,0 @@
{
"shour2": 16,
"fadePeriod2": 30,
"smin2": 0,
"ehour": 22,
"emin": 0
}

7
data/settingsFile3.txt

@ -1,7 +0,0 @@
{
"shour3": 16,
"fadePeriod3": 30,
"smin3": 0,
"ehour": 22,
"emin": 0
}

BIN
data/success.html.gz

BIN
data/temperatures.txt.gz

BIN
data/uploadButtonStyle.js.gz

19
frontend-build.sh

@ -0,0 +1,19 @@
#!/usr/bin/env bash
rm -r frontend/target/
rm -r data/
rsync -avz --progress frontend/src/** frontend/target/
cd frontend/target/
find . \( \
-name '*.css' \
-o -name '*.html' \
-o -name '*.js' \
-o -name '*.jpg' \
-o -name '*.png' \
-o -name '*.ico' \
\) -exec pigz --force --verbose {} \;
cd ../..
rsync -avz --progress frontend/target/** data/

159
frontend/src/colors.css

@ -0,0 +1,159 @@
/*------------------------------------
- COLOR ternary
------------------------------------*/
.alert-ternary {
color: #001b1e;
background-color: #65edff;
border-color: #51eaff;
}
.alert-ternary hr {
border-top-color: #38e7ff;
}
.alert-ternary .alert-link {
color: #000000;
}
.badge-ternary {
color: #fff;
background-color: #008799;
}
.badge-ternary[href]:hover,
.badge-ternary[href]:focus {
color: #fff;
background-color: #005965;
}
.bg-ternary {
background-color: #008799 !important;
}
a.bg-ternary:hover,
a.bg-ternary:focus,
button.bg-ternary:hover,
button.bg-ternary:focus {
background-color: #005965 !important;
}
.border-ternary {
border-color: #008799 !important;
}
.btn-ternary {
color: #fff;
background-color: #008799;
border-color: #008799;
}
.btn-ternary:hover {
color: #fff;
background-color: #006775;
border-color: #005965;
}
.btn-ternary:focus,
.btn-ternary.focus {
box-shadow: 0 0 0 0.2rem rgba(0, 135, 153, 0.5);
}
.btn-ternary.disabled,
.btn-ternary:disabled {
color: #fff;
background-color: #008799;
border-color: #008799;
}
.btn-ternary:not(:disabled):not(.disabled):active,
.btn-ternary:not(:disabled):not(.disabled).active,
.show>.btn-ternary.dropdown-toggle {
color: #fff;
background-color: #005965;
border-color: #004c56;
}
.btn-ternary:not(:disabled):not(.disabled):active:focus,
.btn-ternary:not(:disabled):not(.disabled).active:focus,
.show>.btn-ternary.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(0, 135, 153, 0.5);
}
.btn-outline-ternary {
color: #008799;
background-color: transparent;
border-color: #008799;
}
.btn-outline-ternary:hover {
color: #fff;
background-color: #008799;
border-color: #008799;
}
.btn-outline-ternary:focus,
.btn-outline-ternary.focus {
box-shadow: 0 0 0 0.2rem rgba(0, 135, 153, 0.5);
}
.btn-outline-ternary.disabled,
.btn-outline-ternary:disabled {
color: #008799;
background-color: transparent;
}
.btn-outline-ternary:not(:disabled):not(.disabled):active,
.btn-outline-ternary:not(:disabled):not(.disabled).active,
.show>.btn-outline-ternary.dropdown-toggle {
color: #fff;
background-color: #008799;
border-color: #008799;
}
.btn-outline-ternary:not(:disabled):not(.disabled):active:focus,
.btn-outline-ternary:not(:disabled):not(.disabled).active:focus,
.show>.btn-outline-ternary.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(0, 135, 153, 0.5);
}
.list-group-item-ternary {
color: #001b1e;
background-color: #51eaff;
}
.list-group-item-ternary.list-group-item-action:hover,
.list-group-item-ternary.list-group-item-action:focus {
color: #001b1e;
background-color: #38e7ff;
}
.list-group-item-ternary.list-group-item-action.active {
color: #fff;
background-color: #001b1e;
border-color: #001b1e;
}
.table-ternary,
.table-ternary>th,
.table-ternary>td {
background-color: #51eaff;
}
.table-hover .table-ternary:hover {
background-color: #38e7ff;
}
.table-hover .table-ternary:hover>td,
.table-hover .table-ternary:hover>th {
background-color: #38e7ff;
}
.text-ternary {
color: #008799 !important;
}
a.text-ternary:hover,
a.text-ternary:focus {
color: #005965 !important;
}

0
data/combinedSettingsFile.txt → frontend/src/combinedSettingsFile.txt

61
frontend/src/edit.html

@ -0,0 +1,61 @@
<!DOCTYPE html>
<html>
<head>
<title>ESP8266 SPIFFS File Upload</title>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" sizes="144x144" href="/favicon-144x144.png">
<link rel="icon" type="image/png" sizes="48x48" href="/favicon.ico">
<link rel="manifest" href="manifest.json">
<meta name="theme-color" content="#00878f">
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport'>
<meta charset="utf-8">
<script src="loadMenu.js" defer></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.15.0/esm/popper.js" type="module"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sprintf/1.1.2/sprintf.min.js"></script>
<link href='main.css' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="colors.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-filestyle/2.1.0/bootstrap-filestyle.min.js"></script>
<script src="uploadButtonStyle.js" defer></script>
</head>
<body>
<div id="navigation"></div>
<div class="container shadow-lg">
<section class="py-5 mt-3">
<div class="container">
<div class="row">
<div class="col">
<h1 class="display-4 text-ternary">ESP8266 SPIFFS File Upload</h1>
<div class="row">
<div class="col-md-6 offset-md-3">
<p>Select a new file to upload to the ESP8266. Existing files will be replaced.</p>
<form method="POST" enctype="multipart/form-data">
<div class="form-group">
<input class="filestyle" data-btnClass="btn-ternary" type="file" data-dragdrop="true" name="data" id="upload-button" required>
<p class="form-text text-muted">You can drag and drop files as well</p>
</div>
<div class="form-group text-center">
<input class="btn btn-ternary" type="submit" value="Upload">
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</body>
</html>

109
frontend/src/index.html

@ -0,0 +1,109 @@
<!DOCTYPE html>
<html>
<head>
<title>Home</title>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" sizes="144x144" href="/favicon-144x144.png">
<link rel="icon" type="image/png" sizes="48x48" href="/favicon.ico">
<link rel="manifest" href="manifest.json">
<meta name="theme-color" content="#00878f">
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport'>
<meta charset="utf-8">
<script src="loadMenu.js" defer></script>
<script src="main.js" defer></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.15.0/esm/popper.js" type="module"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sprintf/1.1.2/sprintf.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pretty-checkbox@3.0/dist/pretty-checkbox.min.css">
<link href='main.css' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="colors.css">
</head>
<body>
<!-- <iframe src="menu.html" width="90%"></iframe> -->
<div id="navigation"></div>
<div class="container">
<div class="shadow-lg p-3 mb-5 bg-white rounded">
<header>
<div class="container">
<div class="row">
<div class="col">
<div class="pt-5 mt-3">
<h2 class="display-4 text-ternary text-center"> Welcome </h2>
<p class="text-center">Welcome to the planted aquarium controller.</p>
</div>
</div>
</div>
</div>
</header>
<section>
<div class="container bg-ternary shadow-sm p-3 mb-2 rounded">
<div class="row mb-3">
<div class="col">
<h2 class="text-white text-center display-4">Settings at a glance</h2>
</div>
</div>
<div class="row" id="content-row">
<div class="col-md">
<section id="mySection "></section>
<div class="card mb-3 text-center card-form rounded mx-auto shadow-sm ">
<h2 class="card-header text-center text-ternary">Ballast #1</h2>
<div class="card-body rounded">
<div class="card-text" id="ballast1">
</div>
</div>
</div>
</div>
<div class="col-md">
<div class="card mb-3 text-center card-form rounded mx-auto shadow-sm">
<h2 class="card-header text-center text-ternary">Ballast #2</h2>
<div class="card-body rounded">
<div class="card-text" id="ballast2">
</div>
</div>
</div>
</div>
<div class="col-md">
<div class="card mb-3 text-center card-form rounded mx-auto shadow-sm">
<h2 class="card-header text-center text-ternary">Ballast #3</h2>
<div class="card-body rounded">
<div class="card-text" id="ballast3">
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section>
<div class="container">
<div class="row">
<div class="col">
<div class="pretty p-switch ">
<input type="checkbox" id="temperatures-switch" />
<div class="state p-primary">
<label>Show temperature readings</label>
</div>
</div>
<p id="temperature"></p>
<noscript>No javascript</noscript>
</div>
</div>
</div>
</section>
</div>
</div>
</body>
</html>

39
frontend/src/ledcontrol.html

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<title>LED Control</title>
<link href='main.css' rel='stylesheet' type='text/css'>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" sizes="144x144" href="/favicon-144x144.png">
<link rel="icon" type="image/png" sizes="48x48" href="/favicon.ico">
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#00878f">
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport'>
<script src="WebSocket.js" type="text/javascript"></script>
</head>
<body>
<center>
<header>
<h1>LED Control</h1>
</header>
<div>
<table>
<tr>
<td style="width:14.4px; text-align: right">R: </td>
<td><input class="enabled" id="r" type="range" min="0" max="1023" step="1" oninput="sendRGB();" value="0"></td>
</tr>
<tr>
<td style="width:14.4px; text-align: right">G: </td>
<td><input class="enabled" id="g" type="range" min="0" max="1023" step="1" oninput="sendRGB();" value="0"></td>
</tr>
<tr>
<td style="width:14.4px; text-align: right">B: </td>
<td><input class="enabled" id="b" type="range" min="0" max="1023" step="1" oninput="sendRGB();" value="0"></td>
</tr>
</table>
<p style="margin:8px 0px"><button id="rainbow" class="button" style="background-color:#999" onclick="rainbowEffect();">Rainbow</button></p>
</div>
</center>
</body>
</html>

3
frontend/src/loadMenu.js

@ -0,0 +1,3 @@
$(document).ready(function() {
$('#navigation').load('menu.html');
});

29
frontend/src/main.css

@ -0,0 +1,29 @@
/* .navbar-light .nav-item.active .nav-link,
.navbar-light .nav-item:focus .nav-link,
.navbar-light .nav-item:hover .nav-link {
color: #ffffff;
} */
.navbar-dark .navbar-nav .nav-link {
color: rgba(255, 255, 255, .5);
color: #ffffff;
}
/* #form-section {
width: 30%;
margin: auto;
}
#manual-card {
width: 40%;
} */
@media only screen and (max-width: 900px) {
/* #form-section {
width: 90%;
}
#manual-card {
width: 90%;
} */
}

177
frontend/src/main.js

@ -0,0 +1,177 @@
function incHeight() {
var el = document.getElementById('mySection');
var height = el.offsetHeight;
console.log("Height = " + height);
var newHeight = height + 250;
el.style.height = newHeight + 'px';
}
var header = document.querySelector('header');
var section = document.querySelector('section');
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
async function getData() {
//await the response of the fetch call
let response = await fetch('combinedSettingsFile.txt');
//proceed once the first promise is resolved.
let data = await response.json()
//proceed only when the second promise is resolved
return data;
}
async function getTemperatures() {
//await the response of the fetch call
let response = await fetch('temperatures.txt');
//proceed once the first promise is resolved.
let data = await response.json()
//proceed only when the second promise is resolved
return data;
}
async function getTemperatures2() {
//await the response of the fetch call
let response = await fetch('api/get/temperatures');
//proceed once the first promise is resolved.
let data = await response.json()
//proceed only when the second promise is resolved
return data;
}
getTemperatures()
.then(data => {
data.temperatures.forEach(function(temperature) {
console.log(temperature);
})
})
// .then(result => {
// //Here body is not ready yet, throw promise
// if (!result.ok) throw result;
// return result.json();
// })
// .then(result => {
// //Successful request processing
// console.log(result);
// }).catch(error => {
// //Here is still promise
// console.log(error);
// error.json().then((body) => {
// //Here is already the payload from API
// console.log(body);
// });
// })
setInterval(function() {
let temperaturesSwitch = document.getElementById('temperatures-switch');
if (temperaturesSwitch.checked) {
// getTemperatures2()
fetch('api/get/temperatures')
// .then(handleErrors)
.then(result => {
//Here body is not ready yet, throw promise
if (!result.ok) throw result;
return result.json();
})
.then(data => {
let p = document.getElementById('temperature');
if (data.status == 'failed') {
let errorMessage = sprintf('status = %s reason = %s', data.status, data.message)
p.textContent = errorMessage;
console.log(errorMessage);
} else {
p.textContent = "";
data.temperatures.forEach(function(temperature) {
console.log("Temperature = " + temperature);
temp = sprintf("%05.2f", temperature);
p.textContent += temp + ' ';
})
// let temp = sprintf("%.2f", 36.72);
// p.textContent += temp + ' ';
}
})
.catch(error => {
//Here is still promise
// console.log(error);
// if (error.status == 404) {
// console.log('error = ' + 404);
// }
// else {
// error.json().then((body) => {
//Here is already the payload from API
// let errorMessage = sprintf('status = %s reason = %s', body.status, body.message)
// console.log(errorMessage);
// });
// }
let p = document.getElementById('temperature');
p.textContent = 'Network Error';
})
}
},
2000
);
//call getData function
getData()
//.then(data => console.log(data))//log the data
.then(function showSettings(data) {
var ballasts = data['settings'];
console.log(ballasts);
for (let i = 0; i < 3; i++) {
// var myArticle = document.createElement('article');
// var myH2 = document.createElement('h3');
// var myPara1 = document.createElement('p');
// var myPara2 = document.createElement('p');
// var myPara3 = document.createElement('p');
// var myPara4 = document.createElement('p');
// var myPara5 = document.createElement('p');
// // var myList = document.createElement('ul');
// myH2.textContent = 'Ballast' + ' #' + (i + 1);
// myPara1.textContent = 'Start Hour: ' + ballasts[i].shour;
// myPara2.textContent = 'Start Minute: ' + ballasts[i].smin;
// myPara3.textContent = 'Fade Period: ' + ballasts[i].fadePeriod;
// myPara4.textContent = 'End Hour: ' + ballasts[i].ehour;
// myPara5.textContent = 'End Minute: ' + ballasts[i].emin;
// console.log(ballasts[i].shour);
// myArticle.appendChild(myH2);
// myArticle.appendChild(myPara1);
// myArticle.appendChild(myPara2);
// myArticle.appendChild(myPara3);
// myArticle.appendChild(myPara4);
// myArticle.appendChild(myPara5);
// // myArticle.appendChild(myList);
// section.appendChild(myArticle);
let myDiv = document.getElementById('ballast' + (i + 1));
// let myH2 = document.createElement('h3');
let myPara1 = document.createElement('p');
let myPara2 = document.createElement('p');
let myPara3 = document.createElement('p');
let myPara4 = document.createElement('p');
let myPara5 = document.createElement('p');
// myH2.textContent = 'Ballast' + ' #' + (i + 1);
myPara1.textContent = 'Start Hour: ' + ballasts[i].shour;
myPara2.textContent = 'Start Minute: ' + ballasts[i].smin;
myPara3.textContent = 'Fade Period: ' + ballasts[i].fadePeriod;
myPara4.textContent = 'End Hour: ' + ballasts[i].ehour;
myPara5.textContent = 'End Minute: ' + ballasts[i].emin;
// myDiv.appendChild(myH2);
myDiv.appendChild(myPara1);
myDiv.appendChild(myPara2);
myDiv.appendChild(myPara3);
myDiv.appendChild(myPara4);
myDiv.appendChild(myPara5);
}
return data;
})
.then(data => console.log(data))
// .then(incHeight());

186
frontend/src/main_bak.css

@ -0,0 +1,186 @@
.nav-pills .nav-link.active,
.nav-pills .show>.nav-link {
color: #fff;
background-color: #00878F;
}
@font-face {
font-family: 'nunitoregular';
src: url('nunito-regular-webfont.woff2') format('woff2'), url('nunito-regular-webfont.woff') format('woff');
font-weight: normal;
font-style: normal;
}
iframe {
border: none;
align-self: center;
align-content: center;
align-items: center;
}
center {
width: 70%;
max-width: 100%;
margin: 0px auto;
font-family: 'Roboto', sans-serif;
color: #444;
}
header {
background-color: #00878F;
color: white;
padding: 6px;
font-family: 'Roboto', sans-serif;
box-shadow: 1px 1px 5px #555555;
position: relative;
}
h1 {
margin: 0px;
font-family: 'Roboto', sans-serif;
font-size: 32;
}
h2 {
color: #00878f;
}
h3 {
color: #00878f;
}
.shadow {
box-shadow: 1px 1px 5px #555555;
/* height: 500px; */
}
.navmenu {
margin-top: 10px;
margin-left: 0px;
}
.navm {
margin: 2px;
}
radio {
float: left;
}
.content {
margin: 10px 10px 10px 10px
}
table {
margin: 5px 24px 5px 12px;
border: #000000
}
.tbl {
margin-top: 10px;
margin-bottom: 5px;
border: #000000
}
td {
color: #555;
}
/* tr {
width: 100%;
} */
.button {
text-decoration: none;
border: none;
color: white;
background-color: #00878F;
padding: 6px 24px;
font-size: 16px;
cursor: pointer;
box-shadow: 1px 1px 6px #555;
outline: none;
margin: 12px auto 0px auto;
display: inline-block;
}
.button:hover {
box-shadow: 1px 1px 3px #444;
}
hr {
width: 97%;
margin-right: 10px;
}
input[type=range] {
-webkit-appearance: none;
outline: none;
width: auto;
margin: 6px;
}
input {
width: 95px;
height: 20px;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
border: 0px;
height: 15px;
width: 15px;
margin-top: -6px;
border-radius: 7.5px;
}
input.disabled[type=range]::-webkit-slider-thumb {
background: #999;
}
input.enabled[type=range]::-webkit-slider-thumb {
background: #00878F;
cursor: pointer;
box-shadow: 1px 1px 2px #777, 0px 0px 1px #777;
}
input[type=range]::-webkit-slider-runnable-track {
width: inherit;
height: 4px;
background: #ccc;
border-radius: 1px;
}
input.enabled[type=range]::-webkit-slider-runnable-track {
cursor: pointer;
}
p {
font-family: 'Nunito', sans-serif;
}
/* section styles */
section article {
width: 33%;
float: left;
}
section p {
margin: 5px 0;
}
section ul {
margin-top: 0;
}
@media screen and (max-width: 900px) {
center {
width: 90%;
}
.content {
height: 600px;
}
}

11
frontend/src/manifest.json

@ -0,0 +1,11 @@
{
"name": "LED Control",
"icons": [
{
"src": "\/favicon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
}
]
}

122
frontend/src/manualMode-ajax.html

@ -0,0 +1,122 @@
<!-- <!DOCTYPE html> -->
<html>
<head>
<title>Manual Mode</title>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" sizes="144x144" href="/favicon-144x144.png">
<link rel="icon" type="image/png" sizes="48x48" href="/favicon.ico">
<link rel="manifest" href="manifest.json">
<meta name="theme-color" content="#00878f">
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport'>
<meta charset="utf-8">
<script src="loadMenu.js" defer></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.15.0/esm/popper.js" type="module"></script>
<link href='main.css' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="colors.css">
</head>
<body>
<div id="navigation"></div>
<div class="container">
<div class="shadow-lg p-3 mb-5 bg-white rounded">
<header>
<div class="container">
<div class="row">
<div class="col">
<div class="mt-3 pt-5">
<h2 class="display-4 text-center">
Manual Settings
</h2>
</div>
</div>
</div>
</div>
</header>
<section>
<div class="container">
<div class="row">
<div class="col-lg-6 offset-lg-3">
<div class="card text-white bg-ternary mb-3 card-form rounded mx-auto" id="manual-card">
<div class="card-body">
<div class="card-text text-center">
<form id="manual-form">
<div class="mb-4 mt-2">
<div class="form-check form-check-inline">
<input class="form-check-input" id="yes" type="radio" name="manual" value="True">
<label class="form-check-label" for="yes">Yes</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" id="no" type="radio" name="manual" value="False" checked>
<label class="form-check-label" for="no">No</label>
</div>
</div>
<div class="form-group">
<button class="form-control" class="button">Submit</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
<script type="text/javascript">
var myForm = document.getElementById('manual-form');
myForm.addEventListener('submit', function(e) {
e.preventDefault();
//var data = JSON.stringify(formData(myForm));
loadJSON(formData(myForm));
})
function formData(form) {
// var el = form.querySelectorAll('input[type="text"]');
// var manualRadios = document.getElementsByName('manual').value;
var manualValue = document.querySelector('input[name="manual"]:checked').value;;
var myData = '';
myData += 'manual' + '=' + manualValue;
// for (var x = 0; x < el.length; x++) {
// var name = el[x].name;
// var value = el[x].value;
// //myData[name] = value;
// myData += name + '=' + value + '&'
// }
// return myData.slice(0, -1);
return myData;
}
function loadJSON(data) {
const url = 'manualMode.html';
console.log(data)
const myData = data
fetch(url, {
method: 'post',
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
body: myData
})
// .then(function (response) {
// return response.json()
// }).then(function (data) {
// console.log(data)
// })
.catch(error => console.log(error))
}
</script>
</body>
</html>

78
frontend/src/manualMode.html

@ -0,0 +1,78 @@
<!DOCTYPE html>
<html>
<head>
<title>Manual Mode</title>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" sizes="144x144" href="/favicon-144x144.png">
<link rel="icon" type="image/png" sizes="48x48" href="/favicon.ico">
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#00878f">
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport'>
<!-- <script src="include.js" type="text/javascript"></script> -->
<meta charset="utf-8">
<!-- <script src="jquery-3.4.1.min.js"></script> -->
<script src="loadMenu.js" defer></script>
<link href='main.css' rel='stylesheet' type='text/css'>
<!-- <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet"> -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="colors.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<!-- <link rel="stylesheet" href="bootstrap.min.css"> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<!-- <script src="bootstrap.min.js"></script> -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
<link href='main.css' rel='stylesheet' type='text/css'>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.15.0/esm/popper.js" type="module"></script>
</head>
<body>
<div id="navigation"></div>
<center>
<header>
<h1> Manual Mode </h1>
</header>
</center>
<form action="manualMode.html" method="GET">
<center>
<div class="shadow">
<!-- <iframe src="menu.html" width="90%"></iframe> -->
<table class="tbl">
<tr>
<td colspan="3">
<label>Manual mode?</label>
</td>
</tr>
<tr>
<td>
<input type="radio" name="manual" value="True"> Yes
</td>
<td>
<input type="radio" name="manual" value="False" checked> No
</td>
</tr>
<tr>
<td colspan="2">
<p style="margin:8px 0px" align="center"><button class="button">Submit</button></p>
</td>
</tr>
</table>
<!-- <div class="content">
<label>Manual mode?</label>
<input type="radio" name="manual" value="True"> Yes
<input type="radio" name="manual" value="False" checked> No <br>
<p style="margin:8px 0px"><button class="button">Submit</button></p><br>
</div> -->
</div>
</center>
</form>
</body>
</html>

0
data/manualMode.txt → frontend/src/manualMode.txt

26
frontend/src/menu.html

@ -0,0 +1,26 @@
<nav class="navbar navbar-expand-md bg-ternary navbar-dark fixed-top">
<div class="container">
<a href="home.html" class="navbar-brand">Aquarium Controller</a>
<div class="navbar-header">
<button class="navbar-toggler" data-toggle="collapse" data-target="#navbarCollapse">
<i class="fas fa-chevron-down"></i>
</button>
</div>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a href="index.html" class="nav-link">Home</a>
</li>
<li class="nav-item">
<a href="settings-ajax.html" class="nav-link">Settings</a>
</li>
<li class="nav-item">
<a href="manualMode-ajax.html" class="nav-link">Manual Mode</a>
</li>
<li class="nav-item">
<a href="edit.html" class="nav-link">Edit</a>
</li>
</ul>
</div>
</div>
</nav>

88
frontend/src/settings-ajax.html

@ -0,0 +1,88 @@
<!DOCTYPE html>
<html>
<head>
<title>Settings</title>
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" sizes="144x144" href="favicon-144x144.png">
<link rel="icon" type="image/png" sizes="48x48" href="favicon.ico">
<link rel="manifest" href="manifest.json">
<meta name="theme-color" content="#00878f">
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport'>
<meta charset="utf-8">
<script src="loadMenu.js" defer></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
<link href='main.css' rel='stylesheet' type='text/css'>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.15.0/esm/popper.js" type="module"></script>
<script src="settings.js" defer></script>
<link rel="stylesheet" href="colors.css">
</head>
<body>
<div id="navigation"></div>
<section id="form-section">
<div class="container">
<div class="row">
<div class="col-lg-6 offset-lg-3">
<div class="py-5 mt-3">
<!-- <div class="bg-ternary rounded"> -->
<div class="card text-white bg-ternary card-form rounded mx-auto shadow-lg p-3 mb-5">
<h2 class="card-header text-center">Change Settings</h2>
<div class="card-body rounded">
<form id="myForm">
<div class="form-group">
<label>Select Ballast:</label>
<select class="form-control" id="myBallasts" name="ballast">
<option value = "1">Ballast #1</option>
<option value = "2">Ballast #2</option>
<option value = "3">Ballast #3</option>
</select>
</div>
<div class="form-group">
<label for="">Enter start hour:</label>
<input class="form-control" type="text" name="shour" placeholder="Hour" required>
</div>
<div class="form-group">
<label for="">Enter start minute:</label>
<input class="form-control" type="text" name="smin" placeholder="Minute" required>
</div>
<div class="form-group">
<label for="">Enter amount of time to fade in:</label>
<input class="form-control" type="text" name="fadePeriod" placeholder="Fade Period" required>
<small class="form-text text-white">Must be a whole number</small>
</div>
<div class="form-group">
<label for="">Enter end hour:</label>
<input class="form-control" type="text" name="ehour" placeholder="Hour" required>
</div>
<div class="form-group">
<label for="">Enter start minute:</label>
<input class="form-control" type="text" name="emin" placeholder="Minute" required>
</div>
<div class="form-group">
<button class="button form-control">Submit</button>
</div>
</form>
</div>
<!-- </div> -->
</div>
</div>
</div>
</div>
</div>
</section>
<script type="text/javascript">
</script>
</body>
</html>

23
frontend/src/settings-success.html

@ -0,0 +1,23 @@
<html>
<head>
<title>Settings update successful</title>
<link href='main.css' rel='stylesheet' type='text/css'>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" sizes="144x144" href="/favicon-144x144.png">
<link rel="icon" type="image/png" sizes="48x48" href="/favicon.ico">
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#00878f">
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport'>
</head>
<body>
<center>
<header>
<h1>Success</h1>
</header>
<div>
<p>Settings changed successfully.</p>
<a class="button" href="/">Back</a>
</div>
</center>
</body>
</html>

88
frontend/src/settings.html

@ -0,0 +1,88 @@
<!-- <!DOCTYPE html> -->
<html>
<head>
<title>Settings</title>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" sizes="144x144" href="/favicon-144x144.png">
<link rel="icon" type="image/png" sizes="48x48" href="/favicon.ico">
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#00878f">
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport'>
<!-- <script src="include.js" type="text/javascript"></script> -->
<meta charset="utf-8">
<!-- <script src="jquery-3.4.1.min.js"></script> -->
<link href='main.css' rel='stylesheet' type='text/css'>
<!-- <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet"> -->
</head>
<body>
<center><header><h1> Settings page </h1></header></center>
<form action="/settings.html" method="POST">
<center>
<div class="shadow">
<iframe src="menu.html" width="90%"></iframe>
<div data-include="menu"></div>
<table class="tbl" cellspacing="2" cellpadding = "2">
<tr>
<td>
<label>Select Ballast:</label>
</td>
<td>
<select id = "myList" name="ballast">
<option value = "1">Ballast #1</option>
<option value = "2">Ballast #2</option>
<option value = "3">Ballast #3</option>
</select>
</td>
</tr>
<tr>
<td>
Enter start hour:</br>
</td>
<td>
<input type="text" name="shour" placeholder="Hour" required></br>
</td>
</tr>
<tr>
<td>
Enter start minute:</br>
</td>
<td>
<input type="text" name="smin" placeholder="Minute" required></br>
</td>
</tr>
<tr>
<td>
Enter amount of time to fade in(in mins)(cannot be decimal):</br>
</td>
<td>
<input type="text" name="fadePeriod" placeholder="Fade Period" required></br>
</td>
</tr>
<tr>
<td>
Enter end hour:</br>
</td>
<td>
<input type="text" name="ehour" placeholder="Hour" required></br>
</td>
</tr>
<tr>
<td>
Enter start minute:</br>
</td>
<td>
<input type="text" name="emin" placeholder="Minute" required></br>
<td>
</tr>
<tr align = "center">
<td colspan="3">
<p style="margin:8px 0px"><button class="button">Submit</button></p>
</td>
</tr>
</table>
</div>
</center>
</form>
</body>
</html>

39
frontend/src/settings.js

@ -0,0 +1,39 @@
var myForm = document.getElementById('myForm')
myForm.addEventListener('submit', function(e) {
e.preventDefault();
//var data = JSON.stringify(formData(myForm));
loadJSON(formData(myForm))
})
function formData(form) {
let el = form.querySelectorAll('input[type="text"]');
let ballast = document.getElementById('myBallasts').value;
let myData = '';
myData += 'ballast' + '=' + ballast + '&';
for (var x = 0; x < el.length; x++) {
let name = el[x].name;
let value = el[x].value;
//myData[name] = value;
myData += name + '=' + value + '&'
}
return myData.slice(0, -1);
}
function loadJSON(data) {
const url = '/settings.html';
console.log(data)
const myData = data
fetch(url, {
method: 'post',
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
body: myData
})
// .then(function (response) {
// return response.json()
// }).then(function (data) {
// console.log(data)
// })
.catch(error => console.log(error))
}

7
frontend/src/settingsFile1.txt

@ -0,0 +1,7 @@
{
"shour": 16,
"fadePeriod": 30,
"smin": 0,
"ehour": 22,
"emin": 0
}

7
frontend/src/settingsFile2.txt

@ -0,0 +1,7 @@
{
"shour": 16,
"fadePeriod": 30,
"smin": 0,
"ehour": 22,
"emin": 0
}

7
frontend/src/settingsFile3.txt

@ -0,0 +1,7 @@
{
"shour": 16,
"fadePeriod": 30,
"smin": 0,
"ehour": 22,
"emin": 0
}

23
frontend/src/success.html

@ -0,0 +1,23 @@
<html>
<head>
<title>HTML Upload successful</title>
<link href='main.css' rel='stylesheet' type='text/css'>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" sizes="144x144" href="/favicon-144x144.png">
<link rel="icon" type="image/png" sizes="48x48" href="/favicon.ico">
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#00878f">
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport'>
</head>
<body>
<center>
<header>
<h1>HTML Uploader</h1>
</header>
<div>
<p>The upload was successful.</p>
<a class="button" href="/">Back</a>
</div>
</center>
</body>
</html>

6
frontend/src/temperatures.txt

@ -0,0 +1,6 @@
{
"temperatures": [
48,
2
]
}

8
frontend/src/uploadButtonStyle.js

@ -0,0 +1,8 @@
$('#upload-button').filestyle({
buttonName: 'btn-success',
buttonText: ' File selection',
btnClass: "btn-ternary",
dragDrop: true
});

10
include.js

@ -1,10 +0,0 @@
$(function(){
var includes = $('[data-include]');
jQuery.each(includes, function(){
var file = '/' + $(this).data('include') + '.html';
$(this).load(file);
});
});
// $(document).ready(function(){
// $( "#header" ).load( "/menu.html" );
// });

6
platformio.ini

@ -29,6 +29,6 @@ board_build.f_cpu = 160000000L
; --ip=192.168.1.103
; --port=8266
; --auth=esp8266
build_flags =
-DLC_WIFI_SSID=${sysenv.WIFI_SSID}
-DLC_WIFI_PASS=${sysenv.WIFI_PASS}
; build_flags =
; -DLC_WIFI_SSID=${sysenv.WIFI_SSID}
; -DLC_WIFI_PASS=${sysenv.WIFI_PASS}

21
src/main.cpp

@ -358,6 +358,8 @@ void startServer()
server.send(200, "text/plain", rtcDate);
});
server.serveStatic("/", SPIFFS, "www", "no-cache");
server.begin(); // start the HTTP server
Serial.println("HTTP server started.");
}
@ -366,6 +368,9 @@ void startServer()
void handleNotFound()
{ // if the requested file or page doesn't exist, return a 404 not found error
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
server.sendHeader("Pragma", "no-cache");
server.sendHeader("Expires", "-1");
if (!handleFileRead(server.uri()))
{ // check if the file exists in the flash memory (SPIFFS), if so, send it
server.send(404, "application/json", "{\"status\":\"failed\",\"message\":\"Resource not found\"}");
@ -498,21 +503,24 @@ void combineSettings()
StaticJsonBuffer<100> jsonBuffer10;
JsonObject &root1 = jsonBuffer10.parseObject(buf1.get());
if (root1 == JsonObject::invalid())
if (!root1.success())
{
Serial.println("Error1");
Log.error("Error parsing JSON");
return;
}
StaticJsonBuffer<100> jsonBuffer11;
JsonObject &root2 = jsonBuffer11.parseObject(buf2.get());
if (root2 == JsonObject::invalid())
if (!root2.success())
{
Serial.println("Error2");
Log.error("Error parsing JSON");
return;
}
StaticJsonBuffer<100> jsonBuffer12;
JsonObject &root3 = jsonBuffer12.parseObject(buf3.get());
if (root3 == JsonObject::invalid())
if (!root3.success())
{
Serial.println("Error3");
Log.error("Error parsing JSON");
return;
}
StaticJsonBuffer<50> jsonBuffer16;
JsonObject &root5 = jsonBuffer16.parseObject(buf5.get());
@ -574,6 +582,7 @@ void combineSettings()
file5.close();
}
//FIXME borked - has strange/undefined behaviour
void combineSettings_new()
{
const File file1 = SPIFFS.open("/settingsFile1.txt", "r");

BIN
website-zipped_bak/index.html.gz

BIN
website-zipped_bak/ledcontrol.html.gz

BIN
website-zipped_bak/main.css.gz

BIN
website-zipped_bak/manifest.json.gz

BIN
website-zipped_bak/manualMode-ajax.html.gz

BIN
website-zipped_bak/manualMode.html.gz

BIN
website-zipped_bak/menu.html.gz

BIN
website-zipped_bak/nunito-regular-webfont.woff.gz

BIN
website-zipped_bak/nunito-regular-webfont.woff2.gz

BIN
website-zipped_bak/settings-ajax.html.gz

BIN
website-zipped_bak/settings-success.html.gz

BIN
website-zipped_bak/settings.html.gz

BIN
website-zipped_bak/success.html.gz

Loading…
Cancel
Save