Merge pull request #12813 from curzon01/dev-neopool

Update/fix NeoPool driver
This commit is contained in:
Theo Arends 2021-08-02 10:24:15 +02:00 committed by GitHub
commit 6f6f8e57a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -599,6 +599,18 @@ enum NeoPoolModbusCode {
NEOPOOL_MODBUS_ERROR_DEADLOCK NEOPOOL_MODBUS_ERROR_DEADLOCK
}; };
// NeoPool value resolutions
typedef struct {
uint16_t ph : 2;
uint16_t cl : 2;
uint16_t ion : 2;
} NeoPoolResMBitfield;
NeoPoolResMBitfield neopool_resolution {
.ph = 1,
.cl = 1,
.ion = 1
};
#define D_NEOPOOL_NAME "NeoPool" #define D_NEOPOOL_NAME "NeoPool"
@ -651,11 +663,11 @@ const char kNeoPoolpHAlarms[] PROGMEM =
#define D_STR_BIT "Bit" #define D_STR_BIT "Bit"
#endif // D_STR_BIT #endif // D_STR_BIT
#define NEOPOOL_FMT_PH "%1_f" #define NEOPOOL_FMT_PH "%*_f"
#define NEOPOOL_FMT_RX "%0_f" #define NEOPOOL_FMT_RX "%d"
#define NEOPOOL_FMT_CL "%1_f" #define NEOPOOL_FMT_CL "%*_f"
#define NEOPOOL_FMT_CD "%d" #define NEOPOOL_FMT_CD "%d"
#define NEOPOOL_FMT_ION "%1_f" #define NEOPOOL_FMT_ION "%*_f"
#define NEOPOOL_FMT_HIDRO "%*_f" #define NEOPOOL_FMT_HIDRO "%*_f"
#define D_NEOPOOL_UNIT_GPERH "g/h" #define D_NEOPOOL_UNIT_GPERH "g/h"
@ -697,7 +709,7 @@ const char HTTP_SNS_NEOPOOL_STATUS_ACTIVE[] PROGMEM = "filter:invert(1)";
* any other value of <time> will set time as epoch * any other value of <time> will set time as epoch
* *
* NPLight {<state> {delay}} * NPLight {<state> {delay}}
* get/set light (state = 0|1|2|3) * get/set light (state = 0|1|2|3|4)
* get light state if <state> is omitted, otherwise set new state * get light state if <state> is omitted, otherwise set new state
* 0 - switch light manual off * 0 - switch light manual off
* 1 - switch light manual on * 1 - switch light manual on
@ -722,6 +734,12 @@ const char HTTP_SNS_NEOPOOL_STATUS_ACTIVE[] PROGMEM = "filter:invert(1)";
* 1 - output as hexadecimal strings (default) * 1 - output as hexadecimal strings (default)
* get output format if <format> is omitted, otherwise * get output format if <format> is omitted, otherwise
* *
* NPPHRes {<digits>}
* NPCLRes {<digits>}
* NPIonRes {<digits>}
* get/set number of digits in results for PH, CL and ION values
*
*
* NPRead <addr> {<cnt>} * NPRead <addr> {<cnt>}
* NPReadL <addr> {<cnt>} * NPReadL <addr> {<cnt>}
* read 16/32-bit register (cnt = 1..30|1..15), cnt = 1 if omitted * read 16/32-bit register (cnt = 1..30|1..15), cnt = 1 if omitted
@ -812,6 +830,9 @@ const char HTTP_SNS_NEOPOOL_STATUS_ACTIVE[] PROGMEM = "filter:invert(1)";
#define D_CMND_NP_SAVE "Save" #define D_CMND_NP_SAVE "Save"
#define D_CMND_NP_EXEC "Exec" #define D_CMND_NP_EXEC "Exec"
#define D_CMND_NP_ESCAPE "Escape" #define D_CMND_NP_ESCAPE "Escape"
#define D_CMND_NP_PHRES "PHRes"
#define D_CMND_NP_CLRES "CLRes"
#define D_CMND_NP_IONRES "IONRes"
const char kNPCommands[] PROGMEM = D_PRFX_NEOPOOL "|" // Prefix const char kNPCommands[] PROGMEM = D_PRFX_NEOPOOL "|" // Prefix
D_CMND_NP_RESULT "|" D_CMND_NP_RESULT "|"
@ -827,7 +848,10 @@ const char kNPCommands[] PROGMEM = D_PRFX_NEOPOOL "|" // Prefix
D_CMND_NP_LIGHT "|" D_CMND_NP_LIGHT "|"
D_CMND_NP_SAVE "|" D_CMND_NP_SAVE "|"
D_CMND_NP_EXEC "|" D_CMND_NP_EXEC "|"
D_CMND_NP_ESCAPE D_CMND_NP_ESCAPE "|"
D_CMND_NP_PHRES "|"
D_CMND_NP_CLRES "|"
D_CMND_NP_IONRES
; ;
void (* const NPCommand[])(void) PROGMEM = { void (* const NPCommand[])(void) PROGMEM = {
@ -844,7 +868,10 @@ void (* const NPCommand[])(void) PROGMEM = {
&CmndNeopoolLight, &CmndNeopoolLight,
&CmndNeopoolSave, &CmndNeopoolSave,
&CmndNeopoolExec, &CmndNeopoolExec,
&CmndNeopoolEscape &CmndNeopoolEscape,
&CmndNeopoolPHRes,
&CmndNeopoolCLRes,
&CmndNeopoolIONRes
}; };
@ -1008,13 +1035,29 @@ void NeoPoolLogRW(const char *name, uint16_t addr, uint16_t *data, uint16_t cnt)
#endif // DEBUG_TASMOTA_SENSOR #endif // DEBUG_TASMOTA_SENSOR
void NeoPool250msSetStatus(bool status)
{
neopool_poll = status;
if (!status) {
// clear rec buffer from possible prev periodical communication
uint32_t timeoutMS = millis() + 100 * NEOPOOL_READ_TIMEOUT; // Max delay before we timeout
while (NeoPoolModbus->available() && millis() < timeoutMS) {
NeoPoolModbus->read();
SleepDelay(0);
}
}
}
uint8_t NeoPoolReadRegister(uint16_t addr, uint16_t *data, uint16_t cnt) uint8_t NeoPoolReadRegister(uint16_t addr, uint16_t *data, uint16_t cnt)
{ {
bool data_ready; bool data_ready;
uint32_t timeoutMS; uint32_t timeoutMS;
uint16_t *origin = data; uint16_t *origin = data;
neopool_poll = false; NeoPool250msSetStatus(false);
*data = 0; *data = 0;
NeoPoolModbus->Send(NEOPOOL_MODBUS_ADDRESS, NEOPOOL_READ_REGISTER, addr, cnt); NeoPoolModbus->Send(NEOPOOL_MODBUS_ADDRESS, NEOPOOL_READ_REGISTER, addr, cnt);
@ -1028,14 +1071,14 @@ uint8_t NeoPoolReadRegister(uint16_t addr, uint16_t *data, uint16_t cnt)
#ifdef DEBUG_TASMOTA_SENSOR #ifdef DEBUG_TASMOTA_SENSOR
AddLog(LOG_LEVEL_DEBUG, PSTR("NEO: addr 0x%04X read data error %d"), addr, error); AddLog(LOG_LEVEL_DEBUG, PSTR("NEO: addr 0x%04X read data error %d"), addr, error);
#endif // DEBUG_TASMOTA_SENSOR #endif // DEBUG_TASMOTA_SENSOR
neopool_poll = true; NeoPool250msSetStatus(true);
free(buffer); free(buffer);
return NEOPOOL_MODBUS_ERROR_RW_DATA; return NEOPOOL_MODBUS_ERROR_RW_DATA;
} }
for(uint64_t i = 0; i < cnt; i++) { for(uint64_t i = 0; i < cnt; i++) {
*data++ = (buffer[i*2+3] << 8) | buffer[i*2+4]; *data++ = (buffer[i*2+3] << 8) | buffer[i*2+4];
} }
neopool_poll = true; NeoPool250msSetStatus(true);
delay(2); delay(2);
free(buffer); free(buffer);
#ifdef DEBUG_TASMOTA_SENSOR #ifdef DEBUG_TASMOTA_SENSOR
@ -1051,7 +1094,7 @@ uint8_t NeoPoolReadRegister(uint16_t addr, uint16_t *data, uint16_t cnt)
#ifdef DEBUG_TASMOTA_SENSOR #ifdef DEBUG_TASMOTA_SENSOR
AddLog(LOG_LEVEL_DEBUG, PSTR("NEO: addr 0x%04X read data timeout"), addr); AddLog(LOG_LEVEL_DEBUG, PSTR("NEO: addr 0x%04X read data timeout"), addr);
#endif // DEBUG_TASMOTA_SENSOR #endif // DEBUG_TASMOTA_SENSOR
neopool_poll = true; NeoPool250msSetStatus(true);
return NEOPOOL_MODBUS_ERROR_TIMEOUT; return NEOPOOL_MODBUS_ERROR_TIMEOUT;
} }
@ -1066,7 +1109,7 @@ uint8_t NeoPoolWriteRegister(uint16_t addr, uint16_t *data, uint16_t cnt)
#ifdef DEBUG_TASMOTA_SENSOR #ifdef DEBUG_TASMOTA_SENSOR
NeoPoolLogRW("NeoPoolWriteRegister", addr, data, cnt); NeoPoolLogRW("NeoPoolWriteRegister", addr, data, cnt);
#endif // DEBUG_TASMOTA_SENSOR #endif // DEBUG_TASMOTA_SENSOR
neopool_poll = false; NeoPool250msSetStatus(false);
numbytes = 7+cnt*2; numbytes = 7+cnt*2;
frame = (uint8_t*)malloc(numbytes+2); frame = (uint8_t*)malloc(numbytes+2);
if (nullptr == frame) { if (nullptr == frame) {
@ -1106,7 +1149,7 @@ uint8_t NeoPoolWriteRegister(uint16_t addr, uint16_t *data, uint16_t cnt)
#ifdef DEBUG_TASMOTA_SENSOR #ifdef DEBUG_TASMOTA_SENSOR
AddLog(LOG_LEVEL_DEBUG, PSTR("NEO: addr 0x%04X write data response error %d"), addr, error); AddLog(LOG_LEVEL_DEBUG, PSTR("NEO: addr 0x%04X write data response error %d"), addr, error);
#endif // DEBUG_TASMOTA_SENSOR #endif // DEBUG_TASMOTA_SENSOR
neopool_poll = true; NeoPool250msSetStatus(true);
return NEOPOOL_MODBUS_ERROR_RW_DATA; return NEOPOOL_MODBUS_ERROR_RW_DATA;
} }
if (9 == error) { if (9 == error) {
@ -1115,7 +1158,7 @@ uint8_t NeoPoolWriteRegister(uint16_t addr, uint16_t *data, uint16_t cnt)
NeoPoolModbus->read(); NeoPoolModbus->read();
} }
} }
neopool_poll = true; NeoPool250msSetStatus(true);
delay(2); delay(2);
if (MBF_SAVE_TO_EEPROM == addr) { if (MBF_SAVE_TO_EEPROM == addr) {
// EEPROM write can take some time, wait until device is ready // EEPROM write can take some time, wait until device is ready
@ -1128,7 +1171,7 @@ uint8_t NeoPoolWriteRegister(uint16_t addr, uint16_t *data, uint16_t cnt)
#ifdef DEBUG_TASMOTA_SENSOR #ifdef DEBUG_TASMOTA_SENSOR
AddLog(LOG_LEVEL_DEBUG, PSTR("NEO: addr 0x%04X write data response timeout"), addr); AddLog(LOG_LEVEL_DEBUG, PSTR("NEO: addr 0x%04X write data response timeout"), addr);
#endif // DEBUG_TASMOTA_SENSOR #endif // DEBUG_TASMOTA_SENSOR
neopool_poll = true; NeoPool250msSetStatus(true);
return NEOPOOL_MODBUS_ERROR_TIMEOUT; return NEOPOOL_MODBUS_ERROR_TIMEOUT;
} }
@ -1190,6 +1233,7 @@ uint32_t NeoPoolGetSpeedIndex(uint16_t speedvalue)
#define D_NEOPOOL_JSON_COVER "Cover" #define D_NEOPOOL_JSON_COVER "Cover"
#define D_NEOPOOL_JSON_SHOCK "Boost" #define D_NEOPOOL_JSON_SHOCK "Boost"
#define D_NEOPOOL_JSON_LOW "Low" #define D_NEOPOOL_JSON_LOW "Low"
#define D_NEOPOOL_JSON_MIN "Min"
#define D_NEOPOOL_JSON_MAX "Max" #define D_NEOPOOL_JSON_MAX "Max"
#define D_NEOPOOL_JSON_PHPUMP "Pump" #define D_NEOPOOL_JSON_PHPUMP "Pump"
#define D_NEOPOOL_JSON_FLOW1 "FL1" #define D_NEOPOOL_JSON_FLOW1 "FL1"
@ -1233,11 +1277,13 @@ void NeoPoolShow(bool json)
// pH // pH
if (NeoPoolGetData(MBF_PH_STATUS) & MBMSK_PH_STATUS_MEASURE_ACTIVE) { if (NeoPoolGetData(MBF_PH_STATUS) & MBMSK_PH_STATUS_MEASURE_ACTIVE) {
fvalue = (float)NeoPoolGetData(MBF_MEASURE_PH)/100; fvalue = (float)NeoPoolGetData(MBF_MEASURE_PH)/100;
ResponseAppend_P(PSTR(",\"" D_PH "\":{\"" D_JSON_DATA "\":" NEOPOOL_FMT_PH), &fvalue); ResponseAppend_P(PSTR(",\"" D_PH "\":{\"" D_JSON_DATA "\":" NEOPOOL_FMT_PH), neopool_resolution.ph, &fvalue);
// S1 // S1
float fphmin = (float)NeoPoolGetData(MBF_PAR_PH2)/100;
ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_MIN "\":" NEOPOOL_FMT_PH), neopool_resolution.ph, &fphmin);
float fphmax = (float)NeoPoolGetData(MBF_PAR_PH1)/100; float fphmax = (float)NeoPoolGetData(MBF_PAR_PH1)/100;
ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_MAX "\":" NEOPOOL_FMT_PH), &fphmax); ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_MAX "\":" NEOPOOL_FMT_PH), neopool_resolution.ph, &fphmax);
// S2 // S2
ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_STATE "\":%d"), (NeoPoolGetData(MBF_PH_STATUS) & MBMSK_PH_STATUS_ALARM)); ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_STATE "\":%d"), (NeoPoolGetData(MBF_PH_STATUS) & MBMSK_PH_STATUS_ALARM));
@ -1263,14 +1309,13 @@ void NeoPoolShow(bool json)
// Redox // Redox
if (NeoPoolGetData(MBF_RX_STATUS) & MBMSK_RX_STATUS_MEASURE_ACTIVE) { if (NeoPoolGetData(MBF_RX_STATUS) & MBMSK_RX_STATUS_MEASURE_ACTIVE) {
fvalue = (float)NeoPoolGetData(MBF_MEASURE_RX); ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_REDOX "\":" NEOPOOL_FMT_RX), NeoPoolGetData(MBF_MEASURE_RX));
ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_REDOX "\":" NEOPOOL_FMT_RX), &fvalue);
} }
// Chlorine // Chlorine
if (NeoPoolGetData(MBF_CL_STATUS) & MBMSK_CL_STATUS_MEASURE_ACTIVE) { if (NeoPoolGetData(MBF_CL_STATUS) & MBMSK_CL_STATUS_MEASURE_ACTIVE) {
fvalue = (float)NeoPoolGetData(MBF_MEASURE_CL)/100; fvalue = (float)NeoPoolGetData(MBF_MEASURE_CL)/100;
ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_CHLORINE "\":" NEOPOOL_FMT_CL), &fvalue); ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_CHLORINE "\":" NEOPOOL_FMT_CL), neopool_resolution.cl, &fvalue);
} }
// Conductivity // Conductivity
@ -1281,7 +1326,7 @@ void NeoPoolShow(bool json)
// Ionization // Ionization
if (NeoPoolGetData(MBF_PAR_MODEL) & MBMSK_MODEL_ION) { if (NeoPoolGetData(MBF_PAR_MODEL) & MBMSK_MODEL_ION) {
fvalue = (float)NeoPoolGetData(MBF_ION_CURRENT); fvalue = (float)NeoPoolGetData(MBF_ION_CURRENT);
ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_IONIZATION "\":" NEOPOOL_FMT_ION), &fvalue); ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_IONIZATION "\":" NEOPOOL_FMT_ION), neopool_resolution.ion, &fvalue);
} }
// Hydrolysis // Hydrolysis
@ -1442,11 +1487,11 @@ void NeoPoolShow(bool json)
if (NeoPoolGetData(MBF_PH_STATUS) & MBMSK_PH_STATUS_MEASURE_ACTIVE) { if (NeoPoolGetData(MBF_PH_STATUS) & MBMSK_PH_STATUS_MEASURE_ACTIVE) {
// Data // Data
fvalue = (float)NeoPoolGetData(MBF_MEASURE_PH)/100; fvalue = (float)NeoPoolGetData(MBF_MEASURE_PH)/100;
WSContentSend_PD(HTTP_SNS_NEOPOOL_PH, neopool_type, &fvalue); WSContentSend_PD(HTTP_SNS_NEOPOOL_PH, neopool_type, neopool_resolution.ph, &fvalue);
WSContentSend_PD(PSTR("&nbsp;")); WSContentSend_PD(PSTR("&nbsp;"));
// S1 // S1
float fphmax = (float)NeoPoolGetData(MBF_PAR_PH1)/100; float fphmax = (float)NeoPoolGetData(MBF_PAR_PH1)/100;
ext_snprintf_P(stemp, sizeof(stemp), PSTR(NEOPOOL_FMT_PH), &fphmax); ext_snprintf_P(stemp, sizeof(stemp), PSTR(NEOPOOL_FMT_PH), neopool_resolution.ph, &fphmax);
WSContentSend_PD(HTTP_SNS_NEOPOOL_STATUS, bg_color, WSContentSend_PD(HTTP_SNS_NEOPOOL_STATUS, bg_color,
(((uint16_t)(fvalue*10) > (uint16_t)(fphmax*10)) ? HTTP_SNS_NEOPOOL_STATUS_ACTIVE : HTTP_SNS_NEOPOOL_STATUS_INACTIVE), stemp); (((uint16_t)(fvalue*10) > (uint16_t)(fphmax*10)) ? HTTP_SNS_NEOPOOL_STATUS_ACTIVE : HTTP_SNS_NEOPOOL_STATUS_INACTIVE), stemp);
WSContentSend_PD(PSTR(" ")); WSContentSend_PD(PSTR(" "));
@ -1483,12 +1528,10 @@ void NeoPoolShow(bool json)
// S1: 0 // S1: 0
// S2: FL1 // S2: FL1
if (NeoPoolGetData(MBF_RX_STATUS) & MBMSK_RX_STATUS_MEASURE_ACTIVE) { if (NeoPoolGetData(MBF_RX_STATUS) & MBMSK_RX_STATUS_MEASURE_ACTIVE) {
fvalue = (float)NeoPoolGetData(MBF_MEASURE_RX); WSContentSend_PD(HTTP_SNS_NEOPOOL_REDOX, neopool_type, NeoPoolGetData(MBF_MEASURE_RX));
WSContentSend_PD(HTTP_SNS_NEOPOOL_REDOX, neopool_type, &fvalue);
WSContentSend_PD(PSTR("&nbsp;")); WSContentSend_PD(PSTR("&nbsp;"));
// S1 // S1
float frxset = (float)NeoPoolGetData(MBF_PAR_RX1); ext_snprintf_P(stemp, sizeof(stemp), PSTR(NEOPOOL_FMT_RX " " D_UNIT_MILLIVOLT), NeoPoolGetData(MBF_PAR_RX1));
ext_snprintf_P(stemp, sizeof(stemp), PSTR(NEOPOOL_FMT_RX " " D_UNIT_MILLIVOLT), &frxset);
WSContentSend_PD(HTTP_SNS_NEOPOOL_STATUS, bg_color, WSContentSend_PD(HTTP_SNS_NEOPOOL_STATUS, bg_color,
(NeoPoolGetData(MBF_HIDRO_CURRENT) ? HTTP_SNS_NEOPOOL_STATUS_ACTIVE : HTTP_SNS_NEOPOOL_STATUS_INACTIVE), (NeoPoolGetData(MBF_HIDRO_CURRENT) ? HTTP_SNS_NEOPOOL_STATUS_ACTIVE : HTTP_SNS_NEOPOOL_STATUS_INACTIVE),
stemp); stemp);
@ -1498,7 +1541,7 @@ void NeoPoolShow(bool json)
// Chlorine // Chlorine
if (NeoPoolGetData(MBF_CL_STATUS) & MBMSK_CL_STATUS_MEASURE_ACTIVE) { if (NeoPoolGetData(MBF_CL_STATUS) & MBMSK_CL_STATUS_MEASURE_ACTIVE) {
fvalue = (float)NeoPoolGetData(MBF_MEASURE_CL)/100; fvalue = (float)NeoPoolGetData(MBF_MEASURE_CL)/100;
WSContentSend_PD(HTTP_SNS_NEOPOOL_PPM_CHLORINE, neopool_type, fvalue); WSContentSend_PD(HTTP_SNS_NEOPOOL_PPM_CHLORINE, neopool_type, neopool_resolution.ph, &fvalue);
} }
// Conductivity // Conductivity
@ -1516,7 +1559,7 @@ void NeoPoolShow(bool json)
NeoPoolGetData(MBF_ION_STATUS) & MBMSK_ION_STATUS_PROGTIME_EXCEEDED ? PSTR(" " D_NEOPOOL_PR_OFF) : PSTR("") NeoPoolGetData(MBF_ION_STATUS) & MBMSK_ION_STATUS_PROGTIME_EXCEEDED ? PSTR(" " D_NEOPOOL_PR_OFF) : PSTR("")
); );
fvalue = (float)NeoPoolGetData(MBF_ION_CURRENT); fvalue = (float)NeoPoolGetData(MBF_ION_CURRENT);
WSContentSend_PD(HTTP_SNS_NEOPOOL_IONIZATION, neopool_type, &fvalue, NeoPoolGetData(MBF_ION_STATUS)>>13, NeoPoolGetData(MBF_ION_STATUS)&0x0002?" Low":""); WSContentSend_PD(HTTP_SNS_NEOPOOL_IONIZATION, neopool_type, neopool_resolution.ion, &fvalue, NeoPoolGetData(MBF_ION_STATUS)>>13, NeoPoolGetData(MBF_ION_STATUS)&0x0002?" Low":"");
} }
// Filtration mode // Filtration mode
@ -1968,6 +2011,33 @@ void CmndNeopoolEscape(void)
} }
void CmndNeopoolPHRes(void)
{
if (XdrvMailbox.data_len && XdrvMailbox.payload >= 0 && XdrvMailbox.payload <= 3) {
neopool_resolution.ph = XdrvMailbox.payload;
}
ResponseCmndNumber(neopool_resolution.ph);
}
void CmndNeopoolCLRes(void)
{
if (XdrvMailbox.data_len && XdrvMailbox.payload >= 0 && XdrvMailbox.payload <= 3) {
neopool_resolution.cl = XdrvMailbox.payload;
}
ResponseCmndNumber(neopool_resolution.cl);
}
void CmndNeopoolIONRes(void)
{
if (XdrvMailbox.data_len && XdrvMailbox.payload >= 0 && XdrvMailbox.payload <= 3) {
neopool_resolution.ion = XdrvMailbox.payload;
}
ResponseCmndNumber(neopool_resolution.ion);
}
/*********************************************************************************************\ /*********************************************************************************************\
* Interface * Interface