Compare commits
167 commits
Author | SHA1 | Date | |
---|---|---|---|
|
f041cf8cad | ||
|
d0a5da308d | ||
|
a9e0a1e60d | ||
|
ef04489fa6 | ||
|
f18cfbf2e5 | ||
|
2548191173 | ||
|
21e17d1a2b | ||
|
775f235ba8 | ||
|
24d8a4a7f1 | ||
|
7b36aa27f5 | ||
|
4b3951b465 | ||
|
97f3433158 | ||
|
3129a88cb9 | ||
|
c74f0a76eb | ||
|
b75254220c | ||
|
9ff2d9410b | ||
|
5cdc5c95a5 | ||
|
28bfb28ff6 | ||
|
baf8678e99 | ||
|
b58ed90432 | ||
|
67998747d7 | ||
|
9839571893 | ||
|
4625f98cf3 | ||
|
0ed7ba7e59 | ||
|
4eddcd0f1e | ||
|
3e3ef7d2f2 | ||
|
9c100f1954 | ||
|
8ec438e02a | ||
|
8b8aaf0024 | ||
|
87b1704335 | ||
|
1d80e34c4b | ||
|
4986a4d741 | ||
|
3ca3e633ae | ||
|
06d78860ca | ||
|
41d43813b7 | ||
|
7e1a4940ac | ||
|
083fb63764 | ||
|
88cf18bfcf | ||
|
af1ab021a4 | ||
|
194cc08ac9 | ||
|
f5d72e2ac8 | ||
|
69155f8e45 | ||
|
c76490481d | ||
|
c9298656fa | ||
|
c649517805 | ||
|
6fb7b9d608 | ||
|
eb2e2d4305 | ||
|
d8e71eebc1 | ||
|
53430d3fa0 | ||
|
7081391f63 | ||
|
f2af9c3fda | ||
|
96b3cecdb0 | ||
|
b1cee63ec3 | ||
|
4138d0b2f5 | ||
|
5efce879ce | ||
|
f330d812e6 | ||
|
8893abb575 | ||
|
2e25ad3da4 | ||
|
aabe6a54b3 | ||
|
7c43523d51 | ||
|
ab246244c9 | ||
|
af34331401 | ||
|
112628f103 | ||
|
573ebf3e3b | ||
|
8fb1981552 | ||
|
de9417ff73 | ||
|
6e86571a19 | ||
|
bf537d1ac5 | ||
|
095797f8b0 | ||
|
b2cc6ff36d | ||
|
c51b18dd36 | ||
|
3a70970356 | ||
|
36d1b06ba2 | ||
|
f93e5d7628 | ||
|
d30536e939 | ||
|
3a810d6eea | ||
|
fa36236948 | ||
|
ac5fdc5dfd | ||
|
583a4881cd | ||
|
9fbb6e8dfc | ||
|
77dada9d6b | ||
|
13fb3f715a | ||
|
8a237059fd | ||
|
3e4ce429c7 | ||
|
fdf4e9af99 | ||
|
61e246f6f1 | ||
|
253bc3f728 | ||
|
f6f721bd8a | ||
|
c79522233c | ||
|
08a39a26f7 | ||
|
7853102a4d | ||
|
e7bac339b5 | ||
|
f5a8c3c11e | ||
|
a491db257a | ||
|
79b6c06a2a | ||
|
d7e083b837 | ||
|
4873fa8c71 | ||
|
48a0254f13 | ||
|
10db95733f | ||
|
e205119b24 | ||
|
1c314e14f2 | ||
|
2a788cb2d0 | ||
|
27b988c895 | ||
|
e5e0f87e0b | ||
|
08d0307fc8 | ||
|
ac091fa6d8 | ||
|
945d9c88b7 | ||
|
8daf555950 | ||
|
1b3b478a49 | ||
|
a52143479f | ||
|
c1207e66ef | ||
|
f154580eb2 | ||
|
6c21a9c6a6 | ||
|
d563cb0c8a | ||
|
a7348fdbf5 | ||
|
dfa60eb491 | ||
|
ca0e763da6 | ||
|
d2116fc18c | ||
|
f86ae7cffb | ||
|
1dbfa67163 | ||
|
2084c7d60c | ||
|
c621f7078c | ||
|
9c338fa74c | ||
|
92283a3e0d | ||
|
204007401b | ||
|
04de63b07e | ||
|
8ebf6dbf3e | ||
|
cb79fd5dd0 | ||
|
db3343d362 | ||
|
672645c59a | ||
|
cf41285052 | ||
|
dca26680b4 | ||
|
d6bba90c84 | ||
|
06e69acc77 | ||
|
dd5e62c8cb | ||
|
04ae988d2d | ||
|
a543ba0748 | ||
|
e50d93bb8c | ||
|
77ac324d64 | ||
|
4d6ab5b280 | ||
|
16ee16f97f | ||
|
1f28bb7d5d | ||
|
de1eb48f78 | ||
|
b6b0c7afbd | ||
|
8dd5dc662e | ||
|
278d40af33 | ||
|
66f10445a4 | ||
|
2f38a33984 | ||
|
1b4b6699c5 | ||
|
c20b309184 | ||
|
6d7af0e010 | ||
|
40c0a72c77 | ||
|
4330d2eac5 | ||
|
fcd15ddb34 | ||
|
6b814e70d9 | ||
|
657bec98e7 | ||
|
0378e733ef | ||
|
592ace0f0a | ||
|
4491da1f2f | ||
|
d247d14945 | ||
|
471a423a19 | ||
|
e6b8365f09 | ||
|
8d143c03a5 | ||
|
a435aed47d | ||
|
129631c82a | ||
|
f718611bd6 | ||
|
924a079fb2 |
18
.gitignore
vendored
|
@ -7,3 +7,21 @@
|
||||||
.vs
|
.vs
|
||||||
__vm
|
__vm
|
||||||
/Arduino/BTCDieselHeater/.vscode/*.json
|
/Arduino/BTCDieselHeater/.vscode/*.json
|
||||||
|
.pio
|
||||||
|
.pioenvs
|
||||||
|
.piolibdeps
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
||||||
|
/.vscode/settings.json
|
||||||
|
/.vscode/extensions.json
|
||||||
|
Arduino/Afterburner/data/*
|
||||||
|
Arduino/Afterburner/src/*
|
||||||
|
/Altium
|
||||||
|
/Releases
|
||||||
|
/webdev
|
||||||
|
/case
|
||||||
|
/DieselHeaterV2.PcbDoc
|
||||||
|
/StandardResponse.txt
|
||||||
|
/HeaterHack-Tested.zip
|
||||||
|
/OTA_COM.txt
|
||||||
|
|
67
.travis.yml
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# Continuous Integration (CI) is the practice, in software
|
||||||
|
# engineering, of merging all developer working copies with a shared mainline
|
||||||
|
# several times a day < https://docs.platformio.org/page/ci/index.html >
|
||||||
|
#
|
||||||
|
# Documentation:
|
||||||
|
#
|
||||||
|
# * Travis CI Embedded Builds with PlatformIO
|
||||||
|
# < https://docs.travis-ci.com/user/integration/platformio/ >
|
||||||
|
#
|
||||||
|
# * PlatformIO integration with Travis CI
|
||||||
|
# < https://docs.platformio.org/page/ci/travis.html >
|
||||||
|
#
|
||||||
|
# * User Guide for `platformio ci` command
|
||||||
|
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Please choose one of the following templates (proposed below) and uncomment
|
||||||
|
# it (remove "# " before each line) or use own configuration according to the
|
||||||
|
# Travis CI documentation (see above).
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Template #1: General project. Test it using existing `platformio.ini`.
|
||||||
|
#
|
||||||
|
|
||||||
|
# language: python
|
||||||
|
# python:
|
||||||
|
# - "2.7"
|
||||||
|
#
|
||||||
|
# sudo: false
|
||||||
|
# cache:
|
||||||
|
# directories:
|
||||||
|
# - "~/.platformio"
|
||||||
|
#
|
||||||
|
# install:
|
||||||
|
# - pip install -U platformio
|
||||||
|
# - platformio update
|
||||||
|
#
|
||||||
|
# script:
|
||||||
|
# - platformio run
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Template #2: The project is intended to be used as a library with examples.
|
||||||
|
#
|
||||||
|
|
||||||
|
# language: python
|
||||||
|
# python:
|
||||||
|
# - "2.7"
|
||||||
|
#
|
||||||
|
# sudo: false
|
||||||
|
# cache:
|
||||||
|
# directories:
|
||||||
|
# - "~/.platformio"
|
||||||
|
#
|
||||||
|
# env:
|
||||||
|
# - PLATFORMIO_CI_SRC=path/to/test/file.c
|
||||||
|
# - PLATFORMIO_CI_SRC=examples/file.ino
|
||||||
|
# - PLATFORMIO_CI_SRC=path/to/test/directory
|
||||||
|
#
|
||||||
|
# install:
|
||||||
|
# - pip install -U platformio
|
||||||
|
# - platformio update
|
||||||
|
#
|
||||||
|
# script:
|
||||||
|
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
|
6
ABpartition.csv
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x5000,
|
||||||
|
otadata, data, ota, 0xe000, 0x2000,
|
||||||
|
app0, app, ota_0, 0x10000, 0x1E0000,
|
||||||
|
app1, app, ota_1, 0x1F0000,0x1E0000,
|
||||||
|
spiffs, data, spiffs, 0x3D0000,0x30000,
|
|
BIN
AppInventor/BT.jpg
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
AppInventor/BTsmall.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
AppInventor/BTverysmall.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
AppInventor/BluetoothHeaterTQuery.aia
Normal file
BIN
AppInventor/bluetooth-icon-11.jpg
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
AppInventor/bluetooth-icon-32011.png
Normal file
After Width: | Height: | Size: 2 KiB |
34
Arduino/Afterburner/Afterburner.ino
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/**********************************************************************
|
||||||
|
* This file is deliberately empty.
|
||||||
|
*
|
||||||
|
* It only exists to satisfy the Arduino IDE's perverse requirement that a
|
||||||
|
* .ino must live directly below a parent directory, with the same name.
|
||||||
|
*
|
||||||
|
* In this instance Afterburner\Afterburner.ino
|
||||||
|
*
|
||||||
|
* I seriously recommend you use PLatformIO with your favourite editor.
|
||||||
|
*
|
||||||
|
* The real source code for the entire project is linked to via a symbolic
|
||||||
|
* link to the ClonedRepo\src, lib & data directories.
|
||||||
|
*
|
||||||
|
* ie ClonedRepo\Arduino\Afterburner\src\src -> ClonedRepo\src (..\..\src)
|
||||||
|
* ie ClonedRepo\Arduino\Afterburner\src\lib -> ClonedRepo\lib (..\..\lib)
|
||||||
|
* ie ClonedRepo\Arduino\Afterburner\data -> ClonedRepo\data (..\..\data)
|
||||||
|
*
|
||||||
|
* A batch file is in this folder to create these links, please use it first.
|
||||||
|
*
|
||||||
|
* Whilst initially alarming that is .ino file is empty, the Arduino IDE
|
||||||
|
* happily creates the required executable :-)
|
||||||
|
*
|
||||||
|
* The REAL host of setup() and loop() resides in ClonedRepo\src\Afterburner.cpp
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*****************************************************************************
|
||||||
|
*****************************************************************************
|
||||||
|
** **
|
||||||
|
** DUMP the Arduino IDE, and use PlatformIO. **
|
||||||
|
** Load the ClonedRepo path into PlatformIO. **
|
||||||
|
** Builds much faster and meshes well with decent programming editors :-) **
|
||||||
|
** **
|
||||||
|
*****************************************************************************
|
||||||
|
*****************************************************************************/
|
5
Arduino/Afterburner/MakeSymLinks_Linux.sh
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#!/bin/sh
|
||||||
|
mkdir src
|
||||||
|
ln -s ../../src src/src
|
||||||
|
ln -s ../../lib src/lib
|
||||||
|
ln -s ../../data data
|
7
Arduino/Afterburner/MakeSymLinks_Windows.bat
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
rem mklink /H Afterburner.ino ..\..\src\AfterBurner\Afterburner.cpp
|
||||||
|
mkdir src
|
||||||
|
mklink /J src\lib ..\..\lib
|
||||||
|
mklink /J src\src ..\..\src
|
||||||
|
mklink /J data ..\..\data
|
||||||
|
|
||||||
|
|
20
Arduino/Afterburner/README.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
TO WORK WITH ARDUINO IDE, EVERYTHING IN THIS FOLDER IS FAKE!
|
||||||
|
|
||||||
|
When you pull from gitlab, no symbolic links will be created.
|
||||||
|
|
||||||
|
You need to execute MakeSymLinks_Windows.bat from Explorer.
|
||||||
|
|
||||||
|
Arduino insists upon .ino for their projects, and the .ino
|
||||||
|
file name also has to match the parent directory name.
|
||||||
|
|
||||||
|
The BIG trick here is Afterburner.ino is empty - zilch, nada, nothing!
|
||||||
|
All the REAL source code lives via the src symbolic link.
|
||||||
|
The real core exists as a .cpp file: repo\src\Afterburner.cpp
|
||||||
|
|
||||||
|
Arduino\Afterburner\Afterburner.ino is EMPTY
|
||||||
|
Arduino\Afterburner\src\src links to repo\src\
|
||||||
|
Arduino\Afterburner\src\lib links to repo\lib\
|
||||||
|
Arduino\Afterburner\data links to repo\data
|
||||||
|
|
||||||
|
Ugggh. I hate Arduino IDE (and it's build environment!)
|
Before Width: | Height: | Size: 1.1 KiB |
|
@ -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>
|
|
|
@ -1,102 +0,0 @@
|
||||||
1249177ms [BTC] 76 16 00 11 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 13 74
|
|
||||||
+21ms [HTR] 8B 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 verifyCRC FAILED: calc:E388 data:6400
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
1250198ms [BTC] 76 16 00 11 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 13 74
|
|
||||||
+23ms [HTR] 8B 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 verifyCRC FAILED: calc:E388 data:6400
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
|
|
||||||
*** SWITCHED INTO VERBOSE MODE ****
|
|
||||||
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5
|
|
||||||
1251221ms [BTC] 76 16 00 11 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 13 74 :6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6
|
|
||||||
dT{16}:6,RD(8B)
|
|
||||||
dT{1}:6,RD(1D)
|
|
||||||
dT{1}:6,RD(76) <<<<<<<<<<<<<<<<<<<<<<<<<< THIS SHOULD BE FIRST RX BYTE!!!!
|
|
||||||
dT{1}:6,RD(16)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{2}:6,RD(0)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(84)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(84)
|
|
||||||
dT{2}:6,RD(0)
|
|
||||||
dT{1}:6,RD(2F)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{2}:6,RD(0)
|
|
||||||
dT{1}:6,RD(8)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(1A)
|
|
||||||
dT{1}:6,RD(64)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
:7 +48ms [HTR] 8B 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 verifyCRC FAILED: calc:E388 data:6400
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
:8
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
|
|
||||||
8< (lots of state :0 snipped)
|
|
||||||
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5
|
|
||||||
:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5
|
|
||||||
:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5:5
|
|
||||||
:5:5:5:5:5:5:5:5:5:5
|
|
||||||
1252268ms [BTC] 76 16 00 11 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 13 74
|
|
||||||
:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6:6
|
|
||||||
dT{16}:6,RD(8B)
|
|
||||||
dT{1}:6,RD(1D)
|
|
||||||
dT{1}:6,RD(76) <<<<<<<<<<<<<<<<<<<<<<<<<< THIS SHOULD BE FIRST RX BYTE!!!!
|
|
||||||
dT{2}:6,RD(16)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(84)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{2}:6,RD(0)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(84)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(2F)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{2}:6,RD(0)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(8)
|
|
||||||
dT{1}:6,RD(0)
|
|
||||||
dT{1}:6,RD(1A)
|
|
||||||
dT{2}:6,RD(64)
|
|
||||||
dT{1}:6,RD(0):7
|
|
||||||
+49ms [HTR] 8B 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 verifyCRC FAILED: calc:E388 data:6400
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
:8
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
||||||
:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
|
|
|
@ -1,117 +0,0 @@
|
||||||
Start updating sketch
|
|
||||||
Progress: 100%
|
|
||||||
End
|
|
||||||
*WM: [1] AutoConnect
|
|
||||||
*WM: [2] ESP32 event handler enabled
|
|
||||||
*WM: [2] Connecting as wifi client...
|
|
||||||
*WM: [2] setSTAConfig static ip not set
|
|
||||||
*WM: [3] WIFI station disconnect
|
|
||||||
*WM: [1] Connecting to saved AP: WigginsCorner
|
|
||||||
*WM: [3] WiFi station enable
|
|
||||||
*WM: [1] connectTimeout not set, ESP waitForConnectResult...
|
|
||||||
*WM: [2] [EVENT] 4
|
|
||||||
*WM: [2] [EVENT] 7
|
|
||||||
*WM: [2] Connection result: WL_CONNECTED
|
|
||||||
*WM: [3] lastconxresult: WL_CONNECTED
|
|
||||||
*WM: [1] AutoConnect: SUCCESS
|
|
||||||
*WM: [1] STA IP Address: 192.168.0.101
|
|
||||||
connected...yeey :)
|
|
||||||
Ready
|
|
||||||
IP address: 192.168.0.101
|
|
||||||
|
|
||||||
|
|
||||||
Attempting to detect HC-05 Bluetooth module...
|
|
||||||
@ 9600 baud... OK.
|
|
||||||
|
|
||||||
HC-05 found
|
|
||||||
Setting Name to "Diesel Heater"... OK
|
|
||||||
Setting baud rate to 9600N81...OK
|
|
||||||
|
|
||||||
2313ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +22ms [HTR] 76 16 00 08 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 0B DE
|
|
||||||
3335ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +22ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
4357ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
5380ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
6404ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
7427ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
8451ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
9474ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
10498ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
11521ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
12545ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
13568ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
14592ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
15615ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
16639ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
17662ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
18686ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
19709ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
20732ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
21756ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
22780ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
23803ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
24827ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
25850ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
26873ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
27897ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
28920ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 07 6C 2F 66 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
29944ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
30967ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
31991ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
33014ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
34038ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
35061ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
36084ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
37108ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
38131ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
39155ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
40178ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
41202ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
42225ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
43249ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
44272ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
45296ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
46319ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
47342ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
48366ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
49390ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
50413ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
51436ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
52460ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
53484ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
54507ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
55531ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
56555ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
57578ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
58602ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
59625ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
60649ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +22ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
61671ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
62695ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
63718ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
64742ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
65765ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
66788ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
67812ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
68836ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
69859ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
70882ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
71906ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
72929ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
73952ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
74976ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +24ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
76000ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 +23ms [HTR] 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A 3C
|
|
||||||
77023ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 Timeout collecting BTC heater response data, returning to Idle State
|
|
||||||
78047ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
|
|
||||||
+23ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
79070ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
|
|
||||||
+23ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
80093ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
|
|
||||||
+24ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
81117ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
|
|
||||||
+23ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
82140ms [BTC] 76 16 00 16 17 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC DF 60 verifyCRC FAILED: calc:AE26 data:6A
|
|
||||||
+23ms [HTR] 3C 76 16 00 00 00 90 00 00 00 90 00 0B 00 00 00 00 00 08 00 1C 64 00 6A verifyCRC FAILED: calc:AE26 data:6A
|
|
|
@ -1,46 +0,0 @@
|
||||||
1174404ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+22ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
|
|
||||||
1175426ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+22ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
|
|
||||||
1176448ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+23ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
|
|
||||||
1177471ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+22ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
|
|
||||||
1178493ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+21ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
|
|
||||||
1179515ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+22ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
|
|
||||||
1180537ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+22ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
|
|
||||||
1181559ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+23ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
|
|
||||||
1182583ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30 Timeout collecting BTC heater response data, returning to Idle State
|
|
||||||
1183588ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+22ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
|
|
||||||
1184611ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+21ms [HTR] 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A 4E
|
|
||||||
1185632ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+22ms [HTR] 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B 1D
|
|
||||||
1186654ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30 Timeout collecting BTC heater response data, returning to Idle State
|
|
||||||
1187676ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+22ms [HTR] 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B verifyCRC FAILED: calc:58A8 data:8B
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
1188699ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+22ms [HTR] 1D 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A verifyCRC FAILED: calc:B94 data:9A
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
1189721ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+22ms [HTR] 4E 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A verifyCRC FAILED: calc:27B2 data:9A
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
1190743ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+22ms [HTR] 4E 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B verifyCRC FAILED: calc:748E data:8B
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
1191765ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+22ms [HTR] 1D 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B verifyCRC FAILED: calc:58A8 data:8B
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
1192788ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+21ms [HTR] 1D 76 16 00 00 00 85 00 00 00 85 00 2F 00 00 00 00 00 08 00 1A 64 00 9A verifyCRC FAILED: calc:B94 data:9A
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
1193810ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30
|
|
||||||
+23ms [HTR] 4E 76 16 00 00 00 84 00 00 00 84 00 2F 00 00 00 00 00 08 00 1A 64 00 8B verifyCRC FAILED: calc:748E data:8B
|
|
||||||
Bluetooth data not sent, CRC error
|
|
||||||
1194833ms [BTC] 76 16 00 12 15 0E 28 05 DC 11 94 78 01 32 08 23 05 00 01 2C 0D AC 57 30 Timeout collecting BTC heater response data, returning to Idle State
|
|
|
@ -1,786 +0,0 @@
|
||||||
[Starting] Opening the serial port - COM9
|
|
||||||
oad:0x3fff0018,len:4
|
|
||||||
l<EFBFBD><EFBFBD><EFBFBD><EFBFBD>fff001c,len:952
|
|
||||||
load:0x40078000,len:6084
|
|
||||||
load:0x40080000,len:7936
|
|
||||||
entry 0x40080310
|
|
||||||
[Info] Opened the serial port - COM9
|
|
||||||
1046[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
1086[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
2070[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
2110[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
3093[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
3133[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
4113[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
4153[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
5132[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
5172[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
6155[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
6195[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
7179[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
7219[HTR] 76 16 00 00 00 8B 00 00 00 8B 00 10 00 00 00 00 00 08 00 1B 64 00 A3 A2
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
8202[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
8242[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
9222[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
9262[HTR] 76 16 00 00 00 8B 00 00 00 8B 00 11 00 00 00 00 00 08 00 1B 64 00 5F A6
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
10245[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
10285[HTR] 76 16 00 00 00 8B 00 00 00 8B 00 11 00 00 00 00 00 08 00 1B 64 00 5F A6
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
11265[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
11305[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
12289[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
12329[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
13308[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
13348[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
14331[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
14371[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
15354[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
15394[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
16378[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
16418[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
17401[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
17441[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
18425[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
18465[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
19445[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
19485[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
20468[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
20508[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
21488[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
21528[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96224
|
|
||||||
22508[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
22558[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
Free heap 92384
|
|
||||||
[CMD]degC19
|
|
||||||
Command decode: degC = 19
|
|
||||||
[CMD]save
|
|
||||||
Command decode: NV save
|
|
||||||
[CMD]degC19
|
|
||||||
Command decode: degC = 19
|
|
||||||
[CMD]save
|
|
||||||
Command decode: NV save
|
|
||||||
23531[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
23581[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
|
|
||||||
Free heap 92384
|
|
||||||
[CMD]degC19
|
|
||||||
Command decode: degC = 19
|
|
||||||
[CMD]save
|
|
||||||
Command decode: NV save
|
|
||||||
24550[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
24600[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
Free heap 92384
|
|
||||||
25573[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
25623[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
Free heap 92384
|
|
||||||
26598[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
26648[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
Free heap 92384
|
|
||||||
27620[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
27670[HTR] 76 16 00 00 00 8B 00 00 00 8B 00 10 00 00 00 00 00 08 00 1B 64 00 A3 A2
|
|
||||||
Free heap 92384
|
|
||||||
28643[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
28693[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 10 00 00 00 00 00 08 00 1B 64 00 B2 F1
|
|
||||||
Free heap 92384
|
|
||||||
29667[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
29717[HTR] 76 16 00 00 00 8A 00 00 00 8A 00 11 00 00 00 00 00 08 00 1B 64 00 4E F5
|
|
||||||
Free heap 92384
|
|
||||||
[CMD]ON
|
|
||||||
Command decode: Heater ON
|
|
||||||
30691[BTC] 76 16 A0 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC E1 57
|
|
||||||
30741[HTR] 76 16 01 00 00 8B 00 00 00 53 00 11 00 00 00 00 00 00 00 1B 64 00 96 5A
|
|
||||||
Free heap 92384
|
|
||||||
31712[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
31762[HTR] 76 16 02 01 00 8A 00 00 00 0A 00 10 00 02 00 5F 00 00 00 1B 64 00 C9 1D
|
|
||||||
Free heap 92384
|
|
||||||
32733[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
32783[HTR] 76 16 02 01 00 89 00 00 00 0B 00 10 00 04 00 B7 00 00 00 1B 64 00 16 AC
|
|
||||||
Free heap 92384
|
|
||||||
33753[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
33803[HTR] 76 16 02 01 00 89 00 00 00 0E 00 10 00 07 01 0E 00 00 00 1B 64 00 E4 5D
|
|
||||||
Free heap 92384
|
|
||||||
34777[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
34827[HTR] 76 16 02 01 00 89 00 00 00 11 00 10 00 09 01 62 00 00 00 1B 64 00 1D 97
|
|
||||||
Free heap 92384
|
|
||||||
35800[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
35850[HTR] 76 16 02 01 00 89 00 50 00 14 00 10 00 0A 01 86 00 00 00 1B 64 00 DA 7B
|
|
||||||
Free heap 92384
|
|
||||||
36822[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
36872[HTR] 76 16 02 01 00 89 00 C8 00 17 00 10 00 0B 01 C5 00 00 00 1B 64 00 27 99
|
|
||||||
Free heap 92384
|
|
||||||
37845[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
37895[HTR] 76 16 02 01 00 89 01 C2 00 1A 00 10 00 0E 02 21 00 00 00 1B 64 00 B6 1A
|
|
||||||
Free heap 92384
|
|
||||||
38867[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
38917[HTR] 76 16 02 01 00 89 02 80 00 1C 00 10 00 0F 02 41 00 00 00 1B 64 00 26 FC
|
|
||||||
Free heap 92384
|
|
||||||
39889[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
39939[HTR] 76 16 02 01 00 88 03 D4 00 1D 00 10 00 12 02 80 00 00 00 1B 64 00 04 7F
|
|
||||||
Free heap 92384
|
|
||||||
40912[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
40962[HTR] 76 16 02 01 00 88 04 CE 00 20 00 10 00 14 02 C0 00 00 00 1B 64 00 E4 9F
|
|
||||||
Free heap 92384
|
|
||||||
41935[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
41985[HTR] 76 16 02 01 00 88 06 04 00 20 00 10 00 16 02 EC 00 00 00 1B 64 00 70 A0
|
|
||||||
Free heap 92384
|
|
||||||
42958[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
43008[HTR] 76 16 02 01 00 88 06 9A 00 20 00 10 00 17 02 F8 00 00 00 1B 64 00 89 E7
|
|
||||||
Free heap 92384
|
|
||||||
43981[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
44031[HTR] 76 16 02 01 00 88 07 3A 00 20 00 10 00 1A 03 23 00 00 00 1B 64 00 30 74
|
|
||||||
Free heap 92384
|
|
||||||
45005[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
45055[HTR] 76 16 02 01 00 88 07 80 00 20 00 10 00 1C 03 43 00 00 00 1B 64 00 E5 05
|
|
||||||
Free heap 92384
|
|
||||||
46029[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
46079[HTR] 76 16 02 01 00 88 07 B2 00 1E 00 10 00 1E 03 5F 00 00 00 1B 64 00 2F 24
|
|
||||||
Free heap 92384
|
|
||||||
47052[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
47102[HTR] 76 16 02 01 00 87 07 B2 00 1A 00 10 00 1F 03 5F 00 00 00 1B 64 00 C8 12
|
|
||||||
Free heap 92384
|
|
||||||
48076[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
48126[HTR] 76 16 02 01 00 87 07 80 00 19 00 10 00 21 03 77 00 00 00 1B 64 00 7D 15
|
|
||||||
Free heap 92384
|
|
||||||
49100[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
49150[HTR] 76 16 02 01 00 87 07 26 00 18 00 10 00 23 03 8F 00 00 00 1B 64 00 29 51
|
|
||||||
Free heap 92384
|
|
||||||
50120[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
50170[HTR] 76 16 02 01 00 87 06 E0 00 18 00 10 00 25 03 9F 00 00 00 1B 64 00 8A EC
|
|
||||||
Free heap 92384
|
|
||||||
51144[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
51194[HTR] 76 16 02 01 00 87 06 7C 00 18 00 10 00 28 03 B3 00 00 00 1B 64 00 B1 C5
|
|
||||||
Free heap 92384
|
|
||||||
52163[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
52213[HTR] 76 16 02 01 00 87 06 36 00 18 00 10 00 2A 03 C7 00 00 00 1B 64 00 E1 22
|
|
||||||
Free heap 92384
|
|
||||||
53185[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
53235[HTR] 76 16 02 01 00 87 05 E6 00 19 00 10 00 2C 03 CF 00 00 00 1B 64 00 AD 12
|
|
||||||
Free heap 92384
|
|
||||||
54207[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
54257[HTR] 76 16 02 01 00 87 05 C8 00 18 00 10 00 2D 03 C3 00 00 00 1B 64 00 A0 7F
|
|
||||||
Free heap 92384
|
|
||||||
55229[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
55279[HTR] 76 16 02 01 00 87 05 A0 00 19 00 10 00 2F 03 CF 00 00 00 1B 64 00 6F C0
|
|
||||||
Free heap 92384
|
|
||||||
56249[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
56299[HTR] 76 16 02 01 00 86 05 8C 00 18 00 10 00 32 03 D3 00 00 00 1B 64 00 F2 F7
|
|
||||||
Free heap 92384
|
|
||||||
57272[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
57322[HTR] 76 16 02 01 00 86 05 8C 00 18 00 10 00 33 03 DF 00 00 00 1B 64 00 62 36
|
|
||||||
Free heap 92384
|
|
||||||
58292[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
58342[HTR] 76 16 02 01 00 86 05 8C 00 18 00 10 00 35 03 D3 00 00 00 1B 64 00 C2 D1
|
|
||||||
Free heap 92384
|
|
||||||
59315[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
59365[HTR] 76 16 02 01 00 86 05 8C 00 19 00 10 00 37 03 DF 00 00 00 1B 64 00 23 06
|
|
||||||
Free heap 92384
|
|
||||||
60335[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
60385[HTR] 76 16 02 01 00 86 05 8C 00 19 00 10 00 39 03 DB 00 00 00 1B 64 00 83 0F
|
|
||||||
Free heap 92384
|
|
||||||
61355[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
61405[HTR] 76 16 02 01 00 85 05 8C 00 18 00 10 00 3B 03 E6 00 00 00 1B 64 00 51 08
|
|
||||||
Free heap 92384
|
|
||||||
62379[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
62429[HTR] 76 16 02 01 00 85 05 96 00 19 00 10 00 3D 03 DF 00 00 00 1B 64 00 78 12
|
|
||||||
Free heap 92384
|
|
||||||
63398[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
63448[HTR] 76 16 02 01 00 85 05 8C 00 19 00 10 00 3F 03 DF 00 00 00 1B 64 00 13 91
|
|
||||||
Free heap 92384
|
|
||||||
64418[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
64468[HTR] 76 16 02 01 00 85 05 96 00 19 00 10 00 41 03 E6 00 00 00 1B 64 00 B9 8B
|
|
||||||
Free heap 92384
|
|
||||||
65441[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
65491[HTR] 76 16 02 01 00 85 05 8C 00 1A 00 10 00 42 03 DF 00 00 00 1B 64 00 82 A9
|
|
||||||
Free heap 92384
|
|
||||||
66462[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
66512[HTR] 76 16 02 01 00 85 05 96 00 1A 00 10 00 44 03 E6 00 00 00 1B 64 00 2A B1
|
|
||||||
Free heap 92384
|
|
||||||
67485[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
67535[HTR] 76 16 02 01 00 84 05 96 00 19 00 11 00 47 03 EA 00 00 00 1B 64 00 75 39
|
|
||||||
Free heap 92384
|
|
||||||
68508[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
68558[HTR] 76 16 02 01 00 84 05 A0 00 1A 00 10 00 49 03 F6 00 00 00 1B 64 00 FD 1F
|
|
||||||
Free heap 92384
|
|
||||||
69530[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
69580[HTR] 76 16 02 01 00 84 05 AA 00 1A 00 11 00 4A 03 EE 00 00 00 1B 64 00 F7 1D
|
|
||||||
Free heap 92384
|
|
||||||
70552[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
70602[HTR] 76 16 02 01 00 84 05 AA 00 1A 00 10 00 4C 03 F2 00 00 00 1B 64 00 6A EF
|
|
||||||
Free heap 92384
|
|
||||||
71574[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
71624[HTR] 76 16 02 01 00 83 05 B4 00 19 00 11 00 4F 03 FA 00 00 00 1B 64 00 5C 5F
|
|
||||||
Free heap 92384
|
|
||||||
72597[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
72647[HTR] 76 16 02 01 00 83 05 B4 00 1A 00 10 00 51 04 06 00 00 00 1B 64 00 2A A2
|
|
||||||
Free heap 92384
|
|
||||||
73621[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
73671[HTR] 76 16 02 01 00 83 05 BE 00 1A 00 10 00 52 03 FE 00 00 00 1B 64 00 F4 04
|
|
||||||
Free heap 92384
|
|
||||||
74644[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
74694[HTR] 76 16 02 01 00 83 05 BE 00 1A 00 10 00 54 04 06 00 00 00 1B 64 00 7D 17
|
|
||||||
Free heap 92384
|
|
||||||
75667[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
75717[HTR] 76 16 02 01 00 83 05 BE 00 1B 00 11 00 56 04 06 00 00 00 1B 64 00 60 08
|
|
||||||
Free heap 92384
|
|
||||||
76690[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
76740[HTR] 76 16 02 01 00 82 05 BE 00 1A 00 10 00 58 04 12 00 00 00 1B 64 00 EC 47
|
|
||||||
Free heap 92384
|
|
||||||
77712[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
77762[HTR] 76 16 02 01 00 82 05 C8 00 1A 00 10 00 58 04 06 00 00 00 1B 64 00 CB E5
|
|
||||||
Free heap 92384
|
|
||||||
78735[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
78785[HTR] 76 16 02 01 00 82 05 C8 00 1A 00 10 00 58 03 FA 00 00 00 1B 64 00 22 98
|
|
||||||
Free heap 92384
|
|
||||||
79756[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
79806[HTR] 76 16 02 01 00 82 05 D2 00 1A 00 10 00 59 03 F6 00 00 00 1B 64 00 B9 C3
|
|
||||||
Free heap 92384
|
|
||||||
80779[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
80829[HTR] 76 16 02 01 00 82 05 D2 00 1A 00 10 00 59 03 EE 00 00 00 1B 64 00 B8 5B
|
|
||||||
Free heap 92384
|
|
||||||
81803[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
81853[HTR] 76 16 02 01 00 83 05 D2 00 1C 00 10 00 59 03 E6 00 00 00 1B 64 00 2E 8A
|
|
||||||
Free heap 92384
|
|
||||||
82822[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
82872[HTR] 76 16 02 01 00 82 05 DC 00 1A 00 11 00 59 03 DF 00 00 00 1B 64 00 83 F1
|
|
||||||
Free heap 92384
|
|
||||||
83845[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
83895[HTR] 76 16 02 01 00 82 05 DC 00 1A 00 10 00 59 03 DB 00 00 00 1B 64 00 BF B0
|
|
||||||
Free heap 92384
|
|
||||||
84867[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
84917[HTR] 76 16 02 01 00 83 05 DC 00 1A 00 10 00 59 03 D3 00 00 00 1B 64 00 EF 68
|
|
||||||
Free heap 92384
|
|
||||||
85888[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
85938[HTR] 76 16 02 01 00 83 05 DC 00 1B 00 11 00 59 03 D7 00 00 00 1B 64 00 52 2B
|
|
||||||
Free heap 92384
|
|
||||||
86910[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
86960[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 10 00 59 03 CF 00 00 00 1B 64 00 BC 0D
|
|
||||||
Free heap 92384
|
|
||||||
87933[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
87983[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 10 00 59 03 CF 00 00 00 1B 64 00 BC 0D
|
|
||||||
Free heap 92384
|
|
||||||
88956[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
89006[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 11 00 59 03 CB 00 00 00 1B 64 00 80 4C
|
|
||||||
Free heap 92384
|
|
||||||
89979[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
90029[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 10 00 59 03 C7 00 00 00 1B 64 00 7C 84
|
|
||||||
Free heap 92384
|
|
||||||
91002[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
91052[HTR] 76 16 02 01 00 83 05 E6 00 1A 00 11 00 59 03 C3 00 00 00 1B 64 00 C1 C7
|
|
||||||
Free heap 92384
|
|
||||||
92024[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
92074[HTR] 76 16 02 01 00 83 05 E6 00 1A 00 11 00 59 03 C3 00 00 00 1B 64 00 C1 C7
|
|
||||||
Free heap 92384
|
|
||||||
93047[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
93097[HTR] 76 16 02 01 00 83 05 DC 00 1A 00 11 00 59 03 BF 00 00 00 1B 64 00 15 C0
|
|
||||||
Free heap 92384
|
|
||||||
94070[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
94120[HTR] 76 16 02 01 00 83 05 DC 00 1D 00 11 00 59 03 BF 00 00 00 1B 64 00 52 CB
|
|
||||||
Free heap 92384
|
|
||||||
95094[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
95144[HTR] 76 16 02 01 00 83 05 D2 00 1A 00 10 00 59 03 BF 00 00 00 1B 64 00 ED 4A
|
|
||||||
Free heap 92384
|
|
||||||
96117[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
96167[HTR] 76 16 02 01 00 83 05 D2 00 1A 00 11 00 59 03 BF 00 00 00 1B 64 00 11 4E
|
|
||||||
Free heap 92384
|
|
||||||
97139[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
97189[HTR] 76 16 02 01 00 83 05 D2 00 1A 00 10 00 59 03 BF 00 00 00 1B 64 00 ED 4A
|
|
||||||
Free heap 92384
|
|
||||||
98162[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
98212[HTR] 76 16 02 01 00 83 05 C8 00 1A 00 11 00 59 03 BB 00 00 00 1B 64 00 DA 91
|
|
||||||
Free heap 92384
|
|
||||||
99185[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
99235[HTR] 76 16 02 01 00 83 05 C8 00 1B 00 11 00 59 03 B7 00 00 00 1B 64 00 5B 5F
|
|
||||||
Free heap 92384
|
|
||||||
100207[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
100257[HTR] 76 16 02 01 00 83 05 BE 00 1A 00 11 00 59 03 B7 00 00 00 1B 64 00 FC AB
|
|
||||||
Free heap 92384
|
|
||||||
101230[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
101280[HTR] 76 16 02 01 00 83 05 BE 00 1A 00 10 00 59 03 BB 00 00 00 1B 64 00 00 63
|
|
||||||
Free heap 92384
|
|
||||||
102252[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
102302[HTR] 76 16 02 01 00 83 05 BE 00 1B 00 10 00 59 03 B7 00 00 00 1B 64 00 81 AD
|
|
||||||
Free heap 92384
|
|
||||||
103276[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
103326[HTR] 76 16 02 01 00 83 05 B4 00 1A 00 10 00 59 03 B7 00 00 00 1B 64 00 07 25
|
|
||||||
Free heap 92384
|
|
||||||
104298[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
104348[HTR] 76 16 02 01 00 83 05 BE 00 1B 00 10 00 59 03 B3 00 00 00 1B 64 00 41 E8
|
|
||||||
Free heap 92384
|
|
||||||
105320[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
105370[HTR] 76 16 02 01 00 83 05 BE 00 1B 00 11 00 59 03 B3 00 00 00 1B 64 00 BD EC
|
|
||||||
Free heap 92384
|
|
||||||
106344[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
106394[HTR] 76 16 02 01 00 83 05 D2 00 1B 00 11 00 59 03 B3 00 00 00 1B 64 00 90 80
|
|
||||||
Free heap 92384
|
|
||||||
107366[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
107416[HTR] 76 16 02 01 00 83 05 DC 00 1B 00 10 00 59 03 B3 00 00 00 1B 64 00 68 0A
|
|
||||||
Free heap 92384
|
|
||||||
108388[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
108438[HTR] 76 16 02 01 00 83 05 E6 00 1B 00 11 00 59 03 B3 00 00 00 1B 64 00 87 B4
|
|
||||||
Free heap 92384
|
|
||||||
109411[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
109461[HTR] 76 16 02 01 00 83 05 F0 00 1B 00 11 00 59 03 B3 00 00 00 1B 64 00 89 22
|
|
||||||
Free heap 92384
|
|
||||||
110435[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
110485[HTR] 76 16 02 01 00 83 05 FA 00 1B 00 11 00 59 03 AF 00 00 00 1B 64 00 4F 75
|
|
||||||
Free heap 92384
|
|
||||||
111457[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
111507[HTR] 76 16 02 01 00 83 05 FA 00 1B 00 11 00 59 03 AF 00 00 00 1B 64 00 4F 75
|
|
||||||
Free heap 92384
|
|
||||||
112480[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
112530[HTR] 76 16 02 01 00 83 05 FA 00 1A 00 11 00 59 03 AF 00 00 00 1B 64 00 CE 77
|
|
||||||
Free heap 92384
|
|
||||||
113500[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
113550[HTR] 76 16 02 01 00 83 05 FA 00 1A 00 11 00 59 03 AF 10 00 00 1B 64 00 5E 75
|
|
||||||
Free heap 92384
|
|
||||||
114523[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
114573[HTR] 76 16 02 01 00 81 05 F0 00 1A 00 11 00 59 03 AF 10 00 00 1B 64 00 39 5E
|
|
||||||
Free heap 92384
|
|
||||||
115546[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
115596[HTR] 76 16 02 01 00 83 05 F0 00 1B 00 11 00 59 03 B3 10 00 00 1B 64 00 19 20
|
|
||||||
Free heap 92384
|
|
||||||
116569[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
116619[HTR] 76 16 02 01 00 83 05 F0 00 1B 00 11 00 59 03 AF 10 00 00 1B 64 00 D8 FD
|
|
||||||
Free heap 92384
|
|
||||||
117593[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
117643[HTR] 76 16 02 01 00 82 05 FA 00 1A 00 11 00 59 03 AF 10 00 00 1B 64 00 CE 24
|
|
||||||
Free heap 92384
|
|
||||||
118616[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
118666[HTR] 76 16 02 01 00 83 05 F0 00 1B 00 11 00 59 03 AB 10 00 00 1B 64 00 18 B8
|
|
||||||
Free heap 92384
|
|
||||||
119639[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
119689[HTR] 76 16 02 01 00 83 05 FA 00 1B 00 11 00 59 03 AB 10 00 00 1B 64 00 1F 32
|
|
||||||
Free heap 92384
|
|
||||||
120661[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
120711[HTR] 76 16 02 01 00 80 06 04 00 1A 00 11 00 59 03 AB 10 00 00 1B 64 00 DF FE
|
|
||||||
Free heap 92384
|
|
||||||
121685[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
121735[HTR] 76 16 02 01 00 83 06 18 00 1C 00 11 00 59 03 AF 10 00 00 1B 64 00 20 5E
|
|
||||||
Free heap 92384
|
|
||||||
122708[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
122758[HTR] 76 16 02 01 00 83 06 22 00 1C 00 11 00 59 03 A7 10 00 00 1B 64 00 F3 6D
|
|
||||||
Free heap 92384
|
|
||||||
123728[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
123778[HTR] 76 16 02 01 00 83 06 2C 00 1C 00 11 00 59 03 AB 10 00 00 1B 64 00 F7 2F
|
|
||||||
Free heap 92384
|
|
||||||
124748[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
124798[HTR] 76 16 02 01 00 83 06 40 00 1C 00 11 00 59 03 AB 11 00 00 1B 64 00 0B 42
|
|
||||||
Free heap 92384
|
|
||||||
125770[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
125820[HTR] 76 16 02 01 00 83 06 54 00 1C 00 11 00 59 03 AB 11 00 00 1B 64 00 04 56
|
|
||||||
Free heap 92384
|
|
||||||
126792[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
126842[HTR] 76 16 02 01 00 83 06 5E 00 1C 00 11 00 59 03 AF 11 00 00 1B 64 00 C3 99
|
|
||||||
Free heap 92384
|
|
||||||
127812[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
127862[HTR] 76 16 02 01 00 83 06 68 00 1C 00 11 00 59 03 AB 11 00 00 1B 64 00 15 6A
|
|
||||||
Free heap 92384
|
|
||||||
128833[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
128883[HTR] 76 16 02 01 00 83 06 7C 00 1D 00 11 00 59 03 AB 11 00 00 1B 64 00 9B 7C
|
|
||||||
Free heap 92384
|
|
||||||
129853[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
129903[HTR] 76 16 02 01 00 83 06 7C 00 1D 00 11 00 59 03 AB 11 00 00 1B 64 00 9B 7C
|
|
||||||
Free heap 92384
|
|
||||||
130874[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
130924[HTR] 76 16 02 01 00 83 06 86 00 1D 00 11 00 59 03 AB 11 00 00 1B 64 00 D8 06
|
|
||||||
Free heap 92384
|
|
||||||
131894[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
131944[HTR] 76 16 02 01 00 83 06 90 00 1D 00 11 00 59 03 AF 11 00 00 1B 64 00 16 D5
|
|
||||||
Free heap 92384
|
|
||||||
132915[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
132965[HTR] 76 16 02 01 00 83 06 9A 00 1E 00 11 00 59 03 AB 11 00 00 1B 64 00 12 1F
|
|
||||||
Free heap 92384
|
|
||||||
133938[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
133988[HTR] 76 16 02 01 00 83 06 A4 00 1E 00 11 00 59 03 AF 12 00 00 1B 64 00 F1 E4
|
|
||||||
Free heap 92384
|
|
||||||
134957[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
135007[HTR] 76 16 02 01 00 83 06 AE 00 21 00 11 00 59 03 AB 12 00 00 1B 64 00 C9 7E
|
|
||||||
Free heap 92384
|
|
||||||
135981[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
136031[HTR] 76 16 02 01 00 83 06 C2 00 1F 00 11 00 59 03 AB 12 00 00 1B 64 00 9A 45
|
|
||||||
Free heap 92384
|
|
||||||
137003[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
137053[HTR] 76 16 02 01 00 82 06 CC 00 1E 00 11 00 59 03 A7 12 00 00 1B 64 00 8F 54
|
|
||||||
Free heap 92384
|
|
||||||
ASSERT_PARAM(512 0), in rwbt.c at line 273
|
|
||||||
Guru Meditation Error: Core 0 panic'ed (Interrupt wdt timeout on CPU0)
|
|
||||||
Core 0 register dump:
|
|
||||||
PC : 0x400850c8 PS : 0x00060034 A0 : 0x80088b40 A1 : 0x3ffc05b0
|
|
||||||
A2 : 0x00000001 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x60008054
|
|
||||||
A6 : 0x3ffc1030 A7 : 0x60008050 A8 : 0x800850c5 A9 : 0x3ffc0590
|
|
||||||
A10 : 0x00000004 A11 : 0x00000000 A12 : 0x6000804c A13 : 0xffffffff
|
|
||||||
A14 : 0x00000000 A15 : 0xfffffffc SAR : 0x00000004 EXCCAUSE: 0x00000005
|
|
||||||
EXCVADDR: 0x00000000 LBEG : 0x40084ffd LEND : 0x40085004 LCOUNT : 0x00000000
|
|
||||||
Core 0 was running in ISR context:
|
|
||||||
EPC1 : 0x4017d35e EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x400850c8
|
|
||||||
|
|
||||||
Backtrace: 0x400850c8:0x3ffc05b0 0x40088b3d:0x3ffc05d0 0x400891cf:0x3ffc05f0 0x400817ad:0x3ffc0610 0x4017d35b:0x00000000
|
|
||||||
|
|
||||||
Core 1 register dump:
|
|
||||||
PC : 0x400d1faa PS : 0x00060334 A0 : 0x800d1258 A1 : 0x3ffd55d0
|
|
||||||
A2 : 0x00000000 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x00000000
|
|
||||||
A6 : 0x00000000 A7 : 0x3ffd36c0 A8 : 0x3ffc4920 A9 : 0x3ffd55b0
|
|
||||||
A10 : 0x3ffe7f84 A11 : 0x3ffd0814 A12 : 0xd4000000 A13 : 0x3ffd54d0
|
|
||||||
A14 : 0x00000002 A15 : 0x3ffd36c0 SAR : 0x0000000a EXCCAUSE: 0x00000005
|
|
||||||
EXCVADDR: 0x00000000 LBEG : 0x4000c2e0 LEND : 0x4000c2f6 LCOUNT : 0x00000000
|
|
||||||
|
|
||||||
Backtrace: 0x400d1faa:0x3ffd55d0 0x400d1255:0x3ffd55f0 0x400d1718:0x3ffd5610 0x401692c4:0x3ffd5630
|
|
||||||
|
|
||||||
Rebooting...
|
|
||||||
ets Jun 8 2016 00:22:57
|
|
||||||
|
|
||||||
rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
|
|
||||||
configsip: 0, SPIWP:0xee
|
|
||||||
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
|
|
||||||
mode:DIO, clock div:1
|
|
||||||
load:0x3fff0018,len:4
|
|
||||||
load:0x3fff001c,len:952
|
|
||||||
load:0x40078000,len:6084
|
|
||||||
load:0x40080000,len:7936
|
|
||||||
entry 0x40080310
|
|
||||||
1045[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
1085[HTR] 76 16 02 01 00 81 06 FE 00 1F 00 11 00 59 03 A7 12 00 00 1B 64 00 EB 14
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
2065[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
2105[HTR] 76 16 02 01 00 82 07 26 00 20 00 11 00 59 03 AB 12 00 00 1B 64 00 2E 64
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
3086[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
3126[HTR] 76 16 02 01 00 83 07 3A 00 21 00 11 00 59 03 A7 12 00 00 1B 64 00 36 E7
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
4107[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
4147[HTR] 76 16 02 01 00 82 07 62 00 21 00 11 00 59 03 AF 12 00 00 1B 64 00 5C 67
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
5126[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
5166[HTR] 76 16 02 01 00 82 07 6C 00 20 00 11 00 59 03 AF 13 00 00 1B 64 00 08 EA
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
6146[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
6186[HTR] 76 16 02 01 00 82 07 94 00 22 00 11 00 59 03 AB 13 00 00 1B 64 00 C8 50
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
7167[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
7207[HTR] 76 16 02 01 00 82 07 A8 00 22 00 11 00 59 03 AF 13 00 00 1B 64 00 19 29
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
8187[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
8227[HTR] 76 16 02 01 00 82 07 BC 00 21 00 11 00 59 03 AB 13 00 00 1B 64 00 15 7D
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
9208[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
9248[HTR] 76 16 02 01 00 82 07 C6 00 23 00 11 00 59 03 AB 13 00 00 1B 64 00 74 80
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
10233[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
10273[HTR] 76 16 02 01 00 82 07 E4 00 23 00 11 00 59 03 AF 13 00 00 1B 64 00 AD 67
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
11253[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
11293[HTR] 76 16 02 01 00 82 07 F8 00 24 00 11 00 58 03 AF 13 00 00 1B 64 00 73 7D
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
12274[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
12314[HTR] 76 16 02 01 00 82 08 0C 00 24 00 11 00 59 03 AF 13 00 00 1B 64 00 50 C1
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
13294[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
13334[HTR] 76 16 02 01 00 82 08 20 00 24 00 11 00 59 03 AF 14 00 00 1B 64 00 FA EC
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
14314[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
14354[HTR] 76 16 02 01 00 82 08 48 00 25 00 11 00 59 03 AF 14 00 00 1B 64 00 55 86
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
15338[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
15378[HTR] 76 16 02 01 00 82 08 66 00 25 00 11 00 59 03 B3 14 00 00 1B 64 00 88 F5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
16362[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
16402[HTR] 76 16 02 01 00 82 08 84 00 26 00 11 00 59 03 B3 14 00 00 1B 64 00 02 92
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
17382[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
17422[HTR] 76 16 02 01 00 82 08 A2 00 26 00 11 00 59 03 AF 14 00 00 1B 64 00 D9 E9
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
18403[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
18443[HTR] 76 16 02 01 00 80 08 C0 00 27 00 11 00 59 03 B3 14 00 00 1B 64 00 D0 75
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
19423[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
19463[HTR] 76 16 02 01 00 82 08 D4 00 27 00 11 00 59 03 B3 14 00 00 1B 64 00 BF C0
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
20443[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
20483[HTR] 76 16 02 01 00 82 08 E8 00 27 00 12 00 5A 03 AF 15 00 00 1B 64 00 0A 3B
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
21464[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
21504[HTR] 76 16 02 01 00 82 08 FC 00 28 00 11 00 59 03 B3 15 00 00 1B 64 00 7F FD
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
22488[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
22528[HTR] 76 16 02 01 00 82 09 10 00 27 00 12 00 59 03 AF 15 00 00 1B 64 00 28 16
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
23508[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
23548[HTR] 76 16 02 01 00 82 09 2E 00 28 00 12 00 59 03 B3 15 00 00 1B 64 00 F6 61
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
24529[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
24569[HTR] 76 16 02 01 00 80 09 42 00 28 00 11 00 59 03 B3 15 00 00 1B 64 00 FF A3
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
25549[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
25589[HTR] 76 16 02 01 00 82 09 60 00 2A 00 12 00 59 03 AF 15 00 00 1B 64 00 41 75
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
26570[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
26610[HTR] 76 16 02 01 00 82 09 74 00 2A 00 12 00 59 03 B3 16 00 00 1B 64 00 BC BC
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
27591[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
27631[HTR] 76 16 02 01 00 82 09 9C 00 2A 00 12 00 59 03 B7 16 00 00 1B 64 00 32 11
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
28613[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
28653[HTR] 76 16 02 01 00 82 09 B0 00 2B 00 12 00 59 03 B7 16 00 00 1B 64 00 AE 3F
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
29633[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
29673[HTR] 76 16 02 01 00 82 09 CE 00 2B 00 12 00 59 03 B7 16 00 00 1B 64 00 8E C1
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
30653[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
30693[HTR] 76 16 02 01 00 82 09 EC 00 2B 00 12 00 59 03 B7 16 00 00 1B 64 00 97 63
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
31674[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
31714[HTR] 76 16 02 01 00 82 09 F6 00 2C 00 12 00 59 03 B7 16 00 00 1B 64 00 DB F2
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
32694[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
32734[HTR] 76 16 02 01 00 82 0A 14 00 2C 00 12 00 59 03 B7 17 00 00 1B 64 00 B2 D1
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
33718[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
33758[HTR] 76 16 02 01 00 82 0A 1E 00 2D 00 12 00 59 03 B7 17 00 00 1B 64 00 34 59
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
34740[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
34780[HTR] 76 16 02 01 00 82 0A 32 00 2D 00 12 00 58 03 B7 17 00 00 1B 64 00 B9 78
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
35760[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
35800[HTR] 76 16 02 01 00 82 0A 46 00 2E 00 12 00 59 03 B7 17 00 00 1B 64 00 CD 04
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
36782[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
36822[HTR] 76 16 02 01 00 82 0A 5A 00 2E 00 12 00 59 03 B7 17 00 00 1B 64 00 C4 18
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
37803[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
37843[HTR] 76 16 02 01 00 82 0A 78 00 2F 00 12 00 59 03 B7 17 00 00 1B 64 00 5C B8
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
38823[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
38863[HTR] 76 16 02 01 00 82 0A 8C 00 2F 00 12 00 59 03 B7 18 00 00 1B 64 00 E4 4C
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
39843[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
39883[HTR] 76 16 02 01 00 80 0A AA 00 2F 00 12 00 59 03 B3 18 00 00 1B 64 00 5E 0E
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
40864[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
40904[HTR] 76 16 02 01 00 82 0A D2 00 30 00 12 00 59 03 BB 18 00 00 1B 64 00 43 74
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
41884[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
41924[HTR] 76 16 02 01 00 80 0A E6 00 30 00 12 00 59 03 B7 18 00 00 1B 64 00 34 2D
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
42906[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
42946[HTR] 76 16 02 01 00 82 0B 0E 00 31 00 12 00 59 03 B7 18 00 00 1B 64 00 0B A7
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
43925[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
43965[HTR] 76 16 02 01 00 80 0B 36 00 31 00 12 00 59 03 B7 19 00 00 1B 64 00 A8 3F
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
44946[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
44986[HTR] 76 16 02 01 00 82 0B 54 00 32 00 12 00 59 03 BB 19 00 00 1B 64 00 22 B5
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
45965[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
46005[HTR] 76 16 02 01 00 82 0B 68 00 32 00 13 00 59 03 B7 19 00 00 1B 64 00 CF 41
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
46986[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
47026[HTR] 76 16 02 01 00 82 0B 7C 00 33 00 12 00 59 03 BB 19 00 00 1B 64 00 BD 9F
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
48008[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
48048[HTR] 76 16 02 01 00 82 0B 9A 00 32 00 12 00 59 03 BB 1A 00 00 1B 64 00 45 FB
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
49031[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
49071[HTR] 76 16 02 01 00 82 0B A4 00 33 00 12 00 59 03 BF 1A 00 00 1B 64 00 14 02
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
50053[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
50093[HTR] 76 16 02 01 00 82 0B B8 00 33 00 13 00 59 03 BB 1A 00 00 1B 64 00 21 5F
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
51076[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
51116[HTR] 76 16 02 01 00 82 0B C2 00 34 00 13 00 59 03 BB 1A 00 00 1B 64 00 45 AE
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
52099[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
52139[HTR] 76 16 02 01 00 82 0B E0 00 34 00 13 00 59 03 BF 1A 00 00 1B 64 00 9C 49
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
53122[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
53162[HTR] 76 16 02 01 00 7F 0B EA 00 32 00 13 00 59 03 BB 1B 00 00 1B 64 00 EC 5E
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
54145[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
54185[HTR] 76 16 02 01 00 82 0C 08 00 35 00 13 00 59 03 C3 1B 00 00 1B 64 00 77 5D
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
55167[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
55207[HTR] 76 16 02 01 00 82 0C 1C 00 36 00 13 00 59 03 BB 1B 00 00 1B 64 00 BC B4
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
56187[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
56227[HTR] 76 16 02 01 00 81 0C 3A 00 36 00 13 00 59 03 BF 1B 00 00 1B 64 00 96 A7
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
57207[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
57247[HTR] 76 16 02 01 00 82 0C 58 00 36 00 13 00 59 03 BB 1C 00 00 1B 64 00 38 F1
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
||||||
58230[BTC] 76 16 00 16 13 10 2D 05 DC 11 94 78 01 CD 08 23 02 00 01 2C 0D AC 58 CF
|
|
||||||
No Bluetooth client
|
|
||||||
58270[HTR] 76 16 02 01 00 82 0C 6C 00 37 00 13 00 59 03 BB 1C 00 00 1B 64 00 AE C7
|
|
||||||
No Bluetooth client
|
|
||||||
Free heap 96196
|
|
|
@ -1,263 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "BluetoothHC05.h"
|
|
||||||
#include "../cfg/pins.h"
|
|
||||||
#include "../cfg/BTCConfig.h"
|
|
||||||
#include "../Protocol/Protocol.h"
|
|
||||||
#include "../Utility/helpers.h"
|
|
||||||
#include "../Utility/DebugPort.h"
|
|
||||||
|
|
||||||
// Bluetooth access via HC-05 Module, using a UART
|
|
||||||
|
|
||||||
|
|
||||||
CBluetoothHC05::CBluetoothHC05(int keyPin, int sensePin)
|
|
||||||
{
|
|
||||||
// extra control pins required to fully drive a HC05 module
|
|
||||||
_keyPin = keyPin; // used to enable AT command mode (ONLY ON SUPPORTED MODULES!!!!)
|
|
||||||
_sensePin = sensePin; // feedback signal used to sense if a client is connected
|
|
||||||
|
|
||||||
pinMode(_keyPin, OUTPUT);
|
|
||||||
digitalWrite(_keyPin, LOW); // request HC-05 module to enter data mode
|
|
||||||
// attach to the SENSE line from the HC-05 module
|
|
||||||
// this line goes high when a BT client is connected :-)
|
|
||||||
pinMode(_sensePin, INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
CBluetoothHC05::begin()
|
|
||||||
{
|
|
||||||
const int BTRates[] = {
|
|
||||||
9600, 38400, 115200, 19200, 57600, 2400, 4800, 1200
|
|
||||||
};
|
|
||||||
|
|
||||||
_rxLine.clear();
|
|
||||||
|
|
||||||
digitalWrite(_keyPin, HIGH); // request HC-05 module to enter command mode
|
|
||||||
|
|
||||||
delay(50);
|
|
||||||
|
|
||||||
openSerial(9600); // virtual function, may call derived class method here
|
|
||||||
|
|
||||||
DebugPort.println("\r\n\r\nAttempting to detect HC-05 Bluetooth module...");
|
|
||||||
|
|
||||||
int BTidx = 0;
|
|
||||||
int maxTries = sizeof(BTRates)/sizeof(int);
|
|
||||||
for(BTidx = 0; BTidx < maxTries; BTidx++) {
|
|
||||||
DebugPort.printf(" @ %d baud... ", BTRates[BTidx]);
|
|
||||||
openSerial(BTRates[BTidx]); // open serial port at a std. baud rate
|
|
||||||
delay(10);
|
|
||||||
flush();
|
|
||||||
HC05_SerialPort.print("AT\r\n"); // clear the throat!
|
|
||||||
delay(100);
|
|
||||||
HC05_SerialPort.setTimeout(100);
|
|
||||||
|
|
||||||
if(ATCommand("AT\r\n")) { // probe with a simple "AT"
|
|
||||||
DebugPort.println(" OK."); // got a response - woo hoo found the module!
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(ATCommand("AT\r\n")) { // sometimes a second try is good...
|
|
||||||
DebugPort.println(" OK.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// failed, try another baud rate
|
|
||||||
DebugPort.println("");
|
|
||||||
HC05_SerialPort.flush();
|
|
||||||
HC05_SerialPort.end();
|
|
||||||
delay(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugPort.println("");
|
|
||||||
if(BTidx == maxTries) {
|
|
||||||
// we could not get anywhere with the AT commands, but maybe this is the other module
|
|
||||||
// plough on and assume 9600 baud, but at the mercy of whatever the module name is...
|
|
||||||
DebugPort.println("FAILED to detect a HC-05 Bluetooth module :-(");
|
|
||||||
// leave the EN pin high - if other style module keeps it powered!
|
|
||||||
// assume it is 9600, and just (try to) use it like that...
|
|
||||||
// we will sense the STATE line to prove a client is hanging off the link...
|
|
||||||
DebugPort.println("ASSUMING a HC-05 module @ 9600baud (Unknown name)");
|
|
||||||
openSerial(9600);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// found a HC-05 module at one of its supported baud rates.
|
|
||||||
// now program it's name and force a 9600 baud data interface.
|
|
||||||
// this is the defacto standard as shipped!
|
|
||||||
|
|
||||||
DebugPort.println("HC-05 found");
|
|
||||||
|
|
||||||
DebugPort.print(" Setting Name to \"Afterburner\"... ");
|
|
||||||
if(!ATCommand("AT+NAME=\"Afterburner\"\r\n")) {
|
|
||||||
DebugPort.println("FAILED");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DebugPort.println("OK");
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugPort.print(" Setting baud rate to 9600N81...");
|
|
||||||
if(!ATCommand("AT+UART=9600,1,0\r\n")) {
|
|
||||||
DebugPort.println("FAILED");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DebugPort.println("OK");
|
|
||||||
}
|
|
||||||
DebugPort.print(" Lowering power consumption...");
|
|
||||||
if(!ATCommand("AT+IPSCAN=1024,1,1024,1\r\n")) {
|
|
||||||
DebugPort.println("FAILED");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DebugPort.println("OK");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
DebugPort.print(" Lowering power consumption...");
|
|
||||||
if(!ATCommand("AT+SNIFF=40,20,1,8\r\n")) {
|
|
||||||
DebugPort.println("FAILED");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DebugPort.println("OK");
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugPort.print(" Lowering power consumption...");
|
|
||||||
if(!ATCommand("AT+ENSNIFF=0002,72,0A3C7F\r\n")) {
|
|
||||||
DebugPort.println("FAILED");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DebugPort.println("OK");
|
|
||||||
}*/
|
|
||||||
flush();
|
|
||||||
delay(100);
|
|
||||||
openSerial(9600);
|
|
||||||
|
|
||||||
// leave HC-05 command mode, return to data mode
|
|
||||||
digitalWrite(_keyPin, LOW);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
delay(50);
|
|
||||||
flush(); // ensure any AT command reponse dribbles are cleaned up!
|
|
||||||
|
|
||||||
DebugPort.println("");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
CBluetoothHC05::check()
|
|
||||||
{
|
|
||||||
// check for data coming back over Bluetooth
|
|
||||||
if(HC05_SerialPort.available()) { // serial rx data is available
|
|
||||||
char rxVal = HC05_SerialPort.read();
|
|
||||||
collectRxData(rxVal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CBluetoothHC05::isConnected()
|
|
||||||
{
|
|
||||||
return digitalRead(_sensePin);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CBluetoothHC05::send(const char* Str)
|
|
||||||
{
|
|
||||||
if(isConnected()) {
|
|
||||||
HC05_SerialPort.print(Str);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// DebugPort.print("No Bluetooth client");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
void
|
|
||||||
CBluetoothHC05::sendFrame(const char* pHdr, const CProtocol& Frame, bool lineterm)
|
|
||||||
{
|
|
||||||
// report to debug port
|
|
||||||
CBluetoothAbstract::sendFrame(pHdr, Frame, false);
|
|
||||||
|
|
||||||
if(isConnected()) {
|
|
||||||
if(Frame.verifyCRC()) {
|
|
||||||
// send data frame to HC-05
|
|
||||||
HC05_SerialPort.print(pHdr);
|
|
||||||
HC05_SerialPort.write(Frame.Data, 24);
|
|
||||||
// toggle LED
|
|
||||||
#if BT_LED == 1
|
|
||||||
digitalWrite(LED_Pin, !digitalRead(LED_Pin)); // toggle LED
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DebugPort.print("Bluetooth data not sent, CRC error ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(lineterm) { // only report no client if this will be at end of line (long line support)
|
|
||||||
DebugPort.print("No Bluetooth client");
|
|
||||||
}
|
|
||||||
// force LED off
|
|
||||||
#if BT_LED == 1
|
|
||||||
digitalWrite(LED_Pin, LOW);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
if(lineterm)
|
|
||||||
DebugPort.println("");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
|
||||||
CBluetoothHC05::openSerial(int baudrate)
|
|
||||||
{
|
|
||||||
// standard serial port for Due, Mega (ESP32 uses virtual, derived from this class)
|
|
||||||
HC05_SerialPort.begin(baudrate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// protected function, to perform Hayes commands with HC-05
|
|
||||||
bool
|
|
||||||
CBluetoothHC05::ATCommand(const char* cmd)
|
|
||||||
{
|
|
||||||
flush(); // ensure response is for *this* command!
|
|
||||||
HC05_SerialPort.print(cmd);
|
|
||||||
char RxBuffer[16];
|
|
||||||
memset(RxBuffer, 0, 16);
|
|
||||||
int read = HC05_SerialPort.readBytesUntil('\n', RxBuffer, 16); // \n is not included in returned string!
|
|
||||||
if((read == 3) && (0 == strcmp(RxBuffer, "OK\r")) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CBluetoothHC05::foldbackDesiredTemp()
|
|
||||||
{
|
|
||||||
StaticJsonBuffer<32> jsonBuffer; // create a JSON buffer on the stack
|
|
||||||
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
|
|
||||||
|
|
||||||
if(foldbackModerator.addJson("TempDesired", getTemperatureDesired(), root)) {
|
|
||||||
char opStr[32];
|
|
||||||
root.printTo(opStr);
|
|
||||||
send(opStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CBluetoothHC05::flush()
|
|
||||||
{
|
|
||||||
while(HC05_SerialPort.available())
|
|
||||||
HC05_SerialPort.read();
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
This has been touched up by Ray Jones to deal with a coupole of issues:
|
|
||||||
|
|
||||||
bad return from execHTTPcheck()
|
|
||||||
execHTTPcheck() uses a char[] with a variable
|
|
||||||
|
|
||||||
Examples have been detonated to avoid issues during BTC recompile
|
|
|
@ -1,271 +0,0 @@
|
||||||
/*
|
|
||||||
esp32 firmware OTA
|
|
||||||
Date: December 2018
|
|
||||||
Author: Chris Joyce <https://chrisjoyce911/esp32FOTA>
|
|
||||||
Purpose: Perform an OTA update from a bin located on a webserver (HTTP Only)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "esp32fota.h"
|
|
||||||
#include "Arduino.h"
|
|
||||||
#include <WiFi.h>
|
|
||||||
#include <HTTPClient.h>
|
|
||||||
#include <Update.h>
|
|
||||||
#include "ArduinoJson.h"
|
|
||||||
|
|
||||||
esp32FOTA::esp32FOTA(String firwmareType, int firwmareVersion)
|
|
||||||
{
|
|
||||||
_firwmareType = firwmareType;
|
|
||||||
_firwmareVersion = firwmareVersion;
|
|
||||||
useDeviceID = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utility to extract header value from headers
|
|
||||||
String esp32FOTA::getHeaderValue(String header, String headerName)
|
|
||||||
{
|
|
||||||
return header.substring(strlen(headerName.c_str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// OTA Logic
|
|
||||||
void esp32FOTA::execOTA()
|
|
||||||
{
|
|
||||||
|
|
||||||
WiFiClient client;
|
|
||||||
int contentLength = 0;
|
|
||||||
bool isValidContentType = false;
|
|
||||||
|
|
||||||
Serial.println("Connecting to: " + String(_host));
|
|
||||||
// Connect to Webserver
|
|
||||||
if (client.connect(_host.c_str(), _port))
|
|
||||||
{
|
|
||||||
// Connection Succeed.
|
|
||||||
// Fecthing the bin
|
|
||||||
Serial.println("Fetching Bin: " + String(_bin));
|
|
||||||
|
|
||||||
// Get the contents of the bin file
|
|
||||||
client.print(String("GET ") + _bin + " HTTP/1.1\r\n" +
|
|
||||||
"Host: " + _host + "\r\n" +
|
|
||||||
"Cache-Control: no-cache\r\n" +
|
|
||||||
"Connection: close\r\n\r\n");
|
|
||||||
|
|
||||||
unsigned long timeout = millis();
|
|
||||||
while (client.available() == 0)
|
|
||||||
{
|
|
||||||
if (millis() - timeout > 5000)
|
|
||||||
{
|
|
||||||
Serial.println("Client Timeout !");
|
|
||||||
client.stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (client.available())
|
|
||||||
{
|
|
||||||
// read line till /n
|
|
||||||
String line = client.readStringUntil('\n');
|
|
||||||
// remove space, to check if the line is end of headers
|
|
||||||
line.trim();
|
|
||||||
|
|
||||||
if (!line.length())
|
|
||||||
{
|
|
||||||
//headers ended
|
|
||||||
break; // and get the OTA started
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the HTTP Response is 200
|
|
||||||
// else break and Exit Update
|
|
||||||
if (line.startsWith("HTTP/1.1"))
|
|
||||||
{
|
|
||||||
if (line.indexOf("200") < 0)
|
|
||||||
{
|
|
||||||
Serial.println("Got a non 200 status code from server. Exiting OTA Update.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// extract headers here
|
|
||||||
// Start with content length
|
|
||||||
if (line.startsWith("Content-Length: "))
|
|
||||||
{
|
|
||||||
contentLength = atoi((getHeaderValue(line, "Content-Length: ")).c_str());
|
|
||||||
Serial.println("Got " + String(contentLength) + " bytes from server");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, the content type
|
|
||||||
if (line.startsWith("Content-Type: "))
|
|
||||||
{
|
|
||||||
String contentType = getHeaderValue(line, "Content-Type: ");
|
|
||||||
Serial.println("Got " + contentType + " payload.");
|
|
||||||
if (contentType == "application/octet-stream")
|
|
||||||
{
|
|
||||||
isValidContentType = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Connect to webserver failed
|
|
||||||
// May be try?
|
|
||||||
// Probably a choppy network?
|
|
||||||
Serial.println("Connection to " + String(_host) + " failed. Please check your setup");
|
|
||||||
// retry??
|
|
||||||
// execOTA();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check what is the contentLength and if content type is `application/octet-stream`
|
|
||||||
Serial.println("contentLength : " + String(contentLength) + ", isValidContentType : " + String(isValidContentType));
|
|
||||||
|
|
||||||
// check contentLength and content type
|
|
||||||
if (contentLength && isValidContentType)
|
|
||||||
{
|
|
||||||
// Check if there is enough to OTA Update
|
|
||||||
bool canBegin = Update.begin(contentLength);
|
|
||||||
|
|
||||||
// If yes, begin
|
|
||||||
if (canBegin)
|
|
||||||
{
|
|
||||||
Serial.println("Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience!");
|
|
||||||
// No activity would appear on the Serial monitor
|
|
||||||
// So be patient. This may take 2 - 5mins to complete
|
|
||||||
size_t written = Update.writeStream(client);
|
|
||||||
|
|
||||||
if (written == contentLength)
|
|
||||||
{
|
|
||||||
Serial.println("Written : " + String(written) + " successfully");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?");
|
|
||||||
// retry??
|
|
||||||
// execOTA();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Update.end())
|
|
||||||
{
|
|
||||||
Serial.println("OTA done!");
|
|
||||||
if (Update.isFinished())
|
|
||||||
{
|
|
||||||
Serial.println("Update successfully completed. Rebooting.");
|
|
||||||
ESP.restart();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Serial.println("Update not finished? Something went wrong!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Serial.println("Error Occurred. Error #: " + String(Update.getError()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// not enough space to begin OTA
|
|
||||||
// Understand the partitions and
|
|
||||||
// space availability
|
|
||||||
Serial.println("Not enough space to begin OTA");
|
|
||||||
client.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Serial.println("There was no content in the response");
|
|
||||||
client.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool esp32FOTA::execHTTPcheck()
|
|
||||||
{
|
|
||||||
|
|
||||||
String useURL;
|
|
||||||
|
|
||||||
if (useDeviceID)
|
|
||||||
{
|
|
||||||
// String deviceID = getDeviceID() ;
|
|
||||||
useURL = checkURL + "?id=" + getDeviceID();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
useURL = checkURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
WiFiClient client;
|
|
||||||
_port = 80;
|
|
||||||
|
|
||||||
Serial.println("Getting HTTP");
|
|
||||||
Serial.println(useURL);
|
|
||||||
Serial.println("------");
|
|
||||||
if ((WiFi.status() == WL_CONNECTED))
|
|
||||||
{ //Check the current connection status
|
|
||||||
|
|
||||||
HTTPClient http;
|
|
||||||
|
|
||||||
http.begin(useURL); //Specify the URL
|
|
||||||
int httpCode = http.GET(); //Make the request
|
|
||||||
|
|
||||||
if (httpCode == 200)
|
|
||||||
{ //Check is a file was returned
|
|
||||||
String payload = http.getString();
|
|
||||||
|
|
||||||
int str_len = payload.length() + 1;
|
|
||||||
char* JSONMessage = new char[str_len];
|
|
||||||
payload.toCharArray(JSONMessage, str_len);
|
|
||||||
|
|
||||||
StaticJsonBuffer<300> JSONBuffer; //Memory pool
|
|
||||||
JsonObject &parsed = JSONBuffer.parseObject(JSONMessage); //Parse message
|
|
||||||
|
|
||||||
if (!parsed.success())
|
|
||||||
{ //Check for errors in parsing
|
|
||||||
delete[] JSONMessage;
|
|
||||||
Serial.println("Parsing failed");
|
|
||||||
delay(5000);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *pltype = parsed["type"];
|
|
||||||
int plversion = parsed["version"];
|
|
||||||
const char *plhost = parsed["host"];
|
|
||||||
_port = parsed["port"];
|
|
||||||
const char *plbin = parsed["bin"];
|
|
||||||
|
|
||||||
String jshost(plhost);
|
|
||||||
String jsbin(plbin);
|
|
||||||
|
|
||||||
_host = jshost;
|
|
||||||
_bin = jsbin;
|
|
||||||
|
|
||||||
String fwtype(pltype);
|
|
||||||
|
|
||||||
delete[] JSONMessage;
|
|
||||||
|
|
||||||
if (plversion > _firwmareVersion && fwtype == _firwmareType)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Serial.println("Error on HTTP request");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
http.end(); //Free the resources
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String esp32FOTA::getDeviceID()
|
|
||||||
{
|
|
||||||
char deviceid[21];
|
|
||||||
uint64_t chipid;
|
|
||||||
chipid = ESP.getEfuseMac();
|
|
||||||
sprintf(deviceid, "%" PRIu64, chipid);
|
|
||||||
String thisID(deviceid);
|
|
||||||
return thisID;
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
esp32 firmware OTA
|
|
||||||
Date: December 2018
|
|
||||||
Author: Chris Joyce <https://chrisjoyce911/esp32FOTA>
|
|
||||||
Purpose: Perform an OTA update from a bin located on a webserver (HTTP Only)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef esp32fota_h
|
|
||||||
#define esp32fota_h
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
|
||||||
|
|
||||||
class esp32FOTA
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
esp32FOTA(String firwmareType, int firwmareVersion);
|
|
||||||
void execOTA();
|
|
||||||
bool execHTTPcheck();
|
|
||||||
bool useDeviceID;
|
|
||||||
String checkURL;
|
|
||||||
|
|
||||||
private:
|
|
||||||
String getHeaderValue(String header, String headerName);
|
|
||||||
String getDeviceID();
|
|
||||||
String _firwmareType;
|
|
||||||
int _firwmareVersion;
|
|
||||||
String _host;
|
|
||||||
String _bin;
|
|
||||||
int _port;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,356 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "fonts/tahoma16.h"
|
|
||||||
#include "fonts/tahoma24.h"
|
|
||||||
#include "fonts/Icons.h"
|
|
||||||
#include "BasicScreen.h"
|
|
||||||
#include "KeyPad.h"
|
|
||||||
#include "../Utility/helpers.h"
|
|
||||||
#include "../Utility/UtilClasses.h"
|
|
||||||
#include "../Utility/NVStorage.h"
|
|
||||||
#include "../Protocol/Protocol.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define MAXIFONT tahoma_24ptFontInfo
|
|
||||||
//#define MAXIFONT tahoma_16ptFontInfo
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// CBasicScreen
|
|
||||||
//
|
|
||||||
// This screen provides a basic control function
|
|
||||||
//
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
CBasicScreen::CBasicScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
|
|
||||||
{
|
|
||||||
_showSetModeTime = 0;
|
|
||||||
_showModeTime = 0;
|
|
||||||
_feedbackType = 0;
|
|
||||||
_nModeSel = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CBasicScreen::show()
|
|
||||||
{
|
|
||||||
CScreenHeader::show();
|
|
||||||
|
|
||||||
char msg[20];
|
|
||||||
int xPos, yPos;
|
|
||||||
|
|
||||||
float fTemp = getTemperatureSensor();
|
|
||||||
if(fTemp > -80) {
|
|
||||||
if(NVstore.getUserSettings().degF) {
|
|
||||||
fTemp = fTemp * 9 / 5 + 32;
|
|
||||||
sprintf(msg, "%.1f`F", fTemp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sprintf(msg, "%.1f`C", fTemp);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
CTransientFont AF(_display, &MAXIFONT); // temporarily use a large font
|
|
||||||
_printMenuText(_display.xCentre(), 23, msg, false, eCentreJustify);
|
|
||||||
// _printMenuText(_display.xCentre(), 25, msg, false, eCentreJustify);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_printMenuText(_display.xCentre(), 25, "No Temperature Sensor", false, eCentreJustify);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// at bottom of screen show either:
|
|
||||||
// Selection between Fixed or Thermostat mode
|
|
||||||
// Current heat demand setting
|
|
||||||
// Run state of heater
|
|
||||||
|
|
||||||
if(_showModeTime) {
|
|
||||||
const int border = 3;
|
|
||||||
// Show selection between Fixed or Thermostat mode
|
|
||||||
long tDelta = millis() - _showModeTime;
|
|
||||||
if(tDelta < 0) {
|
|
||||||
|
|
||||||
yPos = _display.height() - _display.textHeight() - border; // bottom of screen, with room for box
|
|
||||||
|
|
||||||
// display "Fixed Hz" at lower right, allowing space for a selection surrounding box
|
|
||||||
strcpy(msg, "Fixed Hz");
|
|
||||||
xPos = _display.width() - border; // set X position to finish short of RHS
|
|
||||||
_printMenuText(xPos, yPos, msg, _nModeSel == 1, eRightJustify);
|
|
||||||
|
|
||||||
// display "Thermostat" at lower left, allowing space for a selection surrounding box
|
|
||||||
strcpy(msg, "Thermostat");
|
|
||||||
xPos = border;
|
|
||||||
_printMenuText(xPos, yPos, msg, _nModeSel == 0);
|
|
||||||
|
|
||||||
// setThermostatMode(_nModeSel == 0 ? 1 : 0); // set the new mode
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// cancel selection mode, apply whatever is boxed
|
|
||||||
_showModeTime = 0;
|
|
||||||
_showSetModeTime = millis() + 5000; // then make the new mode setting be shown
|
|
||||||
_feedbackType = 0;
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if((_showModeTime == 0) && _showSetModeTime) {
|
|
||||||
long tDelta = millis() - _showSetModeTime;
|
|
||||||
if(tDelta < 0) {
|
|
||||||
switch(_feedbackType) {
|
|
||||||
case 0:
|
|
||||||
// Show current heat demand setting
|
|
||||||
|
|
||||||
if(getThermostatModeActive()) {
|
|
||||||
float fTemp = getTemperatureDesired();
|
|
||||||
if(NVstore.getUserSettings().degF) {
|
|
||||||
fTemp = fTemp * 9 / 5 + 32;
|
|
||||||
sprintf(msg, "Setpoint = %.0f`F", fTemp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sprintf(msg, "Setpoint = %.0f`C", fTemp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sprintf(msg, "Setpoint = %.1fHz", getHeaterInfo().getPump_Fixed());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
sprintf(msg, "GPIO output #%d %s", _feedbackType, getGPIOout(_feedbackType-1) ? "ON" : "OFF");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// centre message at bottom of screen
|
|
||||||
_printMenuText(_display.xCentre(), _display.height() - _display.textHeight(), msg, false, eCentreJustify);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_showSetModeTime = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if((_showModeTime == 0) && (_showSetModeTime == 0)) {
|
|
||||||
showRunState();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
CBasicScreen::keyHandler(uint8_t event)
|
|
||||||
{
|
|
||||||
static int repeatCount = -1;
|
|
||||||
|
|
||||||
if(event & keyPressed) {
|
|
||||||
repeatCount = 0; // unlock tracking of repeat events
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// use repeat function for key hold detection
|
|
||||||
//
|
|
||||||
if(event & keyRepeat) {
|
|
||||||
if(repeatCount >= 0) {
|
|
||||||
repeatCount++;
|
|
||||||
// hold LEFT to toggle GPIO output #1
|
|
||||||
if(event & key_Left) {
|
|
||||||
if(repeatCount > 2) {
|
|
||||||
repeatCount = -1; // prevent double handling
|
|
||||||
if(toggleGPIOout(0)) { // toggle GPIO output #1
|
|
||||||
_showSetModeTime = millis() + 2000;
|
|
||||||
_feedbackType = 1;
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// hold RIGHT to toggle GPIO output #2
|
|
||||||
if(event & key_Right) {
|
|
||||||
if(repeatCount > 2) {
|
|
||||||
repeatCount = -1; // prevent double handling
|
|
||||||
if(toggleGPIOout(1)) { // toggle GPIO output #2
|
|
||||||
_showSetModeTime = millis() + 2000;
|
|
||||||
_feedbackType = 2;
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// hold DOWN to enter thermostat / fixed mode selection
|
|
||||||
if(event & key_Down) {
|
|
||||||
if(repeatCount > 2) {
|
|
||||||
repeatCount = -1; // prevent double handling
|
|
||||||
_showModeTime = millis() + 5000;
|
|
||||||
_nModeSel = getThermostatModeActive() ? 0 : 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// hold UP to toggle degC/degF mode selection
|
|
||||||
if(event & key_Up) {
|
|
||||||
if(repeatCount > 2) {
|
|
||||||
repeatCount = -1; // prevent double handling
|
|
||||||
_showModeTime = millis() + 5000;
|
|
||||||
sUserSettings settings = NVstore.getUserSettings();
|
|
||||||
toggle(settings.degF);
|
|
||||||
NVstore.setUserSettings(settings);
|
|
||||||
NVstore.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// hold CENTRE to turn ON or OFF
|
|
||||||
if(event & key_Centre) {
|
|
||||||
int runstate = getHeaterInfo().getRunStateEx();
|
|
||||||
if(runstate) { // running, including cyclic mode idle
|
|
||||||
if(repeatCount > 5) {
|
|
||||||
repeatCount = -1;
|
|
||||||
requestOff();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // standard idle state
|
|
||||||
// standby, request ON
|
|
||||||
if(repeatCount > 3) {
|
|
||||||
repeatCount = -1;
|
|
||||||
requestOn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// key released handling
|
|
||||||
//
|
|
||||||
if(event & keyReleased) {
|
|
||||||
if(!_showModeTime) {
|
|
||||||
// release DOWN key to reduce set demand, provided we are not in mode select
|
|
||||||
if(event & key_Down) {
|
|
||||||
if(reqTempDelta(-1)) {
|
|
||||||
_showSetModeTime = millis() + 2000;
|
|
||||||
_feedbackType = 0;
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_reqOEMWarning();
|
|
||||||
}
|
|
||||||
// release UP key to increase set demand, provided we are not in mode select
|
|
||||||
if(event & key_Up) {
|
|
||||||
if(reqTempDelta(+1)) {
|
|
||||||
_showSetModeTime = millis() + 2000;
|
|
||||||
_feedbackType = 0;
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_reqOEMWarning();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event & key_Left) {
|
|
||||||
if(repeatCount >= 0) {
|
|
||||||
if(!_showModeTime) {
|
|
||||||
_ScreenManager.prevMenu();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(hasOEMcontroller())
|
|
||||||
_reqOEMWarning();
|
|
||||||
else {
|
|
||||||
_showModeTime = millis() + 5000;
|
|
||||||
_nModeSel = 0;
|
|
||||||
setThermostatMode(1); // set the new mode
|
|
||||||
NVstore.save();
|
|
||||||
}
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event & key_Right) {
|
|
||||||
if(repeatCount >= 0) {
|
|
||||||
if(!_showModeTime)
|
|
||||||
_ScreenManager.nextMenu();
|
|
||||||
else {
|
|
||||||
if(hasOEMcontroller())
|
|
||||||
_reqOEMWarning();
|
|
||||||
else {
|
|
||||||
_showModeTime = millis() + 5000;
|
|
||||||
_nModeSel = 1;
|
|
||||||
setThermostatMode(0); // set the new mode
|
|
||||||
NVstore.save();
|
|
||||||
}
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// release CENTRE to accept new mode, and/or show current setting
|
|
||||||
if(event & key_Centre) {
|
|
||||||
if(repeatCount != -2) { // prevent after off commands
|
|
||||||
if(_showModeTime) {
|
|
||||||
_showModeTime = millis(); // force immediate cancellation of showmode (via screen update)
|
|
||||||
}
|
|
||||||
_showSetModeTime = millis() + 2000;
|
|
||||||
_feedbackType = 0;
|
|
||||||
}
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
repeatCount = -1;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CBasicScreen::showRunState()
|
|
||||||
{
|
|
||||||
int runstate = getHeaterInfo().getRunStateEx();
|
|
||||||
int errstate = getHeaterInfo().getErrState();
|
|
||||||
|
|
||||||
if(errstate) errstate--; // correct for +1 biased return value
|
|
||||||
|
|
||||||
static bool toggle = false;
|
|
||||||
const char* toPrint = NULL;
|
|
||||||
_display.setTextColor(WHITE, BLACK);
|
|
||||||
if(errstate && ((runstate == 0) || (runstate > 5))) {
|
|
||||||
|
|
||||||
// flash error code
|
|
||||||
char msg[16];
|
|
||||||
toggle = !toggle;
|
|
||||||
if(toggle) {
|
|
||||||
// create an "E-XX" message to display
|
|
||||||
sprintf(msg, "E-%02d", errstate);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strcpy(msg, " ");
|
|
||||||
}
|
|
||||||
int xPos = _display.xCentre();
|
|
||||||
int yPos = _display.height() - 2*_display.textHeight();
|
|
||||||
_printMenuText(xPos, yPos, msg, false, eCentreJustify);
|
|
||||||
|
|
||||||
toPrint = getHeaterInfo().getErrStateStr();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(runstate) {
|
|
||||||
toPrint = getHeaterInfo().getRunStateStr();
|
|
||||||
// simplify starting states
|
|
||||||
switch(runstate) {
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
toPrint = "Starting";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(toPrint) {
|
|
||||||
// locate at bottom centre
|
|
||||||
_printMenuText(_display.xCentre(), _display.height() - _display.textHeight(), toPrint, false, eCentreJustify);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "FontDumpScreen.h"
|
|
||||||
#include "KeyPad.h"
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// CFontDumpScreen
|
|
||||||
//
|
|
||||||
// This screen provides control over experimental features
|
|
||||||
//
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static const int Lines[4] = { 24, 34, 44, 54 };
|
|
||||||
|
|
||||||
CFontDumpScreen::CFontDumpScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreen(display, mgr)
|
|
||||||
{
|
|
||||||
_initUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CFontDumpScreen::onSelect()
|
|
||||||
{
|
|
||||||
CScreen::onSelect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CFontDumpScreen::_initUI()
|
|
||||||
{
|
|
||||||
_startChar = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CFontDumpScreen::show()
|
|
||||||
{
|
|
||||||
_display.clearDisplay();
|
|
||||||
|
|
||||||
char msg[8];
|
|
||||||
|
|
||||||
_printInverted(_display.xCentre(), 0, " Adafruit Font ", true, eCentreJustify);
|
|
||||||
int column = 15;
|
|
||||||
for(int i=0; i<16; i++) {
|
|
||||||
sprintf(msg, "%X", i);
|
|
||||||
_printMenuText(column, 12, msg);
|
|
||||||
column += 7;
|
|
||||||
}
|
|
||||||
for(int row = 0; row < 4; row++) {
|
|
||||||
int currentChar = row * 16 + _startChar;
|
|
||||||
sprintf(msg, "%02X", currentChar);
|
|
||||||
_printMenuText(0, Lines[row], msg);
|
|
||||||
column = 15;
|
|
||||||
for(int i=0; i<16; i++) {
|
|
||||||
msg[0] = currentChar++;
|
|
||||||
msg[1] = 0;
|
|
||||||
_printMenuText(column, Lines[row], msg);
|
|
||||||
column += 7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_display.drawFastVLine(13, 12, 61, WHITE);
|
|
||||||
_display.drawFastHLine(0, 21, 128, WHITE);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
CFontDumpScreen::keyHandler(uint8_t event)
|
|
||||||
{
|
|
||||||
if(event & keyPressed) {
|
|
||||||
// press LEFT or UP to show prior 64 characters
|
|
||||||
if(event & (key_Left | key_Up)) {
|
|
||||||
_startChar -= 64;
|
|
||||||
}
|
|
||||||
// press RIGHT or DOWN to show next 64 characters
|
|
||||||
if(event & (key_Right | key_Down)) {
|
|
||||||
_startChar += 64;
|
|
||||||
}
|
|
||||||
// CENTRE press
|
|
||||||
if(event & key_Centre) {
|
|
||||||
_ScreenManager.selectMenu(CScreenManager::UserSettingsLoop, CScreenManager::ExThermostatUI); // force return to prior menu
|
|
||||||
}
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,282 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// CFuelMixtureScreen
|
|
||||||
//
|
|
||||||
// This screen allows the fuel mixture endpoints to be adjusted
|
|
||||||
//
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#include "FuelMixtureScreen.h"
|
|
||||||
#include "KeyPad.h"
|
|
||||||
#include "../Utility/helpers.h"
|
|
||||||
#include "../Wifi/BTCWifi.h"
|
|
||||||
#include "../utility/debugPort.h"
|
|
||||||
#include "../Utility/macros.h"
|
|
||||||
#include "../Protocol/Protocol.h"
|
|
||||||
|
|
||||||
|
|
||||||
CFuelMixtureScreen::CFuelMixtureScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
|
|
||||||
{
|
|
||||||
_initUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CFuelMixtureScreen::onSelect()
|
|
||||||
{
|
|
||||||
CPasswordScreen::onSelect();
|
|
||||||
_initUI();
|
|
||||||
|
|
||||||
adjPump[0] = getHeaterInfo().getPump_Min();
|
|
||||||
adjPump[1] = getHeaterInfo().getPump_Max();
|
|
||||||
adjFan[0] = getHeaterInfo().getFan_Min();
|
|
||||||
adjFan[1] = getHeaterInfo().getFan_Max();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CFuelMixtureScreen::_initUI()
|
|
||||||
{
|
|
||||||
_rowSel = 0;
|
|
||||||
_colSel = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CFuelMixtureScreen::show()
|
|
||||||
{
|
|
||||||
char str[16];
|
|
||||||
int xPos, yPos;
|
|
||||||
const int col3 = _display.width() - border;
|
|
||||||
|
|
||||||
_display.clearDisplay();
|
|
||||||
|
|
||||||
if(!CPasswordScreen::show()) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
// Pump Minimum adjustment
|
|
||||||
yPos = border + 36;
|
|
||||||
_printMenuText(80, yPos, "Min", false, eRightJustify);
|
|
||||||
sprintf(str, "%.1f", adjPump[0]);
|
|
||||||
_printMenuText(col3, yPos, str, _rowSel == 1, eRightJustify);
|
|
||||||
// Pump Maximum adjustment
|
|
||||||
yPos = border + 24;
|
|
||||||
_printMenuText(80, yPos, "Pump Hz Max", false, eRightJustify);
|
|
||||||
sprintf(str, "%.1f", adjPump[1]);
|
|
||||||
_printMenuText(col3, yPos, str, _rowSel == 2, eRightJustify);
|
|
||||||
// Fan Minimum adjustment
|
|
||||||
yPos = border + 12;
|
|
||||||
_printMenuText(80, yPos, "Min", false, eRightJustify);
|
|
||||||
sprintf(str, "%d", adjFan[0]);
|
|
||||||
_printMenuText(col3, yPos, str, _rowSel == 3, eRightJustify);
|
|
||||||
// Fan Maximum adjustment
|
|
||||||
yPos = border;
|
|
||||||
_printMenuText(80, yPos, "Fan RPM Max", false, eRightJustify);
|
|
||||||
sprintf(str, "%d", adjFan[1]);
|
|
||||||
_printMenuText(col3, yPos, str, _rowSel == 4, eRightJustify);
|
|
||||||
// navigation line
|
|
||||||
yPos = 53;
|
|
||||||
xPos = _display.xCentre();
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_printMenuText(xPos, yPos, " \021 Exit \020 ", _rowSel == 0, eCentreJustify); // " < Exit > "
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
_printMenuText(xPos, 56, "\030\031Sel Save \033\032 \3600.1", false, eCentreJustify); // "^vSel Save <> +-0.1"
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
_printMenuText(xPos, 56, "\030\031Sel Save \033\032 \36010", false, eCentreJustify); // "^vSel Save <> +-10"
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
_printInverted(_display.xCentre(), 0, " Save Fuel Settings ", true, eCentreJustify);
|
|
||||||
_printMenuText(_display.xCentre(), 35, "Press UP to", false, eCentreJustify);
|
|
||||||
_printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
CFuelMixtureScreen::keyHandler(uint8_t event)
|
|
||||||
{
|
|
||||||
if(event & keyPressed) {
|
|
||||||
// press CENTRE
|
|
||||||
if(event & key_Centre) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
_rowSel = 5; // enter save confirm mode
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
_rowSel = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// press LEFT
|
|
||||||
if(event & key_Left) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_ScreenManager.prevMenu();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
_adjustSetting(-1);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
_rowSel = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// press RIGHT
|
|
||||||
if(event & key_Right) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_ScreenManager.nextMenu();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
_adjustSetting(+1);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
_rowSel = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// press UP
|
|
||||||
if(event & key_Up) {
|
|
||||||
if(hasOEMcontroller())
|
|
||||||
_reqOEMWarning();
|
|
||||||
else {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
// grab current settings upon entry to edit mode
|
|
||||||
adjPump[0] = getHeaterInfo().getPump_Min();
|
|
||||||
adjPump[1] = getHeaterInfo().getPump_Max();
|
|
||||||
adjFan[0] = getHeaterInfo().getFan_Min();
|
|
||||||
adjFan[1] = getHeaterInfo().getFan_Max();
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
_rowSel++;
|
|
||||||
_colSel = 0;
|
|
||||||
UPPERLIMIT(_rowSel, 4);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
_showStoringMessage();
|
|
||||||
setPumpMin(adjPump[0]);
|
|
||||||
setPumpMax(adjPump[1]);
|
|
||||||
setFanMin(adjFan[0]);
|
|
||||||
setFanMax(adjFan[1]);
|
|
||||||
saveNV();
|
|
||||||
_rowSel = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// press DOWN
|
|
||||||
if(event & key_Down) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
_rowSel--;
|
|
||||||
_colSel = 0;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
_rowSel = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(event & keyRepeat) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
int adj = 0;
|
|
||||||
if(event & key_Right) adj = +1;
|
|
||||||
if(event & key_Left) adj = -1;
|
|
||||||
if(adj) {
|
|
||||||
_adjustSetting(adj);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CFuelMixtureScreen::_adjustSetting(int dir)
|
|
||||||
{
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 1:
|
|
||||||
adjPump[0] += (float(dir) * 0.1f);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
adjPump[1] += (float(dir) * 0.1f);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
adjFan[0] += dir * 10;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
adjFan[1] += dir * 10;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
LOWERLIMIT(adjPump[0], 0.5f);
|
|
||||||
UPPERLIMIT(adjPump[0], 10.f);
|
|
||||||
LOWERLIMIT(adjPump[1], 0.5f);
|
|
||||||
UPPERLIMIT(adjPump[1], 10.f);
|
|
||||||
LOWERLIMIT(adjFan[0], 1000);
|
|
||||||
UPPERLIMIT(adjFan[0], 5000);
|
|
||||||
LOWERLIMIT(adjFan[1], 1000);
|
|
||||||
UPPERLIMIT(adjFan[1], 5000);
|
|
||||||
}
|
|
|
@ -1,412 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "GPIOScreen.h"
|
|
||||||
#include "KeyPad.h"
|
|
||||||
#include "../Utility/helpers.h"
|
|
||||||
#include "../Utility/UtilClasses.h"
|
|
||||||
#include "../Utility/NVStorage.h"
|
|
||||||
#include "../Utility/GPIO.h"
|
|
||||||
#include "fonts/Icons.h"
|
|
||||||
|
|
||||||
extern CGPIOout GPIOout;
|
|
||||||
extern CGPIOin GPIOin;
|
|
||||||
extern CGPIOalg GPIOalg;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// CGPIOScreen
|
|
||||||
//
|
|
||||||
// This screen provides control over GPIO features
|
|
||||||
//
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static const int Line3 = 14;
|
|
||||||
static const int Line2 = 27;
|
|
||||||
static const int Line1 = 40;
|
|
||||||
//static const int Column = 58;
|
|
||||||
static const int Column = 38;
|
|
||||||
|
|
||||||
CGPIOScreen::CGPIOScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
|
|
||||||
{
|
|
||||||
_initUI();
|
|
||||||
_GPIOparams.inMode = GPIOinNone;
|
|
||||||
_GPIOparams.outMode = GPIOoutNone;
|
|
||||||
_GPIOparams.algMode = GPIOalgNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOScreen::onSelect()
|
|
||||||
{
|
|
||||||
CPasswordScreen::onSelect();
|
|
||||||
_initUI();
|
|
||||||
_GPIOparams = NVstore.getGPIOparams();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOScreen::_initUI()
|
|
||||||
{
|
|
||||||
_rowSel = 0;
|
|
||||||
_animateCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CGPIOScreen::show()
|
|
||||||
{
|
|
||||||
_display.clearDisplay();
|
|
||||||
|
|
||||||
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 {
|
|
||||||
_printInverted(_display.xCentre(), 0, " GPIO Settings ", true, eCentreJustify);
|
|
||||||
_drawBitmap(10, 14, GPIOIconInfo);
|
|
||||||
{
|
|
||||||
const char* msgText = NULL;
|
|
||||||
switch(_GPIOparams.inMode) {
|
|
||||||
case GPIOinNone: msgText = "Disabled"; break;
|
|
||||||
case GPIOinOn1Off2: msgText = "1-On 2-Off"; break;
|
|
||||||
case GPIOinOnHold1: msgText = "1-On 2-\352T"; break;
|
|
||||||
case GPIOinOn1Off1: msgText = "1-On/Off"; break;
|
|
||||||
}
|
|
||||||
if(msgText)
|
|
||||||
_printMenuText(Column, Line3, msgText, _rowSel == 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const char* msgText = NULL;
|
|
||||||
switch(_GPIOparams.outMode) {
|
|
||||||
case GPIOoutNone: msgText = "Disabled"; break;
|
|
||||||
case GPIOoutStatus: msgText = "1: Status LED"; break;
|
|
||||||
case GPIOoutUser: msgText = "1&2 User"; break;
|
|
||||||
}
|
|
||||||
if(msgText)
|
|
||||||
_printMenuText(Column, Line2, msgText, _rowSel == 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
const char* msgText = NULL;
|
|
||||||
switch(_GPIOparams.algMode) {
|
|
||||||
case GPIOalgNone: msgText = "Disabled"; break;
|
|
||||||
case GPIOalgHeatDemand: msgText = "Ip1 allows"; break;
|
|
||||||
}
|
|
||||||
if(msgText)
|
|
||||||
_printMenuText(Column, Line1, msgText, _rowSel == 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CGPIOScreen::animate()
|
|
||||||
{
|
|
||||||
CPasswordScreen::animate();
|
|
||||||
|
|
||||||
if(_rowSel != 4) {
|
|
||||||
int yPos = 53;
|
|
||||||
int xPos = _display.xCentre();
|
|
||||||
const char* pMsg = NULL;
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_printMenuText(xPos, yPos, " \021 \030Edit Exit \020 ", true, eCentreJustify);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
switch(_GPIOparams.algMode) {
|
|
||||||
case GPIOalgNone: pMsg = " Analogue input is ignored. "; break;
|
|
||||||
case GPIOalgHeatDemand: pMsg = " Input 1 enables reading of analogue input to set temperature. "; break;
|
|
||||||
}
|
|
||||||
if(pMsg)
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
switch(_GPIOparams.outMode) {
|
|
||||||
case GPIOoutNone: pMsg = " Digital outputs are disabled. "; break;
|
|
||||||
case GPIOoutStatus: pMsg = " Output1: LED status indicator. "; break;
|
|
||||||
case GPIOoutUser: pMsg = " Output 1&2: User controlled. "; break;
|
|
||||||
}
|
|
||||||
if(pMsg)
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
switch(_GPIOparams.inMode) {
|
|
||||||
case GPIOinNone: pMsg = " Digital inputs are disabled. "; break;
|
|
||||||
case GPIOinOn1Off2: pMsg = " Input 1: Starts upon closure. Input 2: Stops upon closure. "; break;
|
|
||||||
case GPIOinOnHold1: pMsg = " Input 1: Starts when held closed, stops when opened. Input2: Max fuel when closed, min fuel when open. "; break;
|
|
||||||
case GPIOinOn1Off1: pMsg = " Input 1: Starts or Stops upon closure. "; break;
|
|
||||||
}
|
|
||||||
if(pMsg)
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CGPIOScreen::keyHandler(uint8_t event)
|
|
||||||
{
|
|
||||||
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:
|
|
||||||
_scrollChar = 0;
|
|
||||||
_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:
|
|
||||||
_scrollChar = 0;
|
|
||||||
_adjust(+1);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
_rowSel = 0; // abort save
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event & key_Down) {
|
|
||||||
_scrollChar = 0;
|
|
||||||
_rowSel--;
|
|
||||||
LOWERLIMIT(_rowSel, 0);
|
|
||||||
}
|
|
||||||
// UP press
|
|
||||||
if(event & key_Up) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
_scrollChar = 0;
|
|
||||||
_rowSel++;
|
|
||||||
UPPERLIMIT(_rowSel, 3);
|
|
||||||
break;
|
|
||||||
case 4: // confirmed save
|
|
||||||
_showStoringMessage();
|
|
||||||
NVstore.setGPIOparams(_GPIOparams);
|
|
||||||
saveNV();
|
|
||||||
|
|
||||||
setupGPIO();
|
|
||||||
|
|
||||||
_rowSel = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// CENTRE press
|
|
||||||
if(event & key_Centre) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop, CScreenManager::GPIOInfoUI); // force return to main menu GPIO view
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
_rowSel = 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOScreen::_adjust(int dir)
|
|
||||||
{
|
|
||||||
int tVal;
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 1: // analogue mode
|
|
||||||
tVal = _GPIOparams.algMode;
|
|
||||||
tVal += dir;
|
|
||||||
WRAPLIMITS(tVal, 0, 1);
|
|
||||||
_GPIOparams.algMode = (GPIOalgModes)tVal;
|
|
||||||
break;
|
|
||||||
case 2: // outputs mode
|
|
||||||
tVal = _GPIOparams.outMode;
|
|
||||||
tVal += dir;
|
|
||||||
WRAPLIMITS(tVal, 0, 2);
|
|
||||||
_GPIOparams.outMode = (GPIOoutModes)tVal;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
tVal = _GPIOparams.inMode;
|
|
||||||
tVal += dir;
|
|
||||||
WRAPLIMITS(tVal, 0, 3);
|
|
||||||
_GPIOparams.inMode = (GPIOinModes)tVal;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CGPIOInfoScreen::CGPIOInfoScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
|
|
||||||
{
|
|
||||||
_keyRepeatCount = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOInfoScreen::onSelect()
|
|
||||||
{
|
|
||||||
CScreenHeader::onSelect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOInfoScreen::_initUI()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CGPIOInfoScreen::show()
|
|
||||||
{
|
|
||||||
CScreenHeader::show();
|
|
||||||
char msg[16];
|
|
||||||
|
|
||||||
_display.writeFillRect(49, 18, 30, 12, WHITE);
|
|
||||||
_printInverted(64, 20, "GPIO", true, eCentreJustify);
|
|
||||||
_printMenuText(22, 18, "In", false, eCentreJustify);
|
|
||||||
_printMenuText(104, 18, "Out", false, eCentreJustify);
|
|
||||||
_printMenuText(11, 20, "1", false, eCentreJustify);
|
|
||||||
_printMenuText(34, 20, "2", false, eCentreJustify);
|
|
||||||
_printMenuText(91, 20, "1", false, eCentreJustify);
|
|
||||||
_printMenuText(118, 20, "2", false, eCentreJustify);
|
|
||||||
|
|
||||||
_printMenuText(55, Line1, "Analogue:", false, eRightJustify);
|
|
||||||
|
|
||||||
if(NVstore.getGPIOparams().inMode == GPIOinNone) {
|
|
||||||
_drawBitmap(7, 28, CrossLgIconInfo);
|
|
||||||
_drawBitmap(30, 28, CrossLgIconInfo);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_drawBitmap(4, 29, GPIOin.getState(0) ? CloseIconInfo : OpenIconInfo);
|
|
||||||
if(NVstore.getGPIOparams().inMode == GPIOinOn1Off1)
|
|
||||||
_drawBitmap(30, 28, CrossLgIconInfo);
|
|
||||||
else
|
|
||||||
_drawBitmap(27, 29, GPIOin.getState(1) ? CloseIconInfo : OpenIconInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(NVstore.getGPIOparams().outMode == GPIOoutNone) {
|
|
||||||
_drawBitmap(87, 28, CrossLgIconInfo);
|
|
||||||
_drawBitmap(114, 28, CrossLgIconInfo);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_drawBitmap(86, 29, GPIOout.getState(0) ? BulbOnIconInfo : BulbOffIconInfo);
|
|
||||||
if(NVstore.getGPIOparams().outMode == GPIOoutStatus)
|
|
||||||
_drawBitmap(114, 28, CrossLgIconInfo);
|
|
||||||
else
|
|
||||||
_drawBitmap(113, 29, GPIOout.getState(1) ? BulbOnIconInfo : BulbOffIconInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(NVstore.getGPIOparams().algMode == GPIOalgNone) {
|
|
||||||
_drawBitmap(58, Line1, CrossLgIconInfo);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sprintf(msg, "%d%%", GPIOalg.getValue() * 100 / 4096);
|
|
||||||
_printMenuText(58, Line1, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
_printMenuText(_display.xCentre(), 53, " \021 \020 ", true, eCentreJustify);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
CGPIOInfoScreen::keyHandler(uint8_t event)
|
|
||||||
{
|
|
||||||
if(event & keyPressed) {
|
|
||||||
_keyRepeatCount = 0; // unlock tracking of repeat events
|
|
||||||
// UP press
|
|
||||||
if(event & key_Up) {
|
|
||||||
}
|
|
||||||
// CENTRE press
|
|
||||||
if(event & key_Centre) {
|
|
||||||
}
|
|
||||||
if(event & key_Down) {
|
|
||||||
_ScreenManager.selectMenu(CScreenManager::UserSettingsLoop, CScreenManager::GPIOUI);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event & keyRepeat) {
|
|
||||||
if(_keyRepeatCount >= 0) {
|
|
||||||
_keyRepeatCount++;
|
|
||||||
// hold LEFT to toggle GPIO output #1
|
|
||||||
if(event & key_Left) {
|
|
||||||
if(_keyRepeatCount > 2) {
|
|
||||||
_keyRepeatCount = -1; // prevent double handling
|
|
||||||
toggleGPIOout(0); // toggle GPIO output #1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// hold RIGHT to toggle GPIO output #2
|
|
||||||
if(event & key_Right) {
|
|
||||||
if(_keyRepeatCount > 2) {
|
|
||||||
_keyRepeatCount = -1; // prevent double handling
|
|
||||||
toggleGPIOout(1); // toggle GPIO output #2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// release event
|
|
||||||
if(event & keyReleased) {
|
|
||||||
if(_keyRepeatCount == 0) { // short Up press - lower target
|
|
||||||
// press LEFT to select previous screen
|
|
||||||
if(event & key_Left) {
|
|
||||||
_ScreenManager.prevMenu();
|
|
||||||
}
|
|
||||||
// press RIGHT to select next screen
|
|
||||||
if(event & key_Right) {
|
|
||||||
_ScreenManager.nextMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_keyRepeatCount = -1;
|
|
||||||
}
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,213 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "HomeMenuSelScreen.h"
|
|
||||||
#include "KeyPad.h"
|
|
||||||
#include "../Utility/helpers.h"
|
|
||||||
#include "../Utility/UtilClasses.h"
|
|
||||||
#include "../Utility/NVStorage.h"
|
|
||||||
#include "../Utility/GPIO.h"
|
|
||||||
#include "fonts/Icons.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CHomeMenuSelScreen::CHomeMenuSelScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHomeMenuSelScreen::onSelect()
|
|
||||||
{
|
|
||||||
CScreenHeader::onSelect();
|
|
||||||
_rowSel = 0;
|
|
||||||
_action = NVstore.getHomeMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHomeMenuSelScreen::_initUI()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CHomeMenuSelScreen::show()
|
|
||||||
{
|
|
||||||
char msg[16];
|
|
||||||
|
|
||||||
_display.clearDisplay();
|
|
||||||
|
|
||||||
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 {
|
|
||||||
_printInverted(_display.xCentre(), 0, " Home Menu Actions ", true, eCentreJustify);
|
|
||||||
|
|
||||||
// _printMenuText(66, 14, "On timeout:", false, eRightJustify);
|
|
||||||
_drawBitmap(30, 14, TimeoutIconInfo);
|
|
||||||
switch(_action.onTimeout) {
|
|
||||||
case 0: strcpy(msg, "Default"); break;
|
|
||||||
case 1: strcpy(msg, "Detailed"); break;
|
|
||||||
case 2: strcpy(msg, "Basic"); break;
|
|
||||||
case 3: strcpy(msg, "Clock"); break;
|
|
||||||
}
|
|
||||||
_printMenuText(50, 14, msg, _rowSel == 3);
|
|
||||||
|
|
||||||
// _printMenuText(66, 26, "On start:", false, eRightJustify);
|
|
||||||
_drawBitmap(32, 26, StartIconInfo);
|
|
||||||
switch(_action.onStart) {
|
|
||||||
case 0: strcpy(msg, "Default"); break;
|
|
||||||
case 1: strcpy(msg, "Detailed"); break;
|
|
||||||
case 2: strcpy(msg, "Basic"); break;
|
|
||||||
case 3: strcpy(msg, "Clock"); break;
|
|
||||||
}
|
|
||||||
_printMenuText(50, 26, msg, _rowSel == 2);
|
|
||||||
|
|
||||||
// _printMenuText(66, 38, "On stop:", false, eRightJustify);
|
|
||||||
_drawBitmap(31, 38, StopIconInfo);
|
|
||||||
switch(_action.onStop) {
|
|
||||||
case 0: strcpy(msg, "Default"); break;
|
|
||||||
case 1: strcpy(msg, "Detailed"); break;
|
|
||||||
case 2: strcpy(msg, "Basic"); break;
|
|
||||||
case 3: strcpy(msg, "Clock"); break;
|
|
||||||
}
|
|
||||||
_printMenuText(50, 38, msg, _rowSel == 1);
|
|
||||||
|
|
||||||
/* if(_rowSel == 0)
|
|
||||||
_printMenuText(_display.xCentre(), 53, " \021 \030Edit Exit \020 ", true, eCentreJustify);
|
|
||||||
else {
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
_printMenuText(_display.xCentre(), 56, "\030\031Sel \033\032 Adj", false, eCentreJustify);
|
|
||||||
_printMenuText(_display.xCentre(), 56, "Save", false, eCentreJustify);
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CHomeMenuSelScreen::animate()
|
|
||||||
{
|
|
||||||
if(_rowSel != 4) {
|
|
||||||
int yPos = 53;
|
|
||||||
int xPos = _display.xCentre();
|
|
||||||
const char* pMsg = NULL;
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_printMenuText(xPos, yPos, " \021 \030Edit Exit \020 ", true, eCentreJustify);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
pMsg = " Menu to switch to when the heater stops. ";
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
pMsg = " Menu to switch to when the heater starts. ";
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
pMsg = " Menu to return to after no keypad activity. ";
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
CHomeMenuSelScreen::keyHandler(uint8_t event)
|
|
||||||
{
|
|
||||||
if(event & keyPressed) {
|
|
||||||
// UP press
|
|
||||||
if(event & key_Up) {
|
|
||||||
if(_rowSel == 4) {
|
|
||||||
_showStoringMessage();
|
|
||||||
NVstore.setHomeMenu(_action);
|
|
||||||
saveNV();
|
|
||||||
_rowSel = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_scrollChar = 0;
|
|
||||||
_rowSel++;
|
|
||||||
UPPERLIMIT(_rowSel, 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// DOWN press
|
|
||||||
if(event & key_Down) {
|
|
||||||
_scrollChar = 0;
|
|
||||||
_rowSel--;
|
|
||||||
LOWERLIMIT(_rowSel, 0);
|
|
||||||
}
|
|
||||||
// CENTRE press
|
|
||||||
if(event & key_Centre) {
|
|
||||||
if(_rowSel == 0) {
|
|
||||||
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_rowSel = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// LEFT press
|
|
||||||
if(event & key_Left) {
|
|
||||||
if(_rowSel == 0)
|
|
||||||
_ScreenManager.prevMenu();
|
|
||||||
else
|
|
||||||
adjust(-1);
|
|
||||||
}
|
|
||||||
// RIGHT press
|
|
||||||
if(event & key_Right) {
|
|
||||||
if(_rowSel == 0)
|
|
||||||
_ScreenManager.nextMenu();
|
|
||||||
else
|
|
||||||
adjust(+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHomeMenuSelScreen::adjust(int dir)
|
|
||||||
{
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 1:
|
|
||||||
_action.onStop += dir;
|
|
||||||
WRAPLIMITS(_action.onStop, 0, 3);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_action.onStart += dir;
|
|
||||||
WRAPLIMITS(_action.onStart, 0, 3);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
_action.onTimeout += dir;
|
|
||||||
WRAPLIMITS(_action.onTimeout, 0, 3);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,238 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "OtherOptionsScreen.h"
|
|
||||||
#include "KeyPad.h"
|
|
||||||
#include "../Utility/helpers.h"
|
|
||||||
#include "../Utility/UtilClasses.h"
|
|
||||||
#include "../Utility/NVStorage.h"
|
|
||||||
#include "../Utility/GPIO.h"
|
|
||||||
#include "fonts/Icons.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
COtherOptionsScreen::COtherOptionsScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
COtherOptionsScreen::onSelect()
|
|
||||||
{
|
|
||||||
CScreenHeader::onSelect();
|
|
||||||
_rowSel = 0;
|
|
||||||
_repeatCount = -1;
|
|
||||||
_frameRate = NVstore.getUserSettings().FrameRate;
|
|
||||||
_dispTimeout = NVstore.getUserSettings().dimTime;
|
|
||||||
_menuTimeout = NVstore.getUserSettings().menuTimeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
COtherOptionsScreen::_initUI()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
COtherOptionsScreen::show()
|
|
||||||
{
|
|
||||||
char msg[16];
|
|
||||||
|
|
||||||
_display.clearDisplay();
|
|
||||||
|
|
||||||
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 {
|
|
||||||
_printInverted(_display.xCentre(), 0, " Time Intervals ", true, eCentreJustify);
|
|
||||||
|
|
||||||
// data frame refresh rate
|
|
||||||
_drawBitmap(15, 13, RefreshIconInfo);
|
|
||||||
sprintf(msg, "%dms", _frameRate);
|
|
||||||
_printMenuText(40, 14, msg, _rowSel == 3);
|
|
||||||
|
|
||||||
// display timeout
|
|
||||||
_drawBitmap(10, 26, DisplayTimeoutIconInfo);
|
|
||||||
if(_dispTimeout) {
|
|
||||||
float mins = float(abs(_dispTimeout)) / 60000.f;
|
|
||||||
sprintf(msg, "%s %0.1f min%s", (_dispTimeout < 0) ? "Blank" : "Dim", mins, mins < 2 ? "" : "s");
|
|
||||||
_printMenuText(40, 26, msg, _rowSel == 2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_printMenuText(40, 26, "Always on", _rowSel == 2);
|
|
||||||
|
|
||||||
// menu timeout
|
|
||||||
_drawBitmap(10, 38, MenuTimeoutIconInfo);
|
|
||||||
if(_menuTimeout) {
|
|
||||||
float mins = float(abs(_menuTimeout)) / 60000.f;
|
|
||||||
sprintf(msg, "Home %0.1f min%s", mins, mins < 2 ? "" : "s");
|
|
||||||
_printMenuText(40, 38, msg, _rowSel == 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_printMenuText(40, 38, "Disabled", _rowSel == 1);
|
|
||||||
|
|
||||||
/* if(_rowSel == 0)
|
|
||||||
_printMenuText(_display.xCentre(), 53, " \021 Exit \020 ", _rowSel == 0, eCentreJustify);
|
|
||||||
else {
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
_printMenuText(_display.xCentre(), 56, "\030\031Sel \033\032 Adj", false, eCentreJustify);
|
|
||||||
_printMenuText(_display.xCentre(), 56, "Save", false, eCentreJustify);
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
COtherOptionsScreen::animate()
|
|
||||||
{
|
|
||||||
if(_rowSel != 4) {
|
|
||||||
int yPos = 53;
|
|
||||||
int xPos = _display.xCentre();
|
|
||||||
const char* pMsg = NULL;
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_printMenuText(xPos, yPos, " \021 \030Edit Exit \020 ", true, eCentreJustify);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
pMsg = " No keypad activity returns to the home menu. ";
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
pMsg = " No keypad activity either dims or blanks the display. Hold Left or Right to toggle Dim/Blank mode. ";
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
pMsg = " Define the polling rate of the bluewire communications. ";
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
COtherOptionsScreen::keyHandler(uint8_t event)
|
|
||||||
{
|
|
||||||
if(event & keyPressed) {
|
|
||||||
_repeatCount = 0;
|
|
||||||
// UP press
|
|
||||||
if(event & key_Up) {
|
|
||||||
if(_rowSel == 4) {
|
|
||||||
sUserSettings settings = NVstore.getUserSettings();
|
|
||||||
settings.dimTime = _dispTimeout;
|
|
||||||
settings.menuTimeout = _menuTimeout;
|
|
||||||
settings.FrameRate = _frameRate;
|
|
||||||
NVstore.setUserSettings(settings);
|
|
||||||
NVstore.save();
|
|
||||||
_showStoringMessage();
|
|
||||||
_rowSel = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_scrollChar = 0;
|
|
||||||
_rowSel++;
|
|
||||||
UPPERLIMIT(_rowSel, 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// UP press
|
|
||||||
if(event & key_Down) {
|
|
||||||
_scrollChar = 0;
|
|
||||||
_rowSel--;
|
|
||||||
LOWERLIMIT(_rowSel, 0);
|
|
||||||
}
|
|
||||||
// CENTRE press
|
|
||||||
if(event & key_Centre) {
|
|
||||||
if(_rowSel == 0) {
|
|
||||||
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_rowSel = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event & keyRepeat) {
|
|
||||||
if(keyRepeat >= 0) {
|
|
||||||
_repeatCount++;
|
|
||||||
if(_repeatCount > 4) {
|
|
||||||
// LEFT or RIGHT hold
|
|
||||||
if(event & (key_Right | key_Left)) {
|
|
||||||
if(_rowSel == 2) {
|
|
||||||
_repeatCount = -1;
|
|
||||||
_dispTimeout = -_dispTimeout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event & keyReleased) {
|
|
||||||
if(_repeatCount == 0) {
|
|
||||||
// LEFT short press
|
|
||||||
if(event & key_Left) {
|
|
||||||
if(_rowSel == 0)
|
|
||||||
_ScreenManager.prevMenu();
|
|
||||||
else
|
|
||||||
adjust(-1);
|
|
||||||
}
|
|
||||||
// RIGHT short press
|
|
||||||
if(event & key_Right) {
|
|
||||||
if(_rowSel == 0)
|
|
||||||
_ScreenManager.nextMenu();
|
|
||||||
else
|
|
||||||
adjust(+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
COtherOptionsScreen::adjust(int dir)
|
|
||||||
{
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 1:
|
|
||||||
_menuTimeout += dir * 30000;
|
|
||||||
LOWERLIMIT(_menuTimeout, 0);
|
|
||||||
UPPERLIMIT(_menuTimeout, 300000);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_dispTimeout += dir * 30000;
|
|
||||||
LOWERLIMIT(_dispTimeout, -600000);
|
|
||||||
UPPERLIMIT(_dispTimeout, 600000);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
_frameRate += dir * 50;
|
|
||||||
LOWERLIMIT(_frameRate, 300);
|
|
||||||
UPPERLIMIT(_frameRate, 1500);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,258 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "PrimingScreen.h"
|
|
||||||
#include "KeyPad.h"
|
|
||||||
#include "../Utility/NVStorage.h"
|
|
||||||
#include "../Protocol/Protocol.h"
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// CPrimingScreen
|
|
||||||
//
|
|
||||||
// This screen allows the temperature control mode to be selected and
|
|
||||||
// allows pump priming
|
|
||||||
//
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
CPrimingScreen::CPrimingScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHeader(display, mgr)
|
|
||||||
{
|
|
||||||
_initUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CPrimingScreen::onSelect()
|
|
||||||
{
|
|
||||||
_stopPump();
|
|
||||||
_initUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CPrimingScreen::onExit()
|
|
||||||
{
|
|
||||||
_stopPump();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
CPrimingScreen::_initUI()
|
|
||||||
{
|
|
||||||
_PrimeStop = 0;
|
|
||||||
_PrimeCheck = 0;
|
|
||||||
_rowSel = 0;
|
|
||||||
_colSel = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CPrimingScreen::show()
|
|
||||||
{
|
|
||||||
CScreenHeader::show();
|
|
||||||
|
|
||||||
CRect extents;
|
|
||||||
|
|
||||||
int yPos = 53;
|
|
||||||
// show next/prev menu navigation line
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_printMenuText(_display.xCentre(), yPos, " \021 \030Edit \020 ", _rowSel == 0, eCentreJustify);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
_display.drawFastHLine(0, 53, 128, WHITE);
|
|
||||||
_printMenuText(_display.xCentre(), 57, "\030\031 Sel \033\032 Adj", false, eCentreJustify);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
_display.drawFastHLine(0, 53, 128, WHITE);
|
|
||||||
if(_colSel == 2) {
|
|
||||||
_printMenuText(_display.xCentre(), 57, "\033\030\031 Stop", false, eCentreJustify);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_printMenuText(_display.xCentre(), 57, "\032 Start \031 Sel", false, eCentreJustify);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
yPos = 40;
|
|
||||||
if(_rowSel == 1) {
|
|
||||||
// follow user desired setting, heater info is laggy
|
|
||||||
_printMenuText(border, yPos, "Thermostat", _colSel == 0);
|
|
||||||
_printMenuText(_display.width()-border, yPos, "Fixed Hz", _colSel == 1, eRightJustify);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// follow actual heater settings
|
|
||||||
// int col = getHeaterInfo().isThermostat() ? 0 : 1;
|
|
||||||
int col = getThermostatModeActive() ? 0 : 1;
|
|
||||||
_printInverted(border, yPos, "Thermostat", col == 0);
|
|
||||||
_printInverted(_display.width()-border, yPos, "Fixed Hz", col == 1, eRightJustify);
|
|
||||||
}
|
|
||||||
yPos = 28;
|
|
||||||
if(_rowSel == 2) {
|
|
||||||
_printMenuText(border, yPos, "degC", _colSel == 0);
|
|
||||||
_printMenuText(_display.width()-border, yPos, "degF", _colSel == 1, eRightJustify);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int col = NVstore.getUserSettings().degF ? 1 : 0;
|
|
||||||
_printInverted(border, yPos, "degC", col == 0);
|
|
||||||
_printInverted(_display.width()-border, yPos, "degF", col == 1, eRightJustify);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fuel pump priming menu
|
|
||||||
yPos = 16;
|
|
||||||
_printMenuText(border, yPos, "Pump");
|
|
||||||
if(_rowSel == 3) {
|
|
||||||
_printMenuText(40, yPos, "OFF", _colSel == 1);
|
|
||||||
if(_colSel != 2) {
|
|
||||||
if(!getHeaterInfo().getRunState()) { // prevent option if heater is running
|
|
||||||
_printMenuText(70, yPos, "ON"); // becomes Hz when actually priming
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
float pumpHz = getHeaterInfo().getPump_Actual();
|
|
||||||
// recognise if heater has stopped pump, after an initial holdoff upon first starting
|
|
||||||
long tDelta = millis() - _PrimeCheck;
|
|
||||||
if(_PrimeCheck && tDelta > 0 && pumpHz < 0.1) {
|
|
||||||
_stopPump();
|
|
||||||
}
|
|
||||||
// test if time is up, stop priming if so
|
|
||||||
tDelta = millis() - _PrimeStop;
|
|
||||||
if(_PrimeStop && tDelta > 0) {
|
|
||||||
_stopPump();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_PrimeStop) {
|
|
||||||
char msg[16];
|
|
||||||
sprintf(msg, "%.1fHz", pumpHz);
|
|
||||||
_printMenuText(70, yPos, msg, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
CPrimingScreen::keyHandler(uint8_t event)
|
|
||||||
{
|
|
||||||
|
|
||||||
if(event & keyPressed) {
|
|
||||||
// press LEFT
|
|
||||||
if(event & key_Left) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_ScreenManager.prevMenu();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
_colSel = 0;
|
|
||||||
setThermostatMode(1);
|
|
||||||
saveNV();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_colSel = 0;
|
|
||||||
setDegFMode(false);
|
|
||||||
saveNV();
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
_colSel = 1;
|
|
||||||
break;
|
|
||||||
case 4: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// press RIGHT
|
|
||||||
if(event & key_Right) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_ScreenManager.nextMenu();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
_colSel = 1;
|
|
||||||
setThermostatMode(0);
|
|
||||||
saveNV();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_colSel = 1;
|
|
||||||
setDegFMode(true);
|
|
||||||
saveNV();
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if(!getHeaterInfo().getRunState())
|
|
||||||
_colSel = 2;
|
|
||||||
break;
|
|
||||||
case 4: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// press UP
|
|
||||||
if(event & key_Up) {
|
|
||||||
if(hasOEMcontroller())
|
|
||||||
_reqOEMWarning();
|
|
||||||
else {
|
|
||||||
_rowSel++;
|
|
||||||
UPPERLIMIT(_rowSel, 3);
|
|
||||||
if(_rowSel == 3)
|
|
||||||
_colSel = 1; // select OFF upon entry to priming menu
|
|
||||||
if(_rowSel == 2)
|
|
||||||
_colSel = NVstore.getUserSettings().degF ? 1 : 0;
|
|
||||||
if(_rowSel == 1)
|
|
||||||
_colSel = getThermostatModeActive() ? 0 : 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// press DOWN
|
|
||||||
if(event & key_Down) {
|
|
||||||
if(_rowSel == 0) {
|
|
||||||
_ScreenManager.selectMenu(CScreenManager::UserSettingsLoop, CScreenManager::VersionUI); // force return to main menu
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_rowSel--;
|
|
||||||
LOWERLIMIT(_rowSel, 0);
|
|
||||||
_colSel = 0;
|
|
||||||
if(_rowSel == 1)
|
|
||||||
// _colSel = getHeaterInfo().isThermostat() ? 0 : 1;
|
|
||||||
_colSel = getThermostatModeActive() ? 0 : 1;
|
|
||||||
if(_rowSel == 2)
|
|
||||||
_colSel = NVstore.getUserSettings().degF ? 1 : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if fuel priming was selected
|
|
||||||
if(_rowSel == 3 && _colSel == 2) {
|
|
||||||
reqPumpPrime(true);
|
|
||||||
_PrimeStop = millis() + 150000; // allow 2.5 minutes - much the same as the heater itself cuts out at
|
|
||||||
_PrimeCheck = millis() + 3000; // holdoff upon start before testing for heater shutting off pump
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_stopPump();
|
|
||||||
}
|
|
||||||
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CPrimingScreen::_stopPump()
|
|
||||||
{
|
|
||||||
reqPumpPrime(false);
|
|
||||||
_PrimeCheck = 0;
|
|
||||||
_PrimeStop = 0;
|
|
||||||
if(_colSel == 2)
|
|
||||||
_colSel = 1;
|
|
||||||
}
|
|
|
@ -1,291 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "ScreenHeader.h"
|
|
||||||
#include "../Protocol/Protocol.h"
|
|
||||||
#include "../Utility/helpers.h"
|
|
||||||
#include "../Wifi/BTCWifi.h"
|
|
||||||
#include "../Bluetooth/BluetoothAbstract.h"
|
|
||||||
#include "../Utility/NVStorage.h"
|
|
||||||
#include "../RTC/Clock.h"
|
|
||||||
#include "fonts/Arial.h"
|
|
||||||
#include "fonts/Icons.h"
|
|
||||||
#include "fonts/MiniFont.h"
|
|
||||||
#include "../RTC/TimerManager.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define MINIFONT miniFontInfo
|
|
||||||
|
|
||||||
#define X_BT_ICON 10
|
|
||||||
#define Y_BT_ICON 0
|
|
||||||
#define X_WIFI_ICON 19
|
|
||||||
#define Y_WIFI_ICON 0
|
|
||||||
#define X_CLOCK 50
|
|
||||||
#define Y_CLOCK 0
|
|
||||||
#define X_TIMER_ICON 83
|
|
||||||
#define Y_TIMER_ICON 0
|
|
||||||
#define X_BATT_ICON 103
|
|
||||||
#define Y_BATT_ICON 0
|
|
||||||
|
|
||||||
/*#define X_BT_ICON 20
|
|
||||||
#define Y_BT_ICON 0
|
|
||||||
#define X_WIFI_ICON 29
|
|
||||||
#define Y_WIFI_ICON 0
|
|
||||||
#define X_GPIO_ICON 9
|
|
||||||
#define X_CLOCK 56
|
|
||||||
#define Y_CLOCK 0
|
|
||||||
#define X_TIMER_ICON 84
|
|
||||||
#define Y_TIMER_ICON 0
|
|
||||||
#define X_BATT_ICON 103
|
|
||||||
#define Y_BATT_ICON 0*/
|
|
||||||
|
|
||||||
|
|
||||||
CScreenHeader::CScreenHeader(C128x64_OLED& disp, CScreenManager& mgr) : CScreen(disp, mgr)
|
|
||||||
{
|
|
||||||
_colon = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CScreenHeader::show()
|
|
||||||
{
|
|
||||||
_display.clearDisplay();
|
|
||||||
|
|
||||||
// standard header items
|
|
||||||
// Bluetooth
|
|
||||||
showBTicon();
|
|
||||||
|
|
||||||
// WiFi icon is updated in animate()
|
|
||||||
|
|
||||||
// battery
|
|
||||||
showBatteryIcon(getHeaterInfo().getBattVoltage());
|
|
||||||
|
|
||||||
// clock
|
|
||||||
showTime();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Animate IN/OUT arrows against the WiFi icon, according to actual web server traffic:
|
|
||||||
// an IN (down) arrow is drawn if incoming data has been detected.
|
|
||||||
// an OUT (up) arrow is drawn if outgoing data has been sent.
|
|
||||||
//
|
|
||||||
// Each arrow is drawn for one animation interval with a minimum of one clear interval
|
|
||||||
// creating a clean flash on the display.
|
|
||||||
// Both arrows may appear in the same interval.
|
|
||||||
// The following is a typical sequence, relative to animation ticks, note the gap
|
|
||||||
// that always appears in the animation interval between either arrow shown:
|
|
||||||
//
|
|
||||||
// | | | | | | | | | | | | | | | | |
|
|
||||||
// _________^^^^^________________________________________^^^^^_________________________
|
|
||||||
// ______________vvvvv_____vvvvv_______________vvvvv_____vvvvv_____vvvvv_______________
|
|
||||||
|
|
||||||
bool
|
|
||||||
CScreenHeader::animate()
|
|
||||||
{
|
|
||||||
// animate timer icon,
|
|
||||||
// inserting an update icon if new firmware available from internet web server
|
|
||||||
_animateCount++;
|
|
||||||
WRAPUPPERLIMIT(_animateCount, 10, 0);
|
|
||||||
if(isUpdateAvailable(true)) {
|
|
||||||
int xPos = X_TIMER_ICON - 3;
|
|
||||||
int yPos = Y_TIMER_ICON;
|
|
||||||
switch(_animateCount) {
|
|
||||||
case 0:
|
|
||||||
case 2:
|
|
||||||
_display.fillRect(xPos, yPos, TimerIconInfo.width+3, TimerIconInfo.height, BLACK);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
_drawBitmap(xPos+6, yPos, UpdateIconInfo);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
showTimers();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
showTimers();
|
|
||||||
}
|
|
||||||
|
|
||||||
showWifiIcon();
|
|
||||||
|
|
||||||
return true; // true if we need to update the physical display
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CScreenHeader::showBTicon()
|
|
||||||
{
|
|
||||||
if(getBluetoothClient().isConnected()) {
|
|
||||||
_drawBitmap(X_BT_ICON, Y_BT_ICON, BluetoothIconInfo, WHITE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CScreenHeader::showWifiIcon()
|
|
||||||
{
|
|
||||||
if(isWifiConnected() || isWifiAP()) { // STA or AP mode active
|
|
||||||
_drawBitmap(X_WIFI_ICON, Y_WIFI_ICON, WifiWideIconInfo, WHITE, BLACK); // wide icon erases annotations!
|
|
||||||
|
|
||||||
int xPos = X_WIFI_ICON + WifiIconInfo.width + 1; // x loaction of upload/download arrows
|
|
||||||
|
|
||||||
// UP arrow animation
|
|
||||||
//
|
|
||||||
int yPos = 0;
|
|
||||||
|
|
||||||
if(hasWebServerSpoken(true)) {
|
|
||||||
// we have emitted data to the web client, show an UP arrow
|
|
||||||
_UpAnnotation.holdon = 2; // hold up arrow on for 2 cycles
|
|
||||||
_UpAnnotation.holdoff = 8; // hold blank for 8 cycles
|
|
||||||
};
|
|
||||||
|
|
||||||
if(_UpAnnotation.holdon) {
|
|
||||||
_UpAnnotation.holdon--;
|
|
||||||
_drawBitmap(xPos, yPos, WifiOutIconInfo); // add upload arrow
|
|
||||||
}
|
|
||||||
else if(_UpAnnotation.holdoff > 0) {
|
|
||||||
_UpAnnotation.holdoff--; // animation of arrow is now cleared
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(NVstore.getUserSettings().enableOTA) {
|
|
||||||
// OTA is enabled, show OTA
|
|
||||||
// erase top right portion of wifi icon
|
|
||||||
_display.fillRect(X_WIFI_ICON+11, Y_WIFI_ICON, 2, 6, BLACK);
|
|
||||||
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
|
|
||||||
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON);
|
|
||||||
_display.print("OTA");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// low side wifi icon annotation
|
|
||||||
if(isWifiButton()) {
|
|
||||||
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
|
|
||||||
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON+6);
|
|
||||||
switch(isWifiButton()) {
|
|
||||||
case 1: _display.print("CFG"); break;
|
|
||||||
case 2: _display.print("HTR"); break;
|
|
||||||
case 3: _display.print("ERS"); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// DOWN arrow animation
|
|
||||||
//
|
|
||||||
yPos = WifiIconInfo.height - WifiInIconInfo.height + 1;
|
|
||||||
|
|
||||||
if(hasWebClientSpoken(true)) {
|
|
||||||
// we have received data from the web client, show a DOWN arrow
|
|
||||||
_DnAnnotation.holdon = 2; // hold down arrow on for 2 cycles
|
|
||||||
_DnAnnotation.holdoff = 8; // hold blank for 8 cycles
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_DnAnnotation.holdon) {
|
|
||||||
_DnAnnotation.holdon--;
|
|
||||||
_drawBitmap(xPos, yPos, WifiInIconInfo, WHITE); // add down arrow
|
|
||||||
}
|
|
||||||
else if(_DnAnnotation.holdoff > 0) {
|
|
||||||
_DnAnnotation.holdoff--; // nothing drawn after arrow, side annotation stays clear for a while
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// no activity for a while now
|
|
||||||
if(isWifiConfigPortal()) {
|
|
||||||
// if config portal, show CFG
|
|
||||||
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
|
|
||||||
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON+6);
|
|
||||||
_display.print("CFG");
|
|
||||||
}
|
|
||||||
else if(isWifiAP()) {
|
|
||||||
// if AP only, show AP
|
|
||||||
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
|
|
||||||
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON+6);
|
|
||||||
_display.print("AP");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CScreenHeader::showBatteryIcon(float voltage)
|
|
||||||
{
|
|
||||||
_drawBitmap(X_BATT_ICON, Y_BATT_ICON, BatteryIconInfo);
|
|
||||||
char msg[16];
|
|
||||||
sprintf(msg, "%.1fV", voltage);
|
|
||||||
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
|
|
||||||
_display.setCursor(X_BATT_ICON + BatteryIconInfo.width/2,
|
|
||||||
Y_BATT_ICON + BatteryIconInfo.height + 2);
|
|
||||||
_display.printCentreJustified(msg);
|
|
||||||
|
|
||||||
// nominal 10.5 -> 13.5V bargraph
|
|
||||||
int Capacity = (voltage - 10.7) * 4;
|
|
||||||
if(Capacity < 0) Capacity = 0;
|
|
||||||
if(Capacity > 11) Capacity = 11;
|
|
||||||
_display.fillRect(X_BATT_ICON+2 + Capacity, Y_BATT_ICON+2, BatteryIconInfo.width-4-Capacity, 6, BLACK);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
CScreenHeader::showTimers()
|
|
||||||
{
|
|
||||||
int nextTimer = CTimerManager::getNextTimer();
|
|
||||||
if(nextTimer) {
|
|
||||||
int xPos = X_TIMER_ICON;
|
|
||||||
_drawBitmap(xPos, Y_TIMER_ICON, LargeTimerIconInfo);
|
|
||||||
if(nextTimer & 0x80)
|
|
||||||
_drawBitmap(xPos-3, Y_TIMER_ICON, VerticalRepeatIconInfo);
|
|
||||||
|
|
||||||
CTransientFont AF(_display, &miniFontInfo); // temporarily use a mini font
|
|
||||||
if((nextTimer & 0x0f) >= 10)
|
|
||||||
_display.setCursor(xPos+4, Y_TIMER_ICON+8);
|
|
||||||
else
|
|
||||||
_display.setCursor(xPos+6, Y_TIMER_ICON+8);
|
|
||||||
_display.print(nextTimer & 0x0f);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
CScreenHeader::showTime()
|
|
||||||
{
|
|
||||||
const BTCDateTime& now = Clock.get();
|
|
||||||
|
|
||||||
char msg[16];
|
|
||||||
if(now.day() == 0xA5) {
|
|
||||||
sprintf(msg, "No RTC");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(_colon)
|
|
||||||
sprintf(msg, "%02d:%02d", now.hour(), now.minute());
|
|
||||||
else
|
|
||||||
sprintf(msg, "%02d %02d", now.hour(), now.minute());
|
|
||||||
_colon = !_colon;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
CTransientFont AF(_display, &arial_8ptFontInfo);
|
|
||||||
// determine centre position of remaining real estate
|
|
||||||
int xPos = X_WIFI_ICON + WifiIconInfo.width + WifiInIconInfo.width; // rhs of wifi conglomeration
|
|
||||||
if(isWifiAP()) xPos += 4; // add more if an Access Point
|
|
||||||
|
|
||||||
_printMenuText(X_CLOCK, Y_CLOCK, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,331 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "ThermostatModeScreen.h"
|
|
||||||
#include "KeyPad.h"
|
|
||||||
#include "../Utility/helpers.h"
|
|
||||||
#include "../Utility/UtilClasses.h"
|
|
||||||
#include "fonts/Icons.h"
|
|
||||||
#include "../Utility/NVStorage.h"
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// CThermostatModeScreen
|
|
||||||
//
|
|
||||||
// This screen provides control over experimental features
|
|
||||||
//
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
static const int Line3 = 14;
|
|
||||||
static const int Line2 = 27;
|
|
||||||
static const int Line1 = 40;
|
|
||||||
static const int Column = 40;
|
|
||||||
|
|
||||||
CThermostatModeScreen::CThermostatModeScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
|
|
||||||
{
|
|
||||||
_initUI();
|
|
||||||
_window = 10;
|
|
||||||
_thermoMode = 0;
|
|
||||||
_cyclicMode.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CThermostatModeScreen::onSelect()
|
|
||||||
{
|
|
||||||
CPasswordScreen::onSelect();
|
|
||||||
_initUI();
|
|
||||||
_window = NVstore.getUserSettings().ThermostatWindow;
|
|
||||||
_thermoMode = NVstore.getUserSettings().ThermostatMethod;
|
|
||||||
_cyclicMode = NVstore.getCyclicMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CThermostatModeScreen::_initUI()
|
|
||||||
{
|
|
||||||
_rowSel = 0;
|
|
||||||
_animateCount = 0;
|
|
||||||
_keyRepeat = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CThermostatModeScreen::show()
|
|
||||||
{
|
|
||||||
char msg[20];
|
|
||||||
_display.clearDisplay();
|
|
||||||
|
|
||||||
if(!CPasswordScreen::show()) { // for showing "saving settings"
|
|
||||||
|
|
||||||
if(_rowSel == 10) {
|
|
||||||
_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 {
|
|
||||||
_printInverted(_display.xCentre(), 0, " Thermostat Mode ", true, eCentreJustify);
|
|
||||||
_drawBitmap(3, 14, ThermostatIconInfo);
|
|
||||||
float fTemp = _window;
|
|
||||||
if(NVstore.getUserSettings().degF) {
|
|
||||||
fTemp = fTemp * 9 / 5;
|
|
||||||
sprintf(msg, "%.1f\367F", fTemp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sprintf(msg, "%.1f\367C", fTemp);
|
|
||||||
}
|
|
||||||
_printMenuText(Column, Line2, msg, _rowSel == 3);
|
|
||||||
switch(_thermoMode) {
|
|
||||||
case 1:
|
|
||||||
_printMenuText(Column, Line3, "Deadband", _rowSel == 4);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_printMenuText(Column, Line3, "Linear Hz", _rowSel == 4);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
_printMenuText(Column, Line3, "Standard", _rowSel == 4);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(_cyclicMode.isEnabled()) {
|
|
||||||
float fTemp = _cyclicMode.Stop+1;
|
|
||||||
if(NVstore.getUserSettings().degF) {
|
|
||||||
fTemp = fTemp * 9 / 5;
|
|
||||||
sprintf(msg, "\352>%.0f\367F", fTemp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sprintf(msg, "\352>%.0f\367C", fTemp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strcpy(msg, "OFF");
|
|
||||||
}
|
|
||||||
_printMenuText(Column, Line1, msg, _rowSel == 1);
|
|
||||||
if(_cyclicMode.isEnabled()) {
|
|
||||||
float fTemp = _cyclicMode.Start;
|
|
||||||
// if(NVstore.getDegFMode()) {
|
|
||||||
if(NVstore.getUserSettings().degF) {
|
|
||||||
fTemp = fTemp * 9 / 5;
|
|
||||||
sprintf(msg, "\352<%.0f\367F", fTemp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sprintf(msg, "\352<%.0f\367C", fTemp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strcpy(msg, "");
|
|
||||||
}
|
|
||||||
_printMenuText(Column + 42, Line1, msg, _rowSel == 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CThermostatModeScreen::animate()
|
|
||||||
{
|
|
||||||
if(_rowSel != 10) {
|
|
||||||
int yPos = 53;
|
|
||||||
int xPos = _display.xCentre();
|
|
||||||
const char* pMsg = NULL;
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_printMenuText(xPos, yPos, " \021 \030Edit Exit \020 ", true, eCentreJustify);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
pMsg = " Heater shuts down over set point. ";
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
pMsg = " Heater restarts below setpoint. ";
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
pMsg = " User defined window for custom thermostat modes. ";
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
_display.drawFastHLine(0, 52, 128, WHITE);
|
|
||||||
switch(_thermoMode) {
|
|
||||||
case 1:
|
|
||||||
pMsg = " The user defined window sets the thermostat's hysteresis. ";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
pMsg = " The pump rate is adjusted linearly across the set point window. ";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pMsg = " Use heater's standard thermostat control. ";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(pMsg)
|
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CThermostatModeScreen::keyHandler(uint8_t event)
|
|
||||||
{
|
|
||||||
sUserSettings settings;
|
|
||||||
if(event & keyPressed) {
|
|
||||||
_keyRepeat = 0; // unlock hold function
|
|
||||||
// press LEFT to select previous screen
|
|
||||||
if(event & key_Left) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_ScreenManager.prevMenu();
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
_scrollChar = 0;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
_adjust(-1);
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
_rowSel = 0; // abort save
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// press RIGHT to select next screen
|
|
||||||
if(event & key_Right) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_ScreenManager.nextMenu();
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
_scrollChar = 0;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
_adjust(+1);
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
_rowSel = 0; // abort save
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event & key_Down) {
|
|
||||||
if(_rowSel != 0) {
|
|
||||||
_scrollChar = 0;
|
|
||||||
_rowSel--;
|
|
||||||
if(_rowSel == 2 && !_cyclicMode.isEnabled())
|
|
||||||
_rowSel--;
|
|
||||||
LOWERLIMIT(_rowSel, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// UP press
|
|
||||||
if(event & key_Up) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
_scrollChar = 0;
|
|
||||||
_rowSel++;
|
|
||||||
if(_rowSel == 2 && !_cyclicMode.isEnabled())
|
|
||||||
_rowSel++;
|
|
||||||
UPPERLIMIT(_rowSel, 4);
|
|
||||||
break;
|
|
||||||
case 10: // confirmed save
|
|
||||||
_showStoringMessage();
|
|
||||||
settings = NVstore.getUserSettings();
|
|
||||||
settings.ThermostatMethod = _thermoMode;
|
|
||||||
settings.ThermostatWindow = _window;
|
|
||||||
NVstore.setUserSettings(settings);
|
|
||||||
NVstore.setCyclicMode(_cyclicMode);
|
|
||||||
saveNV();
|
|
||||||
_rowSel = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// CENTRE press
|
|
||||||
if(event & key_Centre) {
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 0:
|
|
||||||
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop, CScreenManager::SettingsUI); // force return to main menu
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
_rowSel = 10;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
if(event & keyRepeat) {
|
|
||||||
_keyRepeat++;
|
|
||||||
if((event & key_Down) && (keyRepeat >= 4)) {
|
|
||||||
_keyRepeat = -1;
|
|
||||||
if(_rowSel == 0) {
|
|
||||||
_ScreenManager.selectMenu(CScreenManager::BranchMenu, CScreenManager::FontDumpUI);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(_rowSel == 3) {
|
|
||||||
if(event & key_Right) {
|
|
||||||
_adjust(+1);
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
if(event & key_Left) {
|
|
||||||
_adjust(-1);
|
|
||||||
_ScreenManager.reqUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event & keyReleased) {
|
|
||||||
_keyRepeat = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CThermostatModeScreen::_adjust(int dir)
|
|
||||||
{
|
|
||||||
switch(_rowSel) {
|
|
||||||
case 1:
|
|
||||||
_cyclicMode.Stop += dir;
|
|
||||||
LOWERLIMIT(_cyclicMode.Stop, 0);
|
|
||||||
UPPERLIMIT(_cyclicMode.Stop, 10);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
_cyclicMode.Start += dir;
|
|
||||||
LOWERLIMIT(_cyclicMode.Start, -20);
|
|
||||||
UPPERLIMIT(_cyclicMode.Start, 0);
|
|
||||||
break;
|
|
||||||
case 3: // window
|
|
||||||
_window += (dir * 0.1);
|
|
||||||
UPPERLIMIT(_window, 10.0);
|
|
||||||
LOWERLIMIT(_window, 0.2);
|
|
||||||
break;
|
|
||||||
case 4: // thermostat mode
|
|
||||||
_thermoMode += dir;
|
|
||||||
WRAPLIMITS(_thermoMode, 0, 2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
#include "FontTypes.h"
|
|
||||||
|
|
||||||
// Font data for Arial 8pt
|
|
||||||
extern const uint8_t PROGMEM arial_8ptBitmaps [];
|
|
||||||
extern const FONT_INFO arial_8ptFontInfo;
|
|
||||||
extern const FONT_CHAR_INFO PROGMEM arial_8ptDescriptors[];
|
|
||||||
|
|
||||||
// Font data for Arial 7pt
|
|
||||||
extern const uint8_t PROGMEM arial_7ptBitmaps [];
|
|
||||||
extern const FONT_INFO arial_7ptFontInfo;
|
|
||||||
extern const FONT_CHAR_INFO PROGMEM arial_7ptDescriptors[];
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
#include "FontTypes.h"
|
|
||||||
|
|
||||||
// Font data for Franklin Gothic Medium Cond 8pt
|
|
||||||
extern const uint8_t PROGMEM franklinGothicMediumCond_8ptBitmaps [] ;
|
|
||||||
extern const FONT_CHAR_INFO PROGMEM franklinGothicMediumCond_8ptDescriptors[] ;
|
|
||||||
extern const FONT_INFO franklinGothicMediumCond_8ptFontInfo;
|
|
||||||
|
|
||||||
// Font data for Franklin Gothic Medium Cond 7pt
|
|
||||||
extern const uint8_t PROGMEM franklinGothicMediumCond_7ptBitmaps [];
|
|
||||||
extern const FONT_INFO franklinGothicMediumCond_7ptFontInfo;
|
|
||||||
extern const FONT_CHAR_INFO PROGMEM franklinGothicMediumCond_7ptDescriptors[];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,314 +0,0 @@
|
||||||
//
|
|
||||||
// Font data for Tahoma 16pt
|
|
||||||
//
|
|
||||||
// Generated by The Dot Factory:
|
|
||||||
// http://www.eran.io/the-dot-factory-an-lcd-font-and-image-generator/
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Dot Factory Settings
|
|
||||||
//
|
|
||||||
// Flip/Rotate Padding Removal Line Wrap Descriptors
|
|
||||||
// [X] Flip X Height(Y): Tightest (O) At column [X] Generate descriptor array
|
|
||||||
// [ ] Flip Y Width(X): Tightest ( ) At bitmap Char Width: In Bits
|
|
||||||
// 90deg Char Height: In Bits
|
|
||||||
// Font Height: In Bits
|
|
||||||
// Comments Byte [ ] Multiple descriptor arrays
|
|
||||||
// [X] Variable Name Bit layout: RowMajor
|
|
||||||
// [X] BMP visualise [#] Order: MSBfirst Create new when exceeds [80]
|
|
||||||
// [X] Char descriptor Format: Hex
|
|
||||||
// Style: Cpp Leading: 0x Image width: In Bits
|
|
||||||
// Image height: In Bits
|
|
||||||
// Variable name format
|
|
||||||
// Bitmaps: const uint8_t PROGMEM {0}Bitmaps Space char generation
|
|
||||||
// Char Info: const FONT_CHAR_INFO PROGMEM {0}Descriptors [ ] Generate space bitmap
|
|
||||||
// Font Info: const FONT_INFO {0}FontInfo [2] pixels for space char
|
|
||||||
// Width: const uint8_t {0}Width
|
|
||||||
// Height: const uint8_t {0}Height
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
#include "tahoma16.h"
|
|
||||||
|
|
||||||
// Character bitmaps for Tahoma 16pt
|
|
||||||
const uint8_t tahoma_16ptBitmaps[] PROGMEM =
|
|
||||||
{
|
|
||||||
// @0 '.' (4 pixels wide)
|
|
||||||
0x00, 0x0F, // ####
|
|
||||||
0x00, 0x0F, // ####
|
|
||||||
0x00, 0x0F, // ####
|
|
||||||
0x00, 0x0F, // ####
|
|
||||||
|
|
||||||
// @8 '0' (11 pixels wide)
|
|
||||||
0x0F, 0xF0, // ########
|
|
||||||
0x3F, 0xFC, // ############
|
|
||||||
0x7F, 0xFE, // ##############
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0xF0, 0x0F, // #### ####
|
|
||||||
0xE0, 0x07, // ### ###
|
|
||||||
0xF0, 0x0F, // #### ####
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0x7F, 0xFE, // ##############
|
|
||||||
0x3F, 0xFC, // ############
|
|
||||||
0x0F, 0xF0, // ########
|
|
||||||
|
|
||||||
// @30 '1' (10 pixels wide)
|
|
||||||
0x38, 0x07, // ### ###
|
|
||||||
0x38, 0x07, // ### ###
|
|
||||||
0x38, 0x07, // ### ###
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0x00, 0x07, // ###
|
|
||||||
0x00, 0x07, // ###
|
|
||||||
0x00, 0x07, // ###
|
|
||||||
|
|
||||||
// @50 '2' (11 pixels wide)
|
|
||||||
0x70, 0x07, // ### ###
|
|
||||||
0xE0, 0x0F, // ### ####
|
|
||||||
0xE0, 0x1F, // ### #####
|
|
||||||
0xE0, 0x3F, // ### ######
|
|
||||||
0xE0, 0x7F, // ### #######
|
|
||||||
0xF1, 0xF7, // #### ##### ###
|
|
||||||
0xFF, 0xE7, // ########### ###
|
|
||||||
0x7F, 0xC7, // ######### ###
|
|
||||||
0x7F, 0x87, // ######## ###
|
|
||||||
0x3E, 0x07, // ##### ###
|
|
||||||
0x00, 0x07, // ###
|
|
||||||
|
|
||||||
// @72 '3' (11 pixels wide)
|
|
||||||
0x70, 0x0E, // ### ###
|
|
||||||
0xF0, 0x0F, // #### ####
|
|
||||||
0xE0, 0x07, // ### ###
|
|
||||||
0xE3, 0x87, // ### ### ###
|
|
||||||
0xE3, 0x87, // ### ### ###
|
|
||||||
0xE3, 0x87, // ### ### ###
|
|
||||||
0xE7, 0xCF, // ### ##### ####
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0x7E, 0xFE, // ###### #######
|
|
||||||
0x7E, 0xFE, // ###### #######
|
|
||||||
0x3C, 0x78, // #### ####
|
|
||||||
|
|
||||||
// @94 '4' (12 pixels wide)
|
|
||||||
0x00, 0xF0, // ####
|
|
||||||
0x01, 0xF0, // #####
|
|
||||||
0x07, 0x70, // ### ###
|
|
||||||
0x0E, 0x70, // ### ###
|
|
||||||
0x38, 0x70, // ### ###
|
|
||||||
0x70, 0x70, // ### ###
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0x00, 0x70, // ###
|
|
||||||
0x00, 0x70, // ###
|
|
||||||
|
|
||||||
// @118 '5' (11 pixels wide)
|
|
||||||
0x00, 0x0E, // ###
|
|
||||||
0xFF, 0x87, // ######### ###
|
|
||||||
0xFF, 0x87, // ######### ###
|
|
||||||
0xFF, 0x87, // ######### ###
|
|
||||||
0xFF, 0x87, // ######### ###
|
|
||||||
0xE3, 0x87, // ### ### ###
|
|
||||||
0xE3, 0xCF, // ### #### ####
|
|
||||||
0xE3, 0xFF, // ### ##########
|
|
||||||
0xE3, 0xFE, // ### #########
|
|
||||||
0xE1, 0xFC, // ### #######
|
|
||||||
0xE0, 0xF8, // ### #####
|
|
||||||
|
|
||||||
// @140 '6' (11 pixels wide)
|
|
||||||
0x07, 0xF0, // #######
|
|
||||||
0x1F, 0xFC, // ###########
|
|
||||||
0x3F, 0xFE, // #############
|
|
||||||
0x7F, 0xFF, // ###############
|
|
||||||
0xFB, 0x0F, // ##### ## ####
|
|
||||||
0xF7, 0x07, // #### ### ###
|
|
||||||
0xE7, 0x8F, // ### #### ####
|
|
||||||
0xE7, 0xFF, // ### ###########
|
|
||||||
0xE7, 0xFE, // ### ##########
|
|
||||||
0xE3, 0xFC, // ### ########
|
|
||||||
0x01, 0xF8, // ######
|
|
||||||
|
|
||||||
// @162 '7' (11 pixels wide)
|
|
||||||
0xE0, 0x01, // ### #
|
|
||||||
0xE0, 0x07, // ### ###
|
|
||||||
0xE0, 0x1F, // ### #####
|
|
||||||
0xE0, 0x7F, // ### #######
|
|
||||||
0xE1, 0xFF, // ### #########
|
|
||||||
0xE7, 0xFC, // ### #########
|
|
||||||
0xFF, 0xF0, // ############
|
|
||||||
0xFF, 0xC0, // ##########
|
|
||||||
0xFF, 0x00, // ########
|
|
||||||
0xFC, 0x00, // ######
|
|
||||||
0xF0, 0x00, // ####
|
|
||||||
|
|
||||||
// @184 '8' (11 pixels wide)
|
|
||||||
0x3C, 0x3C, // #### ####
|
|
||||||
0x7E, 0xFE, // ###### #######
|
|
||||||
0x7F, 0xFE, // ##############
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0xE7, 0x8F, // ### #### ####
|
|
||||||
0xE3, 0x87, // ### ### ###
|
|
||||||
0xE3, 0xC7, // ### #### ###
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0x7F, 0xFE, // ##############
|
|
||||||
0x7E, 0xFE, // ###### #######
|
|
||||||
0x3C, 0x7C, // #### #####
|
|
||||||
|
|
||||||
// @206 '9' (11 pixels wide)
|
|
||||||
0x1F, 0x80, // ######
|
|
||||||
0x3F, 0xC7, // ######## ###
|
|
||||||
0x7F, 0xE7, // ########## ###
|
|
||||||
0xFF, 0xE7, // ########### ###
|
|
||||||
0xF1, 0xE7, // #### #### ###
|
|
||||||
0xE0, 0xEF, // ### ### ####
|
|
||||||
0xF0, 0xDF, // #### ## #####
|
|
||||||
0xFF, 0xFE, // ###############
|
|
||||||
0x7F, 0xFC, // #############
|
|
||||||
0x3F, 0xF8, // ###########
|
|
||||||
0x0F, 0xE0, // #######
|
|
||||||
|
|
||||||
// @228 '`' (8 pixels wide)
|
|
||||||
0x3C, 0x00, // ####
|
|
||||||
0x7E, 0x00, // ######
|
|
||||||
0xE7, 0x00, // ### ###
|
|
||||||
0xC3, 0x00, // ## ##
|
|
||||||
0xC3, 0x00, // ## ##
|
|
||||||
0xE7, 0x00, // ### ###
|
|
||||||
0x7E, 0x00, // ######
|
|
||||||
0x3C, 0x00, // ####
|
|
||||||
|
|
||||||
// @244 'C' (12 pixels wide)
|
|
||||||
0x07, 0xE0, // ######
|
|
||||||
0x1F, 0xF8, // ##########
|
|
||||||
0x3F, 0xFC, // ############
|
|
||||||
0x7F, 0xFE, // ##############
|
|
||||||
0xF8, 0x1F, // ##### #####
|
|
||||||
0xF0, 0x0F, // #### ####
|
|
||||||
0xE0, 0x07, // ### ###
|
|
||||||
0xE0, 0x07, // ### ###
|
|
||||||
0xE0, 0x07, // ### ###
|
|
||||||
0xE0, 0x07, // ### ###
|
|
||||||
0x70, 0x0E, // ### ###
|
|
||||||
0x78, 0x1E, // #### ####
|
|
||||||
|
|
||||||
// @268 ':' (4 pixels wide)
|
|
||||||
0x3C, 0x3C, // #### ####
|
|
||||||
0x3C, 0x3C, // #### ####
|
|
||||||
0x3C, 0x3C, // #### ####
|
|
||||||
0x3C, 0x3C, // #### ####
|
|
||||||
|
|
||||||
// @276 ' ' (4 pixels wide)
|
|
||||||
0x00, 0x00, //
|
|
||||||
0x00, 0x00, //
|
|
||||||
0x00, 0x00, //
|
|
||||||
0x00, 0x00, //
|
|
||||||
|
|
||||||
// @284 '-' (4 pixels wide)
|
|
||||||
0x03, 0xC0, // ####
|
|
||||||
0x03, 0xC0, // ####
|
|
||||||
0x03, 0xC0, // ####
|
|
||||||
0x03, 0xC0, // ####
|
|
||||||
0x03, 0xC0, // ####
|
|
||||||
0x03, 0xC0, // ####
|
|
||||||
0x03, 0xC0, // ####
|
|
||||||
0x03, 0xC0, // ####
|
|
||||||
|
|
||||||
// @300 'F' (9 pixels wide)
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0xFF, 0xFF, // ################
|
|
||||||
0xE3, 0x80, // ### ###
|
|
||||||
0xE3, 0x80, // ### ###
|
|
||||||
0xE3, 0x80, // ### ###
|
|
||||||
0xE3, 0x80, // ### ###
|
|
||||||
0xE3, 0x80, // ### ###
|
|
||||||
0xE3, 0x80, // ### ###
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Character descriptors for Tahoma 16pt
|
|
||||||
// { [Char width in bits], [Char height in bits], [Offset into tahoma_16ptCharBitmaps in bytes] }
|
|
||||||
const FONT_CHAR_INFO tahoma_16ptDescriptors[] PROGMEM =
|
|
||||||
{
|
|
||||||
{4, 16, 276}, // ' '
|
|
||||||
{0, 0, 0}, // '!'
|
|
||||||
{0, 0, 0}, // '"'
|
|
||||||
{0, 0, 0}, // '#'
|
|
||||||
{0, 0, 0}, // '$'
|
|
||||||
{0, 0, 0}, // '%'
|
|
||||||
{0, 0, 0}, // '&'
|
|
||||||
{0, 0, 0}, // '''
|
|
||||||
{0, 0, 0}, // '('
|
|
||||||
{0, 0, 0}, // ')'
|
|
||||||
{0, 0, 0}, // '*'
|
|
||||||
{0, 0, 0}, // '+'
|
|
||||||
{0, 0, 0}, // ,
|
|
||||||
{8, 16, 284}, // -
|
|
||||||
{4, 16, 0}, // '.'
|
|
||||||
{0, 0, 0}, // '/'
|
|
||||||
{11, 16, 8}, // '0'
|
|
||||||
{10, 16, 30}, // '1'
|
|
||||||
{11, 16, 50}, // '2'
|
|
||||||
{11, 16, 72}, // '3'
|
|
||||||
{12, 16, 94}, // '4'
|
|
||||||
{11, 16, 118}, // '5'
|
|
||||||
{11, 16, 140}, // '6'
|
|
||||||
{11, 16, 162}, // '7'
|
|
||||||
{11, 16, 184}, // '8'
|
|
||||||
{11, 16, 206}, // '9'
|
|
||||||
{4, 16, 268}, // ':'
|
|
||||||
{0, 0, 0}, // ';'
|
|
||||||
{0, 0, 0}, // '<'
|
|
||||||
{0, 0, 0}, // '='
|
|
||||||
{0, 0, 0}, // '>'
|
|
||||||
{0, 0, 0}, // '?'
|
|
||||||
{0, 0, 0}, // '@'
|
|
||||||
{0, 0, 0}, // 'A'
|
|
||||||
{0, 0, 0}, // 'B'
|
|
||||||
{12, 16, 244}, // 'C'
|
|
||||||
{0, 0, 0}, // 'D'
|
|
||||||
{0, 0, 0}, // 'E'
|
|
||||||
{10, 16, 300}, // 'F'
|
|
||||||
{0, 0, 0}, // 'G'
|
|
||||||
{0, 0, 0}, // 'H'
|
|
||||||
{0, 0, 0}, // 'I'
|
|
||||||
{0, 0, 0}, // 'J'
|
|
||||||
{0, 0, 0}, // 'K'
|
|
||||||
{0, 0, 0}, // 'L'
|
|
||||||
{0, 0, 0}, // 'M'
|
|
||||||
{0, 0, 0}, // 'N'
|
|
||||||
{0, 0, 0}, // 'O'
|
|
||||||
{0, 0, 0}, // 'P'
|
|
||||||
{0, 0, 0}, // 'Q'
|
|
||||||
{0, 0, 0}, // 'R'
|
|
||||||
{0, 0, 0}, // 'S'
|
|
||||||
{0, 0, 0}, // 'T'
|
|
||||||
{0, 0, 0}, // 'U'
|
|
||||||
{0, 0, 0}, // 'V'
|
|
||||||
{0, 0, 0}, // 'W'
|
|
||||||
{0, 0, 0}, // 'X'
|
|
||||||
{0, 0, 0}, // 'Y'
|
|
||||||
{0, 0, 0}, // 'Z'
|
|
||||||
{0, 0, 0}, // '['
|
|
||||||
{0, 0, 0}, // '\'
|
|
||||||
{0, 0, 0}, // ']'
|
|
||||||
{0, 0, 0}, // '^'
|
|
||||||
{0, 0, 0}, // '_'
|
|
||||||
{8, 16, 228}, // '`' use for degree symbol
|
|
||||||
};
|
|
||||||
|
|
||||||
// Font information for Tahoma 16pt
|
|
||||||
// easier to leave in RAM, not that big anyway
|
|
||||||
const FONT_INFO tahoma_16ptFontInfo =
|
|
||||||
{
|
|
||||||
16, // Character height
|
|
||||||
' ', // Start character
|
|
||||||
'`', // End character
|
|
||||||
2, // Width, in pixels, of space character
|
|
||||||
tahoma_16ptDescriptors, // Character descriptor array
|
|
||||||
tahoma_16ptBitmaps, // Character bitmap array
|
|
||||||
};
|
|
|
@ -1,7 +0,0 @@
|
||||||
#include "FontTypes.h"
|
|
||||||
|
|
||||||
// Font data for Tahoma 16pt
|
|
||||||
extern const uint8_t tahoma_16ptBitmaps[] PROGMEM; // stored in program flash memory
|
|
||||||
extern const FONT_CHAR_INFO tahoma_16ptDescriptors[] PROGMEM; // stored in program flash memory
|
|
||||||
extern const FONT_INFO tahoma_16ptFontInfo;
|
|
||||||
|
|
|
@ -1,252 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 _CPROTOCOL_H_
|
|
||||||
#define _CPROTOCOL_H_
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include "../Utility/UtilClasses.h"
|
|
||||||
|
|
||||||
class CProtocol {
|
|
||||||
public:
|
|
||||||
union {
|
|
||||||
unsigned char Data[24];
|
|
||||||
struct {
|
|
||||||
unsigned char Byte0; // [0] always 0x76
|
|
||||||
unsigned char Len; // [1] always 0x16 == 22
|
|
||||||
unsigned char Command; // [2] transient commands: 00: NOP, 0xa0 START, 0x05: STOP
|
|
||||||
unsigned char ActualTemperature; // [3] 1degC / digit
|
|
||||||
unsigned char DesiredDemand; // [4] typ. 1degC / digit, but also gets used for Fixed Hx demand too!
|
|
||||||
unsigned char MinPumpFreq; // [5] 0.1Hz/digit
|
|
||||||
unsigned char MaxPumpFreq; // [6] 0.1Hz/digit
|
|
||||||
unsigned char MinFanRPM_MSB; // [7] 16 bit - big endian MSB
|
|
||||||
unsigned char MinFanRPM_LSB; // [8] 16 bit - big endian LSB : 1 RPM / digit
|
|
||||||
unsigned char MaxFanRPM_MSB; // [9] 16 bit - big endian MSB
|
|
||||||
unsigned char MaxFanRPM_LSB; // [10] 16 bit - big endian LSB : 1 RPM / digit
|
|
||||||
unsigned char OperatingVoltage; // [11] 120, 240 : 0.1V/digit
|
|
||||||
unsigned char FanSensor; // [12] SN-1 or SN-2
|
|
||||||
unsigned char OperatingMode; // [13] 0x32:Thermostat, 0xCD:Fixed
|
|
||||||
unsigned char MinTemperature; // [14] Minimum settable temperature
|
|
||||||
unsigned char MaxTemperature; // [15] Maximum settable temperature
|
|
||||||
unsigned char GlowDrive; // [16] power to supply to glow plug
|
|
||||||
unsigned char Prime; // [17] 00: normal, 0x5A: fuel prime
|
|
||||||
unsigned char Unknown1_MSB; // [18] always 0x01
|
|
||||||
unsigned char Unknown1_LSB; // [19] always 0x2c "300 secs = max run without burn detected"?
|
|
||||||
unsigned char Unknown2_MSB; // [20] always 0x0d
|
|
||||||
unsigned char Unknown2_LSB; // [21] always 0xac "3500 ?"
|
|
||||||
unsigned char CRC_MSB; // [22]
|
|
||||||
unsigned char CRC_LSB; // [23]
|
|
||||||
} Controller;
|
|
||||||
struct {
|
|
||||||
unsigned char Byte0; // always 0x76
|
|
||||||
unsigned char Len; // always 0x16 == 22 bytes
|
|
||||||
unsigned char RunState; // operating state
|
|
||||||
unsigned char ErrState; // 0: OFF, 1: ON, 2+ (E-0n + 1)
|
|
||||||
unsigned char SupplyV_MSB; // 16 bit - big endian MSB
|
|
||||||
unsigned char SupplyV_LSB; // 16 bit - big endian MSB : 0.1V / digit
|
|
||||||
unsigned char FanRPM_MSB; // 16 bit - big endian MSB
|
|
||||||
unsigned char FanRPM_LSB; // 16 bit - big endian LSB : 1 RPM / digit
|
|
||||||
unsigned char FanVoltage_MSB; // 16 bit - big endian MSB
|
|
||||||
unsigned char FanVoltage_LSB; // 16 bit - big endian LSB : 0.1V / digit
|
|
||||||
unsigned char HeatExchgTemp_MSB; // 16 bit - big endian MSB
|
|
||||||
unsigned char HeatExchgTemp_LSB; // 16 bit - big endian LSB : 1 degC / digit
|
|
||||||
unsigned char GlowPlugVoltage_MSB; // 16 bit - big endian MSB
|
|
||||||
unsigned char GlowPlugVoltage_LSB; // 16 bit - big endian LSB : 0.1V / digit
|
|
||||||
unsigned char GlowPlugCurrent_MSB; // 16 bit - big endian MSB
|
|
||||||
unsigned char GlowPlugCurrent_LSB; // 16 bit - big endian LSB : 10mA / digit
|
|
||||||
unsigned char ActualPumpFreq; // fuel pump freq.: 0.1Hz / digit
|
|
||||||
unsigned char StoredErrorCode; //
|
|
||||||
unsigned char Unknown1; // always 0x00
|
|
||||||
unsigned char FixedPumpFreq; // fixed mode frequency set point: 0.1Hz / digit
|
|
||||||
unsigned char Unknown2; // always 0x64 "100 ?"
|
|
||||||
unsigned char Unknown3; // always 0x00
|
|
||||||
unsigned char CRC_MSB;
|
|
||||||
unsigned char CRC_LSB;
|
|
||||||
} Heater;
|
|
||||||
};
|
|
||||||
static const int CtrlMode = 1;
|
|
||||||
static const int HeatMode = 2;
|
|
||||||
const unsigned short wCRCTable[256] = {
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
CProtocol() { Init(0); };
|
|
||||||
CProtocol(int TxMode) { Init(TxMode); };
|
|
||||||
|
|
||||||
void Init(int Txmode);
|
|
||||||
// CRC handlers
|
|
||||||
unsigned short CalcCRC(int len) const; // calculate the CRC upon len bytes
|
|
||||||
void setCRC(); // calculate and set the CRC in the buffer
|
|
||||||
void setCRC(unsigned short CRC); // set the CRC in the buffer
|
|
||||||
unsigned short getCRC() const; // extract CRC value from buffer
|
|
||||||
bool verifyCRC(bool silent=false) const; // return true for CRC match
|
|
||||||
|
|
||||||
void setActiveMode() { Controller.Byte0 = 0x76; }; // this allows heater to save tuning params to EEPROM
|
|
||||||
void setPassiveMode() { Controller.Byte0 = 0x78; }; // this prevents heater saving tuning params to EEPROM
|
|
||||||
// command helpers
|
|
||||||
void resetCommand() { setRawCommand(0x00); };
|
|
||||||
void onCommand() { setRawCommand(0xA0); };
|
|
||||||
void offCommand() { setRawCommand(0x05); };
|
|
||||||
// raw command
|
|
||||||
int getRawCommand() const { return Controller.Command; };
|
|
||||||
void setRawCommand(int mode) { Controller.Command = mode; };
|
|
||||||
// Run state
|
|
||||||
unsigned char getRunState() const { return Heater.RunState; };
|
|
||||||
void setRunState(unsigned char state) { Heater.RunState = state; };
|
|
||||||
unsigned char getErrState() const { return Heater.ErrState; };
|
|
||||||
void setErrState(unsigned char state) { Heater.ErrState = state; };
|
|
||||||
unsigned char getStoredErrCode() const { return Heater.StoredErrorCode; };
|
|
||||||
void setStoredErrCode(unsigned char state) { Heater.StoredErrorCode = state; };
|
|
||||||
//
|
|
||||||
float getVoltage_Supply() const;
|
|
||||||
float getVoltage_SupplyRaw() const;
|
|
||||||
void setVoltage_Supply(float volts);
|
|
||||||
float getSystemVoltage() const { return float(Controller.OperatingVoltage) * 0.1; };
|
|
||||||
void setSystemVoltage(float val);
|
|
||||||
|
|
||||||
// fan set/get
|
|
||||||
short getFan_Actual() const; // Heater side, actual
|
|
||||||
short getFan_Min() const; // Controller side, define min fan speed
|
|
||||||
short getFan_Max() const; // Controller side, define max fan speed
|
|
||||||
void setFan_Actual(short speed); // Heater side, actual
|
|
||||||
void setFan_Min(short speed); // Controller side, define min fan speed
|
|
||||||
void setFan_Max(short speed); // Controller side, define max fan speed
|
|
||||||
float getFan_Voltage() const; // fan voltage
|
|
||||||
void setFan_Voltage(float volts); // fan voltage
|
|
||||||
|
|
||||||
// pump set/get
|
|
||||||
void setPump_Min(float Freq) { Controller.MinPumpFreq = (uint8_t)(Freq * 10.f + 0.5f); };
|
|
||||||
void setPump_Max(float Freq) { Controller.MaxPumpFreq = (uint8_t)(Freq * 10.f + 0.5f); };
|
|
||||||
void setPump_Actual(float Freq) { Heater.ActualPumpFreq = (uint8_t)(Freq * 10.f + 0.5f); };
|
|
||||||
void setPump_Fixed(float Freq) { Heater.FixedPumpFreq = (uint8_t)(Freq * 10.f + 0.5f); };
|
|
||||||
float getPump_Min() const { return float(Controller.MinPumpFreq) * 0.1f; }; // Tx side, min pump freq
|
|
||||||
float getPump_Max() const { return float(Controller.MaxPumpFreq) * 0.1f; }; // Tx side, max pump freq
|
|
||||||
float getPump_Actual() const { return float(Heater.ActualPumpFreq) * 0.1f; }; // Rx style, actual
|
|
||||||
float getPump_Fixed() const { return float(Heater.FixedPumpFreq) * 0.1f; }; // Fixed mode pump frequency
|
|
||||||
void setPump_Prime(bool on) { Controller.Prime = on ? 0x5A : 0; };
|
|
||||||
// temperature set/get
|
|
||||||
void setHeaterDemand(unsigned char degC) { Controller.DesiredDemand = degC; };
|
|
||||||
void setTemperature_Min(unsigned char degC) { Controller.MinTemperature = degC; };
|
|
||||||
void setTemperature_Max(unsigned char degC) { Controller.MaxTemperature = degC; };
|
|
||||||
void setTemperature_Actual(unsigned char degC) { Controller.ActualTemperature = degC; };
|
|
||||||
unsigned char getHeaterDemand() const { return Controller.DesiredDemand; };
|
|
||||||
unsigned char getTemperature_Min() const { return Controller.MinTemperature; };
|
|
||||||
unsigned char getTemperature_Max() const { return Controller.MaxTemperature; };
|
|
||||||
unsigned char getTemperature_Actual() const { return Controller.ActualTemperature; };
|
|
||||||
void setThermostatModeProtocol(unsigned on);
|
|
||||||
bool isThermostat() const { return Controller.OperatingMode == 0x32; };
|
|
||||||
// glow plug
|
|
||||||
float getGlowPlug_Current() const; // glow plug current
|
|
||||||
float getGlowPlug_Voltage() const; // glow plug voltage
|
|
||||||
void setGlowPlug_Current(short ampsx100); // glow plug current
|
|
||||||
void setGlowPlug_Voltage(short voltsx10); // glow plug voltage
|
|
||||||
void setGlowDrive(unsigned char val) { Controller.GlowDrive = val; };
|
|
||||||
unsigned char getGlowDrive() const { return Controller.GlowDrive; };
|
|
||||||
// heat exchanger
|
|
||||||
short getTemperature_HeatExchg() const; // temperature of heat exchanger
|
|
||||||
void setTemperature_HeatExchg(short degC); // temperature of heat exchanger
|
|
||||||
|
|
||||||
void DebugReport(const char* hdr, const char* ftr);
|
|
||||||
|
|
||||||
CProtocol& operator=(const CProtocol& rhs);
|
|
||||||
};
|
|
||||||
|
|
||||||
class CModeratedFrame : public CProtocol {
|
|
||||||
unsigned long lastTime;
|
|
||||||
public:
|
|
||||||
CModeratedFrame() { lastTime = 0; };
|
|
||||||
void setTime() { lastTime = millis(); };
|
|
||||||
long elapsedTime() { return millis() - lastTime; };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class CProtocolPackage {
|
|
||||||
CProtocol Heater;
|
|
||||||
CProtocol Controller;
|
|
||||||
CContextTimeStamp _timeStamp;
|
|
||||||
public:
|
|
||||||
void set(const CProtocol& htr, const CProtocol& ctl) { Heater = htr; Controller = ctl; };
|
|
||||||
int getRunState() const { return Heater.getRunState(); };
|
|
||||||
int getRunStateEx() const; // extra support for cyclic thermostat mode
|
|
||||||
const char* getRunStateStr() const;
|
|
||||||
int getErrState() const;
|
|
||||||
const char* getErrStateStr() const;
|
|
||||||
const char* getErrStateStrEx() const;
|
|
||||||
float getBattVoltage() const { return Heater.getVoltage_Supply(); };
|
|
||||||
bool isThermostat() const { return Controller.isThermostat(); };
|
|
||||||
float getHeaterDemand() const { return float(Controller.getHeaterDemand()); };
|
|
||||||
float getTemperature_HeatExchg() const { return float(Heater.getTemperature_HeatExchg()); };
|
|
||||||
float getTemperature_Min() const { return float(Controller.getTemperature_Min()); };
|
|
||||||
float getTemperature_Max() const { return float(Controller.getTemperature_Max()); };
|
|
||||||
float getPump_Fixed() const { return Heater.getPump_Fixed(); };
|
|
||||||
float getPump_Actual() const { return Heater.getPump_Actual(); };
|
|
||||||
float getPump_Min() const { return Controller.getPump_Min(); };
|
|
||||||
float getPump_Max() const { return Controller.getPump_Max(); };
|
|
||||||
float getFan_Actual() const { return Heater.getFan_Actual(); };
|
|
||||||
short getFan_Min() const { return Controller.getFan_Min(); };
|
|
||||||
short getFan_Max() const { return Controller.getFan_Max(); };
|
|
||||||
float getFan_Voltage() const { return Heater.getFan_Voltage(); };
|
|
||||||
int getFan_Sensor() const { return Controller.Controller.FanSensor; };
|
|
||||||
float getGlowPlug_Power() const { return Heater.getGlowPlug_Current() * Heater.getGlowPlug_Voltage(); };
|
|
||||||
float getGlow_Voltage() const { return Heater.getGlowPlug_Voltage(); };
|
|
||||||
float getGlow_Current() const { return Heater.getGlowPlug_Current(); };
|
|
||||||
float getSystemVoltage() const { return Controller.getSystemVoltage(); };
|
|
||||||
int getGlow_Drive() const { return Controller.getGlowDrive(); };
|
|
||||||
|
|
||||||
// void setRefTime();
|
|
||||||
void reportFrames(bool isOEM);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const CProtocolPackage& getHeaterInfo();
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,120 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "SmartError.h"
|
|
||||||
#include "TxManage.h"
|
|
||||||
|
|
||||||
CSmartError::CSmartError()
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CSmartError::reset()
|
|
||||||
{
|
|
||||||
m_prevRunState = 0;
|
|
||||||
m_Error = 0;
|
|
||||||
m_bInhibit = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we use inhibit when we manually command the heater off during preheat
|
|
||||||
// otherwise we'll register an ignition fail event
|
|
||||||
void
|
|
||||||
CSmartError::inhibit()
|
|
||||||
{
|
|
||||||
m_bInhibit = true;
|
|
||||||
m_Error = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// accept a fresh heater frame
|
|
||||||
// inpsect the advertised run state, tracking when and how it transitions out
|
|
||||||
// of preheat especially.
|
|
||||||
// abnormal transitions are registered and becoem our smart m_Error
|
|
||||||
// In addition, the hetaer frame has the ErrState updated to track the
|
|
||||||
// smart error, providing no heater error exists!
|
|
||||||
void
|
|
||||||
CSmartError::monitor(const CProtocol& heaterFrame)
|
|
||||||
{
|
|
||||||
bool bSilent = true;
|
|
||||||
if(heaterFrame.verifyCRC(bSilent)) { // check but don't report dodgy frames to debug
|
|
||||||
// only accept valid heater frames!
|
|
||||||
monitor(heaterFrame.getRunState());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// test the new run state value, comparing to previous
|
|
||||||
// detect abnormal transitions
|
|
||||||
void
|
|
||||||
CSmartError::monitor(unsigned char newRunState)
|
|
||||||
{
|
|
||||||
// check if moving away from heater Idle state (S0)
|
|
||||||
// especially useful if an OEM controller exists
|
|
||||||
if((m_prevRunState == 0) && newRunState) {
|
|
||||||
// reset the smart error
|
|
||||||
m_Error = 0;
|
|
||||||
m_bInhibit = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!m_bInhibit) {
|
|
||||||
if(m_prevRunState == 2) { // preheat state (S2)
|
|
||||||
if(newRunState == 4) {
|
|
||||||
// transitioned from preheat to ignited
|
|
||||||
// - all good!
|
|
||||||
m_Error = 0;
|
|
||||||
}
|
|
||||||
else if(newRunState > 5) {
|
|
||||||
// transitioned from preheat to post glow
|
|
||||||
// - second ignition attempt failed, heater is shutting down
|
|
||||||
m_Error = 11;
|
|
||||||
}
|
|
||||||
else if(newRunState == 3) {
|
|
||||||
// transitioned from preheat to retry
|
|
||||||
// - first ignition attempt failed, heater will retry
|
|
||||||
m_Error = 12;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(m_prevRunState != newRunState) {
|
|
||||||
// check for transition to startup
|
|
||||||
// - force cancellation of an on request if we generated it
|
|
||||||
if(newRunState >= 2) {
|
|
||||||
TxManage.queueOnRequest(false); // ensure ON request is cancelled
|
|
||||||
}
|
|
||||||
// check for transition to shutdown
|
|
||||||
// - force cancellation of an off request if we generated it
|
|
||||||
if(newRunState >= 7 || newRunState == 0) {
|
|
||||||
TxManage.queueOffRequest(false); // ensure OFF request is cancelled
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_prevRunState = newRunState;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return our smart error, if it exists, as the registered code
|
|
||||||
unsigned char
|
|
||||||
CSmartError::getError()
|
|
||||||
{
|
|
||||||
if(m_Error) {
|
|
||||||
return m_Error;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,524 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "BTC_JSON.h"
|
|
||||||
#include "DebugPort.h"
|
|
||||||
#include "NVstorage.h"
|
|
||||||
#include "../RTC/BTCDateTime.h"
|
|
||||||
#include "../RTC/Timers.h"
|
|
||||||
#include "../RTC/TimerManager.h"
|
|
||||||
#include "../Bluetooth/BluetoothAbstract.h"
|
|
||||||
#include "../WiFi/BTCWebServer.h"
|
|
||||||
#include "../cfg/BTCConfig.h"
|
|
||||||
#include "macros.h"
|
|
||||||
#include "../Protocol/Protocol.h"
|
|
||||||
|
|
||||||
|
|
||||||
char defaultJSONstr[64];
|
|
||||||
CModerator JSONmoderator;
|
|
||||||
CTimerModerator TimerModerator;
|
|
||||||
int timerConflict = 0;
|
|
||||||
CModerator MQTTmoderator;
|
|
||||||
CModerator GPIOmoderator;
|
|
||||||
|
|
||||||
void validateTimer(int ID);
|
|
||||||
void Expand(std::string& str);
|
|
||||||
|
|
||||||
void interpretJsonCommand(char* pLine)
|
|
||||||
{
|
|
||||||
if(strlen(pLine) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
DebugPort.printf("JSON parse %s...", pLine);
|
|
||||||
|
|
||||||
StaticJsonBuffer<512> jsonBuffer; // create a JSON buffer on the heap
|
|
||||||
JsonObject& obj = jsonBuffer.parseObject(pLine);
|
|
||||||
if(!obj.success()) {
|
|
||||||
DebugPort.println(" FAILED");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DebugPort.println(" OK");
|
|
||||||
|
|
||||||
JsonObject::iterator it;
|
|
||||||
for(it = obj.begin(); it != obj.end(); ++it) {
|
|
||||||
|
|
||||||
if(strcmp("TempDesired", it->key) == 0) {
|
|
||||||
if( !reqTemp(it->value.as<unsigned char>(), false) ) { // this request is blocked if OEM controller active
|
|
||||||
JSONmoderator.reset("TempDesired");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(strcmp("RunState", it->key) == 0) {
|
|
||||||
if(it->value.as<unsigned char>()) {
|
|
||||||
requestOn();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
requestOff();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(strcmp("PumpMin", it->key) == 0) {
|
|
||||||
setPumpMin(it->value.as<float>());
|
|
||||||
}
|
|
||||||
else if(strcmp("PumpMax", it->key) == 0) {
|
|
||||||
setPumpMax(it->value.as<float>());
|
|
||||||
}
|
|
||||||
else if(strcmp("FanMin", it->key) == 0) {
|
|
||||||
setFanMin(it->value.as<short>());
|
|
||||||
}
|
|
||||||
else if(strcmp("FanMax", it->key) == 0) {
|
|
||||||
setFanMax(it->value.as<short>());
|
|
||||||
}
|
|
||||||
else if(strcmp("ThermostatOvertemp", it->key) == 0) {
|
|
||||||
sCyclicThermostat cyclic = NVstore.getCyclicMode();
|
|
||||||
cyclic.Stop = it->value.as<char>();
|
|
||||||
NVstore.setCyclicMode(cyclic);
|
|
||||||
}
|
|
||||||
else if(strcmp("ThermostatUndertemp", it->key) == 0) {
|
|
||||||
sCyclicThermostat cyclic = NVstore.getCyclicMode();
|
|
||||||
cyclic.Start = it->value.as<char>();
|
|
||||||
NVstore.setCyclicMode(cyclic);
|
|
||||||
}
|
|
||||||
else if(strcmp("ThermostatMethod", it->key) == 0) {
|
|
||||||
sUserSettings settings = NVstore.getUserSettings();
|
|
||||||
uint8_t val = it->value.as<uint8_t>();
|
|
||||||
if(val <= 2)
|
|
||||||
settings.ThermostatMethod = val;
|
|
||||||
NVstore.setUserSettings(settings);
|
|
||||||
}
|
|
||||||
else if(strcmp("ThermostatWindow", it->key) == 0) {
|
|
||||||
sUserSettings settings = NVstore.getUserSettings();
|
|
||||||
float val = it->value.as<float>();
|
|
||||||
if(INBOUNDS(val, 0.2f, 10.f))
|
|
||||||
settings.ThermostatWindow = val;
|
|
||||||
NVstore.setUserSettings(settings);
|
|
||||||
}
|
|
||||||
else if(strcmp("Thermostat", it->key) == 0) {
|
|
||||||
if(!setThermostatMode(it->value.as<unsigned char>())) { // this request is blocked if OEM controller active
|
|
||||||
JSONmoderator.reset("ThermoStat");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(strcmp("NVsave", it->key) == 0) {
|
|
||||||
if(it->value.as<int>() == 8861)
|
|
||||||
saveNV();
|
|
||||||
}
|
|
||||||
else if(strcmp("DateTime", it->key) == 0) {
|
|
||||||
setDateTime(it->value.as<const char*>());
|
|
||||||
}
|
|
||||||
else if(strcmp("Date", it->key) == 0) {
|
|
||||||
setDate(it->value.as<const char*>());
|
|
||||||
}
|
|
||||||
else if(strcmp("Time", it->key) == 0) {
|
|
||||||
setTime(it->value.as<const char*>());
|
|
||||||
}
|
|
||||||
else if(strcmp("PumpPrime", it->key) == 0) {
|
|
||||||
reqPumpPrime(it->value.as<unsigned char>());
|
|
||||||
}
|
|
||||||
else if(strcmp("Refresh", it->key) == 0) {
|
|
||||||
resetJSONmoderator();
|
|
||||||
}
|
|
||||||
else if(strcmp("SystemVoltage", it->key) == 0) {
|
|
||||||
setSystemVoltage(it->value.as<float>());
|
|
||||||
}
|
|
||||||
else if(strcmp("TimerDays", it->key) == 0) {
|
|
||||||
// value encoded as "ID Days,Days"
|
|
||||||
decodeJSONTimerDays(it->value.as<const char*>());
|
|
||||||
}
|
|
||||||
else if(strcmp("TimerStart", it->key) == 0) {
|
|
||||||
// value encoded as "ID HH:MM"
|
|
||||||
decodeJSONTimerTime(0, it->value.as<const char*>());
|
|
||||||
}
|
|
||||||
else if(strcmp("TimerStop", it->key) == 0) {
|
|
||||||
// value encoded as "ID HH:MM"
|
|
||||||
decodeJSONTimerTime(1, it->value.as<const char*>());
|
|
||||||
}
|
|
||||||
else if(strcmp("TimerRepeat", it->key) == 0) {
|
|
||||||
// value encoded as "ID val"
|
|
||||||
decodeJSONTimerNumeric(0, it->value.as<const char*>());
|
|
||||||
}
|
|
||||||
else if(strcmp("TimerTemp", it->key) == 0) {
|
|
||||||
decodeJSONTimerNumeric(1, it->value.as<const char*>());
|
|
||||||
}
|
|
||||||
else if(strcmp("TimerConflict", it->key) == 0) {
|
|
||||||
validateTimer(it->value.as<int>());
|
|
||||||
}
|
|
||||||
// request specific timer refresh
|
|
||||||
else if((strcmp("TQuery", it->key) == 0) || (strcmp("TimerRefresh", it->key) == 0) ) {
|
|
||||||
int timerID = it->value.as<int>();
|
|
||||||
if(timerID)
|
|
||||||
TimerModerator.reset(timerID-1);
|
|
||||||
else
|
|
||||||
TimerModerator.reset();
|
|
||||||
}
|
|
||||||
else if(strcmp("FanSensor", it->key) == 0) {
|
|
||||||
setFanSensor(it->value.as<unsigned char>());
|
|
||||||
}
|
|
||||||
// MQTT parameters
|
|
||||||
else if(strcmp("MQuery", it->key) == 0) {
|
|
||||||
MQTTmoderator.reset(); // force MQTT params to be sent
|
|
||||||
}
|
|
||||||
else if(strcmp("MEn", it->key) == 0) {
|
|
||||||
sMQTTparams info = NVstore.getMQTTinfo();
|
|
||||||
info.enabled = it->value.as<unsigned char>();
|
|
||||||
NVstore.setMQTTinfo(info);
|
|
||||||
}
|
|
||||||
else if(strcmp("MPort", it->key) == 0) {
|
|
||||||
sMQTTparams info = NVstore.getMQTTinfo();
|
|
||||||
info.port = it->value.as<unsigned short>();
|
|
||||||
NVstore.setMQTTinfo(info);
|
|
||||||
}
|
|
||||||
else if(strcmp("MHost", it->key) == 0) {
|
|
||||||
sMQTTparams info = NVstore.getMQTTinfo();
|
|
||||||
strncpy(info.host, it->value.as<const char*>(), 127);
|
|
||||||
info.host[127] = 0;
|
|
||||||
NVstore.setMQTTinfo(info);
|
|
||||||
}
|
|
||||||
else if(strcmp("MUser", it->key) == 0) {
|
|
||||||
sMQTTparams info = NVstore.getMQTTinfo();
|
|
||||||
strncpy(info.username, it->value.as<const char*>(), 31);
|
|
||||||
info.username[31] = 0;
|
|
||||||
NVstore.setMQTTinfo(info);
|
|
||||||
}
|
|
||||||
else if(strcmp("MPasswd", it->key) == 0) {
|
|
||||||
sMQTTparams info = NVstore.getMQTTinfo();
|
|
||||||
strncpy(info.password, it->value.as<const char*>(), 31);
|
|
||||||
info.password[31] = 0;
|
|
||||||
NVstore.setMQTTinfo(info);
|
|
||||||
}
|
|
||||||
else if(strcmp("UploadSize", it->key) == 0) {
|
|
||||||
setUploadSize(it->value.as<long>());
|
|
||||||
}
|
|
||||||
else if(strcmp("GPout1", it->key) == 0) {
|
|
||||||
setGPIOout(0, it->value.as<unsigned char>() ? true : false);
|
|
||||||
}
|
|
||||||
else if(strcmp("GPout2", it->key) == 0) {
|
|
||||||
setGPIOout(1, it->value.as<unsigned char>() ? true : false);
|
|
||||||
}
|
|
||||||
else if(strcmp("GPin1", it->key) == 0) {
|
|
||||||
simulateGPIOin(it->value.as<unsigned char>() ? 0x01 : 0x00); // simulate key 1 press
|
|
||||||
}
|
|
||||||
else if(strcmp("GPin2", it->key) == 0) {
|
|
||||||
simulateGPIOin(it->value.as<unsigned char>() ? 0x02 : 0x00); // simulate key 2 press
|
|
||||||
}
|
|
||||||
else if(strcmp("JSONloose", it->key) == 0) {
|
|
||||||
sUserSettings us = NVstore.getUserSettings();
|
|
||||||
uint8_t loose = it->value.as<unsigned char>() ? 0x01 : 0x00;
|
|
||||||
us.JSON.LF = loose;
|
|
||||||
us.JSON.padding = loose;
|
|
||||||
us.JSON.singleElement = loose;
|
|
||||||
NVstore.setUserSettings(us);
|
|
||||||
NVstore.save();
|
|
||||||
resetJSONmoderator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void validateTimer(int ID)
|
|
||||||
{
|
|
||||||
ID--; // supplied as +1
|
|
||||||
if(!INBOUNDS(ID, 0, 13))
|
|
||||||
return;
|
|
||||||
|
|
||||||
timerConflict = CTimerManager::conflictTest(ID); // check targeted timer against other timers
|
|
||||||
|
|
||||||
TimerModerator.reset(ID); // ensure we update client with our (real) version of the selected timer
|
|
||||||
}
|
|
||||||
|
|
||||||
bool makeJSONString(CModerator& moderator, char* opStr, int len)
|
|
||||||
{
|
|
||||||
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
|
|
||||||
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
|
|
||||||
|
|
||||||
bool bSend = false; // reset should send flag
|
|
||||||
|
|
||||||
float tidyTemp = getTemperatureSensor();
|
|
||||||
tidyTemp = int(tidyTemp * 10) * 0.1f; // round to 0.1 resolution
|
|
||||||
if(tidyTemp > -80) {
|
|
||||||
bSend |= moderator.addJson("TempCurrent", tidyTemp, root);
|
|
||||||
}
|
|
||||||
bSend |= moderator.addJson("TempDesired", getTemperatureDesired(), root);
|
|
||||||
bSend |= moderator.addJson("TempMin", getHeaterInfo().getTemperature_Min(), root);
|
|
||||||
bSend |= moderator.addJson("TempMax", getHeaterInfo().getTemperature_Max(), root);
|
|
||||||
bSend |= moderator.addJson("TempBody", getHeaterInfo().getTemperature_HeatExchg(), root);
|
|
||||||
// bSend |= moderator.addJson("RunState", getHeaterInfo().getRunState(), root);
|
|
||||||
bSend |= moderator.addJson("RunState", getHeaterInfo().getRunStateEx(), root);
|
|
||||||
bSend |= moderator.addJson("RunString", getHeaterInfo().getRunStateStr(), root); // verbose it up!
|
|
||||||
bSend |= moderator.addJson("ErrorState", getHeaterInfo().getErrState(), root );
|
|
||||||
bSend |= moderator.addJson("ErrorString", getHeaterInfo().getErrStateStrEx(), root); // verbose it up!
|
|
||||||
bSend |= moderator.addJson("Thermostat", getThermostatModeActive(), root );
|
|
||||||
bSend |= moderator.addJson("PumpFixed", getHeaterInfo().getPump_Fixed(), root );
|
|
||||||
bSend |= moderator.addJson("PumpMin", getHeaterInfo().getPump_Min(), root );
|
|
||||||
bSend |= moderator.addJson("PumpMax", getHeaterInfo().getPump_Max(), root );
|
|
||||||
bSend |= moderator.addJson("PumpActual", getHeaterInfo().getPump_Actual(), root );
|
|
||||||
bSend |= moderator.addJson("FanMin", getHeaterInfo().getFan_Min(), root );
|
|
||||||
bSend |= moderator.addJson("FanMax", getHeaterInfo().getFan_Max(), root );
|
|
||||||
bSend |= moderator.addJson("FanRPM", getHeaterInfo().getFan_Actual(), root );
|
|
||||||
bSend |= moderator.addJson("FanVoltage", getHeaterInfo().getFan_Voltage(), root );
|
|
||||||
bSend |= moderator.addJson("FanSensor", getHeaterInfo().getFan_Sensor(), root );
|
|
||||||
bSend |= moderator.addJson("InputVoltage", getHeaterInfo().getBattVoltage(), root );
|
|
||||||
bSend |= moderator.addJson("SystemVoltage", getHeaterInfo().getSystemVoltage(), root );
|
|
||||||
bSend |= moderator.addJson("GlowVoltage", getHeaterInfo().getGlow_Voltage(), root );
|
|
||||||
bSend |= moderator.addJson("GlowCurrent", getHeaterInfo().getGlow_Current(), root );
|
|
||||||
bSend |= moderator.addJson("BluewireStat", getBlueWireStatStr(), root );
|
|
||||||
bSend |= moderator.addJson("TempMode", NVstore.getUserSettings().degF, root);
|
|
||||||
|
|
||||||
if(bSend) {
|
|
||||||
root.printTo(opStr, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bSend;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool makeJSONStringEx(CModerator& moderator, char* opStr, int len)
|
|
||||||
{
|
|
||||||
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
|
|
||||||
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
|
|
||||||
|
|
||||||
bool bSend = false; // reset should send flag
|
|
||||||
|
|
||||||
bSend |= moderator.addJson("ThermostatMethod", NVstore.getUserSettings().ThermostatMethod, root);
|
|
||||||
bSend |= moderator.addJson("ThermostatWindow", NVstore.getUserSettings().ThermostatWindow, root);
|
|
||||||
bSend |= moderator.addJson("ThermostatOvertemp", NVstore.getCyclicMode().Stop, root);
|
|
||||||
bSend |= moderator.addJson("ThermostatUndertemp", NVstore.getCyclicMode().Start, root);
|
|
||||||
|
|
||||||
if(bSend) {
|
|
||||||
root.printTo(opStr, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bSend;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the way the JSON timer strings are crafted, we have to iterate over each timer's parameters
|
|
||||||
// individually, the JSON name is always the same for each timer, the payload IDs the specific
|
|
||||||
// timer
|
|
||||||
// Only timer parameters that have changed will be sent, after reset the typical string will be
|
|
||||||
// {"TimerStart":XX:XX,"TimerStop":XX:XX,"TimerDays":XX,"TimerRepeat":X}
|
|
||||||
bool makeJSONTimerString(int channel, char* opStr, int len)
|
|
||||||
{
|
|
||||||
bool bSend = false; // reset should send flag
|
|
||||||
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
|
|
||||||
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
|
|
||||||
|
|
||||||
|
|
||||||
sTimer timerInfo;
|
|
||||||
NVstore.getTimerInfo(channel, timerInfo);
|
|
||||||
bSend |= TimerModerator.addJson(channel, timerInfo, root );
|
|
||||||
|
|
||||||
if(bSend) {
|
|
||||||
root.printTo(opStr, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bSend;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool makeJSONStringGPIO(CModerator& moderator, char* opStr, int len)
|
|
||||||
{
|
|
||||||
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
|
|
||||||
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
|
|
||||||
|
|
||||||
bool bSend = false; // reset should send flag
|
|
||||||
|
|
||||||
sGPIO info;
|
|
||||||
getGPIOinfo(info);
|
|
||||||
|
|
||||||
bSend |= moderator.addJson("GPin1", info.inState[0], root);
|
|
||||||
bSend |= moderator.addJson("GPin2", info.inState[1], root);
|
|
||||||
bSend |= moderator.addJson("GPout1", info.outState[0], root);
|
|
||||||
bSend |= moderator.addJson("GPout2", info.outState[1], root);
|
|
||||||
bSend |= moderator.addJson("GPanlg", info.algVal * 100 / 4096, root);
|
|
||||||
bSend |= moderator.addJson("GPmodeIn", GPIOinNames[info.inMode], root);
|
|
||||||
bSend |= moderator.addJson("GPmodeOut", GPIOoutNames[info.outMode], root);
|
|
||||||
bSend |= moderator.addJson("GPmodeAnlg", GPIOalgNames[info.algMode], root);
|
|
||||||
|
|
||||||
if(bSend) {
|
|
||||||
root.printTo(opStr, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bSend;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool makeJSONStringMQTT(CModerator& moderator, char* opStr, int len)
|
|
||||||
{
|
|
||||||
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
|
|
||||||
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
|
|
||||||
|
|
||||||
bool bSend = false; // reset should send flag
|
|
||||||
sMQTTparams info = NVstore.getMQTTinfo();
|
|
||||||
|
|
||||||
bSend |= moderator.addJson("MEn", info.enabled, root);
|
|
||||||
bSend |= moderator.addJson("MPort", info.port, root);
|
|
||||||
bSend |= moderator.addJson("MHost", info.host, root);
|
|
||||||
bSend |= moderator.addJson("MUser", info.username, root);
|
|
||||||
bSend |= moderator.addJson("MPasswd", info.password, root);
|
|
||||||
|
|
||||||
if(bSend) {
|
|
||||||
root.printTo(opStr, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bSend;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void updateJSONclients(bool report)
|
|
||||||
{
|
|
||||||
// update general parameters
|
|
||||||
char jsonStr[800];
|
|
||||||
{
|
|
||||||
if(makeJSONString(JSONmoderator, jsonStr, sizeof(jsonStr))) {
|
|
||||||
if (report) {
|
|
||||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
|
||||||
}
|
|
||||||
sendWebServerString( jsonStr );
|
|
||||||
std::string expand = jsonStr;
|
|
||||||
Expand(expand);
|
|
||||||
getBluetoothClient().send( expand.c_str() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// update extended params
|
|
||||||
{
|
|
||||||
if(makeJSONStringEx(JSONmoderator, jsonStr, sizeof(jsonStr))) {
|
|
||||||
if (report) {
|
|
||||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
|
||||||
}
|
|
||||||
sendWebServerString( jsonStr );
|
|
||||||
std::string expand = jsonStr;
|
|
||||||
Expand(expand);
|
|
||||||
getBluetoothClient().send( expand.c_str() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// update timer parameters
|
|
||||||
bool bNewTimerInfo = false;
|
|
||||||
for(int tmr=0; tmr<14; tmr++)
|
|
||||||
{
|
|
||||||
unsigned long tStart = millis();
|
|
||||||
if(makeJSONTimerString(tmr, jsonStr, sizeof(jsonStr))) {
|
|
||||||
unsigned long tJSON = millis() - tStart;
|
|
||||||
if (report) {
|
|
||||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
|
||||||
}
|
|
||||||
tStart = millis();
|
|
||||||
sendWebServerString( jsonStr );
|
|
||||||
unsigned long tWF = millis() - tStart;
|
|
||||||
tStart = millis();
|
|
||||||
std::string expand = jsonStr;
|
|
||||||
Expand(expand);
|
|
||||||
getBluetoothClient().send( expand.c_str() );
|
|
||||||
unsigned long tBT = millis() - tStart;
|
|
||||||
bNewTimerInfo = true;
|
|
||||||
DebugPort.printf("JSON times : %ld,%ld,%ld\r\n", tJSON, tBT, tWF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// request timer refesh upon clients
|
|
||||||
if(bNewTimerInfo) {
|
|
||||||
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
|
|
||||||
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
|
|
||||||
|
|
||||||
if(timerConflict) {
|
|
||||||
root.set("TimerConflict", timerConflict);
|
|
||||||
timerConflict = 0;
|
|
||||||
}
|
|
||||||
root.set("TimerRefresh", 1);
|
|
||||||
root.printTo(jsonStr, 800);
|
|
||||||
|
|
||||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
|
||||||
sendWebServerString( jsonStr );
|
|
||||||
std::string expand = jsonStr;
|
|
||||||
Expand(expand);
|
|
||||||
getBluetoothClient().send( expand.c_str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
// report MQTT params
|
|
||||||
{
|
|
||||||
if(makeJSONStringMQTT(MQTTmoderator, jsonStr, sizeof(jsonStr))) {
|
|
||||||
if (report) {
|
|
||||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
|
||||||
}
|
|
||||||
sendWebServerString( jsonStr );
|
|
||||||
std::string expand = jsonStr;
|
|
||||||
Expand(expand);
|
|
||||||
getBluetoothClient().send( expand.c_str() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
if(makeJSONStringGPIO(GPIOmoderator, jsonStr, sizeof(jsonStr))) {
|
|
||||||
if (report) {
|
|
||||||
DebugPort.printf("JSON send: %s\r\n", jsonStr);
|
|
||||||
}
|
|
||||||
sendWebServerString( jsonStr );
|
|
||||||
std::string expand = jsonStr;
|
|
||||||
Expand(expand);
|
|
||||||
getBluetoothClient().send( expand.c_str() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void resetJSONmoderator()
|
|
||||||
{
|
|
||||||
JSONmoderator.reset();
|
|
||||||
#ifdef SALWAYS_SEND_TIMERS
|
|
||||||
TimerModerator.reset();
|
|
||||||
#else
|
|
||||||
initTimerJSONmoderator();
|
|
||||||
#endif
|
|
||||||
initMQTTJSONmoderator();
|
|
||||||
GPIOmoderator.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void initMQTTJSONmoderator()
|
|
||||||
{
|
|
||||||
char jsonStr[800];
|
|
||||||
makeJSONStringMQTT(MQTTmoderator, jsonStr, sizeof(jsonStr));
|
|
||||||
}
|
|
||||||
|
|
||||||
void initTimerJSONmoderator()
|
|
||||||
{
|
|
||||||
char jsonStr[800];
|
|
||||||
for(int tmr=0; tmr<14; tmr++)
|
|
||||||
makeJSONTimerString(tmr, jsonStr, sizeof(jsonStr));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Expand(std::string& str)
|
|
||||||
{
|
|
||||||
const sUserSettings& userOptions = NVstore.getUserSettings();
|
|
||||||
|
|
||||||
if(userOptions.JSON.singleElement) {
|
|
||||||
size_t pos = str.find(",\"");
|
|
||||||
while(pos != std::string::npos) {
|
|
||||||
if(userOptions.JSON.LF)
|
|
||||||
str.replace(pos, 2, "}\n{\""); // converts {"name":value,"name2":value"} to {"name":value}\n{"name2":value}
|
|
||||||
else
|
|
||||||
str.replace(pos, 2, "}{\""); // converts {"name":value,"name2":value"} to {"name":value}{"name2":value}
|
|
||||||
pos = str.find(",\"");
|
|
||||||
}
|
|
||||||
if(userOptions.JSON.padding) { // converts {"name":value} to {"name": value}
|
|
||||||
pos = str.find("\":");
|
|
||||||
while(pos != std::string::npos) {
|
|
||||||
str.replace(pos, 2, "\": ");
|
|
||||||
pos = str.find("\":", pos+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(userOptions.JSON.LF)
|
|
||||||
str.append("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,424 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "GPIO.h"
|
|
||||||
#include "../Utility/helpers.h"
|
|
||||||
#include <driver/adc.h>
|
|
||||||
#include "DebugPort.h"
|
|
||||||
#include "../Protocol/Protocol.h"
|
|
||||||
|
|
||||||
const int BREATHINTERVAL = 45;
|
|
||||||
const int FADEAMOUNT = 3;
|
|
||||||
const int FLASHPERIOD = 2000;
|
|
||||||
const int ONFLASHINTERVAL = 50;
|
|
||||||
|
|
||||||
const char* GPIOinNames[4] = {
|
|
||||||
"Disabled",
|
|
||||||
"On1Off2",
|
|
||||||
"Hold1",
|
|
||||||
"On1Off1"
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* GPIOoutNames[3] = {
|
|
||||||
"Disabled",
|
|
||||||
"Status",
|
|
||||||
"User"
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* GPIOalgNames[2] = {
|
|
||||||
"Disabled",
|
|
||||||
"HeatDemand"
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
CGPIOin::CGPIOin()
|
|
||||||
{
|
|
||||||
_Mode = GPIOinNone;
|
|
||||||
_lastKey = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOin::begin(int pin1, int pin2, GPIOinModes mode, int activeState)
|
|
||||||
{
|
|
||||||
_Debounce.addPin(pin1);
|
|
||||||
_Debounce.addPin(pin2);
|
|
||||||
_Debounce.setActiveState(activeState);
|
|
||||||
|
|
||||||
setMode(mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t
|
|
||||||
CGPIOin::getState(int channel)
|
|
||||||
{
|
|
||||||
uint8_t retval = 0;
|
|
||||||
|
|
||||||
if((channel & ~0x01) == 0) {
|
|
||||||
// index is in bounds 0 or 1
|
|
||||||
|
|
||||||
// check for transient events
|
|
||||||
if(_eventList[channel].empty()) {
|
|
||||||
// read last actual state
|
|
||||||
int mask = 0x01 << (channel & 0x01);
|
|
||||||
retval = (_Debounce.getState() & mask) != 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// emit transient events if they occured
|
|
||||||
retval = _eventList[channel].front() != 0;
|
|
||||||
_eventList[channel].pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
GPIOinModes CGPIOin::getMode() const
|
|
||||||
{
|
|
||||||
return _Mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOin::manage()
|
|
||||||
{
|
|
||||||
uint8_t newKey = _Debounce.manage();
|
|
||||||
// determine edge events
|
|
||||||
uint8_t keyChange = newKey ^ _lastKey;
|
|
||||||
_lastKey = newKey;
|
|
||||||
|
|
||||||
if(keyChange) {
|
|
||||||
simulateKey(newKey);
|
|
||||||
|
|
||||||
// record possible sub sample transients - JSON usage especially
|
|
||||||
if(keyChange & 0x01)
|
|
||||||
_eventList[0].push_back(newKey & 0x01); // mask the channel bit
|
|
||||||
if(keyChange & 0x02)
|
|
||||||
_eventList[1].push_back(newKey & 0x02); // mask the channel bit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOin::simulateKey(uint8_t newKey)
|
|
||||||
{
|
|
||||||
switch (_Mode) {
|
|
||||||
case GPIOinNone:
|
|
||||||
break;
|
|
||||||
case GPIOinOn1Off2:
|
|
||||||
_doOn1Off2(newKey);
|
|
||||||
break;
|
|
||||||
case GPIOinOnHold1:
|
|
||||||
_doOnHold1(newKey);
|
|
||||||
break;
|
|
||||||
case GPIOinOn1Off1:
|
|
||||||
_doOn1Off1(newKey);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOin::_doOn1Off2(uint8_t newKey)
|
|
||||||
{
|
|
||||||
if(newKey & 0x01) {
|
|
||||||
requestOn();
|
|
||||||
}
|
|
||||||
if(newKey & 0x02) {
|
|
||||||
requestOff();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mode where heater runs if input 1 is shorted
|
|
||||||
// stops when open
|
|
||||||
void
|
|
||||||
CGPIOin::_doOnHold1(uint8_t newKey)
|
|
||||||
{
|
|
||||||
if(newKey & 0x01) {
|
|
||||||
requestOn();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
requestOff();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mode where heater runs if input 1 is shorted
|
|
||||||
// stops when open
|
|
||||||
void
|
|
||||||
CGPIOin::_doOn1Off1(uint8_t newKey)
|
|
||||||
{
|
|
||||||
if(newKey & 0x01) {
|
|
||||||
if(getHeaterInfo().getRunStateEx())
|
|
||||||
requestOff();
|
|
||||||
else
|
|
||||||
requestOn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CGPIOout::CGPIOout()
|
|
||||||
{
|
|
||||||
_Mode = GPIOoutNone;
|
|
||||||
_pins[0] = 0;
|
|
||||||
_pins[1] = 0;
|
|
||||||
_breatheDelay = 0;
|
|
||||||
_statusState = 0;
|
|
||||||
_statusDelay = 0;
|
|
||||||
_userState = 0;
|
|
||||||
_prevState = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOout::begin(int pin1, int pin2, GPIOoutModes mode)
|
|
||||||
{
|
|
||||||
_pins[0] = pin1;
|
|
||||||
_pins[1] = pin2;
|
|
||||||
if(pin1) {
|
|
||||||
pinMode(pin1, OUTPUT); // GPIO output pin #1
|
|
||||||
digitalWrite(pin1, LOW);
|
|
||||||
ledcSetup(0, 500, 8); // create PWM channel for GPIO1: 500Hz, 8 bits
|
|
||||||
}
|
|
||||||
if(pin2) {
|
|
||||||
pinMode(pin2, OUTPUT); // GPIO output pin #2
|
|
||||||
digitalWrite(pin2, LOW);
|
|
||||||
ledcSetup(1, 500, 8); // create PWM channel for GPIO2: 500Hz, 8 bits
|
|
||||||
}
|
|
||||||
|
|
||||||
setMode(mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOout::setMode(GPIOoutModes mode)
|
|
||||||
{
|
|
||||||
_Mode = mode;
|
|
||||||
_prevState = -1;
|
|
||||||
ledcDetachPin(_pins[0]); // ensure PWM detached from IO line
|
|
||||||
ledcDetachPin(_pins[1]); // ensure PWM detached from IO line
|
|
||||||
};
|
|
||||||
|
|
||||||
GPIOoutModes CGPIOout::getMode() const
|
|
||||||
{
|
|
||||||
return _Mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOout::manage()
|
|
||||||
{
|
|
||||||
switch (_Mode) {
|
|
||||||
case GPIOoutNone: break;
|
|
||||||
case GPIOoutStatus: _doStatus(); break;
|
|
||||||
case GPIOoutUser: _doUser(); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOout::_doStatus()
|
|
||||||
{
|
|
||||||
if(_pins[0] == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// DebugPort.println("GPIOout::_doStatus()");
|
|
||||||
int runstate = getHeaterInfo().getRunStateEx();
|
|
||||||
int statusMode = 0;
|
|
||||||
switch(runstate) {
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
case 9:
|
|
||||||
// starting modes
|
|
||||||
statusMode = 1;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
// run mode
|
|
||||||
statusMode = 2;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
case 7:
|
|
||||||
case 8:
|
|
||||||
case 11:
|
|
||||||
case 12:
|
|
||||||
// cooldown modes
|
|
||||||
statusMode = 3;
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
// suspend mode
|
|
||||||
statusMode = 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// change of mode typically requires changing from simple digital out
|
|
||||||
// to PWM or vice versa
|
|
||||||
if(_prevState != statusMode) {
|
|
||||||
_prevState = statusMode;
|
|
||||||
_statusState = 0;
|
|
||||||
_statusDelay = millis() + BREATHINTERVAL;
|
|
||||||
switch(statusMode) {
|
|
||||||
case 0:
|
|
||||||
ledcDetachPin(_pins[0]); // detach PWM from IO line
|
|
||||||
digitalWrite(_pins[0], LOW);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
ledcAttachPin(_pins[0], 0); // attach PWM to GPIO line
|
|
||||||
ledcWrite(0, _statusState);
|
|
||||||
_breatheDelay = millis() + BREATHINTERVAL;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
ledcDetachPin(_pins[0]); // detach PWM from IO line
|
|
||||||
digitalWrite(_pins[0], HIGH);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
ledcAttachPin(_pins[0], 0); // attach PWM to GPIO line
|
|
||||||
_statusState = 255;
|
|
||||||
ledcWrite(0, _statusState);
|
|
||||||
_breatheDelay = millis() + BREATHINTERVAL;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
ledcDetachPin(_pins[0]); // detach PWM from IO line
|
|
||||||
_breatheDelay += (FLASHPERIOD - ONFLASHINTERVAL); // extended off
|
|
||||||
digitalWrite(_pins[0], LOW);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch(statusMode) {
|
|
||||||
case 1: _doStartMode(); break;
|
|
||||||
case 3: _doStopMode(); break;
|
|
||||||
case 4: _doSuspendMode(); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOout::_doUser()
|
|
||||||
{
|
|
||||||
// DebugPort.println("GPIOout::_doUser()");
|
|
||||||
if(_pins[0]) {
|
|
||||||
digitalWrite(_pins[0], (_userState & 0x01) ? HIGH : LOW);
|
|
||||||
}
|
|
||||||
if(_pins[1]) {
|
|
||||||
digitalWrite(_pins[1], (_userState & 0x02) ? HIGH : LOW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOout::_doStartMode() // breath up PWM
|
|
||||||
{
|
|
||||||
long tDelta = millis() - _breatheDelay;
|
|
||||||
if(tDelta >= 0) {
|
|
||||||
_breatheDelay += BREATHINTERVAL;
|
|
||||||
int expo = ((_statusState >> 5) + 1);
|
|
||||||
_statusState += expo;
|
|
||||||
_statusState &= 0xff;
|
|
||||||
ledcWrite(0, _statusState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOout::_doStopMode() // breath down PWM
|
|
||||||
{
|
|
||||||
long tDelta = millis() - _breatheDelay;
|
|
||||||
if(tDelta >= 0) {
|
|
||||||
_breatheDelay += BREATHINTERVAL;
|
|
||||||
int expo = ((_statusState >> 5) + 1);
|
|
||||||
_statusState -= expo;
|
|
||||||
_statusState &= 0xff;
|
|
||||||
ledcWrite(0, _statusState);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOout::_doSuspendMode() // brief flash
|
|
||||||
{
|
|
||||||
long tDelta = millis() - _breatheDelay;
|
|
||||||
if(tDelta >= 0) {
|
|
||||||
_statusState++;
|
|
||||||
if(_statusState & 0x01) {
|
|
||||||
_breatheDelay += ONFLASHINTERVAL; // brief flash on
|
|
||||||
digitalWrite(_pins[0], HIGH);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_breatheDelay += (FLASHPERIOD - ONFLASHINTERVAL); // extended off
|
|
||||||
digitalWrite(_pins[0], LOW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOout::setState(int channel, bool state)
|
|
||||||
{
|
|
||||||
int mask = 0x01 << (channel & 0x01);
|
|
||||||
if(state)
|
|
||||||
_userState |= mask;
|
|
||||||
else
|
|
||||||
_userState &= ~mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CGPIOout::getState(int channel)
|
|
||||||
{
|
|
||||||
int mask = 0x01 << (channel & 0x01);
|
|
||||||
return (_userState & mask) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// expected external analogue circuit is a 10k pot.
|
|
||||||
// Top end of pot is connected to GPIO Vcc (red wire) via 5k6 fixed resistor. (GPIO Vcc is 5V via schottky diode)
|
|
||||||
// Bottom end of pot is connected to GND (black wire) via 1k fixed resistor.
|
|
||||||
// Wiper is into Pin 6 of GPIO (white wire) - analogue input
|
|
||||||
|
|
||||||
CGPIOalg::CGPIOalg()
|
|
||||||
{
|
|
||||||
_expMean = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CGPIOalg::begin(adc1_channel_t pin, GPIOalgModes mode)
|
|
||||||
{
|
|
||||||
_pin = pin;
|
|
||||||
_Mode = mode;
|
|
||||||
|
|
||||||
if(_Mode != GPIOalgNone) {
|
|
||||||
adc_gpio_init(ADC_UNIT_1, ADC_CHANNEL_5);
|
|
||||||
adc1_config_width(ADC_WIDTH_BIT_12);
|
|
||||||
adc1_config_channel_atten(ADC1_CHANNEL_5, ADC_ATTEN_11db);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GPIOalgModes CGPIOalg::getMode() const
|
|
||||||
{
|
|
||||||
return _Mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void CGPIOalg::manage()
|
|
||||||
{
|
|
||||||
const float fAlpha = 0.95; // exponential mean alpha
|
|
||||||
|
|
||||||
if(_Mode != GPIOalgNone) {
|
|
||||||
int read_raw;
|
|
||||||
char msg[32];
|
|
||||||
read_raw = adc1_get_raw( ADC1_CHANNEL_5);
|
|
||||||
sprintf(msg, "ADC: %d", read_raw );
|
|
||||||
_expMean = _expMean * fAlpha + (1-fAlpha) * float(read_raw);
|
|
||||||
// DebugPort.println(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
CGPIOalg::getValue()
|
|
||||||
{
|
|
||||||
return _expMean;
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 __BTCGPIO_H__
|
|
||||||
#define __BTCGPIO_H__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <driver/adc.h>
|
|
||||||
#include "Debounce.h"
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
extern const char* GPIOinNames[4];
|
|
||||||
extern const char* GPIOoutNames[3];
|
|
||||||
extern const char* GPIOalgNames[2];
|
|
||||||
|
|
||||||
enum GPIOinModes {
|
|
||||||
GPIOinNone,
|
|
||||||
GPIOinOn1Off2, // input 1 closure, heater starts; input2 closure, heater stops
|
|
||||||
GPIOinOnHold1, // hold input 1 closure, heater runs; input 1 open, heater stops
|
|
||||||
GPIOinOn1Off1 // alternate input 1 closures start or stop the heater
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum GPIOoutModes {
|
|
||||||
GPIOoutNone,
|
|
||||||
GPIOoutStatus,
|
|
||||||
GPIOoutUser
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
enum GPIOalgModes {
|
|
||||||
GPIOalgNone, // Unmodified V2.0 PCBs must use this - ADC2 / Wifi unresolvable conflict
|
|
||||||
GPIOalgHeatDemand,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct sGPIOparams {
|
|
||||||
GPIOinModes inMode;
|
|
||||||
GPIOoutModes outMode;
|
|
||||||
GPIOalgModes algMode;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class CGPIOin {
|
|
||||||
GPIOinModes _Mode;
|
|
||||||
CDebounce _Debounce;
|
|
||||||
uint8_t _lastKey;
|
|
||||||
std::list<uint8_t> _eventList[2];
|
|
||||||
void _doOn1Off2(uint8_t newKey);
|
|
||||||
void _doOnHold1(uint8_t newKey);
|
|
||||||
void _doOn1Off1(uint8_t newKey);
|
|
||||||
public:
|
|
||||||
CGPIOin();
|
|
||||||
void setMode(GPIOinModes mode) { _Mode = mode; };
|
|
||||||
void begin(int pin1, int pin2, GPIOinModes mode, int activeState);
|
|
||||||
void manage();
|
|
||||||
uint8_t getState(int channel);
|
|
||||||
GPIOinModes getMode() const;
|
|
||||||
void simulateKey(uint8_t newKey);
|
|
||||||
};
|
|
||||||
|
|
||||||
class CGPIOout {
|
|
||||||
GPIOoutModes _Mode;
|
|
||||||
void _doStatus();
|
|
||||||
void _doUser();
|
|
||||||
int _pins[2];
|
|
||||||
int _prevState;
|
|
||||||
int _statusState;
|
|
||||||
int _statusDelay;
|
|
||||||
unsigned long _breatheDelay;
|
|
||||||
uint8_t _userState;
|
|
||||||
void _doStartMode();
|
|
||||||
void _doStopMode();
|
|
||||||
void _doSuspendMode();
|
|
||||||
public:
|
|
||||||
CGPIOout();
|
|
||||||
void setMode(GPIOoutModes mode);
|
|
||||||
void begin(int pin1, int pin2, GPIOoutModes mode);
|
|
||||||
void manage();
|
|
||||||
void setState(int channel, bool state);
|
|
||||||
bool getState(int channel);
|
|
||||||
GPIOoutModes getMode() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CGPIOalg {
|
|
||||||
GPIOalgModes _Mode;
|
|
||||||
float _expMean;
|
|
||||||
adc1_channel_t _pin;
|
|
||||||
public:
|
|
||||||
CGPIOalg();
|
|
||||||
void begin(adc1_channel_t pin, GPIOalgModes mode);
|
|
||||||
void manage();
|
|
||||||
int getValue();
|
|
||||||
GPIOalgModes getMode() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sGPIO {
|
|
||||||
bool outState[2];
|
|
||||||
bool inState[2];
|
|
||||||
int algVal;
|
|
||||||
GPIOoutModes outMode;
|
|
||||||
GPIOinModes inMode;
|
|
||||||
GPIOalgModes algMode;
|
|
||||||
sGPIO& operator=(const sGPIO& rhs) {
|
|
||||||
outState[0] = rhs.outState[0];
|
|
||||||
outState[1] = rhs.outState[1];
|
|
||||||
inState[0] = rhs.inState[0];
|
|
||||||
inState[1] = rhs.inState[1];
|
|
||||||
algVal = rhs.algVal;
|
|
||||||
outMode = rhs.outMode;
|
|
||||||
inMode = rhs.inMode;
|
|
||||||
algMode = rhs.algMode;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __BTCGPIO_H__
|
|
|
@ -1,454 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "NVStorage.h"
|
|
||||||
#include "DebugPort.h"
|
|
||||||
#include <driver/adc.h>
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
sNVStore::valid()
|
|
||||||
{
|
|
||||||
bool retval = true;
|
|
||||||
retval &= heaterTuning.valid();
|
|
||||||
retval &= userSettings.valid();
|
|
||||||
for(int i=0; i<2; i++) {
|
|
||||||
retval &= timer[i].valid();
|
|
||||||
}
|
|
||||||
retval &= MQTT.valid();
|
|
||||||
retval &= Credentials.valid();
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sNVStore::init()
|
|
||||||
{
|
|
||||||
heaterTuning.init();
|
|
||||||
userSettings.init();
|
|
||||||
|
|
||||||
for(int i=0; i<14; i++) {
|
|
||||||
timer[i].init(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
MQTT.init();
|
|
||||||
Credentials.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
CHeaterStorage::CHeaterStorage()
|
|
||||||
{
|
|
||||||
_calValues.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
float
|
|
||||||
sHeaterTuning::getPmin() const
|
|
||||||
{
|
|
||||||
return float(Pmin) * 0.1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float
|
|
||||||
sHeaterTuning::getPmax() const
|
|
||||||
{
|
|
||||||
return float(Pmax) * 0.1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
sHeaterTuning::setPmin(float val)
|
|
||||||
{
|
|
||||||
uint8_t cVal = (uint8_t)(val * 10.f + 0.5f);
|
|
||||||
Pmin = cVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sHeaterTuning::setPmax(float val)
|
|
||||||
{
|
|
||||||
uint8_t cVal = (uint8_t)(val * 10.f + 0.5f);
|
|
||||||
Pmax = cVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
sHeaterTuning::setSysVoltage(float fVal)
|
|
||||||
{
|
|
||||||
int val = int(fVal * 10.0);
|
|
||||||
if(val == 120 || val == 240) {
|
|
||||||
sysVoltage = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
CHeaterStorage::getTimerInfo(int idx, sTimer& timerInfo)
|
|
||||||
{
|
|
||||||
if(INBOUNDS(idx, 0, 13)) {
|
|
||||||
timerInfo = _calValues.timer[idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHeaterStorage::setTimerInfo(int idx, const sTimer& timerInfo)
|
|
||||||
{
|
|
||||||
if(INBOUNDS(idx, 0, 13)) {
|
|
||||||
_calValues.timer[idx] = timerInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const sCyclicThermostat&
|
|
||||||
CHeaterStorage::getCyclicMode() const
|
|
||||||
{
|
|
||||||
return _calValues.userSettings.cyclic;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHeaterStorage::setCyclicMode(const sCyclicThermostat& val)
|
|
||||||
{
|
|
||||||
_calValues.userSettings.cyclic = val;
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
const sGPIOparams&
|
|
||||||
CHeaterStorage::getGPIOparams() const
|
|
||||||
{
|
|
||||||
return _calValues.userSettings.GPIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHeaterStorage::setGPIOparams(const sGPIOparams& params)
|
|
||||||
{
|
|
||||||
_calValues.userSettings.GPIO = params;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const sHomeMenuActions&
|
|
||||||
CHeaterStorage::getHomeMenu() const
|
|
||||||
{
|
|
||||||
return _calValues.userSettings.HomeMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHeaterStorage::setHomeMenu(const sHomeMenuActions& val)
|
|
||||||
{
|
|
||||||
_calValues.userSettings.HomeMenu = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// MQTT parameter read/save
|
|
||||||
const sMQTTparams&
|
|
||||||
CHeaterStorage::getMQTTinfo() const
|
|
||||||
{
|
|
||||||
return _calValues.MQTT;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHeaterStorage::setMQTTinfo(const sMQTTparams& info)
|
|
||||||
{
|
|
||||||
_calValues.MQTT = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
// credentials read/save
|
|
||||||
const sCredentials&
|
|
||||||
CHeaterStorage::getCredentials() const
|
|
||||||
{
|
|
||||||
return _calValues.Credentials;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHeaterStorage::setCredentials(const sCredentials& info)
|
|
||||||
{
|
|
||||||
_calValues.Credentials = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sUserSettings&
|
|
||||||
CHeaterStorage::getUserSettings() const
|
|
||||||
{
|
|
||||||
return _calValues.userSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHeaterStorage::setUserSettings(const sUserSettings& info) {
|
|
||||||
_calValues.userSettings = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sHeaterTuning&
|
|
||||||
CHeaterStorage::getHeaterTuning() const
|
|
||||||
{
|
|
||||||
return _calValues.heaterTuning;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHeaterStorage::setHeaterTuning(const sHeaterTuning& info)
|
|
||||||
{
|
|
||||||
_calValues.heaterTuning = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// ESP32
|
|
||||||
//
|
|
||||||
//#ifdef ESP32
|
|
||||||
|
|
||||||
CESP32HeaterStorage::CESP32HeaterStorage()
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
CESP32HeaterStorage::~CESP32HeaterStorage()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CESP32HeaterStorage::init()
|
|
||||||
{
|
|
||||||
_calValues.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CESP32HeaterStorage::load()
|
|
||||||
{
|
|
||||||
DebugPort.println("Reading from NV storage");
|
|
||||||
_calValues.heaterTuning.load();
|
|
||||||
for(int i=0; i<14; i++) {
|
|
||||||
_calValues.timer[i].load();
|
|
||||||
}
|
|
||||||
_calValues.userSettings.load();
|
|
||||||
_calValues.MQTT.load();
|
|
||||||
_calValues.Credentials.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CESP32HeaterStorage::save()
|
|
||||||
{
|
|
||||||
DebugPort.println("Saving to NV storage");
|
|
||||||
_calValues.heaterTuning.save();
|
|
||||||
for(int i=0; i<14; i++) {
|
|
||||||
_calValues.timer[i].save();
|
|
||||||
}
|
|
||||||
_calValues.userSettings.save();
|
|
||||||
_calValues.MQTT.save();
|
|
||||||
_calValues.Credentials.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sHeaterTuning::load()
|
|
||||||
{
|
|
||||||
// section for heater calibration params
|
|
||||||
// **** MAX LENGTH is 15 for names ****
|
|
||||||
preferences.begin("Calibration", false);
|
|
||||||
validatedLoad("minPump", Pmin, 14, u8inBounds, 4, 100);
|
|
||||||
validatedLoad("maxPump", Pmax, 45, u8inBounds, 4, 150);
|
|
||||||
validatedLoad("minFan", Fmin, 1500, u16inBounds, 100, 5000);
|
|
||||||
validatedLoad("maxFan", Fmax, 4500, u16inBounds, 100, 6000);
|
|
||||||
validatedLoad("systemVoltage", sysVoltage, 120, u8Match2, 120, 240);
|
|
||||||
validatedLoad("fanSensor", fanSensor, 1, u8inBounds, 1, 2);
|
|
||||||
validatedLoad("glowDrive", glowDrive, 5, u8inBounds, 1, 6);
|
|
||||||
preferences.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sHeaterTuning::save()
|
|
||||||
{
|
|
||||||
// section for heater calibration params
|
|
||||||
// **** MAX LENGTH is 15 for names ****
|
|
||||||
preferences.begin("Calibration", false);
|
|
||||||
preferences.putUChar("minPump", Pmin);
|
|
||||||
preferences.putUChar("maxPump", Pmax);
|
|
||||||
preferences.putUShort("minFan", Fmin);
|
|
||||||
preferences.putUShort("maxFan", Fmax);
|
|
||||||
preferences.putUChar("systemVoltage", sysVoltage);
|
|
||||||
preferences.putUChar("fanSensor", fanSensor);
|
|
||||||
preferences.putUChar("glowDrive", glowDrive);
|
|
||||||
preferences.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sTimer::load()
|
|
||||||
{
|
|
||||||
// **** MAX LENGTH is 15 for names ****
|
|
||||||
char SectionName[16];
|
|
||||||
sprintf(SectionName, "timer%d", timerID+1);
|
|
||||||
preferences.begin(SectionName, false);
|
|
||||||
validatedLoad("startHour", start.hour, 0, s8inBounds, 0, 23);
|
|
||||||
validatedLoad("startMin", start.min, 0, s8inBounds, 0, 59);
|
|
||||||
validatedLoad("stopHour", stop.hour, 0, s8inBounds, 0, 23);
|
|
||||||
validatedLoad("stopMin", stop.min, 0, s8inBounds, 0, 59);
|
|
||||||
validatedLoad("enabled", enabled, 0, u8inBounds, 0, 255); // all 8 bits used!
|
|
||||||
validatedLoad("repeat", repeat, 0, u8inBounds, 0, 1);
|
|
||||||
validatedLoad("temperature", temperature, 22, u8inBounds, 8, 35);
|
|
||||||
preferences.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sTimer::save()
|
|
||||||
{
|
|
||||||
// **** MAX LENGTH is 15 for names ****
|
|
||||||
char SectionName[16];
|
|
||||||
sprintf(SectionName, "timer%d", timerID+1);
|
|
||||||
preferences.begin(SectionName, false);
|
|
||||||
preferences.putChar("startHour", start.hour);
|
|
||||||
preferences.putChar("startMin", start.min);
|
|
||||||
preferences.putChar("stopHour", stop.hour);
|
|
||||||
preferences.putChar("stopMin", stop.min);
|
|
||||||
preferences.putUChar("enabled", enabled);
|
|
||||||
preferences.putUChar("repeat", repeat);
|
|
||||||
preferences.putUChar("temperature", temperature);
|
|
||||||
preferences.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sUserSettings::load()
|
|
||||||
{
|
|
||||||
// **** MAX LENGTH is 15 for names ****
|
|
||||||
preferences.begin("user", false);
|
|
||||||
validatedLoad("dimTime", dimTime, 60000, -600000, 600000);
|
|
||||||
validatedLoad("menuTimeout", menuTimeout, 60000, 0, 300000);
|
|
||||||
validatedLoad("degF", degF, 0, u8inBounds, 0, 1);
|
|
||||||
validatedLoad("thermostat", useThermostat, 1, u8inBounds, 0, 1);
|
|
||||||
validatedLoad("demandDegC", demandDegC, 22, u8inBounds, 8, 35);
|
|
||||||
validatedLoad("demandPump", demandPump, 22, u8inBounds, 8, 35);
|
|
||||||
validatedLoad("thermoMethod", ThermostatMethod, 0, u8inBounds, 0, 255);
|
|
||||||
// catch and migrate old combined method & window
|
|
||||||
if(ThermostatMethod & 0xFC) {
|
|
||||||
float defVal = float(ThermostatMethod>>2) * 0.1f;
|
|
||||||
validatedLoad("thermoWindow", ThermostatWindow, defVal, 0.2f, 10.0f);
|
|
||||||
preferences.putUChar("thermoMethod", ThermostatMethod & 0x03); // strip old window
|
|
||||||
}
|
|
||||||
validatedLoad("thermoWindow", ThermostatWindow, 1.0f, 0.2f, 10.f);
|
|
||||||
DebugPort.printf("2) Window = %f\r\n", ThermostatWindow);
|
|
||||||
validatedLoad("enableWifi", enableWifi, 1, u8inBounds, 0, 1);
|
|
||||||
validatedLoad("enableOTA", enableOTA, 1, u8inBounds, 0, 1);
|
|
||||||
validatedLoad("cyclicStop", cyclic.Stop, 0, s8inBounds, 0, 10);
|
|
||||||
validatedLoad("cyclicStart", cyclic.Start, -1, s8inBounds, -20, 0);
|
|
||||||
uint8_t tVal;
|
|
||||||
validatedLoad("GPIOinMode", tVal, 0, u8inBounds, 0, 3); GPIO.inMode = (GPIOinModes)tVal;
|
|
||||||
validatedLoad("GPIOoutMode", tVal, 0, u8inBounds, 0, 2); GPIO.outMode = (GPIOoutModes)tVal;
|
|
||||||
validatedLoad("GPIOalgMode", tVal, 0, u8inBounds, 0, 2); GPIO.algMode = (GPIOalgModes)tVal;
|
|
||||||
validatedLoad("MenuOnTimeout", HomeMenu.onTimeout, 0, u8inBounds, 0, 3);
|
|
||||||
validatedLoad("MenuonStart", HomeMenu.onStart, 0, u8inBounds, 0, 3);
|
|
||||||
validatedLoad("MenuonStop", HomeMenu.onStop, 0, u8inBounds, 0, 3);
|
|
||||||
validatedLoad("FrameRate", FrameRate, 1000, u16inBounds, 300, 1500);
|
|
||||||
validatedLoad("JSONsingle", JSON.singleElement, 0, u8inBounds, 0, 1);
|
|
||||||
validatedLoad("JSONLF", JSON.LF, 0, u8inBounds, 0, 1);
|
|
||||||
validatedLoad("JSONpad", JSON.padding, 0, u8inBounds, 0, 1);
|
|
||||||
preferences.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sUserSettings::save()
|
|
||||||
{
|
|
||||||
// **** MAX LENGTH is 15 for names ****
|
|
||||||
preferences.begin("user", false);
|
|
||||||
preferences.putLong("dimTime", dimTime);
|
|
||||||
preferences.putLong("menuTimeout", menuTimeout);
|
|
||||||
preferences.putUChar("thermostat", useThermostat);
|
|
||||||
preferences.putUChar("demandDegC", demandDegC);
|
|
||||||
preferences.putUChar("demandPump", demandPump);
|
|
||||||
preferences.putUChar("degF", degF);
|
|
||||||
preferences.putUChar("thermoMethod", ThermostatMethod);
|
|
||||||
preferences.putFloat("thermoWindow", ThermostatWindow);
|
|
||||||
preferences.putUChar("enableWifi", enableWifi);
|
|
||||||
preferences.putUChar("enableOTA", enableOTA);
|
|
||||||
preferences.putChar("cyclicStop", cyclic.Stop);
|
|
||||||
preferences.putChar("cyclicStart",cyclic.Start);
|
|
||||||
preferences.putUChar("GPIOinMode", GPIO.inMode);
|
|
||||||
preferences.putUChar("GPIOoutMode", GPIO.outMode);
|
|
||||||
preferences.putUChar("GPIOalgMode", GPIO.algMode);
|
|
||||||
preferences.putUChar("MenuOnTimeout", HomeMenu.onTimeout);
|
|
||||||
preferences.putUChar("MenuonStart", HomeMenu.onStart);
|
|
||||||
preferences.putUChar("MenuonStop", HomeMenu.onStop);
|
|
||||||
preferences.putUShort("FrameRate", FrameRate);
|
|
||||||
preferences.putUChar("JSONsingle", JSON.singleElement);
|
|
||||||
preferences.putUChar("JSONLF", JSON.LF);
|
|
||||||
preferences.putUChar("JSONpad", JSON.padding);
|
|
||||||
preferences.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sMQTTparams::load()
|
|
||||||
{
|
|
||||||
// **** MAX LENGTH is 15 for names ****
|
|
||||||
preferences.begin("mqtt", false);
|
|
||||||
validatedLoad("enabled", enabled, 0, u8inBounds, 0, 1);
|
|
||||||
validatedLoad("port", port, 0, u16inBounds, 0, 0xffff);
|
|
||||||
validatedLoad("host", host, 127, "hostIP");
|
|
||||||
validatedLoad("username", username, 31, "username");
|
|
||||||
validatedLoad("password", password, 31, "password");
|
|
||||||
preferences.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sMQTTparams::save()
|
|
||||||
{
|
|
||||||
// **** MAX LENGTH is 15 for names ****
|
|
||||||
preferences.begin("mqtt", false);
|
|
||||||
preferences.putUChar("enabled", enabled);
|
|
||||||
preferences.putUShort("port", port);
|
|
||||||
preferences.putString("host", host);
|
|
||||||
preferences.putString("username", username);
|
|
||||||
preferences.putString("password", password);
|
|
||||||
preferences.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
sMQTTparams::valid()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sCredentials::load()
|
|
||||||
{
|
|
||||||
// **** MAX LENGTH is 15 for names ****
|
|
||||||
preferences.begin("credentials", false);
|
|
||||||
validatedLoad("SSID", SSID, 31, "Afterburner");
|
|
||||||
validatedLoad("APpassword", APpassword, 31, "thereisnospoon");
|
|
||||||
validatedLoad("webUpdateUser", webUpdateUsername, 31, "Afterburner");
|
|
||||||
validatedLoad("webUpdatePass", webUpdatePassword, 31, "BurnBabyBurn");
|
|
||||||
preferences.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sCredentials::save()
|
|
||||||
{
|
|
||||||
// **** MAX LENGTH is 15 for names ****
|
|
||||||
preferences.begin("credentials", false);
|
|
||||||
preferences.putString("SSID", SSID);
|
|
||||||
preferences.putString("APpassword", APpassword);
|
|
||||||
preferences.putString("webUpdateUser", webUpdateUsername);
|
|
||||||
preferences.putString("webUpdatePass", webUpdatePassword);
|
|
||||||
preferences.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
sCredentials::valid()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void toggle(bool& ref)
|
|
||||||
{
|
|
||||||
ref = !ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
void toggle(uint8_t& ref)
|
|
||||||
{
|
|
||||||
ref = ref ? 0 : 1;
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "../Protocol/Protocol.h"
|
|
||||||
#include "UtilClasses.h"
|
|
||||||
|
|
||||||
|
|
||||||
// a class to track the blue wire receive / transmit states
|
|
||||||
// class CommStates
|
|
||||||
|
|
||||||
void
|
|
||||||
CommStates::set(eCS eState)
|
|
||||||
{
|
|
||||||
_State = eState;
|
|
||||||
_Count = 0;
|
|
||||||
if(_report) {
|
|
||||||
static const char* stateNames[] = {
|
|
||||||
"Idle", "OEMCtrlRx", "OEMCtrlValidate", "HeaterRx1", "HeaterValidate1", "HeaterReport1",
|
|
||||||
"BTC_Tx", "HeaterRx2", "HeaterValidate2", "HeaterReport2", "TemperatureRead"
|
|
||||||
};
|
|
||||||
if(_State == Idle) DebugPort.println(""); // clear screen
|
|
||||||
DebugPort.printf("State: %s\r\n", stateNames[_State]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CommStates::collectData(CProtocol& Frame, unsigned char val, int limit) { // returns true when buffer filled
|
|
||||||
Frame.Data[_Count++] = val;
|
|
||||||
return _Count >= limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CommStates::collectDataEx(CProtocol& Frame, unsigned char val, int limit) { // returns true when buffer filled
|
|
||||||
// guarding against rogue rx kernel buffer stutters....
|
|
||||||
if((_Count == 0) && (val != 0x76)) {
|
|
||||||
DebugPort.println("First heater byte not 0x76 - SKIPPING");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Frame.Data[_Count++] = val;
|
|
||||||
return _Count >= limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CommStates::checkValidStart(unsigned char val)
|
|
||||||
{
|
|
||||||
if(_Count)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return val == 0x76;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CommStates::setDelay(int ms)
|
|
||||||
{
|
|
||||||
_delay = millis() + ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CommStates::delayExpired()
|
|
||||||
{
|
|
||||||
long test = millis() - _delay;
|
|
||||||
return(test >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
CProfile::CProfile()
|
|
||||||
{
|
|
||||||
tStart = millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long
|
|
||||||
CProfile::elapsed(bool reset/* = false*/)
|
|
||||||
{
|
|
||||||
unsigned long now = millis();
|
|
||||||
unsigned long retval = now - tStart;
|
|
||||||
if(reset)
|
|
||||||
tStart = now;
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifdef USEMQTT
|
|
||||||
#include "ABMqtt.h"
|
|
||||||
|
|
||||||
|
|
||||||
void MqttCallback(char* topic, byte* payload, unsigned int length) {
|
|
||||||
// handle message arrived
|
|
||||||
}
|
|
||||||
|
|
||||||
void MqttSetup() {
|
|
||||||
WiFiClient espClient;
|
|
||||||
PubSubClient client(espClient);
|
|
||||||
|
|
||||||
long lastReconnectAttempt = 0;
|
|
||||||
|
|
||||||
boolean reconnect() {
|
|
||||||
if (client.connect("arduinoClient")) {
|
|
||||||
// Once connected, publish an announcement...
|
|
||||||
client.publish("outTopic", "hello world");
|
|
||||||
// ... and resubscribe
|
|
||||||
client.subscribe("inTopic");
|
|
||||||
}
|
|
||||||
return client.connected();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,22 +0,0 @@
|
||||||
// ABMqtt.h
|
|
||||||
|
|
||||||
#ifndef _ABMQTT_h
|
|
||||||
#define _ABMQTT_h
|
|
||||||
|
|
||||||
#if defined(ARDUINO) && ARDUINO >= 100
|
|
||||||
#include "arduino.h"
|
|
||||||
#else
|
|
||||||
#include "WProgram.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include <PubSubClient.h>
|
|
||||||
#include "BTCWifi.h""
|
|
||||||
#include "BTCWebServer.h"
|
|
||||||
|
|
||||||
|
|
||||||
void MqttCallback(char* topic, byte* payload, unsigned int length);
|
|
||||||
void MqttSetup();
|
|
|
@ -1,489 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the "bluetoothheater" distribution
|
|
||||||
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
|
|
||||||
* Copyright (C) 2018 James Clark
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define USE_EMBEDDED_WEBUPDATECODE
|
|
||||||
|
|
||||||
#include "BTCWebServer.h"
|
|
||||||
#include "../Utility/DebugPort.h"
|
|
||||||
#include "../Protocol/TxManage.h"
|
|
||||||
#include "../Utility/helpers.h"
|
|
||||||
#include "../cfg/pins.h"
|
|
||||||
#include "../cfg/BTCConfig.h"
|
|
||||||
#include "Index.h"
|
|
||||||
#include "../Utility/BTC_JSON.h"
|
|
||||||
#include "../Utility/Moderator.h"
|
|
||||||
#include <WiFiManager.h>
|
|
||||||
#if USE_SPIFFS == 1
|
|
||||||
#include <FS.H>
|
|
||||||
#include <SPIFFS.h>
|
|
||||||
#endif
|
|
||||||
#include "../Utility/NVStorage.h"
|
|
||||||
|
|
||||||
extern WiFiManager wm;
|
|
||||||
|
|
||||||
File fsUploadFile; // a File object to temporarily store the received file
|
|
||||||
int SPIFFSupload = 0;
|
|
||||||
|
|
||||||
WebServer server(80);
|
|
||||||
WebSocketsServer webSocket = WebSocketsServer(81);
|
|
||||||
|
|
||||||
bool bRxWebData = false; // flags for OLED animation
|
|
||||||
bool bTxWebData = false;
|
|
||||||
bool bUpdateAccessed = false; // flag used to ensure web update always starts via /update. direct accesses to /updatenow will FAIL
|
|
||||||
long _SuppliedFileSize = 0;
|
|
||||||
|
|
||||||
const int led = 13;
|
|
||||||
|
|
||||||
#if USE_SPIFFS == 1
|
|
||||||
|
|
||||||
String getContentType(String filename) { // convert the file extension to the MIME type
|
|
||||||
if (filename.endsWith(".html")) return "text/html";
|
|
||||||
else if (filename.endsWith(".css")) return "text/css";
|
|
||||||
else if (filename.endsWith(".js")) return "application/javascript";
|
|
||||||
else if (filename.endsWith(".ico")) return "image/x-icon";
|
|
||||||
else if (filename.endsWith(".bin")) return "application/octet-stream";
|
|
||||||
return "text/plain";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool handleFileRead(String path) { // send the right file to the client (if it exists)
|
|
||||||
DebugPort.println("handleFileRead: " + path);
|
|
||||||
if (path.endsWith("/")) path += "index.html"; // If a folder is requested, send the index file
|
|
||||||
String contentType = getContentType(path); // Get the MIME type
|
|
||||||
if (SPIFFS.exists(path)) { // If the file exists
|
|
||||||
File file = SPIFFS.open(path, "r"); // Open it
|
|
||||||
server.streamFile(file, contentType); // And send it to the client
|
|
||||||
file.close(); // Then close the file again
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
DebugPort.println("\tFile Not Found");
|
|
||||||
return false; // If the file doesn't exist, return false
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleBTCRoot() {
|
|
||||||
handleFileRead("/index.html");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void handleBTCRoot() {
|
|
||||||
String s = MAIN_PAGE; //Read HTML contents
|
|
||||||
server.send(200, "text/html", s); //Send web page
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void handleWMConfig() {
|
|
||||||
DebugPort.println("WEB: GET /wmconfig");
|
|
||||||
server.send(200, "text/plain", "Start Config Portal - Retaining credential");
|
|
||||||
DebugPort.println("Starting web portal for wifi config");
|
|
||||||
delay(500);
|
|
||||||
wifiEnterConfigPortal(true, false, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleReset() {
|
|
||||||
DebugPort.println("WEB: GET /resetwifi");
|
|
||||||
server.send(200, "text/plain", "Start Config Portal - Resetting Wifi credentials!");
|
|
||||||
DebugPort.println("diconnecting client and wifi, then rebooting");
|
|
||||||
delay(500);
|
|
||||||
wifiEnterConfigPortal(true, true, 3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleFormat() {
|
|
||||||
DebugPort.println("WEB: GET /formatspiffs");
|
|
||||||
server.send(200, "text/plain", "Formatting SPIFFS partition!");
|
|
||||||
DebugPort.println("Formatting SPIFFS partition");
|
|
||||||
delay(500);
|
|
||||||
SPIFFS.format();
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleBTCNotFound() {
|
|
||||||
digitalWrite(led, 1);
|
|
||||||
String message = "File Not Found\n\n";
|
|
||||||
message += "URI: ";
|
|
||||||
message += server.uri();
|
|
||||||
message += "\nMethod: ";
|
|
||||||
message += (server.method() == HTTP_GET) ? "GET" : "POST";
|
|
||||||
message += "\nArguments: ";
|
|
||||||
message += server.args();
|
|
||||||
message += "\n";
|
|
||||||
for (uint8_t i = 0; i < server.args(); i++) {
|
|
||||||
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
|
|
||||||
}
|
|
||||||
server.send(404, "text/plain", message);
|
|
||||||
digitalWrite(led, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// embedded HTML & Javascript to perform browser based updates of firmware or SPIFFS
|
|
||||||
const char* updateIndex = R"=====(
|
|
||||||
<!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">
|
|
||||||
<script>
|
|
||||||
// global variables
|
|
||||||
var sendSize;
|
|
||||||
var ws;
|
|
||||||
|
|
||||||
function _(el) {
|
|
||||||
return document.getElementById(el);
|
|
||||||
}
|
|
||||||
function init() {
|
|
||||||
ws = new WebSocket('ws://' + window.location.hostname + ':81/');
|
|
||||||
|
|
||||||
ws.onmessage = function(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 uploadFile() {
|
|
||||||
_("cancel").hidden = true;
|
|
||||||
var file = _("file1").files[0];
|
|
||||||
sendSize = file.size;
|
|
||||||
|
|
||||||
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 () {
|
|
||||||
window.location.reload();
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function errorHandler(event) {
|
|
||||||
_("status").innerHTML = "Upload Failed";
|
|
||||||
}
|
|
||||||
function abortHandler(event) {
|
|
||||||
_("status").innerHTML = "Upload Aborted";
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style>
|
|
||||||
body {font-family: Arial, Helvetica, sans-serif;}
|
|
||||||
</style>
|
|
||||||
<title>Afterburner firmware update</title>
|
|
||||||
</head>
|
|
||||||
<body onload="javascript:init()">
|
|
||||||
<h1>Afterburner firmware update</h1>
|
|
||||||
<form id="upload_form" method="POST" enctype="multipart/form-data" autocomplete="off">
|
|
||||||
<input type="file" name="file1" id="file1"> <BR>
|
|
||||||
<input type="button" value="Update" onclick="uploadFile()">
|
|
||||||
<progress id="progressBar" value="0" max="100" style="width:300px;"></progress><BR>
|
|
||||||
<h3 id="status"></h3>
|
|
||||||
<p id="loaded_n_total"></p>
|
|
||||||
<BR>
|
|
||||||
<input type="button" onclick=window.location.assign("/") value="Cancel" id="cancel">
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
)=====";
|
|
||||||
|
|
||||||
|
|
||||||
void rootRedirect()
|
|
||||||
{
|
|
||||||
server.sendHeader("Location","/"); // reselect the update page
|
|
||||||
server.send(303);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void initWebServer(void) {
|
|
||||||
|
|
||||||
Update
|
|
||||||
.onProgress([](unsigned int progress, unsigned int total) {
|
|
||||||
int percent = (progress / (total / 100));
|
|
||||||
DebugPort.printf("Progress: %u%%\r", percent);
|
|
||||||
DebugPort.handle(); // keep telnet spy alive
|
|
||||||
ShowOTAScreen(percent, eOTAWWW); // WWW update in place
|
|
||||||
DebugPort.print("^");
|
|
||||||
});
|
|
||||||
|
|
||||||
if (MDNS.begin("Afterburner")) {
|
|
||||||
DebugPort.println("MDNS responder started");
|
|
||||||
}
|
|
||||||
|
|
||||||
// server.on("/", handleBTCRoot);
|
|
||||||
|
|
||||||
server.on("/wmconfig", handleWMConfig);
|
|
||||||
server.on("/resetwifi", handleReset);
|
|
||||||
server.on("/formatspiffs", handleFormat);
|
|
||||||
|
|
||||||
server.on("/tst", HTTP_GET, []() {
|
|
||||||
DebugPort.println("WEB: GET /tst");
|
|
||||||
server.sendHeader("Location","/"); // reselect the update page
|
|
||||||
server.send(303);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Magical code originally shamelessly lifted from Arduino WebUpdate example, then modified
|
|
||||||
// This allows pushing new firmware to the ESP from a WEB BROWSER!
|
|
||||||
// Added authentication and a sequencing flag to ensure this is not bypassed
|
|
||||||
//
|
|
||||||
// Initial launch page
|
|
||||||
server.on("/update", HTTP_GET, []() {
|
|
||||||
DebugPort.println("WEB: GET /update");
|
|
||||||
sCredentials creds = NVstore.getCredentials();
|
|
||||||
if (!server.authenticate(creds.webUpdateUsername, creds.webUpdatePassword)) {
|
|
||||||
return server.requestAuthentication();
|
|
||||||
}
|
|
||||||
bUpdateAccessed = true;
|
|
||||||
#ifdef USE_EMBEDDED_WEBUPDATECODE
|
|
||||||
server.send(200, "text/html", updateIndex);
|
|
||||||
#else
|
|
||||||
handleFileRead("/uploadfirmware.html");
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
|
|
||||||
// handle attempts to just browse the /updatenow path - force redirect to root
|
|
||||||
server.on("/updatenow", HTTP_GET, []() {
|
|
||||||
DebugPort.println("WEB: GET /updatenow - ILLEGAL - root redirect");
|
|
||||||
rootRedirect();
|
|
||||||
});
|
|
||||||
|
|
||||||
// actual guts that manages the new firmware upload
|
|
||||||
server.on("/updatenow", HTTP_POST, []() {
|
|
||||||
DebugPort.println("WEB: POST /updatenow completion");
|
|
||||||
// completion functionality
|
|
||||||
if(SPIFFSupload) {
|
|
||||||
if(SPIFFSupload == 1) {
|
|
||||||
DebugPort.println("WEB: SPIFFS OK");
|
|
||||||
server.send(200, "text/plain", "OK - File uploaded to SPIFFS");
|
|
||||||
// javascript reselects the /update page!
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DebugPort.println("WEB: SPIFFS FAIL");
|
|
||||||
server.send(500, "text/plain", "500: couldn't create file");
|
|
||||||
}
|
|
||||||
SPIFFSupload = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(Update.hasError()) {
|
|
||||||
DebugPort.println("WEB: UDPATE FAIL");
|
|
||||||
server.send(200, "text/plain", "FAIL - Afterburner will reboot shortly");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DebugPort.println("WEB: UDPATE OK");
|
|
||||||
server.send(200, "text/plain", "OK - Afterburner will reboot shortly");
|
|
||||||
}
|
|
||||||
delay(1000);
|
|
||||||
// javascript redirects to root page so we go there after reboot!
|
|
||||||
ESP.restart(); // reboot
|
|
||||||
}
|
|
||||||
}, []() {
|
|
||||||
if(bUpdateAccessed) { // only allow progression via /update, attempts to directly access /updatenow will fail
|
|
||||||
HTTPUpload& upload = server.upload();
|
|
||||||
if (upload.status == UPLOAD_FILE_START) {
|
|
||||||
String filename = upload.filename;
|
|
||||||
DebugPort.setDebugOutput(true);
|
|
||||||
if(filename.endsWith(".bin")) {
|
|
||||||
DebugPort.printf("Update: %s %d\r\n", filename.c_str(), upload.totalSize);
|
|
||||||
if (!Update.begin()) { //start with max available size
|
|
||||||
Update.printError(DebugPort);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(!filename.startsWith("/")) filename = "/"+filename;
|
|
||||||
DebugPort.printf("handleFileUpload Name: %s\r\n", filename.c_str());
|
|
||||||
fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist)
|
|
||||||
SPIFFSupload = fsUploadFile ? 1 : 2;
|
|
||||||
//filename = String();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle file segments
|
|
||||||
else if (upload.status == UPLOAD_FILE_WRITE) {
|
|
||||||
#if USE_SW_WATCHDOG == 1
|
|
||||||
feedWatchdog(); // we get stuck here for a while, don't let the watchdog bite!
|
|
||||||
#endif
|
|
||||||
if(upload.totalSize) {
|
|
||||||
char JSON[64];
|
|
||||||
sprintf(JSON, "{\"progress\":%d}", upload.totalSize);
|
|
||||||
sendWebServerString(JSON); // feedback proper byte count of update to browser via websocket
|
|
||||||
}
|
|
||||||
int percent = 0;
|
|
||||||
if(_SuppliedFileSize)
|
|
||||||
percent = 100 * upload.totalSize / _SuppliedFileSize;
|
|
||||||
ShowOTAScreen(percent, eOTAbrowser); // browser update
|
|
||||||
|
|
||||||
DebugPort.print(".");
|
|
||||||
if(fsUploadFile) {
|
|
||||||
fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
|
|
||||||
Update.printError(DebugPort);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle end of upload
|
|
||||||
else if (upload.status == UPLOAD_FILE_END) {
|
|
||||||
if(SPIFFSupload) {
|
|
||||||
if(fsUploadFile) {
|
|
||||||
fsUploadFile.close(); // Close the file again
|
|
||||||
DebugPort.printf("handleFileUpload Size: %d\r\n", upload.totalSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (Update.end(true)) { //true to set the size to the current progress
|
|
||||||
DebugPort.printf("Update Success: %u\r\nRebooting...\r\n", upload.totalSize);
|
|
||||||
} else {
|
|
||||||
Update.printError(DebugPort);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DebugPort.setDebugOutput(false);
|
|
||||||
bUpdateAccessed = false;
|
|
||||||
} else {
|
|
||||||
DebugPort.printf("Update Failed Unexpectedly (likely broken connection): status=%d\r\n", upload.status);
|
|
||||||
bUpdateAccessed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// attempt to POST without using /update - forced redirect to root
|
|
||||||
DebugPort.println("WEB: POST /updatenow forbidden entry");
|
|
||||||
rootRedirect();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
#if USE_SPIFFS == 1
|
|
||||||
// NOTE: this serves the default home page, and favicon.ico
|
|
||||||
server.onNotFound([]()
|
|
||||||
{ // If the client requests any URI
|
|
||||||
if (!handleFileRead(server.uri())) { // send it if it exists
|
|
||||||
DebugPort.printf("WEB: NOT FOUND : %s\r\n", server.uri().c_str());
|
|
||||||
server.send(404, "text/plain", "404: Not Found"); // otherwise, respond with a 404 (Not Found) error
|
|
||||||
}
|
|
||||||
});
|
|
||||||
#else
|
|
||||||
server.onNotFound(handleBTCNotFound);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
server.begin();
|
|
||||||
webSocket.begin();
|
|
||||||
webSocket.onEvent(webSocketEvent);
|
|
||||||
|
|
||||||
DebugPort.println("HTTP server started");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// called by main sketch loop()
|
|
||||||
bool doWebServer(void)
|
|
||||||
{
|
|
||||||
webSocket.loop();
|
|
||||||
server.handleClient();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isWebServerClientChange()
|
|
||||||
{
|
|
||||||
static int prevNumClients = -1;
|
|
||||||
|
|
||||||
int numClients = webSocket.connectedClients();
|
|
||||||
if(numClients != prevNumClients) {
|
|
||||||
prevNumClients = numClients;
|
|
||||||
DebugPort.println("Changed number of web clients, should reset JSON moderator");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sendWebServerString(const char* Str)
|
|
||||||
{
|
|
||||||
CProfile profile;
|
|
||||||
if(webSocket.connectedClients()) {
|
|
||||||
unsigned long tCon = profile.elapsed(true);
|
|
||||||
bTxWebData = true; // OLED tx data animation flag
|
|
||||||
webSocket.broadcastTXT(Str);
|
|
||||||
unsigned long tWeb = profile.elapsed(true);
|
|
||||||
DebugPort.printf("Websend times : %ld,%ld\r\n", tCon, tWeb);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length)
|
|
||||||
{
|
|
||||||
if (type == WStype_TEXT) {
|
|
||||||
bRxWebData = true;
|
|
||||||
char cmd[256];
|
|
||||||
memset(cmd, 0, 256);
|
|
||||||
for (int i = 0; i < length && i < 256; i++) {
|
|
||||||
cmd[i] = payload[i];
|
|
||||||
}
|
|
||||||
interpretJsonCommand(cmd); // send to the main heater controller decode routine
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasWebClientSpoken(bool reset)
|
|
||||||
{
|
|
||||||
bool retval = bRxWebData;
|
|
||||||
if(reset)
|
|
||||||
bRxWebData = false;
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasWebServerSpoken(bool reset)
|
|
||||||
{
|
|
||||||
bool retval = bTxWebData;
|
|
||||||
if(reset)
|
|
||||||
bTxWebData = false;
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setUploadSize(long val)
|
|
||||||
{
|
|
||||||
_SuppliedFileSize = val;
|
|
||||||
};
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the "bluetoothheater" distribution
|
|
||||||
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 James Clark
|
|
||||||
*
|
|
||||||
* 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 __BTCWIFI_H__
|
|
||||||
#define __BTCWIFI_H__
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <WiFiManager.h>
|
|
||||||
#include <WiFi.h>
|
|
||||||
|
|
||||||
void doWiFiManager();
|
|
||||||
bool initWifi(int initpin,const char *failedssid, const char *failedpassword);
|
|
||||||
const char* getWifiAPAddrStr();
|
|
||||||
const char* getWifiSTAAddrStr();
|
|
||||||
const char* getWifiAPMACStr();
|
|
||||||
const char* getWifiSTAMACStr();
|
|
||||||
|
|
||||||
bool isWifiConnected();
|
|
||||||
bool isWifiAP();
|
|
||||||
bool isWifiSTA();
|
|
||||||
bool isWifiConfigPortal();
|
|
||||||
bool isWebClientConnected();
|
|
||||||
bool hasWebClientSpoken(bool reset = false);
|
|
||||||
bool hasWebServerSpoken(bool reset = false);
|
|
||||||
void wifiEnterConfigPortal(bool state, bool erase = false, long timeout = 7000);
|
|
||||||
void wifiDisable(long rebootDelay = 7000);
|
|
||||||
void wifiFactoryDefault();
|
|
||||||
int isWifiButton();
|
|
||||||
|
|
||||||
#endif // __BTCWIFI_H__
|
|
|
@ -1,138 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the "bluetoothheater" distribution
|
|
||||||
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 James Clark
|
|
||||||
*
|
|
||||||
* 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 "BTCota.h"
|
|
||||||
#include "../cfg/BTCConfig.h"
|
|
||||||
#if USE_SPIFFS == 1
|
|
||||||
#include <SPIFFS.h>
|
|
||||||
#endif
|
|
||||||
#include "../Libraries/esp32FOTA/src/esp32fota.h" // local copy used due to a couple of issues
|
|
||||||
#include "../Utility/helpers.h"
|
|
||||||
|
|
||||||
|
|
||||||
esp32FOTA FOTA("afterburner-fota-http", int(getVersion()*1000));
|
|
||||||
unsigned long FOTAtime = millis() + 60000; // initial check in a minutes time
|
|
||||||
int FOTAauth = 0;
|
|
||||||
|
|
||||||
#include <esp_int_wdt.h>
|
|
||||||
#include <esp_task_wdt.h>
|
|
||||||
|
|
||||||
void hard_restart() {
|
|
||||||
esp_task_wdt_init(1,true);
|
|
||||||
esp_task_wdt_add(NULL);
|
|
||||||
while(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void initOTA(){
|
|
||||||
ArduinoOTA.setHostname("AfterburnerOTA");
|
|
||||||
|
|
||||||
ArduinoOTA
|
|
||||||
.onStart([]() {
|
|
||||||
String type;
|
|
||||||
if (ArduinoOTA.getCommand() == U_FLASH)
|
|
||||||
type = "sketch";
|
|
||||||
else // U_SPIFFS
|
|
||||||
type = "filesystem";
|
|
||||||
|
|
||||||
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
|
|
||||||
SPIFFS.end();
|
|
||||||
DebugPort.println("Start updating " + type);
|
|
||||||
DebugPort.handle(); // keep telnet spy alive
|
|
||||||
ShowOTAScreen();
|
|
||||||
#if USE_SW_WATCHDOG == 1
|
|
||||||
feedWatchdog(); // we get stuck here for a while, don't let the watchdog bite!
|
|
||||||
#endif
|
|
||||||
})
|
|
||||||
.onEnd([]() {
|
|
||||||
DebugPort.println("\nEnd");
|
|
||||||
DebugPort.handle(); // keep telnet spy alive
|
|
||||||
delay(100);
|
|
||||||
// DebugPort.end(); // force graceful close of telnetspy - ensures a client will reconnect cleanly
|
|
||||||
})
|
|
||||||
.onProgress([](unsigned int progress, unsigned int total) {
|
|
||||||
int percent = (progress / (total / 100));
|
|
||||||
DebugPort.printf("Progress: %u%%\r", percent);
|
|
||||||
DebugPort.handle(); // keep telnet spy alive
|
|
||||||
ShowOTAScreen(percent);
|
|
||||||
})
|
|
||||||
.onError([](ota_error_t error) {
|
|
||||||
DebugPort.printf("Error[%u]: ", error);
|
|
||||||
if (error == OTA_AUTH_ERROR) DebugPort.println("Auth Failed");
|
|
||||||
else if (error == OTA_BEGIN_ERROR) DebugPort.println("Begin Failed");
|
|
||||||
else if (error == OTA_CONNECT_ERROR) DebugPort.println("Connect Failed");
|
|
||||||
else if (error == OTA_RECEIVE_ERROR) DebugPort.println("Receive Failed");
|
|
||||||
else if (error == OTA_END_ERROR) DebugPort.println("End Failed");
|
|
||||||
DebugPort.handle(); // keep telnet spy alive
|
|
||||||
});
|
|
||||||
|
|
||||||
ArduinoOTA.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DoOTA()
|
|
||||||
{
|
|
||||||
ArduinoOTA.handle();
|
|
||||||
|
|
||||||
// manage Firmware OTA
|
|
||||||
// this is where the controller contacts a web server to discover if new firmware is available
|
|
||||||
// if so, it can download and implant using OTA and become effective next reboot!
|
|
||||||
long tDelta = millis() - FOTAtime;
|
|
||||||
if(tDelta > 0) {
|
|
||||||
// FOTAtime = millis() + 6000; // 6 seconds
|
|
||||||
// FOTAtime = millis() + 60000; // 60 seconds
|
|
||||||
// FOTAtime = millis() + 600000; // 10 minutes
|
|
||||||
FOTAtime = millis() + 3600000; // 1 hour
|
|
||||||
if ((WiFi.status() == WL_CONNECTED)) { // bug workaround in FOTA where execHTTPcheck does not return false in this condition
|
|
||||||
FOTA.checkURL = "http://www.mrjones.id.au/afterburner/fota/fota.json";
|
|
||||||
DebugPort.println("Checking for new firmware...");
|
|
||||||
if(FOTA.execHTTPcheck()) {
|
|
||||||
DebugPort.println("New firmware available on web server!");
|
|
||||||
if(FOTAauth == 2) { // user has authorised update (was == 1 before auth.)
|
|
||||||
FOTA.execOTA(); // go ahead and do the update, reading new file from web server
|
|
||||||
FOTAauth = 0; // and we're done.
|
|
||||||
}
|
|
||||||
else
|
|
||||||
FOTAauth = 1; // flag that new firmware is available
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
FOTAauth = 0; // cancel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool isUpdateAvailable(bool test)
|
|
||||||
{
|
|
||||||
if(test) {
|
|
||||||
return FOTAauth == 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FOTAauth = 2;
|
|
||||||
FOTAtime = millis(); // force immediate update test
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkFOTA()
|
|
||||||
{
|
|
||||||
FOTAtime = millis();
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <stdint.h>
|
|
||||||
#include <driver/adc.h>
|
|
||||||
|
|
||||||
const uint8_t UART_Tx = 1;
|
|
||||||
const uint8_t LED_Pin = 2;
|
|
||||||
const uint8_t UART_Rx = 3;
|
|
||||||
const uint8_t HC05_KeyPin = 4;
|
|
||||||
const uint8_t TxEnbPin = 5;
|
|
||||||
const uint8_t Tx433MHz_pin = 12; // HSPI std pins
|
|
||||||
const uint8_t Rx433MHz_pin = 13; // "
|
|
||||||
const uint8_t GPIOout2_pin = 14; // "
|
|
||||||
const uint8_t DS18B20_Pin = 15;
|
|
||||||
const uint8_t Rx1Pin = 16;
|
|
||||||
const uint8_t Tx1Pin = 17;
|
|
||||||
const uint8_t Tx2Pin = 18;
|
|
||||||
const uint8_t Rx2Pin = 19;
|
|
||||||
const uint8_t OLED_SDA_pin = 21; // I2C std pins
|
|
||||||
const uint8_t OLED_SCL_pin = 22; // "
|
|
||||||
const uint8_t HC05_SensePin = 23;
|
|
||||||
const uint8_t GPIOin2_pin = 25;
|
|
||||||
const uint8_t GPIOin1_pinV21V10 = 26;
|
|
||||||
const adc2_channel_t GPIOalg_pinINVALID = ADC2_CHANNEL_9; // GPIO 26 - Cannot use ADC2 with WiFi enabled!!!
|
|
||||||
const uint8_t GPIOout1_pin = 27;
|
|
||||||
|
|
||||||
const uint8_t keyUp_pin = 32;
|
|
||||||
const uint8_t GPIOin1_pinV20 = 33;
|
|
||||||
const adc1_channel_t GPIOalg_pin = ADC1_CHANNEL_5; // GPIO 33 - OK with Wifi, ADC1 channel
|
|
||||||
const uint8_t keyDown_pin = 34; // input only, no chip pullup
|
|
||||||
const uint8_t keyCentre_pin = 35; // input only, no chip pullup
|
|
||||||
const uint8_t keyRight_pin = 36; // input only, no chip pullup
|
|
||||||
const uint8_t keyLeft_pin = 39; // input only, no chip pullup
|
|
||||||
|
|
||||||
//const uint8_t ListenOnlyPin = 33;
|
|
||||||
const uint8_t WiFi_TriggerPin = 0; // BOOT switch!
|
|
||||||
|
|
BIN
Bootload/AfterburnerV3.1.9.bin
Normal file
|
@ -1 +1,5 @@
|
||||||
esptool.exe --chip esp32 --port COM14 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0xe000 boot_app0.bin 0x1000 bootloader_qio_80m.bin 0x10000 Afterburner.bin 0x8000 Afterburner.partitions.bin
|
REM Firmware
|
||||||
|
esptool.exe --chip esp32 --port COM5 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0xe000 boot_app0.bin 0x1000 bootloader_qio_80m.bin 0x10000 AfterburnerV3.1.9.bin 0x8000 Afterburner.partitions.bin
|
||||||
|
REM SPIFFS
|
||||||
|
esptool.exe --chip esp32 --port COM5 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_size detect 0x3d0000 spiffs.bin
|
||||||
|
|
||||||
|
|
22
Bootload/Checklist.txt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Afterburner operation checklist
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
OLED intact
|
||||||
|
Latest firmware uploaded
|
||||||
|
SPIFFS uploaded
|
||||||
|
Check temperature sensor
|
||||||
|
Keypad functions OK
|
||||||
|
Indicator LEDs function
|
||||||
|
Web server functions and serves heater control page
|
||||||
|
Bluetooth pairs and streams SPP data
|
||||||
|
Set time
|
||||||
|
Install battery
|
||||||
|
|
||||||
|
GPIO units only
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
Check pressure sensor
|
||||||
|
GPIO functions:
|
||||||
|
Input x2
|
||||||
|
Output x2
|
||||||
|
Analogue
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
espota.exe -i 192.168.1.1 -p 3232 --auth= -f Afterburner.bin
|
espota.exe -i 192.168.1.1 -p 3232 --auth= -f AfterburnerV3.0.1.bin
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
espota.exe -i 192.168.4.1 -p 3232 --auth= -f Afterburner.bin
|
espota.exe -i 192.168.4.1 -p 3232 --auth= -f AfterburnerV3.0.1.bin
|
||||||
|
|
16
BuildREADME.txt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
This directory structure includes an Arduino path, and a src path.
|
||||||
|
|
||||||
|
The Arduino path is only to support builing with the restrictive Arduino IDE.
|
||||||
|
The src path is for the awesome PlatformIO under VScode.
|
||||||
|
Use it, you will not regret it.
|
||||||
|
|
||||||
|
Arduino builds are sloooooowwwww.
|
||||||
|
Do it that way if you must, but seriously don't!
|
||||||
|
PlatformIO rocks - just load the root repo directory with PIO in VScode
|
||||||
|
and away you go.
|
||||||
|
|
||||||
|
The Arduino\Afterburner\Afterburner.ino file is a hard symbolic link to the
|
||||||
|
proper src\Afterburner\Afterburner.cpp file.
|
||||||
|
|
||||||
|
Likewise the Arduino\Afterburner\src and Arduino\Afterburner\data paths are
|
||||||
|
hard junctions to the src\Afterburner\src and src\Afterburner\data files.
|
BIN
CRCgen/AfterBurnerCRC.cpp
Normal file
11
CRCgen/Readme.txt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
AfterburnerCRC.cpp is used to append a CRC-16 value to the
|
||||||
|
compiled binary file.
|
||||||
|
|
||||||
|
This CRC is used to confirm the binary image uploaded to the
|
||||||
|
Afterburner was genuinely intended for the Afterburner.
|
||||||
|
|
||||||
|
Naively attempting to upload the direct compiled output binary
|
||||||
|
will result in rejection of the upload attempt.
|
||||||
|
|
||||||
|
You will need to compile Afterburner.cpp and copy the resultant
|
||||||
|
executable to the repository root (adjacent to plaformio.ini)
|
BIN
Documentation/20181220_122310.jpg
Normal file
After Width: | Height: | Size: 157 KiB |
BIN
Documentation/20181220_123008.jpg
Normal file
After Width: | Height: | Size: 3.8 MiB |
BIN
Documentation/20181220_123137.jpg
Normal file
After Width: | Height: | Size: 4.3 MiB |
BIN
Documentation/20181220_123410.jpg
Normal file
After Width: | Height: | Size: 3.4 MiB |
BIN
Documentation/20181220_123436.jpg
Normal file
After Width: | Height: | Size: 4.5 MiB |
BIN
Documentation/20181220_131828.jpg
Normal file
After Width: | Height: | Size: 933 KiB |
BIN
Documentation/20190110_201613.jpg
Normal file
After Width: | Height: | Size: 262 KiB |
BIN
Documentation/20190111_083207.jpg
Normal file
After Width: | Height: | Size: 122 KiB |
BIN
Documentation/20190111_124322.jpg
Normal file
After Width: | Height: | Size: 570 KiB |
BIN
Documentation/20190111_133926.jpg
Normal file
After Width: | Height: | Size: 4.8 MiB |
BIN
Documentation/20190111_134737.jpg
Normal file
After Width: | Height: | Size: 476 KiB |
BIN
Documentation/20190226_185402.jpg
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
Documentation/20190226_190048.jpg
Normal file
After Width: | Height: | Size: 92 KiB |
BIN
Documentation/20190323_095325.jpg
Normal file
After Width: | Height: | Size: 604 KiB |
BIN
Documentation/3pinplug.jpg
Normal file
After Width: | Height: | Size: 449 KiB |
BIN
Documentation/3pinplugcircular.jpg
Normal file
After Width: | Height: | Size: 580 KiB |
After Width: | Height: | Size: 43 KiB |
BIN
Documentation/56161804_427457621343959_2334075276654280704_n.jpg
Normal file
After Width: | Height: | Size: 635 KiB |
BIN
Documentation/6a00d8341c5c8953ef0154379fb397970c-800wi.jpg
Normal file
After Width: | Height: | Size: 198 KiB |
BIN
Documentation/BTC1.jpg
Normal file
After Width: | Height: | Size: 427 KiB |
BIN
Documentation/BTC2.jpg
Normal file
After Width: | Height: | Size: 228 KiB |
BIN
Documentation/BTCavatar.jpg
Normal file
After Width: | Height: | Size: 133 KiB |
BIN
Documentation/Battery.jpg
Normal file
After Width: | Height: | Size: 1.2 MiB |
BIN
Documentation/Battery2.jpg
Normal file
After Width: | Height: | Size: 476 KiB |
BIN
Documentation/BlackHeaterControlBoard.PNG
Normal file
After Width: | Height: | Size: 625 KiB |
BIN
Documentation/BlackLCD.jpg
Normal file
After Width: | Height: | Size: 395 KiB |
BIN
Documentation/BlueLCD.jpg
Normal file
After Width: | Height: | Size: 3.4 MiB |
BIN
Documentation/BlueLCDRFchip.jpg
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
Documentation/BlueLCDRx.jpg
Normal file
After Width: | Height: | Size: 182 KiB |
BIN
Documentation/BlueWireIF.PNG
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
Documentation/Bluewire Serial State Machine.dia~
Normal file
BIN
Documentation/Bluewire Serial State Machine.png~
Normal file
After Width: | Height: | Size: 152 KiB |