11/*
22 xsns_83_neopool.ino - Sugar Valley NeoPool Control System Modbus support for Tasmota
33
4- Copyright (C) 2023 Norbert Richter
4+ Copyright (C) 2025 Norbert Richter
55
66 This program is free software: you can redistribute it and/or modify
77 it under the terms of the GNU General Public License as published by
5050 * Only one Modbus client (master) can be connected to the Modbus connector
5151 * of the same name. It is not possible to operate several clients on
5252 * connectors with the same name.
53- *
5453 * The differently labelled Modbus connectors are completely independent
5554 * physical Modbus interfaces. Data traffic on one of the connector is
5655 * invisible on the other connectors. One exception is the DISPLAY connector,
5756 * which is present twice and is normally occupied by the built-in LCD.
5857 * Since only one Modbus client can operate one Modbus server at a time, the
5958 * DISPLAY connector is useless for our purposes as long as the internal LCD
6059 * is connected to one of the two DISPLAY connectors at the same time.
61- *
62- * Conclusion:
63- * Use the WIFI or EXTERNAL connector only.
60+ * Conclusion: Use the WIFI or EXTERNAL connector only.
6461\****************************************************************************/
6562
6663#define XSNS_83 83
@@ -290,7 +287,7 @@ enum NeoPoolRegister {
290287 // Contains the configuration parameters for the screen controllers (language, colours, sound, etc).
291288 MBF_PAR_UICFG_MACHINE = 0x0600 , // 0x0600* Machine type (see MBV_PAR_MACH_* and kNeoPoolMachineNames[])
292289 MBF_PAR_UICFG_LANGUAGE, // 0x0601* Selected language (see MBV_PAR_LANG_*)
293- MBF_PAR_UICFG_BACKLIGHT, // 0x0602* Display backlight function (see MBV_PAR_BACKLIGHT_*)
290+ MBF_PAR_UICFG_BACKLIGHT, // 0x0602* Display backlight brightness (in %, upper part (8-bit MSB)=0-100) and function (lower part 8-bit LSB, see MBV_PAR_BACKLIGHT_*)
294291 MBF_PAR_UICFG_SOUND, // 0x0603* mask Audible alerts (see MBMSK_PAR_SOUND_*)
295292 MBF_PAR_UICFG_PASSWORD, // 0x0604* System password encoded in BCD
296293 MBF_PAR_UICFG_VISUAL_OPTIONS, // 0x0605* mask Stores the different display options for the user interface menus (bitmask). Some bits allow you to hide options that are normally visible (bits 0 to 3) while other bits allow you to show options that are normally hidden (bits 9 to 15)
@@ -517,7 +514,7 @@ enum NeoPoolConstAndBitMask {
517514 MBV_PAR_LANG_HUNGARIAN = 10 ,
518515 MBV_PAR_LANG_RUSSIAN = 11 ,
519516
520- // MBF_PAR_UICFG_BACKLIGHT
517+ // MBF_PAR_UICFG_BACKLIGHT (LSB)
521518 MBV_PAR_BACKLIGHT_15SEC = 0 , // Backlight off after 15 sec
522519 MBV_PAR_BACKLIGHT_30SEC = 1 , // Backlight off after 30 sec
523520 MBV_PAR_BACKLIGHT_60SEC = 2 , // Backlight off after 60 sec
@@ -1174,15 +1171,23 @@ const char HTTP_SNS_NEOPOOL_STATUS_ACTIVE[] PROGMEM = "filter:invert(1)";
11741171 *
11751172 * NPRead <addr> {<cnt>}
11761173 * NPReadL <addr> {<cnt>}
1177- * read 16/32-bit register (cnt = 1..30|1..15), cnt = 1 if omitted
1178- * NPRead read 16-bit register
1179- * NPReadL read 32-bit register
1174+ * NPReadLSB <addr> {<cnt>}
1175+ * NPReadMSB <addr> {<cnt>}
1176+ * read 16|32-bit register (cnt = 1..30|1..15), cnt = 1 if omitted
1177+ * NPRead read 16-bit register
1178+ * NPReadL read 32-bit register
1179+ * NPReadLSB read 16-bit register LSB only (like NPRead, but only reads the least significant byte (LSB) of 16-bit register)
1180+ * NPReadMSB read 16-bit register MSB only (like NPRead, but only reads the most significant byte (MSB) of 16-bit register)
11801181 *
11811182 * NPWrite <addr> <data> {<data>...}
11821183 * NPWriteL <addr> <data> {<data>...}
1183- * NPWrite write 16-bit register (data = 0..65535)
1184- * NPWriteL write 32-bit register (data = 0..4294967295)
1185- * The max. number of <data> parameters is 10
1184+ * NPWriteLSB <addr> <data> {<data>...}
1185+ * NPWriteMSB <addr> <data> {<data>...}
1186+ * write 16|32-bit register (the max. number of <data> parameters is 20|10)
1187+ * NPWrite write 16-bit register (data = 0..65535)
1188+ * NPWriteL write 32-bit register (data = 0..4294967295)
1189+ * NPWriteLSB write 16-bit register LSB only (data = 0..255, like NPWrite, but only writes the least significant byte (LSB) of 16-bit register)
1190+ * NPWriteMSB write 16-bit register MSB only (data = 0..255, like NPWrite, but only writes the most significant byte (LSB) of 16-bit register)
11861191 *
11871192 * NPBit <addr> <bit> {<data>}
11881193 * NPBitL <addr> <bit> {<data>}
@@ -1253,8 +1258,12 @@ const char HTTP_SNS_NEOPOOL_STATUS_ACTIVE[] PROGMEM = "filter:invert(1)";
12531258#define D_CMND_NP_RESULT " Result"
12541259#define D_CMND_NP_READ " Read"
12551260#define D_CMND_NP_READL " ReadL"
1261+ #define D_CMND_NP_READLSB D_CMND_NP_READ " LSB"
1262+ #define D_CMND_NP_READMSB D_CMND_NP_READ " MSB"
12561263#define D_CMND_NP_WRITE " Write"
12571264#define D_CMND_NP_WRITEL " WriteL"
1265+ #define D_CMND_NP_WRITELSB D_CMND_NP_WRITE " LSB"
1266+ #define D_CMND_NP_WRITEMSB D_CMND_NP_WRITE " MSB"
12581267#define D_CMND_NP_BIT " Bit"
12591268#define D_CMND_NP_BITL " BitL"
12601269#define D_CMND_NP_FILTRATION " Filtration"
@@ -1289,8 +1298,12 @@ const char kNPCommands[] PROGMEM = D_PRFX_NEOPOOL "|" // Prefix
12891298 D_CMND_NP_RESULT " |"
12901299 D_CMND_NP_READ " |"
12911300 D_CMND_NP_READL " |"
1301+ D_CMND_NP_READLSB " |"
1302+ D_CMND_NP_READMSB " |"
12921303 D_CMND_NP_WRITE " |"
12931304 D_CMND_NP_WRITEL " |"
1305+ D_CMND_NP_WRITELSB " |"
1306+ D_CMND_NP_WRITEMSB " |"
12941307 D_CMND_NP_BIT " |"
12951308 D_CMND_NP_BITL " |"
12961309 D_CMND_NP_FILTRATION " |"
@@ -1326,6 +1339,10 @@ void (* const NPCommand[])(void) PROGMEM = {
13261339 &CmndNeopoolResult,
13271340 &CmndNeopoolReadReg,
13281341 &CmndNeopoolReadReg,
1342+ &CmndNeopoolReadReg,
1343+ &CmndNeopoolReadReg,
1344+ &CmndNeopoolWriteReg,
1345+ &CmndNeopoolWriteReg,
13291346 &CmndNeopoolWriteReg,
13301347 &CmndNeopoolWriteReg,
13311348 &CmndNeopoolBit,
@@ -2520,7 +2537,7 @@ void NeoPoolShow(bool json)
25202537 * Command implementation
25212538\****************************************************************************/
25222539
2523- void NeopoolReadWriteResponse (uint16_t addr, uint16_t *data, uint16_t cnt, bool fbits32, int16_t bit)
2540+ void NeopoolReadWriteResponse (uint16_t addr, uint16_t *data, uint16_t cnt, bool fbits32, bool flsb, bool fmsb, int16_t bit)
25242541{
25252542 const char *data_fmt;
25262543 uint32_t ldata;
@@ -2531,27 +2548,32 @@ void NeopoolReadWriteResponse(uint16_t addr, uint16_t *data, uint16_t cnt, bool
25312548
25322549 data_fmt = PSTR (" %ld" );
25332550 if (NEOPOOL_RESULT_HEX == NeoPoolSettings.result ) {
2534- data_fmt = fbits32 ? PSTR (" \" 0x%08X\" " ) : PSTR (" \" 0x%04X\" " );
2535- }
2536- ldata = (uint32_t )data[0 ];
2537- if (fbits32) {
2538- ldata |= (uint32_t )data[1 ] << 16 ;
2551+ data_fmt = fbits32 ? PSTR (" \" 0x%08X\" " ) : (!flsb && !fmsb) ? PSTR (" \" 0x%04X\" " ) : PSTR (" \" 0x%02X\" " );
25392552 }
2553+ char sdel[2 ] = {0 };
25402554 if ( cnt > 1 ) {
2541- char sdel[2 ] = {0 };
25422555 ResponseAppend_P (PSTR (" [" ));
2543- for (uint16_t i=0 ; i<cnt; i++) {
2556+ }
2557+ for (uint16_t i=0 ; i<cnt; i++) {
2558+ if ( cnt > 1 ) {
25442559 ResponseAppend_P (PSTR (" %s" ), sdel);
2545- ldata = (uint32_t )data[(fbits32+1 )*i];
2546- if (fbits32) {
2547- ldata |= (uint32_t )data[(fbits32+1 )*i+1 ] << 16 ;
2548- }
2549- ResponseAppend_P (data_fmt, ldata);
2550- *sdel = ' ,' ;
25512560 }
2552- ResponseAppend_P (PSTR (" ]" ));
2553- } else {
2561+ ldata = (uint32_t )data[(fbits32+1 )*i];
2562+ if (fbits32) {
2563+ ldata |= (uint32_t )data[(fbits32+1 )*i+1 ] << 16 ;
2564+ }
2565+ else if (flsb) {
2566+ ldata &= 0xff ;
2567+ }
2568+ else if (fmsb) {
2569+ ldata >>= 8 ;
2570+ ldata &= 0xff ;
2571+ }
25542572 ResponseAppend_P (data_fmt, ldata);
2573+ *sdel = ' ,' ;
2574+ }
2575+ if ( cnt > 1 ) {
2576+ ResponseAppend_P (PSTR (" ]" ));
25552577 }
25562578 if (bit >= 0 ) {
25572579 ResponseAppend_P (PSTR (" ,\" " D_NEOPOOL_JSON_BIT " %d\" :%ld" ), bit, (ldata>>bit) & 1 );
@@ -2587,6 +2609,8 @@ void CmndNeopoolReadReg(void)
25872609 uint32_t value[2 ] = { 0 };
25882610 uint32_t params_cnt = ParseParameters (nitems (value), value);
25892611 bool fbits32 = !strcasecmp_P (XdrvMailbox.command , PSTR (D_PRFX_NEOPOOL D_CMND_NP_READL));
2612+ bool flsb = !strcasecmp_P (XdrvMailbox.command , PSTR (D_PRFX_NEOPOOL D_CMND_NP_READLSB));
2613+ bool fmsb = !strcasecmp_P (XdrvMailbox.command , PSTR (D_PRFX_NEOPOOL D_CMND_NP_READMSB));
25902614
25912615 cnt = 1 ;
25922616 if (2 == params_cnt) {
@@ -2599,7 +2623,7 @@ void CmndNeopoolReadReg(void)
25992623 return ;
26002624 }
26012625 }
2602- NeopoolReadWriteResponse (addr, data, cnt, fbits32, -1 );
2626+ NeopoolReadWriteResponse (addr, data, cnt, fbits32, flsb, fmsb, -1 );
26032627}
26042628
26052629
@@ -2609,16 +2633,34 @@ void CmndNeopoolWriteReg(void)
26092633 uint32_t value[(nitems (data)/2 )+1 ] = { 0 };
26102634 uint32_t params_cnt = ParseParameters (nitems (value), value);
26112635 bool fbits32 = !strcasecmp_P (XdrvMailbox.command , PSTR (D_PRFX_NEOPOOL D_CMND_NP_WRITEL));
2636+ bool flsb = !strcasecmp_P (XdrvMailbox.command , PSTR (D_PRFX_NEOPOOL D_CMND_NP_WRITELSB));
2637+ bool fmsb = !strcasecmp_P (XdrvMailbox.command , PSTR (D_PRFX_NEOPOOL D_CMND_NP_WRITEMSB));
26122638
2613- if (params_cnt > 1 ) {
2639+ cnt = params_cnt-1 ;
2640+ if (params_cnt > 1 && cnt < (fbits32 ? (nitems (data)/2 ) : nitems (data))) {
26142641 addr = value[0 ];
2615- cnt = params_cnt-1 ;
2642+ if (flsb || fmsb) {
2643+ if (NEOPOOL_MODBUS_OK != NeoPoolReadRegister (addr, data, fbits32 ? (cnt*2 ) : cnt)) {
2644+ NeopoolResponseError ();
2645+ return ;
2646+ }
2647+ }
26162648 for (uint32_t i = 0 ; i < cnt; i++) {
26172649 if (fbits32) {
26182650 data[i*2 ] = value[i+1 ]; // LSB
26192651 data[i*2 +1 ] = value[i+1 ]>>16 ; // MSB
26202652 } else {
2621- data[i] = value[i+1 ];
2653+ if (flsb) {
2654+ data[i] &= 0xff00 ;
2655+ data[i] |= (value[i+1 ] & 0xff );
2656+ }
2657+ else if (fmsb) {
2658+ data[i] &= 0x00ff ;
2659+ data[i] |= (value[i+1 ] & 0xff )<<8 ;
2660+ }
2661+ else {
2662+ data[i] = value[i+1 ];
2663+ }
26222664 }
26232665 }
26242666 if (NEOPOOL_MODBUS_OK != NeoPoolWriteRegister (addr, data, fbits32 ? cnt*2 : cnt)) {
@@ -2630,7 +2672,7 @@ void CmndNeopoolWriteReg(void)
26302672 NeopoolResponseError ();
26312673 return ;
26322674 }
2633- NeopoolReadWriteResponse (addr, data, cnt, fbits32, -1 );
2675+ NeopoolReadWriteResponse (addr, data, cnt, fbits32, flsb, fmsb, -1 );
26342676}
26352677
26362678
@@ -2674,7 +2716,7 @@ void CmndNeopoolBit(void)
26742716 NeopoolResponseError ();
26752717 return ;
26762718 }
2677- NeopoolReadWriteResponse (addr, &data, 1 , fbits32, bit);
2719+ NeopoolReadWriteResponse (addr, &data, 1 , fbits32, false , false , bit);
26782720 return ;
26792721 }
26802722
0 commit comments