Added module files for fuelgauge, RTCStore, HourMeter
This commit is contained in:
parent
204007401b
commit
92283a3e0d
14 changed files with 715 additions and 1258 deletions
BIN
data/favicon.ico
BIN
data/favicon.ico
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
609
data/index.html
609
data/index.html
|
@ -1,609 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<!-- <link rel="icon" href="data;,"> -->
|
||||
<script>
|
||||
|
||||
var Socket;
|
||||
function init() {
|
||||
Socket = new WebSocket('ws://' + window.location.hostname + ':81/');
|
||||
|
||||
Socket.onmessage = function(event){
|
||||
var heater = JSON.parse(event.data);
|
||||
var key;
|
||||
for(key in heater) {
|
||||
console.log("JSON decode:", key, heater[key]);
|
||||
switch(key) {
|
||||
case "RunState":
|
||||
if (heater[key] == 0) {
|
||||
document.getElementById("myonoffswitch").checked = false;
|
||||
document.getElementById("myonoffswitch").style = "block";
|
||||
document.getElementById("onoffswitch").style.visibility = "visible";
|
||||
} else if(heater[key] >= 7 && heater[key] <= 8) { // new runstates 9+ for heat plug & suspend mode
|
||||
document.getElementById("myonoffswitch").checked = false;
|
||||
document.getElementById("myonoffswitch").style = "none";
|
||||
document.getElementById("onoffswitch").style.visibility = "hidden";
|
||||
} else {
|
||||
document.getElementById("myonoffswitch").checked = true;
|
||||
document.getElementById("myonoffswitch").style = "block";
|
||||
document.getElementById("onoffswitch").style.visibility = "visible";
|
||||
}
|
||||
document.getElementById("RunString").style.visibility = (heater[key] == 5 || heater[key] == 0) ? "hidden" : "visible";
|
||||
break;
|
||||
case "ErrorString":
|
||||
case "RunString":
|
||||
document.getElementById(key).innerHTML = heater[key];
|
||||
break;
|
||||
case "MEn":
|
||||
document.getElementById(key).value = heater[key];
|
||||
break;
|
||||
case "MPort":
|
||||
document.getElementById(key).value = heater[key];
|
||||
break;
|
||||
case "MHost":
|
||||
document.getElementById(key).value = heater[key];
|
||||
break;
|
||||
case "MUser":
|
||||
document.getElementById(key).value = heater[key];
|
||||
break;
|
||||
case "MPasswd":
|
||||
document.getElementById(key).value = heater[key];
|
||||
break;
|
||||
case "PumpFixed":
|
||||
case "TempCurrent":
|
||||
document.getElementById(key).innerHTML = parseFloat(heater[key]).toFixed(1);
|
||||
break;
|
||||
case "TempDesired":
|
||||
document.getElementById(key).value = heater[key];
|
||||
var ValKey = key + 'Val'; // eg 'PumpMinVal'
|
||||
document.getElementById(ValKey).innerHTML = heater[key];
|
||||
break;
|
||||
case "ErrorState":
|
||||
document.getElementById("ErrorDiv").hidden = heater[key] <= 1;
|
||||
break;
|
||||
case "TempBody":
|
||||
//The threshold levels for each bar to come on are: 21°C, 41°C, 61°C, 81°C, 101°C, 121°C
|
||||
if(heater[key] > 120){
|
||||
document.getElementById("TopBar").className = "active121";
|
||||
}
|
||||
else if(heater[key] > 100){
|
||||
document.getElementById("TopBar").className = "active101";
|
||||
}
|
||||
else if(heater[key] > 80){
|
||||
document.getElementById("TopBar").className = "active81";
|
||||
}
|
||||
else if(heater[key] > 60){
|
||||
document.getElementById("TopBar").className = "active61";
|
||||
}
|
||||
else if(heater[key] > 40){
|
||||
document.getElementById("TopBar").className = "active41";
|
||||
}
|
||||
else if(heater[key] > 20){
|
||||
document.getElementById("TopBar").className = "active21";
|
||||
}
|
||||
else {
|
||||
document.getElementById("TopBar").className = "active0";
|
||||
}
|
||||
break;
|
||||
case "PumpMin":
|
||||
case "PumpMax":
|
||||
var OneDecimalPlace = parseFloat(heater[key]).toFixed(1);
|
||||
var ValKey = key + 'Val'; // eg 'PumpMinVal'
|
||||
document.getElementById(key).value = OneDecimalPlace;
|
||||
document.getElementById(key).innerHTML = OneDecimalPlace;
|
||||
document.getElementById(ValKey).innerHTML = OneDecimalPlace;
|
||||
break;
|
||||
case "FanMin":
|
||||
case "FanMax":
|
||||
var RPM = heater[key];
|
||||
var ValKey = key + 'Val'; // eg 'FanMinVal'
|
||||
document.getElementById(key).value = RPM;
|
||||
document.getElementById(key).innerHTML = RPM;
|
||||
document.getElementById(ValKey).innerHTML = RPM;
|
||||
break;
|
||||
case "Thermostat":
|
||||
if(heater[key] != 0) {
|
||||
document.getElementById("FixedDiv").hidden = true;
|
||||
document.getElementById("ThermoDiv").hidden = false;
|
||||
}
|
||||
else {
|
||||
document.getElementById("FixedDiv").hidden = false;
|
||||
document.getElementById("ThermoDiv").hidden = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setSchedule(){
|
||||
//clearly need to add some code here to send the Json formatted data to the esp
|
||||
console.log("Set Schedule Button Press")
|
||||
}
|
||||
|
||||
Date.prototype.toDateInputValue = (function() {
|
||||
var local = new Date(this);
|
||||
local.setMinutes(this.getMinutes() - this.getTimezoneOffset());
|
||||
return local.toJSON().slice(0,10);
|
||||
});
|
||||
|
||||
function sendJSONobject(obj){
|
||||
var str = JSON.stringify(obj);
|
||||
console.log("JSON Tx:", str);
|
||||
Socket.send(str);
|
||||
}
|
||||
|
||||
// Scripts for date handling
|
||||
Date.prototype.today = function () {
|
||||
return ((this.getDate() < 10)?"0":"") + this.getDate() +"/"+(((this.getMonth()+1) < 10)?"0":"") + (this.getMonth()+1) +"/"+ this.getFullYear();
|
||||
}
|
||||
|
||||
// Scripts for setting date and time
|
||||
|
||||
function setcurrenttime(){
|
||||
var cmd = {};
|
||||
cmd.Time = document.getElementById("curtime").value;
|
||||
sendJSONobject(cmd);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
function setMQTTDetails(){
|
||||
var cmd = {};
|
||||
cmd.MEn = document.getElementById("MEn").checked ? 1 : 0;
|
||||
sendJSONobject(cmd);
|
||||
cmd.MHost = document.getElementById("MHost").value;
|
||||
sendJSONobject(cmd);
|
||||
cmd.MPasswd = document.getElementById("MPasswd").value;
|
||||
sendJSONobject(cmd);
|
||||
cmd.MUser = document.getElementById("MUser").value;
|
||||
sendJSONobject(cmd);
|
||||
}
|
||||
*/
|
||||
|
||||
function setcurrentdate(){
|
||||
var cmd = {};
|
||||
cmd.Date = document.getElementById("curdate").value;
|
||||
sendJSONobject(cmd);
|
||||
}
|
||||
|
||||
function funcNavLinks() {
|
||||
var x = document.getElementById("myLinks");
|
||||
if (x.style.display === "block") {
|
||||
x.style.display = "none";
|
||||
} else {
|
||||
x.style.display = "block";
|
||||
}
|
||||
}
|
||||
|
||||
function checkTime(i)
|
||||
{
|
||||
if (i<10)
|
||||
{
|
||||
i="0" + i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
function funcdispSettings() {
|
||||
document.getElementById("Settings").style.display = "block";
|
||||
currentTime = new Date();
|
||||
var h = currentTime.getHours();
|
||||
var m = currentTime.getMinutes();
|
||||
var s = currentTime.getSeconds();
|
||||
// add a zero in front of numbers<10
|
||||
h = checkTime(h);
|
||||
m = checkTime(m);
|
||||
s = checkTime(s);
|
||||
|
||||
console.log("Hours",h);
|
||||
console.log("Minutes",m);
|
||||
console.log("Seconds",s);
|
||||
document.getElementById("curtime").value = h + ":" + m + ":" + s;
|
||||
document.getElementById("curdate").value = currentTime.today()
|
||||
document.getElementById("Home").style.display = "none";
|
||||
document.getElementById("Advanced").style.display = "none";
|
||||
document.getElementById("myLinks").style.display ="none";
|
||||
document.getElementById('curdate').valueAsDate = new Date();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
function funcdispHome(){
|
||||
document.getElementById("Settings").style.display = "none";
|
||||
document.getElementById("Home").style.display = "block";
|
||||
document.getElementById("Advanced").style.display = "none";
|
||||
document.getElementById("myLinks").style.display ="none";
|
||||
|
||||
}
|
||||
|
||||
function funcdispAdvanced(){
|
||||
document.getElementById("Settings").style.display = "none";
|
||||
document.getElementById("Home").style.display = "none";
|
||||
document.getElementById("Advanced").style.display = "block";
|
||||
document.getElementById("myLinks").style.display ="none";
|
||||
}
|
||||
|
||||
// Function to check the power on/off slide switch.
|
||||
function OnOffCheck(){
|
||||
|
||||
// Get the checkbox status and place in the checkbox variable
|
||||
var checkBox = document.getElementById("myonoffswitch");
|
||||
|
||||
// Send a message to the Devel console of web browser for debugging
|
||||
console.log("OnOffCheck:", document.getElementById("myonoffswitch").checked);
|
||||
|
||||
// If the checkbox is checked, display the output text
|
||||
// We also need to send a message back into the esp as we cannot directly run Arduino Functions from within the javascript
|
||||
|
||||
var cmd = {};
|
||||
if (checkBox.checked){
|
||||
//Insert Code Here To Turn On The Heater
|
||||
console.log("Turning On Heater");
|
||||
|
||||
cmd.RunState = 1;
|
||||
sendJSONobject(cmd);
|
||||
}
|
||||
else{
|
||||
//Insert Code Here To Turn Off The Heater
|
||||
console.log("Turning Off Heater");
|
||||
|
||||
cmd.RunState = 0;
|
||||
sendJSONobject(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
function onSlideDone(newVal, JSONKey) {
|
||||
//elementid must equal the JSON name for each setting
|
||||
|
||||
document.getElementById(JSONKey).innerHTML = newVal;
|
||||
|
||||
var cmd = {};
|
||||
cmd[JSONKey] = newVal; // note: variable name needs []
|
||||
cmd.NVsave = 8861; // named variable DOESN'T !!
|
||||
sendJSONobject(cmd);
|
||||
}
|
||||
|
||||
|
||||
function UpdateMQTTSettings() {
|
||||
var cmd = {};
|
||||
cmd.MPort = document.getElementById("MPort").value;
|
||||
cmd.MEn = document.getElementById("MEn").checked ? 1 : 0;
|
||||
cmd.MHost = document.getElementById("MHost").value;
|
||||
cmd.MUser = document.getElementById("MUser").value;
|
||||
cmd.MPasswd = document.getElementById("MPasswd").value;
|
||||
sendJSONobject(cmd);
|
||||
var cmd = {};
|
||||
cmd.NVsave = 8861;
|
||||
sendJSONobject(cmd);
|
||||
}
|
||||
|
||||
function onSlideUpdate(newVal, JSONKey) {
|
||||
//elementid must equal the JSON name for each setting
|
||||
|
||||
document.getElementById(JSONKey).innerHTML = newVal;
|
||||
}
|
||||
|
||||
function SetPumpMin(){
|
||||
var cmd = {};
|
||||
cmd['PumpMin'] = document.getElementById("PumpMin").value;
|
||||
cmd.NVsave = 8861;
|
||||
sendJSONobject(cmd);
|
||||
}
|
||||
|
||||
function funcShowMQTT() {
|
||||
var checkbox = document.getElementById("MEn");
|
||||
if (checkbox.checked == false) {
|
||||
document.getElementById("DIVMPort").style.display = "none";
|
||||
}
|
||||
else {
|
||||
document.getElementById("DIVMPort").style.display = "block";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<meta name="viewport" content="height=device-height, width=device-width, initial-scale=1">
|
||||
<style>
|
||||
|
||||
.throb_me {
|
||||
animation: throbber 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes throbber {
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
left: 4px;
|
||||
bottom: 4px;
|
||||
background-color: white;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.onoffswitch {
|
||||
position: relative; width: 90px;
|
||||
-webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
|
||||
}
|
||||
.onoffswitch-checkbox {
|
||||
display: none;
|
||||
}
|
||||
.onoffswitch-label {
|
||||
display: block; overflow: hidden; cursor: pointer;
|
||||
border: 2px solid #999999; border-radius: 20px;
|
||||
}
|
||||
.onoffswitch-inner {
|
||||
display: block; width: 200%; margin-left: -100%;
|
||||
transition: margin 0.3s ease-in 0s;
|
||||
}
|
||||
.onoffswitch-inner:before, .onoffswitch-inner:after {
|
||||
display: block; float: left; width: 50%; height: 30px; padding: 0; line-height: 30px;
|
||||
font-size: 14px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.onoffswitch-inner:before {
|
||||
content: "ON";
|
||||
padding-left: 10px;
|
||||
background-color: #34A7C1; color: #FFFFFF;
|
||||
}
|
||||
.onoffswitch-inner:after {
|
||||
content: "OFF";
|
||||
padding-right: 10px;
|
||||
background-color: #EEEEEE; color: #999999;
|
||||
text-align: right;
|
||||
}
|
||||
.onoffswitch-switch {
|
||||
display: block; width: 18px; margin: 6px;
|
||||
background: #FFFFFF;
|
||||
position: absolute; top: 0; bottom: 0;
|
||||
right: 56px;
|
||||
border: 2px solid #999999; border-radius: 20px;
|
||||
transition: all 0.3s ease-in 0s;
|
||||
}
|
||||
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
|
||||
margin-left: 0;
|
||||
}
|
||||
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.mobile-container {
|
||||
|
||||
margin: auto;
|
||||
background-color: #555;
|
||||
height: 500px;
|
||||
color: white;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.topnav {
|
||||
overflow: hidden;
|
||||
background-color: #333;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.topnav #myLinks {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.topnav a {
|
||||
color: white;
|
||||
padding: 14px 16px;
|
||||
text-decoration: none;
|
||||
font-size: 17px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.topnav a.icon {
|
||||
background: black;
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.topnav a:hover {
|
||||
background-color: #ddd;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.active0 {
|
||||
background-color: #5e4fa2;
|
||||
color: black;
|
||||
}
|
||||
.active21 {
|
||||
background-color: #427bb1;
|
||||
color: #ffffff;
|
||||
}
|
||||
.active41 {
|
||||
background-color: #36c0a3;
|
||||
color: #ffffff;
|
||||
}
|
||||
.active61 {
|
||||
background-color: #29cf38;
|
||||
color: #000000;
|
||||
}
|
||||
.active81 {
|
||||
background-color: #92df1b;
|
||||
color: #ffffff;
|
||||
}
|
||||
.active101 {
|
||||
background-color: #efab0e;
|
||||
color: #ffffff;
|
||||
}
|
||||
.active121 {
|
||||
background-color: #ff0000;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: #2196F3;
|
||||
}
|
||||
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px #2196F3;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
-webkit-transform: translateX(26px);
|
||||
-ms-transform: translateX(26px);
|
||||
transform: translateX(26px);
|
||||
}
|
||||
|
||||
.slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
MainPage {
|
||||
display: block
|
||||
}
|
||||
#Advanced {
|
||||
display: none
|
||||
}
|
||||
#Settings {
|
||||
display: none
|
||||
}
|
||||
|
||||
#DIVMPort {
|
||||
display: none
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<title>Chinese Diesel Heater Web Controller Interface</title>
|
||||
</head>
|
||||
<body onload="javascript:init()">
|
||||
<div class="mobile-container">
|
||||
|
||||
<!-- Top Navigation Menu -->
|
||||
<div class="topnav">
|
||||
<div id="TopBar" style="padding-left:30px"><a href="javascript:void(0);" onclick="funcdispHome()" >Chinese Diesel Heater Web Control</a></div>
|
||||
<div id="myLinks">
|
||||
<a href="javascript:void(0);" onclick="funcdispHome()">Home</a>
|
||||
<a href="javascript:void(0);" onclick="funcdispSettings()">Settings</a>
|
||||
<a href="javascript:void(0);" onclick="funcdispAdvanced()">Advanced Settings</a>
|
||||
</div>
|
||||
<a href="javascript:void(0);" class="icon" onclick="funcNavLinks()">
|
||||
</i>≡
|
||||
</a>
|
||||
</div>
|
||||
<div style="padding-left:16px">
|
||||
<span class="MaingPage" id="Home">
|
||||
<div><H2>Power Control</H2></div>
|
||||
|
||||
<div class="onoffswitch" id="onoffswitch">
|
||||
<input type="checkbox" onclick="OnOffCheck()" name="onoffswitch" class="onoffswitch-checkbox" id="myonoffswitch" clicked>
|
||||
<label class="onoffswitch-label" for="myonoffswitch">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
</label>
|
||||
</div>
|
||||
<span class="throb_me" id="RunString" style="visibility:hidden"></span>
|
||||
|
||||
<div>
|
||||
<h2>Temperature Control</h2>
|
||||
</div>
|
||||
<input type="range" id="TempDesired" min="8" max="35" step="1" value="22" oninput="onSlideUpdate(this.value, 'TempDesiredVal')" onchange="onSlideDone(this.value, 'TempDesired')">
|
||||
<div id="ThermoDiv">
|
||||
<b>Desired Temp: </b> <span id="TempDesiredVal"></span>
|
||||
</div>
|
||||
<div id="FixedDiv">
|
||||
<b>Fixed Hz: </b>
|
||||
<span id="PumpFixed"></span>
|
||||
</div>
|
||||
<div>
|
||||
<b>Current Temp: </b><span id="TempCurrent">
|
||||
</div>
|
||||
<div id="ErrorDiv" style="color:crimson" hidden>
|
||||
<b>Error <span id="ErrorString"> </b>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<div id="Advanced">
|
||||
<h2><b>Advanced Settings</b></h2>
|
||||
<br>
|
||||
<h3><b>Minimum Fuel Settings</b></h3>
|
||||
<div>
|
||||
<b>Pump Min: </b><span id="PumpMinVal"> </span>
|
||||
<input type="range" id="PumpMin" min="1" max="10" step=".1" oninput="onSlideUpdate(parseFloat(this.value).toFixed(1), 'PumpMinVal')" onchange="onSlideDone(this.value, 'PumpMin')">
|
||||
</div>
|
||||
<div>
|
||||
<b>Fan Min: </b><span id="FanMinVal"> </span>
|
||||
<input type="range" id="FanMin" min="1000" max="5000" step="10" oninput="onSlideUpdate(this.value, 'FanMinVal')" onchange="onSlideDone(this.value, 'FanMin')">
|
||||
</div>
|
||||
<br>
|
||||
<h3><b>Maximum Fuel Settings</b></h3>
|
||||
<div>
|
||||
<b>Pump Max: </b><span id="PumpMaxVal"> </span>
|
||||
<input type="range" id="PumpMax" min=".5" max="10" step=".1" oninput="onSlideUpdate(parseFloat(this.value).toFixed(1), 'PumpMaxVal')" onchange="onSlideDone(this.value, 'PumpMax')">
|
||||
</div>
|
||||
<div>
|
||||
<b>Fan Max: </b><span id="FanMaxVal"> </span>
|
||||
<input type="range" id="FanMax" min="1000" max="5000" step="10" oninput="onSlideUpdate(this.value, 'FanMaxVal')" onchange="onSlideDone(this.value, 'FanMax')">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="Settings">
|
||||
Current Date:<br>
|
||||
<input type="date" id="curdate"><input type="button" Value="Set Date" onclick="setcurrentdate()">
|
||||
|
||||
<br>
|
||||
Current Time (24 Hour Format):<br>
|
||||
<input type="time" id="curtime"> <input type="button" Value="Set Time" onclick="setcurrenttime()">
|
||||
|
||||
<br><br>
|
||||
<hr></hr>
|
||||
|
||||
<H2>MQTT Settings</H2>
|
||||
<b>Enabled: </b><input type="checkbox" border-radius="4px" name="MEn" id="MEn" onclick="funcShowMQTT()">
|
||||
<div id="DIVMPort">
|
||||
<b>Host/Server: </b><input type="text" name="MHost" id="MHost" value=""></br>
|
||||
<b>Port: </b><input type="text" name="MPort" id="MPort" defaultvalue="1883" value="1883"></br>
|
||||
<b>Username: </b><input type="text" name="MUser" id="MUser" value=""></br>
|
||||
<b>Password: </b><input type="text" name="MPasswd" id="MPasswd" value=""></br></br>
|
||||
<input type="button" name="mqttsubmit" value="Save/Update Settings" onclick="UpdateMQTTSettings()">
|
||||
</div>
|
||||
<br><br>
|
||||
|
||||
<hr></hr>
|
||||
<br><br>
|
||||
<div id="Timer"
|
||||
Timer1: <input type="checkbox" border-radius="4px" name="Timer" id="Timer1onoff"> <input type="text" class="schedule" id="Timer1Start"> <input type="text" id="Timer1End"> <br>
|
||||
Timer2: <input type="checkbox" border-radius="4px" name="Tue"> <input type="text" class="schedule" id="Timer2Start"> <input type="text" id="Timer2End"><br>
|
||||
<input type="button" Value="Save Schedule" onclick="setSchedule()">
|
||||
</Div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
191
data/update.html
191
data/update.html
|
@ -1,191 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="-1">
|
||||
<meta http-equiv="CACHE-CONTROL" content="NO-CACHE">
|
||||
<style>
|
||||
body { font-family: Arial, Helvetica, sans-serif; }
|
||||
th { text-align: left; }
|
||||
.throb { animation: throbber 1s linear infinite; }
|
||||
@keyframes throbber { 50% { opacity: 0; } }
|
||||
</style>
|
||||
<script>
|
||||
// globals
|
||||
var sendSize;
|
||||
var ws;
|
||||
var CRCTable = new Uint16Array([
|
||||
0X0000, 0XC0C1, 0XC181, 0X0140, 0XC301, 0X03C0, 0X0280, 0XC241,
|
||||
0XC601, 0X06C0, 0X0780, 0XC741, 0X0500, 0XC5C1, 0XC481, 0X0440,
|
||||
0XCC01, 0X0CC0, 0X0D80, 0XCD41, 0X0F00, 0XCFC1, 0XCE81, 0X0E40,
|
||||
0X0A00, 0XCAC1, 0XCB81, 0X0B40, 0XC901, 0X09C0, 0X0880, 0XC841,
|
||||
0XD801, 0X18C0, 0X1980, 0XD941, 0X1B00, 0XDBC1, 0XDA81, 0X1A40,
|
||||
0X1E00, 0XDEC1, 0XDF81, 0X1F40, 0XDD01, 0X1DC0, 0X1C80, 0XDC41,
|
||||
0X1400, 0XD4C1, 0XD581, 0X1540, 0XD701, 0X17C0, 0X1680, 0XD641,
|
||||
0XD201, 0X12C0, 0X1380, 0XD341, 0X1100, 0XD1C1, 0XD081, 0X1040,
|
||||
0XF001, 0X30C0, 0X3180, 0XF141, 0X3300, 0XF3C1, 0XF281, 0X3240,
|
||||
0X3600, 0XF6C1, 0XF781, 0X3740, 0XF501, 0X35C0, 0X3480, 0XF441,
|
||||
0X3C00, 0XFCC1, 0XFD81, 0X3D40, 0XFF01, 0X3FC0, 0X3E80, 0XFE41,
|
||||
0XFA01, 0X3AC0, 0X3B80, 0XFB41, 0X3900, 0XF9C1, 0XF881, 0X3840,
|
||||
0X2800, 0XE8C1, 0XE981, 0X2940, 0XEB01, 0X2BC0, 0X2A80, 0XEA41,
|
||||
0XEE01, 0X2EC0, 0X2F80, 0XEF41, 0X2D00, 0XEDC1, 0XEC81, 0X2C40,
|
||||
0XE401, 0X24C0, 0X2580, 0XE541, 0X2700, 0XE7C1, 0XE681, 0X2640,
|
||||
0X2200, 0XE2C1, 0XE381, 0X2340, 0XE101, 0X21C0, 0X2080, 0XE041,
|
||||
0XA001, 0X60C0, 0X6180, 0XA141, 0X6300, 0XA3C1, 0XA281, 0X6240,
|
||||
0X6600, 0XA6C1, 0XA781, 0X6740, 0XA501, 0X65C0, 0X6480, 0XA441,
|
||||
0X6C00, 0XACC1, 0XAD81, 0X6D40, 0XAF01, 0X6FC0, 0X6E80, 0XAE41,
|
||||
0XAA01, 0X6AC0, 0X6B80, 0XAB41, 0X6900, 0XA9C1, 0XA881, 0X6840,
|
||||
0X7800, 0XB8C1, 0XB981, 0X7940, 0XBB01, 0X7BC0, 0X7A80, 0XBA41,
|
||||
0XBE01, 0X7EC0, 0X7F80, 0XBF41, 0X7D00, 0XBDC1, 0XBC81, 0X7C40,
|
||||
0XB401, 0X74C0, 0X7580, 0XB541, 0X7700, 0XB7C1, 0XB681, 0X7640,
|
||||
0X7200, 0XB2C1, 0XB381, 0X7340, 0XB101, 0X71C0, 0X7080, 0XB041,
|
||||
0X5000, 0X90C1, 0X9181, 0X5140, 0X9301, 0X53C0, 0X5280, 0X9241,
|
||||
0X9601, 0X56C0, 0X5780, 0X9741, 0X5500, 0X95C1, 0X9481, 0X5440,
|
||||
0X9C01, 0X5CC0, 0X5D80, 0X9D41, 0X5F00, 0X9FC1, 0X9E81, 0X5E40,
|
||||
0X5A00, 0X9AC1, 0X9B81, 0X5B40, 0X9901, 0X59C0, 0X5880, 0X9841,
|
||||
0X8801, 0X48C0, 0X4980, 0X8941, 0X4B00, 0X8BC1, 0X8A81, 0X4A40,
|
||||
0X4E00, 0X8EC1, 0X8F81, 0X4F40, 0X8D01, 0X4DC0, 0X4C80, 0X8C41,
|
||||
0X4400, 0X84C1, 0X8581, 0X4540, 0X8701, 0X47C0, 0X4680, 0X8641,
|
||||
0X8201, 0X42C0, 0X4380, 0X8341, 0X4100, 0X81C1, 0X8081, 0X4040
|
||||
]);
|
||||
|
||||
function calcCRC(data) { // expect Uint8Array input
|
||||
// calculate a CRC-16/MODBUS checksum using the all except the last 2 bytes of the data array
|
||||
var CRCWord = 0xFFFF;
|
||||
|
||||
var Length = data.length - 2;
|
||||
var idx = 0;
|
||||
|
||||
while (idx < Length)
|
||||
{
|
||||
var nTemp = (data[idx] ^ CRCWord) & 0xff;
|
||||
CRCWord >>= 8;
|
||||
CRCWord ^= CRCTable[nTemp];
|
||||
idx++;
|
||||
}
|
||||
return CRCWord;
|
||||
}
|
||||
|
||||
|
||||
function _(el) {
|
||||
return document.getElementById(el);
|
||||
}
|
||||
|
||||
function onWebSocket(event) {
|
||||
var response = JSON.parse(event.data);
|
||||
var key;
|
||||
for(key in response) {
|
||||
switch(key) {
|
||||
case "progress":
|
||||
// actual data bytes received as fed back via web socket
|
||||
var bytes = response[key];
|
||||
_("loaded_n_total").innerHTML = "Uploaded " + bytes + " bytes of " + sendSize;
|
||||
var percent = Math.round( 100 * (bytes / sendSize));
|
||||
_("progressBar").value = percent;
|
||||
_("status").innerHTML = percent+"% uploaded.. please wait";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
ws = new WebSocket('ws://' + window.location.hostname + ':81/');
|
||||
ws.onmessage = onWebSocket;
|
||||
}
|
||||
|
||||
function uploadFile() {
|
||||
_("cancel").hidden = true;
|
||||
var file = _("file1").files[0];
|
||||
sendSize = file.size;
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(event) {
|
||||
var buffer = event.target.result;
|
||||
var uint8 = new Uint8Array(buffer);
|
||||
console.log("Array length: " + uint8.length);
|
||||
console.log("Buffer length: " + buffer.size);
|
||||
console.log("CRC: " + calcCRC(uint8));
|
||||
}
|
||||
reader.onerror = function(event) {
|
||||
console.error("File could not be read! Code " + event.target.error);
|
||||
}
|
||||
reader.readAsArrayBuffer(file);
|
||||
|
||||
/* var JSONmsg = {};
|
||||
JSONmsg['UploadSize'] = sendSize;
|
||||
var str = JSON.stringify(JSONmsg);
|
||||
console.log("JSON Tx:", str);
|
||||
ws.send(str);
|
||||
var formdata = new FormData();
|
||||
formdata.append("update", file);
|
||||
var ajax = new XMLHttpRequest();
|
||||
// progress is handled via websocket JSON sent from controller
|
||||
// using server side progress only shows the buffer filling, not actual delivery.
|
||||
ajax.addEventListener("load", completeHandler, false);
|
||||
ajax.addEventListener("error", errorHandler, false);
|
||||
ajax.addEventListener("abort", abortHandler, false);
|
||||
ajax.open("POST", "/updatenow");
|
||||
ajax.send(formdata);*/
|
||||
}
|
||||
|
||||
function completeHandler(event) {
|
||||
_("status").innerHTML = event.target.responseText;
|
||||
_("progressBar").value = 0;
|
||||
_("loaded_n_total").innerHTML = "Uploaded " + sendSize + " bytes of " + sendSize;
|
||||
var file = _("file1").files[0];
|
||||
if(file.name.endsWith(".bin")) {
|
||||
setTimeout( function() { window.location.assign('/'); }, 5000);
|
||||
}
|
||||
else {
|
||||
setTimeout( function() { location.assign('/update'); }, 500);
|
||||
}
|
||||
}
|
||||
|
||||
function errorHandler(event) {
|
||||
_("status").innerHTML = "Upload Failed";
|
||||
}
|
||||
|
||||
function abortHandler(event) {
|
||||
_("status").innerHTML = "Upload Aborted";
|
||||
}
|
||||
|
||||
function onErase(fn) {
|
||||
if(confirm('Do you really want to erase ' + fn +' ?')) {
|
||||
var formdata = new FormData();
|
||||
formdata.append("filename", fn);
|
||||
var ajax = new XMLHttpRequest();
|
||||
ajax.open("POST", "/erase");
|
||||
ajax.send(formdata);
|
||||
setTimeout(function () { location.reload(); }, 500);
|
||||
}
|
||||
}
|
||||
|
||||
function onBrowseChange() {
|
||||
_("upload").hidden = false;
|
||||
_("progressBar").hidden = false;
|
||||
_("status").hidden = false;
|
||||
_("loaded_n_total").hidden = false;
|
||||
_("spacer").hidden = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<title>Afterburner update</title>
|
||||
</head>
|
||||
<body onload="javascript:init()">
|
||||
<h1>Afterburner update</h1>
|
||||
<form id='upload_form' method="POST" enctype="multipart/form-data" autocomplete="off">
|
||||
<label for='file1'>Select a file to upload:<br></label>
|
||||
<input type="file" name="file1" id="file1" size="50" onchange="onBrowseChange()">
|
||||
<p>
|
||||
<input id="upload" type='button' onclick='uploadFile()' value='Upload' >
|
||||
<progress id='progressBar' value='0' max='100' style='width:300px;' hidden></progress>
|
||||
<p id='spacer' hidden> </p>
|
||||
<input type='button' onclick=window.location.assign('/') id='cancel' value='Cancel'>
|
||||
<h3 id='status' hidden></h3>
|
||||
<div id='loaded_n_total' hidden></div>
|
||||
</form>
|
||||
<p><button onclick=window.location.assign('/formatspiffs')>Format SPIFFS</button>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
@ -90,6 +90,7 @@
|
|||
#include "cfg/pins.h"
|
||||
#include "RTC/Timers.h"
|
||||
#include "RTC/Clock.h"
|
||||
#include "RTC/RTCStore.h"
|
||||
#include "WiFi/BTCWifi.h"
|
||||
#include "WiFi/BTCWebServer.h"
|
||||
#include "WiFi/BTCota.h"
|
||||
|
@ -109,6 +110,7 @@
|
|||
#include "OLED/KeyPad.h"
|
||||
#include "Utility/TempSense.h"
|
||||
#include "Utility/DataFilter.h"
|
||||
#include "Utility/HourMeter.h"
|
||||
#include <rom/rtc.h>
|
||||
#include <esp_spiffs.h>
|
||||
#include <SPIFFS.h>
|
||||
|
@ -183,6 +185,10 @@ bool bHasOEMLCDController = false;
|
|||
bool bHasHtrData = false;
|
||||
|
||||
// these variables will persist over a soft reboot.
|
||||
__NOINIT_ATTR int persistentRunTime;
|
||||
__NOINIT_ATTR int persistentGlowTime;
|
||||
CHourMeter* pHourMeter = NULL;
|
||||
|
||||
__NOINIT_ATTR bool bForceInit; // = false;
|
||||
//__NOINIT_ATTR bool bUserON; // = false;
|
||||
//__NOINIT_ATTR uint8_t demandDegC;
|
||||
|
@ -310,11 +316,11 @@ extern "C" unsigned long __wrap_millis() {
|
|||
void setup() {
|
||||
|
||||
// ensure cyclic mode is disabled after power on
|
||||
// bool bPowerUpInit = false;
|
||||
// if(rtc_get_reset_reason(0) == 1/* || bForceInit*/) {
|
||||
// bPowerUpInit = true;
|
||||
bool bESP32PowerUpInit = false;
|
||||
if(rtc_get_reset_reason(0) == 1/* || bForceInit*/) {
|
||||
bESP32PowerUpInit = true;
|
||||
// bForceInit = false;
|
||||
// }
|
||||
}
|
||||
|
||||
// initially, ensure the GPIO outputs are not activated during startup
|
||||
// (GPIO2 tends to be one with default chip startup)
|
||||
|
@ -459,6 +465,11 @@ void setup() {
|
|||
// bCyclicEngaged = RTC_Store.getCyclicEngaged();
|
||||
DebugPort.printf("Previous cyclic active = %d\r\n", RTC_Store.getCyclicEngaged()); // state flag required for cyclic mode to persist properly after a WD reboot :-)
|
||||
|
||||
pHourMeter = new CHourMeter(persistentRunTime, persistentGlowTime);
|
||||
if(bESP32PowerUpInit) {
|
||||
pHourMeter->powerOnInit(); // ensure persistent memory variable are reset after powerup
|
||||
}
|
||||
|
||||
delay(1000); // just to hold the splash screeen for while
|
||||
}
|
||||
|
||||
|
|
299
src/OLED/FuelCalScreen.cpp
Normal file
299
src/OLED/FuelCalScreen.cpp
Normal file
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* This file is part of the "bluetoothheater" distribution
|
||||
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
||||
*
|
||||
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "128x64OLED.h"
|
||||
#include "FuelCalScreen.h"
|
||||
#include "KeyPad.h"
|
||||
#include "../Utility/helpers.h"
|
||||
#include "../Utility/macros.h"
|
||||
#include "../Utility/NVStorage.h"
|
||||
#include "../Protocol/Protocol.h"
|
||||
#include "fonts/Icons.h"
|
||||
|
||||
static const int Line3 = 14;
|
||||
static const int Line2 = 27;
|
||||
static const int Line1 = 40;
|
||||
|
||||
|
||||
CFuelCalScreen::CFuelCalScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
|
||||
{
|
||||
_initUI();
|
||||
_mlPerStroke = 0.02;
|
||||
_LVC = 115;
|
||||
_tOfs = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CFuelCalScreen::onSelect()
|
||||
{
|
||||
CPasswordScreen::onSelect();
|
||||
_initUI();
|
||||
_mlPerStroke = NVstore.getHeaterTuning().pumpCal;
|
||||
_LVC = NVstore.getHeaterTuning().lowVolts;
|
||||
_tOfs = NVstore.getHeaterTuning().tempOfs;
|
||||
}
|
||||
|
||||
void
|
||||
CFuelCalScreen::_initUI()
|
||||
{
|
||||
_rowSel = 0;
|
||||
_animateCount = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
CFuelCalScreen::show()
|
||||
{
|
||||
char msg[20];
|
||||
const int col = 90;
|
||||
|
||||
_display.fillRect(0, 50, 128, 14, BLACK);
|
||||
_display.fillRect(col-border, Line3-border, 128-(col-1), 64-Line3-border, BLACK);
|
||||
|
||||
if(!CPasswordScreen::show()) { // for showing "saving settings"
|
||||
|
||||
if(_rowSel == 4) {
|
||||
_printInverted(_display.xCentre(), 0, " Saving Settings ", true, eCentreJustify);
|
||||
_printMenuText(_display.xCentre(), 35, "Press UP to", false, eCentreJustify);
|
||||
_printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify);
|
||||
}
|
||||
else {
|
||||
if(_animateCount < 0) {
|
||||
_display.clearDisplay();
|
||||
_animateCount = 0;
|
||||
}
|
||||
_printInverted(_display.xCentre(), 0, " Special Features ", true, eCentreJustify);
|
||||
// fuel calibration
|
||||
int yPos = Line1;
|
||||
_printMenuText(col, yPos, "mL/stroke : ", false, eRightJustify);
|
||||
sprintf(msg, "%.03f", _mlPerStroke);
|
||||
_printMenuText(col, yPos, msg, _rowSel == 1);
|
||||
// low voltage cutout
|
||||
yPos = Line2;
|
||||
_printMenuText(col, yPos, "L.V.C. < ", false, eRightJustify);
|
||||
if(_LVC)
|
||||
sprintf(msg, "%.1fV", float(_LVC) * 0.1);
|
||||
else
|
||||
strcpy(msg, "OFF");
|
||||
_printMenuText(col, yPos, msg, _rowSel == 2);
|
||||
// temp offset
|
||||
yPos = Line3;
|
||||
_printMenuText(col, yPos, "\367C offset : ", false, eRightJustify);
|
||||
sprintf(msg, "%+.1f", _tOfs);
|
||||
_printMenuText(col, yPos, msg, _rowSel == 3);
|
||||
// navigation line
|
||||
yPos = 53;
|
||||
int xPos = _display.xCentre();
|
||||
|
||||
switch(_rowSel) {
|
||||
case 0:
|
||||
_printMenuText(xPos, yPos, " \021 Exit \020 ", true, eCentreJustify);
|
||||
break;
|
||||
default:
|
||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
||||
_printMenuText(xPos, 56, "\030\031Sel \033\032 Adj", false, eCentreJustify);
|
||||
_printMenuText(xPos, 56, "Save", false, eCentreJustify);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CFuelCalScreen::animate()
|
||||
{
|
||||
if(_animateCount >= 0) {
|
||||
switch(_animateCount) {
|
||||
case 0:
|
||||
_display.fillRect(0, Line3-4, BatteryIconInfo.width, 40, BLACK);
|
||||
_drawBitmap(6, Line1-3, FuelIconSmallInfo);
|
||||
_drawBitmap(0, Line2-1 , BatteryIconInfo);
|
||||
_drawBitmap(5, Line3-4, miniThermoIconInfo);
|
||||
break;
|
||||
case 2:
|
||||
_display.fillRect(6, Line1-3, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip
|
||||
_drawBitmap(6, Line1-2, FuelIconSmallInfo); // drip fuel
|
||||
_display.fillRect(BatteryIconInfo.width - 4, Line2+2, 2, 5, BLACK); // deplete battery
|
||||
_display.fillRect(7, Line3+2, 2, 2, WHITE); // grow thermometer
|
||||
break;
|
||||
case 4:
|
||||
_display.fillRect(6, Line1-2, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip
|
||||
_drawBitmap(6, Line1-1, FuelIconSmallInfo); // drip fuel
|
||||
_display.fillRect(BatteryIconInfo.width - 7, Line2+2, 2, 5, BLACK); // deplete battery
|
||||
_display.fillRect(7, Line3+1, 2, 1, WHITE); // grow thermometer
|
||||
break;
|
||||
case 6:
|
||||
_display.fillRect(6, Line1-1, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip
|
||||
_drawBitmap(6, Line1, FuelIconSmallInfo); // drip fuel
|
||||
_display.fillRect(BatteryIconInfo.width - 10, Line2+2, 2, 5, BLACK); // deplete battery
|
||||
_display.fillRect(7, Line3, 2, 1, WHITE); // grow thermometer
|
||||
break;
|
||||
case 8:
|
||||
_display.fillRect(6, Line1, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip
|
||||
_drawBitmap(6, Line1+1, FuelIconSmallInfo); // drip fuel
|
||||
_display.fillRect(BatteryIconInfo.width - 13, Line2+2, 2, 5, BLACK); // deplete battery
|
||||
_display.fillRect(7, Line3-1, 2, 1, WHITE); // grow thermometer
|
||||
break;
|
||||
}
|
||||
|
||||
_animateCount++;
|
||||
WRAPUPPERLIMIT(_animateCount, 9, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CFuelCalScreen::keyHandler(uint8_t event)
|
||||
{
|
||||
sHeaterTuning tuning;
|
||||
|
||||
if(event & keyRepeat) {
|
||||
if(event & key_Left) {
|
||||
_adjust(-1);
|
||||
}
|
||||
if(event & key_Right) {
|
||||
_adjust(+1);
|
||||
}
|
||||
}
|
||||
|
||||
if(event & keyPressed) {
|
||||
// press LEFT to select previous screen
|
||||
if(event & key_Left) {
|
||||
switch(_rowSel) {
|
||||
case 0:
|
||||
_ScreenManager.prevMenu();
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
_adjust(-1);
|
||||
break;
|
||||
case 4:
|
||||
_rowSel = 0; // abort save
|
||||
break;
|
||||
}
|
||||
}
|
||||
// press RIGHT to select next screen
|
||||
if(event & key_Right) {
|
||||
switch(_rowSel) {
|
||||
case 0:
|
||||
_ScreenManager.nextMenu();
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
_adjust(+1);
|
||||
break;
|
||||
case 4:
|
||||
_rowSel = 0; // abort save
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(event & key_Down) {
|
||||
_rowSel--;
|
||||
LOWERLIMIT(_rowSel, 0);
|
||||
}
|
||||
// UP press
|
||||
if(event & key_Up) {
|
||||
switch(_rowSel) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
_rowSel++;
|
||||
UPPERLIMIT(_rowSel, 3);
|
||||
break;
|
||||
case 4: // confirmed save
|
||||
_display.clearDisplay();
|
||||
_animateCount = -1;
|
||||
_showStoringMessage();
|
||||
tuning = NVstore.getHeaterTuning();
|
||||
tuning.pumpCal = _mlPerStroke;
|
||||
tuning.lowVolts = _LVC;
|
||||
tuning.tempOfs = _tOfs;
|
||||
NVstore.setHeaterTuning(tuning);
|
||||
saveNV();
|
||||
_rowSel = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// CENTRE press
|
||||
if(event & key_Centre) {
|
||||
switch(_rowSel) {
|
||||
case 0:
|
||||
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
_animateCount = -1;
|
||||
_display.clearDisplay();
|
||||
_rowSel = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ScreenManager.reqUpdate();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CFuelCalScreen::_adjust(int dir)
|
||||
{
|
||||
switch(_rowSel) {
|
||||
case 1:
|
||||
_mlPerStroke += dir * 0.001;
|
||||
BOUNDSLIMIT(_mlPerStroke, 0.001, 1);
|
||||
break;
|
||||
case 2:
|
||||
if(_LVC == 0) {
|
||||
if(NVstore.getHeaterTuning().sysVoltage == 120)
|
||||
_LVC = dir > 0 ? 115 : 0;
|
||||
else
|
||||
_LVC = dir > 0 ? 230 : 0;
|
||||
}
|
||||
else {
|
||||
_LVC += dir;
|
||||
if(NVstore.getHeaterTuning().sysVoltage == 120) {
|
||||
if(_LVC < 100)
|
||||
_LVC = 0;
|
||||
else
|
||||
UPPERLIMIT(_LVC, 125);
|
||||
}
|
||||
else {
|
||||
if(_LVC < 200)
|
||||
_LVC = 0;
|
||||
else
|
||||
UPPERLIMIT(_LVC, 250);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
_tOfs += dir * 0.1;
|
||||
BOUNDSLIMIT(_tOfs, -10, 10);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -27,7 +27,6 @@
|
|||
#include "../Utility/macros.h"
|
||||
#include "../Utility/NVStorage.h"
|
||||
#include "../Protocol/Protocol.h"
|
||||
#include "fonts/Icons.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -249,280 +248,3 @@ CHeaterSettingsScreen::_adjust(int dir)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
CFuelCalScreen::CFuelCalScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
|
||||
{
|
||||
_initUI();
|
||||
_mlPerStroke = 0.02;
|
||||
_LVC = 115;
|
||||
_tOfs = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CFuelCalScreen::onSelect()
|
||||
{
|
||||
CPasswordScreen::onSelect();
|
||||
_initUI();
|
||||
_mlPerStroke = NVstore.getHeaterTuning().pumpCal;
|
||||
_LVC = NVstore.getHeaterTuning().lowVolts;
|
||||
_tOfs = NVstore.getHeaterTuning().tempOfs;
|
||||
}
|
||||
|
||||
void
|
||||
CFuelCalScreen::_initUI()
|
||||
{
|
||||
_rowSel = 0;
|
||||
_animateCount = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
CFuelCalScreen::show()
|
||||
{
|
||||
char msg[20];
|
||||
const int col = 90;
|
||||
|
||||
_display.fillRect(0, 50, 128, 14, BLACK);
|
||||
_display.fillRect(col-border, Line3-border, 128-(col-1), 64-Line3-border, BLACK);
|
||||
|
||||
if(!CPasswordScreen::show()) { // for showing "saving settings"
|
||||
|
||||
if(_rowSel == 4) {
|
||||
_printInverted(_display.xCentre(), 0, " Saving Settings ", true, eCentreJustify);
|
||||
_printMenuText(_display.xCentre(), 35, "Press UP to", false, eCentreJustify);
|
||||
_printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify);
|
||||
}
|
||||
else {
|
||||
if(_animateCount < 0) {
|
||||
_display.clearDisplay();
|
||||
_animateCount = 0;
|
||||
}
|
||||
_printInverted(_display.xCentre(), 0, " Special Features ", true, eCentreJustify);
|
||||
// fuel calibration
|
||||
int yPos = Line1;
|
||||
_printMenuText(col, yPos, "mL/stroke : ", false, eRightJustify);
|
||||
sprintf(msg, "%.03f", _mlPerStroke);
|
||||
_printMenuText(col, yPos, msg, _rowSel == 1);
|
||||
// low voltage cutout
|
||||
yPos = Line2;
|
||||
_printMenuText(col, yPos, "L.V.C. < ", false, eRightJustify);
|
||||
if(_LVC)
|
||||
sprintf(msg, "%.1fV", float(_LVC) * 0.1);
|
||||
else
|
||||
strcpy(msg, "OFF");
|
||||
_printMenuText(col, yPos, msg, _rowSel == 2);
|
||||
// temp offset
|
||||
yPos = Line3;
|
||||
_printMenuText(col, yPos, "\367C offset : ", false, eRightJustify);
|
||||
sprintf(msg, "%+.1f", _tOfs);
|
||||
_printMenuText(col, yPos, msg, _rowSel == 3);
|
||||
// navigation line
|
||||
yPos = 53;
|
||||
int xPos = _display.xCentre();
|
||||
|
||||
switch(_rowSel) {
|
||||
case 0:
|
||||
_printMenuText(xPos, yPos, " \021 Exit \020 ", true, eCentreJustify);
|
||||
break;
|
||||
default:
|
||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
||||
_printMenuText(xPos, 56, "\030\031Sel \033\032 Adj", false, eCentreJustify);
|
||||
_printMenuText(xPos, 56, "Save", false, eCentreJustify);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CFuelCalScreen::animate()
|
||||
{
|
||||
if(_animateCount >= 0) {
|
||||
switch(_animateCount) {
|
||||
case 0:
|
||||
_display.fillRect(0, Line3-4, BatteryIconInfo.width, 40, BLACK);
|
||||
_drawBitmap(6, Line1-3, FuelIconSmallInfo);
|
||||
_drawBitmap(0, Line2-1 , BatteryIconInfo);
|
||||
_drawBitmap(5, Line3-4, miniThermoIconInfo);
|
||||
break;
|
||||
case 2:
|
||||
_display.fillRect(6, Line1-3, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip
|
||||
_drawBitmap(6, Line1-2, FuelIconSmallInfo); // drip fuel
|
||||
_display.fillRect(BatteryIconInfo.width - 4, Line2+2, 2, 5, BLACK); // deplete battery
|
||||
_display.fillRect(7, Line3+2, 2, 2, WHITE); // grow thermometer
|
||||
break;
|
||||
case 4:
|
||||
_display.fillRect(6, Line1-2, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip
|
||||
_drawBitmap(6, Line1-1, FuelIconSmallInfo); // drip fuel
|
||||
_display.fillRect(BatteryIconInfo.width - 7, Line2+2, 2, 5, BLACK); // deplete battery
|
||||
_display.fillRect(7, Line3+1, 2, 1, WHITE); // grow thermometer
|
||||
break;
|
||||
case 6:
|
||||
_display.fillRect(6, Line1-1, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip
|
||||
_drawBitmap(6, Line1, FuelIconSmallInfo); // drip fuel
|
||||
_display.fillRect(BatteryIconInfo.width - 10, Line2+2, 2, 5, BLACK); // deplete battery
|
||||
_display.fillRect(7, Line3, 2, 1, WHITE); // grow thermometer
|
||||
break;
|
||||
case 8:
|
||||
_display.fillRect(6, Line1, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip
|
||||
_drawBitmap(6, Line1+1, FuelIconSmallInfo); // drip fuel
|
||||
_display.fillRect(BatteryIconInfo.width - 13, Line2+2, 2, 5, BLACK); // deplete battery
|
||||
_display.fillRect(7, Line3-1, 2, 1, WHITE); // grow thermometer
|
||||
break;
|
||||
}
|
||||
|
||||
_animateCount++;
|
||||
WRAPUPPERLIMIT(_animateCount, 9, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CFuelCalScreen::keyHandler(uint8_t event)
|
||||
{
|
||||
sHeaterTuning tuning;
|
||||
|
||||
if(event & keyRepeat) {
|
||||
if(event & key_Left) {
|
||||
_adjust(-1);
|
||||
}
|
||||
if(event & key_Right) {
|
||||
_adjust(+1);
|
||||
}
|
||||
}
|
||||
|
||||
if(event & keyPressed) {
|
||||
// press LEFT to select previous screen
|
||||
if(event & key_Left) {
|
||||
switch(_rowSel) {
|
||||
case 0:
|
||||
_ScreenManager.prevMenu();
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
_adjust(-1);
|
||||
break;
|
||||
case 4:
|
||||
_rowSel = 0; // abort save
|
||||
break;
|
||||
}
|
||||
}
|
||||
// press RIGHT to select next screen
|
||||
if(event & key_Right) {
|
||||
switch(_rowSel) {
|
||||
case 0:
|
||||
_ScreenManager.nextMenu();
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
_adjust(+1);
|
||||
break;
|
||||
case 4:
|
||||
_rowSel = 0; // abort save
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(event & key_Down) {
|
||||
_rowSel--;
|
||||
LOWERLIMIT(_rowSel, 0);
|
||||
}
|
||||
// UP press
|
||||
if(event & key_Up) {
|
||||
switch(_rowSel) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
_rowSel++;
|
||||
UPPERLIMIT(_rowSel, 3);
|
||||
break;
|
||||
case 4: // confirmed save
|
||||
_display.clearDisplay();
|
||||
_animateCount = -1;
|
||||
_showStoringMessage();
|
||||
tuning = NVstore.getHeaterTuning();
|
||||
tuning.pumpCal = _mlPerStroke;
|
||||
tuning.lowVolts = _LVC;
|
||||
tuning.tempOfs = _tOfs;
|
||||
NVstore.setHeaterTuning(tuning);
|
||||
saveNV();
|
||||
_rowSel = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// CENTRE press
|
||||
if(event & key_Centre) {
|
||||
switch(_rowSel) {
|
||||
case 0:
|
||||
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
_animateCount = -1;
|
||||
_display.clearDisplay();
|
||||
_rowSel = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ScreenManager.reqUpdate();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CFuelCalScreen::_adjust(int dir)
|
||||
{
|
||||
switch(_rowSel) {
|
||||
case 1:
|
||||
_mlPerStroke += dir * 0.001;
|
||||
BOUNDSLIMIT(_mlPerStroke, 0.001, 1);
|
||||
break;
|
||||
case 2:
|
||||
if(_LVC == 0) {
|
||||
if(NVstore.getHeaterTuning().sysVoltage == 120)
|
||||
_LVC = dir > 0 ? 115 : 0;
|
||||
else
|
||||
_LVC = dir > 0 ? 230 : 0;
|
||||
}
|
||||
else {
|
||||
_LVC += dir;
|
||||
if(NVstore.getHeaterTuning().sysVoltage == 120) {
|
||||
if(_LVC < 100)
|
||||
_LVC = 0;
|
||||
else
|
||||
UPPERLIMIT(_LVC, 125);
|
||||
}
|
||||
else {
|
||||
if(_LVC < 200)
|
||||
_LVC = 0;
|
||||
else
|
||||
UPPERLIMIT(_LVC, 250);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
_tOfs += dir * 0.1;
|
||||
BOUNDSLIMIT(_tOfs, -10, 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,153 +205,3 @@ RTC_DS3231Ex::resetLostPower()
|
|||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
// RTC storage, using alarm registers as GP storage
|
||||
// MAXIMUM OF 7 BYTES
|
||||
//
|
||||
// [0..3] float fuelGauge strokes
|
||||
// [4] uint8_t DesiredTemp (typ. 8-35)
|
||||
// [5] uint8_t DesiredPump (typ. 8-35)
|
||||
// [6] uint8_t spare
|
||||
//
|
||||
// ____________________________________________________
|
||||
// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
|
||||
// |---------------|------|-----------------------------|
|
||||
// Byte[4]: | CyclicEngaged | bit6 | Desired Deg Celcius |
|
||||
// |---------------|------|-----------------------------|
|
||||
// Byte[5]: | | | Desired Pump Speed |
|
||||
// ----------------------------------------------------
|
||||
|
||||
CRTC_Store::CRTC_Store()
|
||||
{
|
||||
_accessed[0] = false;
|
||||
_accessed[1] = false;
|
||||
_accessed[2] = false;
|
||||
_accessed[3] = false;
|
||||
_fuelgauge = 0;
|
||||
_demandDegC = 22;
|
||||
_demandPump = 22;
|
||||
_CyclicEngaged = false;
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::begin()
|
||||
{
|
||||
if(Clock.lostPower()) {
|
||||
// RTC lost power - reset internal NV values to defaults
|
||||
DebugPort.println("CRTC_Store::begin() RTC lost power, re-initialising NV aspect");
|
||||
_demandPump = _demandDegC = 22;
|
||||
_CyclicEngaged = false;
|
||||
setFuelGauge(0);
|
||||
setDesiredTemp(_demandDegC);
|
||||
setDesiredPump(_demandPump);
|
||||
Clock.resetLostPower();
|
||||
}
|
||||
getFuelGauge();
|
||||
getDesiredTemp();
|
||||
getDesiredPump();
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::setFuelGauge(float val)
|
||||
{
|
||||
_accessed[0] = true;
|
||||
_fuelgauge = val;
|
||||
Clock.saveData((uint8_t*)&val, 4, 0);
|
||||
}
|
||||
|
||||
float
|
||||
CRTC_Store::getFuelGauge()
|
||||
{
|
||||
if(!_accessed[0]) {
|
||||
float NVval;
|
||||
Clock.readData((uint8_t*)&NVval, 4, 0);
|
||||
_fuelgauge = NVval;
|
||||
_accessed[0] = true;
|
||||
DebugPort.printf("RTC_Store - read fuel gauge %.2f\r\n", _fuelgauge);
|
||||
}
|
||||
return _fuelgauge;
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::setDesiredTemp(uint8_t val)
|
||||
{
|
||||
_demandDegC = val;
|
||||
_PackAndSaveByte4();
|
||||
}
|
||||
|
||||
uint8_t
|
||||
CRTC_Store::getDesiredTemp()
|
||||
{
|
||||
_ReadAndUnpackByte4();
|
||||
return _demandDegC;
|
||||
}
|
||||
|
||||
bool
|
||||
CRTC_Store::getCyclicEngaged()
|
||||
{
|
||||
_ReadAndUnpackByte4();
|
||||
return _CyclicEngaged;
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::setCyclicEngaged(bool active)
|
||||
{
|
||||
_CyclicEngaged = active;
|
||||
_PackAndSaveByte4();
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::setDesiredPump(uint8_t val)
|
||||
{
|
||||
_demandPump = val;
|
||||
_PackAndSaveByte5();
|
||||
}
|
||||
|
||||
uint8_t
|
||||
CRTC_Store::getDesiredPump()
|
||||
{
|
||||
_ReadAndUnpackByte5();
|
||||
return _demandPump;
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::_ReadAndUnpackByte4()
|
||||
{
|
||||
if(!_accessed[1]) {
|
||||
uint8_t NVval = 0;
|
||||
Clock.readData((uint8_t*)&NVval, 1, 4);
|
||||
_demandDegC = NVval & 0x3f;
|
||||
_CyclicEngaged = (NVval & 0x80) != 0;
|
||||
_bit6 = (NVval & 0x40) != 0;
|
||||
_accessed[1] = true;
|
||||
DebugPort.printf("RTC_Store - read byte4: degC=%d, CyclicOn=%d, bit6=%d\r\n", _demandDegC, _CyclicEngaged, _bit6);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::_PackAndSaveByte4()
|
||||
{
|
||||
uint8_t NVval = (_CyclicEngaged ? 0x80 : 0x00)
|
||||
| (_bit6 ? 0x40 : 0x00)
|
||||
| (_demandDegC & 0x3f);
|
||||
Clock.saveData((uint8_t*)&NVval, 1, 4);
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::_ReadAndUnpackByte5()
|
||||
{
|
||||
if(!_accessed[2]) {
|
||||
uint8_t NVval = 0;
|
||||
Clock.readData((uint8_t*)&NVval, 1, 5);
|
||||
_demandPump = NVval & 0x3f;
|
||||
_accessed[2] = true;
|
||||
DebugPort.printf("RTC_Store - read byte5: pump=%d\r\n", _demandPump);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::_PackAndSaveByte5()
|
||||
{
|
||||
uint8_t NVval = (_demandPump & 0x3f);
|
||||
Clock.saveData((uint8_t*)&NVval, 1, 5);
|
||||
}
|
||||
|
|
|
@ -73,31 +73,6 @@ public:
|
|||
void resetLostPower();
|
||||
};
|
||||
|
||||
class CRTC_Store {
|
||||
bool _accessed[4]; // [0] - bytes 0..3, [1] byte 4, [2] byte 5, [3] byte 6
|
||||
float _fuelgauge;
|
||||
uint8_t _demandDegC;
|
||||
uint8_t _demandPump;
|
||||
bool _CyclicEngaged;
|
||||
bool _bit6;
|
||||
void _ReadAndUnpackByte4();
|
||||
void _PackAndSaveByte4();
|
||||
void _ReadAndUnpackByte5();
|
||||
void _PackAndSaveByte5();
|
||||
public:
|
||||
CRTC_Store();
|
||||
void begin();
|
||||
void setFuelGauge(float val);
|
||||
void setDesiredTemp(uint8_t val);
|
||||
void setDesiredPump(uint8_t val);
|
||||
void setCyclicEngaged(bool _CyclicEngaged);
|
||||
float getFuelGauge();
|
||||
uint8_t getDesiredTemp();
|
||||
uint8_t getDesiredPump();
|
||||
bool getCyclicEngaged();
|
||||
};
|
||||
|
||||
extern CClock Clock;
|
||||
extern CRTC_Store RTC_Store;
|
||||
|
||||
#endif // __BTC_TIMERS_H__
|
||||
|
|
238
src/RTC/RTCStore.cpp
Normal file
238
src/RTC/RTCStore.cpp
Normal file
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* This file is part of the "bluetoothheater" distribution
|
||||
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
||||
*
|
||||
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "RTCStore.h"
|
||||
#include "Clock.h"
|
||||
#include <Wire.h>
|
||||
//#include "../Utility/helpers.h"
|
||||
//#include "../Utility/NVStorage.h"
|
||||
#include "../Utility/DebugPort.h"
|
||||
|
||||
|
||||
|
||||
// RTC storage, using alarm registers as GP storage
|
||||
// MAXIMUM OF 7 BYTES
|
||||
//
|
||||
// [0..3] float fuelGauge strokes
|
||||
// [4] uint8_t DesiredTemp (typ. 8-35)
|
||||
// [5] uint8_t DesiredPump (typ. 8-35)
|
||||
// [6] uint8_t spare
|
||||
//
|
||||
// ____________________________________________________
|
||||
// | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
|
||||
// |---------------|------|-----------------------------|
|
||||
// Byte[4]: | CyclicEngaged | bit6 | Desired Deg Celcius |
|
||||
// |---------------|------|-----------------------------|
|
||||
// Byte[5]: | | | Desired Pump Speed |
|
||||
// ----------------------------------------------------
|
||||
|
||||
CRTC_Store::CRTC_Store()
|
||||
{
|
||||
_accessed[0] = false;
|
||||
_accessed[1] = false;
|
||||
_accessed[2] = false;
|
||||
_accessed[3] = false;
|
||||
_fuelgauge = 0;
|
||||
_demandDegC = 22;
|
||||
_demandPump = 22;
|
||||
_CyclicEngaged = false;
|
||||
_RunTime = 0;
|
||||
_GlowTime = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::begin()
|
||||
{
|
||||
if(Clock.lostPower()) {
|
||||
// RTC lost power - reset internal NV values to defaults
|
||||
DebugPort.println("CRTC_Store::begin() RTC lost power, re-initialising NV aspect");
|
||||
_demandPump = _demandDegC = 22;
|
||||
_CyclicEngaged = false;
|
||||
setFuelGauge(0);
|
||||
setDesiredTemp(_demandDegC);
|
||||
setDesiredPump(_demandPump);
|
||||
Clock.resetLostPower();
|
||||
}
|
||||
getFuelGauge();
|
||||
getDesiredTemp();
|
||||
getDesiredPump();
|
||||
getRunTime();
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::setFuelGauge(float val)
|
||||
{
|
||||
_accessed[0] = true;
|
||||
_fuelgauge = val;
|
||||
Clock.saveData((uint8_t*)&val, 4, 0);
|
||||
}
|
||||
|
||||
float
|
||||
CRTC_Store::getFuelGauge()
|
||||
{
|
||||
if(!_accessed[0]) {
|
||||
float NVval;
|
||||
Clock.readData((uint8_t*)&NVval, 4, 0);
|
||||
_fuelgauge = NVval;
|
||||
_accessed[0] = true;
|
||||
DebugPort.printf("RTC_Store - read fuel gauge %.2f\r\n", _fuelgauge);
|
||||
}
|
||||
return _fuelgauge;
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::setDesiredTemp(uint8_t val)
|
||||
{
|
||||
_demandDegC = val;
|
||||
_PackAndSaveByte4();
|
||||
}
|
||||
|
||||
uint8_t
|
||||
CRTC_Store::getDesiredTemp()
|
||||
{
|
||||
_ReadAndUnpackByte4();
|
||||
return _demandDegC;
|
||||
}
|
||||
|
||||
bool
|
||||
CRTC_Store::getCyclicEngaged()
|
||||
{
|
||||
_ReadAndUnpackByte4();
|
||||
return _CyclicEngaged;
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::setCyclicEngaged(bool active)
|
||||
{
|
||||
_CyclicEngaged = active;
|
||||
_PackAndSaveByte4();
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::setDesiredPump(uint8_t val)
|
||||
{
|
||||
_demandPump = val;
|
||||
_PackAndSaveByte5();
|
||||
}
|
||||
|
||||
uint8_t
|
||||
CRTC_Store::getDesiredPump()
|
||||
{
|
||||
_ReadAndUnpackByte5();
|
||||
return _demandPump;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CRTC_Store::incRunTime()
|
||||
{
|
||||
_RunTime++;
|
||||
_RunTime &= 0x1f;
|
||||
_PackAndSaveByte6();
|
||||
return _RunTime == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
CRTC_Store::incGlowTime()
|
||||
{
|
||||
_GlowTime++;
|
||||
_GlowTime &= 0x07;
|
||||
_PackAndSaveByte6();
|
||||
return _GlowTime == 0;
|
||||
}
|
||||
|
||||
int
|
||||
CRTC_Store::getRunTime()
|
||||
{
|
||||
_ReadAndUnpackByte6();
|
||||
return _RunTime;
|
||||
}
|
||||
|
||||
int
|
||||
CRTC_Store::getGlowTime()
|
||||
{
|
||||
_ReadAndUnpackByte6();
|
||||
return _GlowTime;
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::_ReadAndUnpackByte4()
|
||||
{
|
||||
if(!_accessed[1]) {
|
||||
uint8_t NVval = 0;
|
||||
Clock.readData((uint8_t*)&NVval, 1, 4);
|
||||
_demandDegC = NVval & 0x3f;
|
||||
_CyclicEngaged = (NVval & 0x80) != 0;
|
||||
_bit6 = (NVval & 0x40) != 0;
|
||||
_accessed[1] = true;
|
||||
DebugPort.printf("RTC_Store - read byte4: degC=%d, CyclicOn=%d, bit6=%d\r\n", _demandDegC, _CyclicEngaged, _bit6);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::_PackAndSaveByte4()
|
||||
{
|
||||
uint8_t NVval = (_CyclicEngaged ? 0x80 : 0x00)
|
||||
| (_bit6 ? 0x40 : 0x00)
|
||||
| (_demandDegC & 0x3f);
|
||||
Clock.saveData((uint8_t*)&NVval, 1, 4);
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::_ReadAndUnpackByte5()
|
||||
{
|
||||
if(!_accessed[2]) {
|
||||
uint8_t NVval = 0;
|
||||
Clock.readData((uint8_t*)&NVval, 1, 5);
|
||||
_demandPump = NVval & 0x3f;
|
||||
_accessed[2] = true;
|
||||
DebugPort.printf("RTC_Store - read byte5: pump=%d\r\n", _demandPump);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::_PackAndSaveByte5()
|
||||
{
|
||||
uint8_t NVval = (_demandPump & 0x3f);
|
||||
Clock.saveData((uint8_t*)&NVval, 1, 5);
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::_PackAndSaveByte6()
|
||||
{
|
||||
uint8_t NVval = ((_GlowTime & 0x07)<<5) | (_RunTime & 0x1f);
|
||||
Clock.saveData((uint8_t*)&NVval, 1, 6);
|
||||
}
|
||||
|
||||
void
|
||||
CRTC_Store::_ReadAndUnpackByte6()
|
||||
{
|
||||
if(!_accessed[3]) {
|
||||
uint8_t NVval = 0;
|
||||
Clock.readData((uint8_t*)&NVval, 1, 6);
|
||||
_GlowTime = (NVval >> 5) & 0x07;
|
||||
_RunTime = NVval & 0x1f;
|
||||
_accessed[3] = true;
|
||||
DebugPort.printf("RTC_Store - read byte6: glow=%d, run=%d\r\n", _GlowTime, _RunTime);
|
||||
}
|
||||
}
|
||||
|
62
src/RTC/RTCStore.h
Normal file
62
src/RTC/RTCStore.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* This file is part of the "bluetoothheater" distribution
|
||||
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
||||
*
|
||||
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BTC_RTC_STORE_H__
|
||||
#define __BTC_RTC_STORE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
class CRTC_Store {
|
||||
bool _accessed[4]; // [0] - bytes 0..3, [1] byte 4, [2] byte 5, [3] byte 6
|
||||
float _fuelgauge;
|
||||
uint8_t _demandDegC;
|
||||
uint8_t _demandPump;
|
||||
bool _CyclicEngaged;
|
||||
bool _bit6;
|
||||
uint8_t _RunTime;
|
||||
uint8_t _GlowTime;
|
||||
void _ReadAndUnpackByte4();
|
||||
void _PackAndSaveByte4();
|
||||
void _ReadAndUnpackByte5();
|
||||
void _PackAndSaveByte5();
|
||||
void _ReadAndUnpackByte6();
|
||||
void _PackAndSaveByte6();
|
||||
public:
|
||||
CRTC_Store();
|
||||
void begin();
|
||||
void setFuelGauge(float val);
|
||||
void setDesiredTemp(uint8_t val);
|
||||
void setDesiredPump(uint8_t val);
|
||||
bool incRunTime();
|
||||
bool incGlowTime();
|
||||
void setCyclicEngaged(bool _CyclicEngaged);
|
||||
float getFuelGauge();
|
||||
uint8_t getDesiredTemp();
|
||||
uint8_t getDesiredPump();
|
||||
bool getCyclicEngaged();
|
||||
int getRunTime();
|
||||
int getGlowTime();
|
||||
};
|
||||
|
||||
extern CRTC_Store RTC_Store;
|
||||
|
||||
#endif // __BTC_RTC_STORE_H__
|
|
@ -23,6 +23,7 @@
|
|||
#include "DebugPort.h"
|
||||
#include "NVStorage.h"
|
||||
#include "../RTC/Clock.h"
|
||||
#include "../RTC/RTCStore.h"
|
||||
#include "../RTC/BTCDateTime.h"
|
||||
#include "../RTC/Timers.h"
|
||||
#include "../RTC/TimerManager.h"
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "FuelGauge.h"
|
||||
#include "NVStorage.h"
|
||||
#include "DebugPort.h"
|
||||
#include "../RTC/Clock.h"
|
||||
#include "../RTC/RTCStore.h"
|
||||
|
||||
CFuelGauge::CFuelGauge()
|
||||
{
|
||||
|
|
53
src/Utility/HourMeter.cpp
Normal file
53
src/Utility/HourMeter.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of the "bluetoothheater" distribution
|
||||
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
||||
*
|
||||
* Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "HourMeter.h"
|
||||
#include "NVStorage.h"
|
||||
#include "../RTC/RTCStore.h"
|
||||
#include "../RTC/Clock.h"
|
||||
#include "../Protocol/Protocol.h"
|
||||
|
||||
|
||||
void
|
||||
CHourMeter::powerOnInit()
|
||||
{
|
||||
_RunTime = 0;
|
||||
_GlowTime = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CHourMeter::monitor(const CProtocol& frame)
|
||||
{
|
||||
Clock.get().secondstime();
|
||||
}
|
||||
|
||||
unsigned long
|
||||
CHourMeter::getRunTime()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
CHourMeter::getGlowTime()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
46
src/Utility/HourMeter.h
Normal file
46
src/Utility/HourMeter.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* This file is part of the "bluetoothheater" distribution
|
||||
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
||||
*
|
||||
* Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../RTC/RTCStore.h"
|
||||
#include "NVStorage.h"
|
||||
|
||||
class CProtocol;
|
||||
|
||||
class CHourMeter {
|
||||
int& _RunTime;
|
||||
int& _GlowTime;
|
||||
public:
|
||||
CHourMeter(int &runtime, int& glowtime) :
|
||||
_RunTime(runtime),
|
||||
_GlowTime(glowtime)
|
||||
{};
|
||||
void associate(int &runtime, int& glowtime) {
|
||||
_RunTime = runtime;
|
||||
_GlowTime = glowtime;
|
||||
};
|
||||
void powerOnInit();
|
||||
void monitor(const CProtocol& frame);
|
||||
unsigned long getRunTime();
|
||||
unsigned long getGlowTime();
|
||||
};
|
||||
|
||||
extern CHourMeter* pHourMeter;
|
Loading…
Reference in a new issue