Skip to content

Commit def24f9

Browse files
authored
Merge pull request tasmota#1072 from curzon01/neopool
Update Neopool
2 parents 09bdd71 + e28b317 commit def24f9

File tree

2 files changed

+218
-30
lines changed

2 files changed

+218
-30
lines changed

docs/NeoPool.md

+218-30
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
When [compiling your build](Compile-your-build) add the following to `user_config_override.h`:
66
```arduino
7+
#ifndef USE_NEOPOOL
78
#define USE_NEOPOOL // Add support for Sugar Valley NeoPool Controller - also known under brands Hidrolife, Aquascenic, Oxilife, Bionet, Hidroniser, UVScenic, Station, Brilix, Bayrol and Hay (+6k flash, +60 mem)
8-
#define NEOPOOL_MODBUS_ADDRESS 1 // Any modbus address
9-
#endif
10-
```
9+
#endif
10+
```
1111

1212
[Sugar Valley](https://sugar-valley.net/en/productos/) NeoPool are water treatment systems also known under the names Hidrolife, Aquascenic, Oxilife, Bionet, Hidroniser, UVScenic, Station, Brilix, Bayrol and Hay.
1313
It uses a [RS485](https://en.wikipedia.org/wiki/RS-485) interface with the [Modbus](https://en.wikipedia.org/wiki/Modbus) data protocol for enhancment equipments like Wifi-Interface or a second attached control panel. All functions and parameters can be queried and controlled via this bus interface.
@@ -17,7 +17,7 @@ The Tasmota Sugar Valley NeoPool Controller sensor module shows the most of para
1717
![](_media/xsns_83_neopool_s.png)
1818

1919
There are [Tasmota commands](#commands) implemented to control the high level functions for filtration, light and system parameters such as pH set point, hydrolysis level, redox set point etc.
20-
However, the sensor also provides low-level commands to directly [read]#NPRead) and [write](#NPWrite) NeoPool register, means that you have the option to implement your own commands via home automation systems or by using the Tasmota build-in possibilities [Rules](Commands#rules) with [Backlog](Commands#the-power-of-backlog) or the powerful Berry language on ESP32.
20+
However, the sensor also provides low-level commands to directly [read](#NPRead) and [write](#NPWrite) NeoPool register, means that you have the option to implement your own commands via home automation systems or by using the Tasmota build-in possibilities [Rules](Commands#rules) with [Backlog](Commands#the-power-of-backlog) or the powerful Berry language on ESP32.
2121

2222
## Connection
2323

@@ -84,7 +84,7 @@ After Tasmota restarts, the main screen should display the controller data as sh
8484

8585
## SENSOR data
8686

87-
Sensor data is sent via the Tasmota topic `tele/%topic%/SENSOR` in JSON format every TelePeriod interval. To get the data immediately, use the Tasmota `TelePeriod` command without parameter:
87+
Sensor data is sent via the Tasmota topic `tele/%topic%/SENSOR` in JSON format every [TelePeriod](Commands#teleperiod) interval. To get the data immediately, use the Tasmota [TelePeriod](Commands#teleperiod) command without parameter:
8888

8989
```json
9090
{
@@ -192,9 +192,9 @@ To check which modules are installed use the "Module" value from SENSOR topic or
192192

193193
## Commands
194194

195-
This sensor supports some high-level [Tasmota commands](#commands) for end user.
195+
This sensor supports some high-level [commands](#commands) for end user.
196196

197-
Regardless, all other Modbus registers can be read and write, so you can [enhance](#Enhancements) your Sugar Valley control by using low-level [NPRead]#NPRead)/[NPWrite]#NPWrite) commands.
197+
Regardless, all other Modbus registers can be read and write, so you can [enhance](#Enhancements) your Sugar Valley control by using low-level [NPRead](#NPRead)/[NPWrite](#NPWrite) commands.
198198

199199
Modbus register addresses and their meaning are described within source file [xsns_83_neopool.ino](https://github.com/arendst/Tasmota/blob/development/tasmota/xsns_83_neopool.ino) at the beginning and (partly) within document [171-Modbus-registers](https://downloads.vodnici.net/uploads/wpforo/attachments/69/171-Modbus-registers.pdf).<BR>
200200
Please note that Sugar Valley Modbus registers are not byte addresses but modbus registers containing 16-bit values - don't think in byte memory layout.
@@ -491,13 +491,38 @@ NPAux<x\><a id="NPAux"></a>|`{<state>}`<BR>get/set auxiliary relay <x\> (state =
491491

492492
The class members `NPBoost` and `NPAux` can also be used as templates for further commands.
493493

494-
Store the following code using the WebGUI "Console" / "Manage File system".
494+
Store the following code into a Tasmota file by using the WebGUI "Console" / "Manage File system".
495+
496+
#### neopoolcmd.be
495497

496-
ESP32 file `neopool.be`:
497498
```python
499+
# File: neopoolcmd.be
500+
#
501+
# Add new commands NPBoost and NPAux
502+
503+
# Neopool definitions
504+
var MBF_RELAY_STATE = 0x010E
505+
var MBF_NOTIFICATION = 0x0110
506+
var MBF_CELL_BOOST = 0x020C
507+
508+
var MBF_PAR_TIMER_BLOCK_AUX1_INT1 = 0x04AC
509+
var MBF_PAR_TIMER_BLOCK_AUX2_INT1 = 0x04BB
510+
var MBF_PAR_TIMER_BLOCK_AUX3_INT1 = 0x04CA
511+
var MBF_PAR_TIMER_BLOCK_AUX4_INT1 = 0x04D9
512+
var PAR_TIMER_BLOCK_AUX = [
513+
MBF_PAR_TIMER_BLOCK_AUX1_INT1,
514+
MBF_PAR_TIMER_BLOCK_AUX2_INT1,
515+
MBF_PAR_TIMER_BLOCK_AUX3_INT1,
516+
MBF_PAR_TIMER_BLOCK_AUX4_INT1
517+
]
518+
var MBV_PAR_CTIMER_ALWAYS_ON = 3
519+
var MBV_PAR_CTIMER_ALWAYS_OFF = 4
520+
521+
# NeoPool command class
498522
class NeoPoolCommands
499523
var TEXT_OFF
500524
var TEXT_ON
525+
var TEXT_TOGGLE
501526

502527
# string helper
503528
def ltrim(s)
@@ -514,12 +539,13 @@ class NeoPoolCommands
514539
end
515540

516541
# NPBoost OFF|0|ON|1|REDOX|2
517-
# 0|OFF: Switch boost off
518-
# 1|ON: Switch boost on without redox control
519-
# 2|REDOX: Switch boost on with redox control
542+
# 0|OFF: Switch boost off
543+
# 1|ON: Switch boost on without redox control
544+
# 2|REDOX: Switch boost on with redox control
520545
def NPBoost(cmd, idx, payload)
521546
import string
522547
var ctrl, parm
548+
523549
try
524550
parm = string.toupper(self.trim(payload))
525551
except ..
@@ -536,21 +562,25 @@ class NeoPoolCommands
536562
tasmota.resp_cmnd_error()
537563
return
538564
end
539-
tasmota.cmd(string.format("Backlog NPWrite 0x020C,0x%04X;NPSave;NPExec;NPWrite 0x0110,0x7F", ctrl))
565+
tasmota.cmd(string.format("NPWrite 0x%04X,0x%04X", MBF_CELL_BOOST, ctrl))
566+
tasmota.cmd("NPSave")
567+
tasmota.cmd("NPExec")
568+
tasmota.cmd(string.format("NPWrite 0x%04X,0x7F", MBF_NOTIFICATION))
540569
else
541570
try
542-
ctrl = compile("return "+str(tasmota.cmd("NPRead 0x020C")['NPRead']['Data']))()
571+
ctrl = compile("return "..tasmota.cmd(string.format("NPRead 0x%04X", MBF_CELL_BOOST))['NPRead']['Data'])()
543572
except ..
544573
tasmota.resp_cmnd_error()
545574
return
546575
end
547576
end
548-
tasmota.resp_cmnd(string.format('{"NPBoost":"%s"}', ctrl == 0 ? self.TEXT_OFF : (ctrl & 0x8500) == 0x8500 ? self.TEXT_ON : "REDOX"))
577+
tasmota.resp_cmnd(string.format('{"%s":"%s"}', cmd, ctrl == 0 ? self.TEXT_OFF : (ctrl & 0x8500) == 0x8500 ? self.TEXT_ON : "REDOX"))
549578
end
550579

551-
# NPAux<x> OFF|0|ON|1 (<x> = 1..4)
552-
# 0|OFF: Switch aux x off
553-
# 1|ON: Switch aux x on
580+
# NPAux<x> OFF|0|ON|1 t (<x> = 1..4)
581+
# 0|OFF: Switch Aux x to off
582+
# 1|ON: Switch Aux x to on
583+
# 2|TOGGLE: Toggle Aux x
554584
def NPAux(cmd, idx, payload)
555585
import string
556586
var ctrl, parm
@@ -567,52 +597,210 @@ class NeoPoolCommands
567597
end
568598
if parm != ""
569599
if string.find(parm, 'OFF')>=0 || string.find(parm, self.TEXT_OFF)>=0 || string.find(parm, '0')>=0
570-
ctrl = 4
600+
ctrl = MBV_PAR_CTIMER_ALWAYS_OFF
571601
elif string.find(parm, 'ON')>=0 || string.find(parm, self.TEXT_ON)>=0 || string.find(parm, '1')>=0
572-
ctrl = 3
602+
ctrl = MBV_PAR_CTIMER_ALWAYS_ON
603+
elif string.find(parm, 'TOGGLE')>=0 || string.find(parm, self.TEXT_TOGGLE)>=0 || string.find(parm, '2')>=0
604+
try
605+
ctrl = (compile("return "..tasmota.cmd(string.format("NPRead 0x%04X", MBF_RELAY_STATE))['NPRead']['Data'])() >> (idx+2)) & 1 ? MBV_PAR_CTIMER_ALWAYS_OFF : MBV_PAR_CTIMER_ALWAYS_ON
606+
except ..
607+
tasmota.resp_cmnd_error()
608+
return
609+
end
573610
else
574611
tasmota.resp_cmnd_error()
575612
return
576613
end
577-
tasmota.cmd(string.format("Backlog NPWrite 0x%04X,%d;NPExec", [0x04AC, 0x04BB, 0x04CA, 0x04D9][idx-1], ctrl))
614+
tasmota.cmd(string.format("NPWrite 0x%04X,%d", PAR_TIMER_BLOCK_AUX[idx-1], ctrl))
615+
tasmota.cmd("NPExec")
578616
else
579617
try
580-
ctrl = (compile("return "+str(tasmota.cmd("NPRead 0x010E")['NPRead']['Data']))() >> (idx+2)) & 1
618+
ctrl = (compile("return "..tasmota.cmd(string.format("NPRead 0x%04X", MBF_RELAY_STATE))['NPRead']['Data'])() >> (idx+2)) & 1
581619
except ..
582620
tasmota.resp_cmnd_error()
583621
return
584622
end
585623
end
586-
tasmota.resp_cmnd(string.format('{"NPAux%d":"%s"}', idx, ctrl == (parm != "" ? 4 : 0) ? self.TEXT_OFF : self.TEXT_ON))
587624
end
588625

589626
def init()
627+
# get tasmota settings
590628
self.TEXT_OFF = tasmota.cmd("StateText1")['StateText1']
591629
self.TEXT_ON = tasmota.cmd("StateText2")['StateText2']
592-
# Add commands
630+
self.TEXT_TOGGLE = tasmota.cmd("StateText3")['StateText3']
631+
# add commands
593632
tasmota.add_cmd('NPBoost', / cmd, idx, payload -> self.NPBoost(cmd, idx, payload))
594633
tasmota.add_cmd('NPAux', / cmd, idx, payload -> self.NPAux(cmd, idx, payload))
595634
end
596635

597636
def deinit()
637+
# remove commands
598638
tasmota.remove_cmd('NPBoost')
599639
tasmota.remove_cmd('NPAux')
600640
end
601641
end
642+
neopoolcommands = NeoPoolCommands()
643+
```
644+
645+
To activate the new commands, go to WebGUI "Consoles" / "Berry Scripting console" and execute
602646

603-
neopool_commands = NeoPoolCommands()
647+
```python
648+
load("neopoolcmd.be")
604649
```
605650

606-
To activate the new commands go to WebGUI "Consoles" / "Berry Scripting console" and execute
651+
### ESP32: Add GUI controls for filtration, light and aux relais
652+
653+
The following enhancements are made using the [Berry Scripting Language](Berry) which is available on ESP32 only.
654+
655+
The class `NeoPoolButtonMethods` below adds new GUI elements to control filtration, light and aux relais:
656+
657+
![](_media/xsns_83_neopool_gui.png)
658+
659+
Store the following code into a Tasmota file by using the WebGUI "Console" / "Manage File system".
660+
661+
#### neopoolgui.be
607662

608663
```python
609-
load("neopool.be")
664+
# File: neopoolgui.be
665+
#
666+
# Add GUI elements for filtration control, light and aux relais
667+
668+
import webserver
669+
import string
670+
671+
class NeoPoolButtonMethods : Driver
672+
673+
#- method for adding elements to the main menu -#
674+
def web_add_main_button()
675+
676+
def selected(value, comp)
677+
return comp == value ? 'selected=""' : ''
678+
end
679+
680+
var speed = tasmota.cmd('NPFiltration')['Speed']
681+
var mode = tasmota.cmd('NPFiltrationmode')['NPFiltrationmode']
682+
683+
var html = '<p></p>'
684+
685+
# Filtration mode/speed
686+
html+= '<table style="width:100%"><tbody><tr>'
687+
html+= ' <td style="width:50%;padding: 0 4px 0 4px;">'
688+
html+= ' <label for="mode"><small>Mode:</small></label>'
689+
html+= ' <select id="mode" name="mode">'
690+
html+= string.format('<option value="m_sv_manual"%s>Manual</option>', selected(mode, 'Manual'))
691+
html+= string.format('<option value="m_sv_auto"%s>Auto</option>', selected(mode, 'Auto'))
692+
html+= string.format('<option value="m_sv_heating"%s>Heating</option>', selected(mode, 'Heating'))
693+
html+= string.format('<option value="m_sv_smart"%s>Smart</option>', selected(mode, 'Smart'))
694+
html+= string.format('<option value="m_sv_intelligent"%s>Intelligent</option>', selected(mode, 'Intelligent'))
695+
html+= ' </select>'
696+
html+= ' </td>'
697+
html+= ' <td style="width:50%;padding: 0 4px 0 4px;">'
698+
html+= ' <label for="speed"><small>Speed:</label>'
699+
html+= ' <select id="speed" name="speed">'
700+
html+= string.format('<option value="m_sv_slow"%s>Slow</option>', selected(speed, '1'))
701+
html+= string.format('<option value="m_sv_medium"%s>Medium</option>', selected(speed, '2'))
702+
html+= string.format('<option value="m_sv_fast"%s>Fast</option>', selected(speed, '3'))
703+
html+= ' </select>'
704+
html+= ' </td>'
705+
html+= '</tr><tr></tr></tbody></table>'
706+
html+= '<script>'
707+
html+= 'document.getElementById("speed").addEventListener ("change",function(){la("&"+this.value+"=1");});'
708+
html+= 'document.getElementById("mode").addEventListener ("change",function(){la("&"+this.value+"=1");});'
709+
html+= '</script>'
710+
711+
# Filtration button
712+
html+= '<table style="width:100%"><tbody><tr>'
713+
html+= ' <td style="width:100%">'
714+
html+= ' <button id="bn_filtration" name="bn_filtration" onclick="la(\'&m_sv_filtration=1\');">Filtration</button>'
715+
html+= ' </td>'
716+
html+= '</tr><tr></tr></tbody></table>'
717+
718+
# Light button
719+
html+= '<table style="width:100%"><tbody><tr>'
720+
html+= ' <td style="width:100%">'
721+
html+= ' <button onclick="la(\'&m_sv_light=1\');">Light</button>'
722+
html+= ' </td>'
723+
html+= '</tr><tr></tr></tbody></table>'
724+
725+
# Aux buttons
726+
html+= '<table style="width:100%"><tbody><tr>'
727+
html+= ' <td style="width:25%"><button onclick="la(\'&m_sv_aux=1\');">Aux1</button></td>'
728+
html+= ' <td style="width:25%"><button onclick="la(\'&m_sv_aux=2\');">Aux2</button></td>'
729+
html+= ' <td style="width:25%"><button onclick="la(\'&m_sv_aux=3\');">Aux3</button></td>'
730+
html+= ' <td style="width:25%"><button onclick="la(\'&m_sv_aux=4\');">Aux4</button></td>'
731+
html+= '</tr><tr></tr></tbody></table>'
732+
733+
webserver.content_send(html)
734+
html = nil
735+
tasmota.gc()
736+
end
737+
738+
#- As we can add only one sensor method we will have to combine them besides all other sensor readings in one method -#
739+
def web_sensor()
740+
if webserver.has_arg("m_sv_filtration")
741+
tasmota.cmd("NPFiltration 2")
742+
end
743+
744+
if webserver.has_arg("m_sv_slow")
745+
tasmota.cmd("NPFiltration 1,1")
746+
end
747+
if webserver.has_arg("m_sv_medium")
748+
tasmota.cmd("NPFiltration 1,2")
749+
end
750+
if webserver.has_arg("m_sv_fast")
751+
tasmota.cmd("NPFiltration 1,3")
752+
end
753+
754+
if webserver.has_arg("m_sv_manual")
755+
tasmota.cmd("NPFiltrationMode 0")
756+
end
757+
if webserver.has_arg("m_sv_auto")
758+
tasmota.cmd("NPFiltrationMode 1")
759+
end
760+
if webserver.has_arg("m_sv_heating")
761+
tasmota.cmd("NPFiltrationMode 2")
762+
end
763+
if webserver.has_arg("m_sv_smart")
764+
tasmota.cmd("NPFiltrationMode 3")
765+
end
766+
if webserver.has_arg("m_sv_intelligent")
767+
tasmota.cmd("NPFiltrationMode 4")
768+
end
769+
770+
if webserver.has_arg("m_sv_light")
771+
tasmota.cmd("NPLight 2")
772+
end
773+
774+
if webserver.has_arg("m_sv_aux")
775+
tasmota.cmd("NPAux"+webserver.arg("m_sv_aux")+" TOGGLE")
776+
end
777+
end
778+
779+
def init()
780+
end
781+
782+
def deinit()
783+
end
784+
end
785+
786+
neopool_driver = NeoPoolButtonMethods()
787+
tasmota.add_driver(neopool_driver)
610788
```
611789

612-
If you want get the new commands available after a restart of your ESP32, store the load command into the special file
790+
To activate the new gui elements, go to WebGUI "Consoles" / "Berry Scripting console" and execute
791+
792+
```python
793+
load("neopoolgui.be")
794+
```
795+
796+
### ESP32: Make the scripts persistent
797+
798+
If you want the extensions to be activated automatically every time you restart your ESP32, save the `load()` commands into the special file
613799
`autoexec.be`:
614800

615-
ESP32 file `autoexec.be`:
801+
#### autoexec.be
802+
616803
```python
617-
load("neopool.be")
804+
load("neopoolcmd.be")
805+
load("neopoolgui.be")
618806
```

docs/_media/xsns_83_neopool_gui.png

10.2 KB
Loading

0 commit comments

Comments
 (0)