diff --git a/Build-instructions-Bestway-WiFi-remote.pdf b/Build-instructions-Bestway-WiFi-remote.pdf
index 1636fc4e..599b8d0d 100644
Binary files a/Build-instructions-Bestway-WiFi-remote.pdf and b/Build-instructions-Bestway-WiFi-remote.pdf differ
diff --git a/Code/4-wire-version/data/WebSocket.js b/Code/4-wire-version/data/WebSocket.js
index b02f01b9..ecbb93b6 100644
--- a/Code/4-wire-version/data/WebSocket.js
+++ b/Code/4-wire-version/data/WebSocket.js
@@ -99,10 +99,14 @@ function handlemsg(e)
]
document.getElementById('mqtt').innerHTML = "MQTT: " + mqtt_states[msgobj.MQTT + 4];
- // hydro jets available
- document.getElementById('jetstitle').style.display = (msgobj.HASJETS ? 'table-row' : 'none');
- document.getElementById('jetsbutton').style.display = (msgobj.HASJETS ? 'table-row' : 'none');
+
+ document.getElementById('jetstitle').style.display = (msgobj.HASJETS ? 'inherit' : 'none');
+ document.getElementById('jetsbutton').style.display = (msgobj.HASJETS ? 'inherit' : 'none');
document.getElementById('jetstotals').style.display = (msgobj.HASJETS ? 'table-row' : 'none');
+
+ document.getElementById('airtitle').style.display = (msgobj.HASAIR ? 'inherit' : 'none');
+ document.getElementById('airbutton').style.display = (msgobj.HASAIR ? 'inherit' : 'none');
+ document.getElementById('airtotals').style.display = (msgobj.HASAIR ? 'table-row' : 'none');
document.getElementById('ciotx').innerHTML = 'CIO TX: ' + (msgobj.CIOTX ? 'Active' : 'Dead');
document.getElementById('dsptx').innerHTML = 'DSP TX: ' + (msgobj.DSPTX ? 'Active' : 'Dead');
diff --git a/Code/4-wire-version/data/config.html b/Code/4-wire-version/data/config.html
index b4a016bd..98f7d4ab 100644
--- a/Code/4-wire-version/data/config.html
+++ b/Code/4-wire-version/data/config.html
@@ -80,10 +80,9 @@
-
+
@@ -129,7 +128,9 @@
Command queue
const rebootesp = 6;
const gettarget = 7;
const setjets = 11;
-const commandlist = ["Set target", "Set unit", "Set bubbles", "Set heat", "Set pump", "Reset queue", "Reboot ESP", "Internal cmd", "Set jets"];
+const setgodmode = 12;
+const commandlist = ["Set target", "Set unit", "Set bubbles", "Set heat", "Set pump", "Reset queue", "Reboot ESP", "Internal cmd", "resetTotals:", "resetTimerChlorine", "resetTimerFilter", "Set jets", "Take Control"];
+
function loadconfig(){
const Http = new XMLHttpRequest();
@@ -195,7 +196,7 @@ Command queue
"FINT":parseInt(document.getElementById("finterval").value),
"CLINT":parseInt(document.getElementById("clinterval").value),
"AUDIO":document.getElementById("audio").checked//,
- //"RESTORE":document.getElementById("restore").value
+ //"RESTORE":parseInt(document.getElementById("restore").value)
}
Http.send(JSON.stringify(msgobj));
console.log(msgobj);
diff --git a/Code/4-wire-version/data/index.html b/Code/4-wire-version/data/index.html
index 8b0e20f8..afe22577 100644
--- a/Code/4-wire-version/data/index.html
+++ b/Code/4-wire-version/data/index.html
@@ -67,12 +67,14 @@ Control:
- Bubbles |
+ Bubbles |
-
+
+
+
|
Heater |
@@ -156,7 +158,7 @@ Totals:
| Heating: |
n/a |
-
+
Air: |
n/a |
diff --git a/Code/4-wire-version/lib/BWC4W/BWC_8266_4w.cpp b/Code/4-wire-version/lib/BWC4W/BWC_8266_4w.cpp
index d9ee3a2c..1d446e17 100644
--- a/Code/4-wire-version/lib/BWC4W/BWC_8266_4w.cpp
+++ b/Code/4-wire-version/lib/BWC4W/BWC_8266_4w.cpp
@@ -31,11 +31,13 @@ void CIO::loop(void) {
{
msglen = cio_serial.readBytes(from_CIO_buf, PAYLOADSIZE);
//copy from_CIO_buf -> to_DSP_buf
- if(msglen == PAYLOADSIZE){
+ if(msglen == PAYLOADSIZE)
+ {
//discard message if checksum is wrong
uint8_t calculatedChecksum;
calculatedChecksum = from_CIO_buf[1]+from_CIO_buf[2]+from_CIO_buf[3]+from_CIO_buf[4];
- if(from_CIO_buf[CIO_CHECKSUMINDEX] == calculatedChecksum){
+ if(from_CIO_buf[CIO_CHECKSUMINDEX] == calculatedChecksum)
+ {
for(int i = 0; i < PAYLOADSIZE; i++){
if(to_DSP_buf[i] != from_CIO_buf[i]) dataAvailable = true;
to_DSP_buf[i] = from_CIO_buf[i];
@@ -48,7 +50,8 @@ void CIO::loop(void) {
states[CHAR1] = ' ';
states[CHAR2] = ' ';
states[CHAR3] = ' ';
- if(states[ERROR]){
+ if(states[ERROR])
+ {
to_CIO_buf[COMMANDINDEX] = 0; //clear any commands
GODMODE = false;
states[CHAR1] = 'E';
@@ -83,7 +86,8 @@ void CIO::loop(void) {
{
msglen = dsp_serial.readBytes(from_DSP_buf, PAYLOADSIZE);
//copy from_DSP_buf -> to_CIO_buf
- if(msglen == PAYLOADSIZE){
+ if(msglen == PAYLOADSIZE)
+ {
//discard message if checksum is wrong
uint8_t calculatedChecksum;
calculatedChecksum = from_DSP_buf[1]+from_DSP_buf[2]+from_DSP_buf[3]+from_DSP_buf[4];
diff --git a/Code/4-wire-version/lib/BWC4W/BWC_8266_4w_globals.h b/Code/4-wire-version/lib/BWC4W/BWC_8266_4w_globals.h
index fa3fa0d8..9cdd6397 100644
--- a/Code/4-wire-version/lib/BWC4W/BWC_8266_4w_globals.h
+++ b/Code/4-wire-version/lib/BWC4W/BWC_8266_4w_globals.h
@@ -255,4 +255,52 @@ const bool HASJETS = false;
const String MYMODEL = "NO54154";
#endif
+#ifdef NO54144
+
+//what row in allowedstates to go to when pressing Bubbles, Jets, Pump, Heat (columns in that order)
+//Example: We are in state zero (first row). If we press Bubbles (first column) then there is a 6
+//meaning current state (row) is now 6. According to ALLOWEDSTATES table, we turn on Bubbles and keep
+//everything else off. (1,0,0,0)
+const uint8_t JUMPTABLE[][4] = {
+// b,j,p,h
+ {1,2,3,4},
+ {0,2,3,4},
+ {1,0,3,4},
+ {1,2,0,4},
+ {1,2,0,3}
+};
+//Bubbles, Jets, Pump, Heat
+const uint8_t ALLOWEDSTATES[][4] = {
+ {0,0,0,0},
+ {1,0,0,0},
+ {0,1,0,0},
+ {0,0,1,0},
+ {0,0,1,2} //the "2" means both heater elements
+};
+
+//cio
+const uint8_t TEMPINDEX = 2;
+const uint8_t ERRORINDEX = 3;
+const uint8_t CIO_CHECKSUMINDEX = 5;
+//dsp
+const uint8_t COMMANDINDEX = 2;
+const uint8_t DSP_CHECKSUMINDEX = 5;
+
+const uint8_t PAYLOADSIZE = 7;
+
+const uint8_t PUMPBITMASK = B00000101; //5
+const uint8_t BUBBLESBITMASK = B00000010; //2
+const uint8_t JETSBITMASK = B00001000; //8
+// const uint8_t HEATBITMASK1 = B00000000; //0 heater stage 1 = off
+// const uint8_t HEATBITMASK2 = B00110000; //48 heater stage 2 = on
+//lines below should be tested. It would be consistent with 54173 model.
+//If heating is slow this is probably the cause but I don't want to change it before someone tests it.
+const uint8_t HEATBITMASK1 = B00110000; //48 heater stage 1 = 50%
+const uint8_t HEATBITMASK2 = B01000000; //64 heater stage 2 = 100%
+const uint8_t POWERBITMASK = B10000000; //128
+const bool HASJETS = true;
+const bool HASAIR = false;
+const String MYMODEL = "NO54144";
+#endif
+
#endif
\ No newline at end of file
diff --git a/Code/4-wire-version/lib/BWC4W/model.h b/Code/4-wire-version/lib/BWC4W/model.h
index ffd99a54..11daf852 100644
--- a/Code/4-wire-version/lib/BWC4W/model.h
+++ b/Code/4-wire-version/lib/BWC4W/model.h
@@ -4,11 +4,16 @@
//#define NO54173 //this is same as 54138 but can run heater on 50% when bubbles are on.
//#define NO54123 //not tested. ref https://github.com/mrQ000/layz-rc link to presentation slides
//#define NO54154 //no jets. Works for Palm Springs 54129
+//#define NO54144 //with jets, but no bubbles. Palm Springs 54144
//WARNING: DEVICES HAVE DIFFERENT PINOUTS!!! CHECK BEFORE USING
//The 54123 should work also for 54112 judging from a comment from @jenswalit in the forum
//If using/testing the new PCB choose PCB_V2
-#define PCB_V1
-//#define PCB_V2 //The PCB with rounded corners
\ No newline at end of file
+//#define PCB_V1
+#define PCB_V2 //The PCB with rounded corners
+
+#ifdef PCB_V2
+#warning "USING PINOUT FOR PCB V2. EDIT lib/BWC/model.h IF USING OTHER PCB"
+#endif
\ No newline at end of file
diff --git a/Code/4-wire-version/platformio.ini b/Code/4-wire-version/platformio.ini
index f8a9c840..cbe243bd 100644
--- a/Code/4-wire-version/platformio.ini
+++ b/Code/4-wire-version/platformio.ini
@@ -23,12 +23,14 @@ lib_deps =
knolleary/PubSubClient@^2.8
tzapu/WiFiManager@^0.16
plerup/EspSoftwareSerial@^6.15.2
+ me-no-dev/ESPAsyncTCP
board_build.filesystem = littlefs
monitor_speed = 115200
;Set upload speed to 115200 if you get transfer errors
;upload_speed = 921600
;board_build.f_cpu = 160000000L
-
+build_flags =
+ -DWEBSOCKETS_NETWORK_TYPE="NETWORK_ESP8266_ASYNC"
; Uncomment the lines below by removing semicolons and edit IP for OTA upload.
; You have to upload via USB cable the first time. (upload_protocol = esptool)
; Make sure to use a data-USB cable. There is power only cables that wont work.
diff --git a/Code/4-wire-version/src/config.h b/Code/4-wire-version/src/config.h
index 2163f78a..6ab63646 100644
--- a/Code/4-wire-version/src/config.h
+++ b/Code/4-wire-version/src/config.h
@@ -2,7 +2,7 @@
#include
#define LEGACY_NAME "layzspa"
-#define FW_VERSION "4W_2022-05-20"
+#define FW_VERSION "4W_2022-06-27"
/*
* Miscellaneous
diff --git a/Code/4-wire-version/src/main.cpp b/Code/4-wire-version/src/main.cpp
index 5477f3f4..8fa80a0f 100644
--- a/Code/4-wire-version/src/main.cpp
+++ b/Code/4-wire-version/src/main.cpp
@@ -47,6 +47,17 @@ void setup()
void loop()
{
+ // calc looptime
+ static bool firstloopdone = false;
+ unsigned long ms = millis();
+ unsigned long looptime;
+ if(ms>prevlooptime && firstloopdone){
+ looptime = ms - prevlooptime;
+ looptime_min = min(looptime, looptime_min);
+ looptime_max = max(looptime, looptime_max);
+ }
+ prevlooptime = ms;
+ firstloopdone = true;
// We need this self-destructing info several times, so save it locally
bool newData = bwc.newData();
// Fiddle with the pump computer
@@ -125,9 +136,6 @@ void loop()
}
if (WiFi.status() == WL_CONNECTED)
{
- // could be interesting to display the IP
- //bwc.print(WiFi.localIP().toString());
-
if (!DateTime.isTimeValid())
{
Serial.println(F("NTP > Start synchronisation"));
@@ -208,14 +216,18 @@ String getOtherInfo()
String json = "";
// Set the values in the document
doc["CONTENT"] = "OTHER";
+ doc["MQTT"] = mqttClient.state();
doc["CIOTX"] = bwc.cio_tx_ok;
doc["DSPTX"] = bwc.dsp_tx_ok;
doc["HASJETS"] = HASJETS;
+ doc["HASAIR"] = HASAIR;
doc["RSSI"] = WiFi.RSSI();
doc["IP"] = WiFi.localIP().toString();
doc["SSID"] = WiFi.SSID();
doc["FW"] = FW_VERSION;
doc["MODEL"] = MYMODEL;
+ doc["LOOPMAX"] = looptime_max;
+ doc["LOOPMIN"] = looptime_min;
// Serialize JSON to string
if (serializeJson(doc, json) == 0)
@@ -258,6 +270,18 @@ void sendMQTT()
{
//Serial.println(F("MQTT > times not published"));
}
+
+
+ //send other info
+ json = getOtherInfo();
+ if (mqttClient.publish((String(mqttBaseTopic) + "/other").c_str(), String(json).c_str(), true))
+ {
+ //Serial.println(F("MQTT > other published"));
+ }
+ else
+ {
+ //Serial.println(F("MQTT > other not published"));
+ }
}
@@ -1016,10 +1040,10 @@ void handleDir()
while (root.next())
{
Serial.println(root.fileName());
- mydir += root.fileName() + F(" \t Size: ");
- mydir += String(root.fileSize()) + F(" Bytes\r\n");
+ mydir += "" + root.fileName() + "" + F(" \t Size: ");
+ mydir += String(root.fileSize()) + F(" Bytes
");
}
- server.send(200, "text/plain", mydir);
+ server.send(200, "text/html", mydir);
}
/**
@@ -1244,6 +1268,12 @@ void mqttConnect()
// Watch the 'command' topic for incoming MQTT messages
mqttClient.subscribe((String(mqttBaseTopic) + "/command").c_str());
mqttClient.loop();
+
+ mqttClient.publish((String(mqttBaseTopic) + "/reboot_time").c_str(), DateTime.format(DateFormatter::ISO8601).c_str(), true);
+ mqttClient.publish((String(mqttBaseTopic) + "/reboot_reason").c_str(), ESP.getResetReason().c_str(), true);
+ mqttClient.loop();
+ sendMQTT();
+ //setupHA(); //Setup MQTT Device
}
else
{
diff --git a/Code/4-wire-version/src/main.h b/Code/4-wire-version/src/main.h
index df5c7664..170828cf 100644
--- a/Code/4-wire-version/src/main.h
+++ b/Code/4-wire-version/src/main.h
@@ -61,7 +61,8 @@ bool runonce = true;
const int solarpin = D0;
/** pulled to GND. Boot fails if pulled HIGH. */
const int myoutputpin = D8;
-
+/** track loop times */
+unsigned long prevlooptime, looptime_max, looptime_min;
void handleAUX();
diff --git a/Code/6-wire-version/data/config.html b/Code/6-wire-version/data/config.html
index cd334797..73f9ed43 100644
--- a/Code/6-wire-version/data/config.html
+++ b/Code/6-wire-version/data/config.html
@@ -205,7 +205,7 @@ Command queue
"FINT":parseInt(document.getElementById("finterval").value),
"CLINT":parseInt(document.getElementById("clinterval").value),
"AUDIO":document.getElementById("audio").checked,
- "RESTORE":document.getElementById("restore").value
+ "RESTORE":parseInt(document.getElementById("restore").value)
}
Http.send(JSON.stringify(msgobj));
console.log(msgobj);
diff --git a/Code/6-wire-version/lib/BWC/BWC_6w_type1.cpp b/Code/6-wire-version/lib/BWC/BWC_6w_type1.cpp
index 009aa2a0..abdd21ca 100644
--- a/Code/6-wire-version/lib/BWC/BWC_6w_type1.cpp
+++ b/Code/6-wire-version/lib/BWC/BWC_6w_type1.cpp
@@ -30,78 +30,90 @@ void CIO::stop(){
void CIO::loop(void) {
//newdata is true when a data packet has arrived from cio
- if(newData) {
+ if(!newData) return;
+ if(_packet_error)
+ {
+ _packet_error = false;
newData = false;
- static int capturePhase = 0;
- static uint32_t buttonReleaseTime;
+ return;
+ }
+ newData = false;
+ static uint32_t buttonReleaseTime;
+ enum Readmode: int {readtemperature, uncertain, readtarget};
+ static int capturePhase = readtemperature;
- //capture TARGET after UP/DOWN has been pressed...
- if ((button == ButtonCodes[UP]) || (button == ButtonCodes[DOWN]))
- {
- buttonReleaseTime = millis();
- capturePhase = 1;
- }
- //require two consecutive messages to be equal before registering
- static uint8_t prev_checksum = 0;
- uint8_t checksum = 0;
- for(int i = 0; i < 11; i++){
- checksum += _payload[i];
- }
- if(checksum != prev_checksum) {
- prev_checksum = checksum;
- return;
- }
-
- //copy private array to public array
- for(unsigned int i = 0; i < sizeof(payload); i++){
- payload[i] = _payload[i];
- }
+ //capture TARGET after UP/DOWN has been pressed...
+ if ((button == ButtonCodes[UP]) || (button == ButtonCodes[DOWN]))
+ {
+ buttonReleaseTime = millis(); //updated as long as buttons are pressed
+ capturePhase = readtarget;
+ }
+ //require two consecutive messages to be equal before registering
+ static uint8_t prev_checksum = 0;
+ uint8_t checksum = 0;
+ for(int i = 0; i < 11; i++){
+ checksum += _payload[i];
+ }
+ if(checksum != prev_checksum) {
+ prev_checksum = checksum;
+ return;
+ }
+
+ //copy private array to public array
+ for(unsigned int i = 0; i < sizeof(payload); i++){
+ payload[i] = _payload[i];
+ }
- //determine if anything changed, so we can update webclients
- for(unsigned int i = 0; i < sizeof(payload); i++){
- if (payload[i] != _prevPayload[i]) dataAvailable = true;
- _prevPayload[i] = payload[i];
- }
+ //determine if anything changed, so we can update webclients
+ for(unsigned int i = 0; i < sizeof(payload); i++){
+ if (payload[i] != _prevPayload[i]) dataAvailable = true;
+ _prevPayload[i] = payload[i];
+ }
- brightness = _brightness & 7; //extract only the brightness bits (0-7)
- //extract information from payload to a better format
- states[LOCKEDSTATE] = (payload[LCK_IDX] & (1 << LCK_BIT)) > 0;
- states[POWERSTATE] = (payload[PWR_IDX] & (1 << PWR_BIT)) > 0;
- states[UNITSTATE] = (payload[C_IDX] & (1 << C_BIT)) > 0;
- states[BUBBLESSTATE] = (payload[AIR_IDX] & (1 << AIR_BIT)) > 0;
- states[HEATGRNSTATE] = (payload[GRNHTR_IDX] & (1 << GRNHTR_BIT)) > 0;
- states[HEATREDSTATE] = (payload[REDHTR_IDX] & (1 << REDHTR_BIT)) > 0;
- states[HEATSTATE] = states[HEATGRNSTATE] || states[HEATREDSTATE];
- states[PUMPSTATE] = (payload[FLT_IDX] & (1 << FLT_BIT)) > 0;
- states[CHAR1] = (uint8_t)_getChar(payload[DGT1_IDX]);
- states[CHAR2] = (uint8_t)_getChar(payload[DGT2_IDX]);
- states[CHAR3] = (uint8_t)_getChar(payload[DGT3_IDX]);
- if(HASJETS) states[JETSSTATE] = (payload[HJT_IDX] & (1 << HJT_BIT)) > 0;
- else states[JETSSTATE] = 0;
- //Determine if display is showing target temp or actual temp or anything else.
- //...until 4 seconds after UP/DOWN released
- if((millis()-buttonReleaseTime) > 2000) capturePhase = 0;
- //convert text on display to a value if the chars are recognized
- if(states[CHAR1] == '*' || states[CHAR2] == '*' || states[CHAR3] == '*') return;
- String tempstring = String((char)states[CHAR1])+String((char)states[CHAR2])+String((char)states[CHAR3]);
- uint8_t tmpTemp = tempstring.toInt();
- //capture only if showing plausible values (not blank screen while blinking)
- if( (capturePhase == 1) && (tmpTemp > 19) ) {
- states[TARGET] = tmpTemp;
- }
- //wait 6 seconds after UP/DOWN is released to be sure that actual temp is shown
- if( (capturePhase == 0) && (states[CHAR3]!='H') && (states[CHAR3]!=' ') && ((millis()-buttonReleaseTime) > 6000) )
- {
- if(states[TEMPERATURE] != tmpTemp) dataAvailable = true;
- states[TEMPERATURE] = tmpTemp;
- }
+ brightness = _brightness & 7; //extract only the brightness bits (0-7)
+ //extract information from payload to a better format
+ states[LOCKEDSTATE] = (payload[LCK_IDX] & (1 << LCK_BIT)) > 0;
+ states[POWERSTATE] = (payload[PWR_IDX] & (1 << PWR_BIT)) > 0;
+ states[UNITSTATE] = (payload[C_IDX] & (1 << C_BIT)) > 0;
+ states[BUBBLESSTATE] = (payload[AIR_IDX] & (1 << AIR_BIT)) > 0;
+ states[HEATGRNSTATE] = (payload[GRNHTR_IDX] & (1 << GRNHTR_BIT)) > 0;
+ states[HEATREDSTATE] = (payload[REDHTR_IDX] & (1 << REDHTR_BIT)) > 0;
+ states[HEATSTATE] = states[HEATGRNSTATE] || states[HEATREDSTATE];
+ states[PUMPSTATE] = (payload[FLT_IDX] & (1 << FLT_BIT)) > 0;
+ states[CHAR1] = (uint8_t)_getChar(payload[DGT1_IDX]);
+ states[CHAR2] = (uint8_t)_getChar(payload[DGT2_IDX]);
+ states[CHAR3] = (uint8_t)_getChar(payload[DGT3_IDX]);
+ if(HASJETS) states[JETSSTATE] = (payload[HJT_IDX] & (1 << HJT_BIT)) > 0;
+ else states[JETSSTATE] = 0;
+ //Determine if display is showing target temp or actual temp or anything else.
+ //Unreadable characters - exit
+ if(states[CHAR1] == '*' || states[CHAR2] == '*' || states[CHAR3] == '*') return;
+ //Error or user plays with timer button - exit (error notification can be dealt with in main.cpp or elsewhere)
+ if(states[CHAR1] == 'E' || states[CHAR3] == 'H' || states[CHAR3] == ' ') return;
+
+ //Stop expecting target temp after timeout
+ if((millis()-buttonReleaseTime) > 2000) capturePhase = uncertain;
+ if((millis()-buttonReleaseTime) > 6000) capturePhase = readtemperature;
+ //convert text on display to a value if the chars are recognized
+ String tempstring = String((char)states[CHAR1])+String((char)states[CHAR2])+String((char)states[CHAR3]);
+ uint8_t parsedValue = tempstring.toInt();
+ //capture target temperature only if showing plausible values (not blank screen while blinking)
+ if( (capturePhase == readtarget) && (parsedValue > 19) ) {
+ states[TARGET] = parsedValue;
+ }
+ //wait 6 seconds after UP/DOWN is released to be sure that actual temp is shown
+ if(capturePhase == readtemperature)
+ {
+ if(states[TEMPERATURE] != parsedValue) dataAvailable = true;
+ states[TEMPERATURE] = parsedValue;
+ }
- if(states[UNITSTATE] != _prevUNT || states[HEATSTATE] != _prevHTR || states[PUMPSTATE] != _prevFLT) {
- stateChanged = true;
- _prevUNT = states[UNITSTATE];
- _prevHTR = states[HEATSTATE];
- _prevFLT = states[PUMPSTATE];
- }
+ //If any of these states changes, we need to set a flag to save states. Used to restore them after reboot.
+ if(states[UNITSTATE] != _prevUNT || states[HEATSTATE] != _prevHTR || states[PUMPSTATE] != _prevFLT) {
+ stateChanged = true;
+ _prevUNT = states[UNITSTATE];
+ _prevHTR = states[HEATSTATE];
+ _prevFLT = states[PUMPSTATE];
}
}
@@ -110,6 +122,8 @@ void IRAM_ATTR CIO::eopHandler(void) {
//process latest data and enter corresponding mode (like listen for DSP_STS or send BTN_OUT)
//pinMode(_DATA_PIN, INPUT);
WRITE_PERI_REG( PIN_DIR_INPUT, 1 << _DATA_PIN);
+ if(_byteCount != 11 && _byteCount != 0) _packet_error = true;
+ if(_bitCount != 0) _packet_error = true;
_byteCount = 0;
_bitCount = 0;
uint8_t msg = _receivedByte;
@@ -141,6 +155,7 @@ void IRAM_ATTR CIO::eopHandler(void) {
//CIO comm
//packet start
//arduino core 3.0.1+ should work with digitalWrite() now.
+//CS line toggles
void IRAM_ATTR CIO::packetHandler(void) {
if (!(READ_PERI_REG(PIN_IN) & (1 << _CS_PIN))) {
//packet start
@@ -156,6 +171,7 @@ void IRAM_ATTR CIO::packetHandler(void) {
//CIO comm
//Read incoming bits, and take action after a complete byte
+//CLK line toggles
void IRAM_ATTR CIO::clkHandler(void) {
//sanity check on clock signal
static uint32_t prev_us = 0;
@@ -195,11 +211,22 @@ void IRAM_ATTR CIO::clkHandler(void) {
_bitCount++;
if (_bitCount == 8) {
_bitCount = 0;
- if (_CIO_cmd_matches == 2) { //meaning we have received the header for 11 data bytes to come
- _payload[_byteCount] = _receivedByte;
- _byteCount++;
+ //We have received the header for 11 data bytes to come
+ if (_CIO_cmd_matches == 2)
+ {
+ if(_byteCount < 11)
+ {
+ _payload[_byteCount] = _receivedByte;
+ _byteCount++;
+ }
+ else
+ {
+ _packet_error = true;
+ }
}
- else if (_receivedByte == DSP_CMD2_DATAREAD) {
+ //We have received request for button pressed
+ else if (_receivedByte == DSP_CMD2_DATAREAD)
+ {
_sendBit = 8;
_dataIsOutput = true;
//pinMode(_DATA_PIN, OUTPUT);
diff --git a/Code/6-wire-version/lib/BWC/BWC_6w_type1.h b/Code/6-wire-version/lib/BWC/BWC_6w_type1.h
index 9db34c57..f4b57bb7 100644
--- a/Code/6-wire-version/lib/BWC/BWC_6w_type1.h
+++ b/Code/6-wire-version/lib/BWC/BWC_6w_type1.h
@@ -128,6 +128,7 @@ class CIO {
bool _prevUNT;
bool _prevHTR;
bool _prevFLT;
+ volatile bool _packet_error = false;
char _getChar(uint8_t value);
};
diff --git a/Code/6-wire-version/lib/BWC/BWC_6w_type2.cpp b/Code/6-wire-version/lib/BWC/BWC_6w_type2.cpp
index ec0ceebc..857d8f6b 100644
--- a/Code/6-wire-version/lib/BWC/BWC_6w_type2.cpp
+++ b/Code/6-wire-version/lib/BWC/BWC_6w_type2.cpp
@@ -31,85 +31,80 @@ void CIO::stop(){
void CIO::loop(void) {
//newdata is true when a data packet has arrived from cio
- if(newData) {
- newData = false;
- static int capturePhase = 0;
- static uint32_t buttonReleaseTime;
-
- //capture TARGET after UP/DOWN has been pressed...
- if ((button == ButtonCodes[UP]) || (button == ButtonCodes[DOWN]))
- {
- buttonReleaseTime = millis();
- capturePhase = 1;
- }
-
- /*
- * This model is only sending messages when something updated
- * so this section is not useful
- */
- /*
- //require two consecutive messages to be equal before registering
- static uint8_t prev_checksum = 0;
- uint8_t checksum = 0;
- for(unsigned int i = 0; i < sizeof(payload); i++){
- checksum += _payload[i];
- }
- if(checksum != prev_checksum) {
- prev_checksum = checksum;
- return;
- }
- */
-
- //copy private array to public array
- for(unsigned int i = 0; i < sizeof(payload); i++){
- payload[i] = _payload[i];
- }
+ if(!newData) return;
+ newData = false;
+ static uint32_t buttonReleaseTime;
+ enum Readmode: int {readtemperature, uncertain, readtarget};
+ static int capturePhase = readtemperature;
+
+ //capture TARGET after UP/DOWN has been pressed...
+ if ((button == ButtonCodes[UP]) || (button == ButtonCodes[DOWN]))
+ {
+ buttonReleaseTime = millis(); //updated as long as buttons are pressed
+ capturePhase = readtarget;
+ }
+
+ /*
+ * This model is only sending messages when something updated
+ * so this section is not useful
+ */
+ //require two consecutive messages to be equal before registering
+
+ //copy private array to public array
+ for(unsigned int i = 0; i < sizeof(payload); i++){
+ payload[i] = _payload[i];
+ }
- //determine if anything changed, so we can update webclients
- for(unsigned int i = 0; i < sizeof(payload); i++){
- if (payload[i] != _prevPayload[i]) dataAvailable = true;
- _prevPayload[i] = payload[i];
- }
+ //determine if anything changed, so we can update webclients
+ for(unsigned int i = 0; i < sizeof(payload); i++){
+ if (payload[i] != _prevPayload[i]) dataAvailable = true;
+ _prevPayload[i] = payload[i];
+ }
- //brightness = _brightness & 7; //extract only the brightness bits (0-7)
- //extract information from payload to a better format
- states[LOCKEDSTATE] = (payload[LCK_IDX] & (1 << LCK_BIT)) > 0;
- states[POWERSTATE] = 1; //(payload[PWR_IDX] & (1 << PWR_BIT)) > 0;
- states[UNITSTATE] = (payload[C_IDX] & (1 << C_BIT)) > 0;
- states[BUBBLESSTATE] = (payload[AIR_IDX] & (1 << AIR_BIT)) > 0;
- states[HEATGRNSTATE] = (payload[GRNHTR_IDX] & (1 << GRNHTR_BIT)) > 0;
- states[HEATREDSTATE] = (payload[REDHTR_IDX] & (1 << REDHTR_BIT)) > 0;
- states[HEATSTATE] = states[HEATGRNSTATE] || states[HEATREDSTATE];
- states[PUMPSTATE] = (payload[FLT_IDX] & (1 << FLT_BIT)) > 0;
- states[CHAR1] = (uint8_t)_getChar(payload[DGT1_IDX]);
- states[CHAR2] = (uint8_t)_getChar(payload[DGT2_IDX]);
- states[CHAR3] = (uint8_t)_getChar(payload[DGT3_IDX]);
- if(HASJETS) states[JETSSTATE] = (payload[HJT_IDX] & (1 << HJT_BIT)) > 0;
- else states[JETSSTATE] = 0;
- //Determine if display is showing target temp or actual temp or anything else.
- //...until 4 seconds after UP/DOWN released
- if((millis()-buttonReleaseTime) > 2000) capturePhase = 0;
- //convert text on display to a value if the chars are recognized
- if(states[CHAR1] == '*' || states[CHAR2] == '*' || states[CHAR3] == '*') return;
- String tempstring = String((char)states[CHAR1])+String((char)states[CHAR2])+String((char)states[CHAR3]);
- uint8_t tmpTemp = tempstring.toInt();
- //capture only if showing plausible values (not blank screen while blinking)
- if( (capturePhase == 1) && (tmpTemp > 19) ) {
- states[TARGET] = tmpTemp;
- }
- //wait 6 seconds after UP/DOWN is released to be sure that actual temp is shown
- if( (capturePhase == 0) && (states[CHAR3]!='H') && (states[CHAR3]!=' ') && ((millis()-buttonReleaseTime) > 6000) )
- {
- if(states[TEMPERATURE] != tmpTemp) dataAvailable = true;
- states[TEMPERATURE] = tmpTemp;
- }
+ //brightness = _brightness & 7; //extract only the brightness bits (0-7)
+ //extract information from payload to a better format
+ states[LOCKEDSTATE] = (payload[LCK_IDX] & (1 << LCK_BIT)) > 0;
+ states[POWERSTATE] = 1; //(payload[PWR_IDX] & (1 << PWR_BIT)) > 0;
+ states[UNITSTATE] = (payload[C_IDX] & (1 << C_BIT)) > 0;
+ states[BUBBLESSTATE] = (payload[AIR_IDX] & (1 << AIR_BIT)) > 0;
+ states[HEATGRNSTATE] = (payload[GRNHTR_IDX] & (1 << GRNHTR_BIT)) > 0;
+ states[HEATREDSTATE] = (payload[REDHTR_IDX] & (1 << REDHTR_BIT)) > 0;
+ states[HEATSTATE] = states[HEATGRNSTATE] || states[HEATREDSTATE];
+ states[PUMPSTATE] = (payload[FLT_IDX] & (1 << FLT_BIT)) > 0;
+ states[CHAR1] = (uint8_t)_getChar(payload[DGT1_IDX]);
+ states[CHAR2] = (uint8_t)_getChar(payload[DGT2_IDX]);
+ states[CHAR3] = (uint8_t)_getChar(payload[DGT3_IDX]);
+ if(HASJETS) states[JETSSTATE] = (payload[HJT_IDX] & (1 << HJT_BIT)) > 0;
+ else states[JETSSTATE] = 0;
+ //Determine if display is showing target temp or actual temp or anything else.
+ //Unreadable characters - exit
+ if(states[CHAR1] == '*' || states[CHAR2] == '*' || states[CHAR3] == '*') return;
+ //Error or user plays with timer button - exit (error notification can be dealt with in main.cpp or elsewhere)
+ if(states[CHAR1] == 'E' || states[CHAR3] == 'H' || states[CHAR3] == ' ') return;
+
+ //Stop expecting target temp after timeout
+ if((millis()-buttonReleaseTime) > 2000) capturePhase = uncertain;
+ if((millis()-buttonReleaseTime) > 6000) capturePhase = readtemperature;
+ //convert text on display to a value if the chars are recognized
+ String tempstring = String((char)states[CHAR1])+String((char)states[CHAR2])+String((char)states[CHAR3]);
+ uint8_t parsedValue = tempstring.toInt();
+ //capture target temperature only if showing plausible values (not blank screen while blinking)
+ if( (capturePhase == readtarget) && (parsedValue > 19) ) {
+ states[TARGET] = parsedValue;
+ }
+ //wait 6 seconds after UP/DOWN is released to be sure that actual temp is shown
+ if(capturePhase == readtemperature)
+ {
+ if(states[TEMPERATURE] != parsedValue) dataAvailable = true;
+ states[TEMPERATURE] = parsedValue;
+ }
- if(states[UNITSTATE] != _prevUNT || states[HEATSTATE] != _prevHTR || states[PUMPSTATE] != _prevFLT) {
- stateChanged = true;
- _prevUNT = states[UNITSTATE];
- _prevHTR = states[HEATSTATE];
- _prevFLT = states[PUMPSTATE];
- }
+ //If any of these states changes, we need to set a flag to save states. Used to restore them after reboot.
+ if(states[UNITSTATE] != _prevUNT || states[HEATSTATE] != _prevHTR || states[PUMPSTATE] != _prevFLT) {
+ stateChanged = true;
+ _prevUNT = states[UNITSTATE];
+ _prevHTR = states[HEATSTATE];
+ _prevFLT = states[PUMPSTATE];
}
}
diff --git a/Code/6-wire-version/lib/BWC/BWC_common.cpp b/Code/6-wire-version/lib/BWC/BWC_common.cpp
index 2956221c..7d50ddda 100644
--- a/Code/6-wire-version/lib/BWC/BWC_common.cpp
+++ b/Code/6-wire-version/lib/BWC/BWC_common.cpp
@@ -101,7 +101,6 @@ void BWC::loop(){
//queue overrides real buttons
_handleButtonQ();
if(_saveEventlogNeeded) saveEventlog();
- if(_saveCmdqNeeded) _saveCommandQueue();
if(_saveSettingsNeeded) saveSettings();
if(_cio.stateChanged) {
_saveStatesNeeded = true;
@@ -183,7 +182,6 @@ void BWC::_handleButtonQ(void) {
//check if state is as desired, or duration is up. If so - remove row. Else set BTNCODE
if( (_cio.states[_buttonQ[0][1]] == _buttonQ[0][2]) || (_buttonQ[0][3] <= 0) )
{
- if(_buttonQ[0][0] == UP || _buttonQ[0][0] == DOWN) maxeffort = false;
//remove row
for(int i = 0; i < _qButtonLen-1; i++){
_buttonQ[i][0] = _buttonQ[i+1][0];
@@ -196,7 +194,6 @@ void BWC::_handleButtonQ(void) {
}
else
{
- if(_buttonQ[0][0] == UP || _buttonQ[0][0] == DOWN) maxeffort = true;
//set buttoncode
_cio.button = ButtonCodes[_buttonQ[0][0]];
}
@@ -531,7 +528,6 @@ String BWC::getJSONCommandQueue(){
}
bool BWC::newData(){
- if(maxeffort) return false;
bool result = _cio.dataAvailable;
_cio.dataAvailable = false;
if (result && _audio) _dsp.beep();
@@ -596,10 +592,6 @@ void BWC::saveSettingsFlag(){
}
void BWC::saveSettings(){
- if(maxeffort) {
- _saveSettingsNeeded = true;
- return;
- }
//kill the dog
ESP.wdtDisable();
_saveSettingsNeeded = false;
@@ -673,14 +665,8 @@ void BWC::_loadCommandQueue(){
}
void BWC::_saveCommandQueue(){
- if(maxeffort) {
- _saveCmdqNeeded = true;
- return;
- }
//kill the dog
ESP.wdtDisable();
-
- _saveCmdqNeeded = false;
File file = LittleFS.open("cmdq.txt", "w");
if (!file) {
Serial.println(F("Failed to save cmdq.txt"));
@@ -719,10 +705,6 @@ void BWC::reloadSettings(){
}
void BWC::_saveStates() {
- if(maxeffort) {
- _saveStatesNeeded = true;
- return;
- }
//kill the dog
ESP.wdtDisable();
@@ -777,11 +759,6 @@ void BWC::_restoreStates() {
}
void BWC::saveEventlog(){
- if(maxeffort) {
- _saveEventlogNeeded = true;
- return;
- }
- _saveEventlogNeeded = false;
//kill the dog
ESP.wdtDisable();
File file = LittleFS.open("eventlog.txt", "a");
diff --git a/Code/6-wire-version/lib/BWC/model.h b/Code/6-wire-version/lib/BWC/model.h
index 2ddf7ae6..a701571b 100644
--- a/Code/6-wire-version/lib/BWC/model.h
+++ b/Code/6-wire-version/lib/BWC/model.h
@@ -6,5 +6,7 @@
//#define MALDIVES2021 //hydrojets
//If using/testing the new PCB choose PCB_V2
-#define PCB_V1
-//#define PCB_V2 //The PCB with rounded corners
\ No newline at end of file
+//#define PCB_V1
+#define PCB_V2 //The PCB with rounded corners
+
+#warning "USING PINOUT FOR PCB V2 (PCB WITH ROUND CORNERS). EDIT lib/BWC/model.h IF USING OTHER PCB!"
\ No newline at end of file
diff --git a/Code/6-wire-version/platformio.ini b/Code/6-wire-version/platformio.ini
index 9c6e05bc..da1f8437 100644
--- a/Code/6-wire-version/platformio.ini
+++ b/Code/6-wire-version/platformio.ini
@@ -22,11 +22,14 @@ lib_deps =
links2004/WebSockets@^2.3.3
knolleary/PubSubClient@^2.8
tzapu/WiFiManager@^0.16.0
+ me-no-dev/ESPAsyncTCP
board_build.filesystem = littlefs
monitor_speed = 115200
; Set upload speed to 115200 if you get transfer errors
-upload_speed = 921600
+; upload_speed = 921600
; board_build.f_cpu = 160000000L
+build_flags =
+ -DWEBSOCKETS_NETWORK_TYPE="NETWORK_ESP8266_ASYNC"
; build_type = debug
; monitor_filters = esp8266_exception_decoder, default
diff --git a/Code/6-wire-version/src/config.h b/Code/6-wire-version/src/config.h
index 37c09330..444f56aa 100644
--- a/Code/6-wire-version/src/config.h
+++ b/Code/6-wire-version/src/config.h
@@ -2,7 +2,7 @@
#include
#define DEVICE_NAME "layzspa"
-#define FW_VERSION "2022-05-24"
+#define FW_VERSION "2022-06-29"
#define HA_PREFIX "homeassistant"
/*
diff --git a/Code/6-wire-version/src/main.cpp b/Code/6-wire-version/src/main.cpp
index e3ce4223..946ed935 100644
--- a/Code/6-wire-version/src/main.cpp
+++ b/Code/6-wire-version/src/main.cpp
@@ -67,7 +67,7 @@ void loop()
if (WiFi.status() == WL_CONNECTED)
{
// listen for websocket events
- webSocket.loop();
+ // webSocket.loop();
// listen for webserver events
server.handleClient();
// listen for OTA events
@@ -434,14 +434,18 @@ void startOTA()
void stopall()
{
bwc.stop();
+ updateMqttTimer.detach();
periodicTimer.detach();
updateWSTimer.detach();
LittleFS.end();
server.stop();
webSocket.close();
mqttClient.disconnect();
+ bwc.saveSettings();
}
+
+
/**
* start a web socket server
*/
@@ -1068,10 +1072,10 @@ void handleDir()
while (root.next())
{
Serial.println(root.fileName());
- mydir += root.fileName() + F(" \t Size: ");
- mydir += String(root.fileSize()) + F(" Bytes\r\n");
+ mydir += "" + root.fileName() + "" + F(" \t Size: ");
+ mydir += String(root.fileSize()) + F(" Bytes
");
}
- server.send(200, "text/plain", mydir);
+ server.send(200, "text/html", mydir);
}
/**
@@ -1186,14 +1190,11 @@ void handleRestart()
server.send(303);
delay(1000);
- periodicTimer.detach();
- updateMqttTimer.detach();
- updateWSTimer.detach();
- bwc.stop();
- bwc.saveSettings();
-
+ stopall();
+ delay(1000);
Serial.println(F("ESP restart ..."));
ESP.restart();
+ delay(3000);
}