Covrex Pool Control

I own a LPW pool and with it comes a PoolControl 2 ECO control unit. Now I have seen that there is a ModBus connector on the motherboard, labelled JP4. I would like to read out the PT1000 temperature sensors for water and air temperature. Has anyone managed to achieve this?

BTW - this is JP4 - looks exactly like a ModBus connector:

Photo 14.11.24, 17 40 55

I’ll write to the pool manufacturer and ask how to do this…

I received the following answer:


We do not work with the Modbus protocol.

There are only commands between the modules and the display.

It is possible to read the date coming from the display.

There is a payload of data every 10 seconds

Parameters: 57600bd, 1 stop bit, no parity

The first 4 values after the serial number are measured water temp, air temp, water level, and solar temp.

Do not, under any circumstance send data to the bus.


Does anyone know how to read out the data with the description above? Is it possible to do this with a serial/TCP-converter like HF5111S?

I have a similar controller and was trying to do the same thing. Ideally I’d also like to send commands for the cover, lights, etc but I haven’t gotten that far yet (just had it installed).

For reading out the temp sensors the easiest way I found was to use Node-Red.

Basically you set the remote server address on your controller to your Node-Red.
There you accept and parse the data, publish it to MQTT. In HA you then create the corresponding MQTT sensors.

You can set Node-Red to forward on the data so you don’t lose the PoolControl app functionality.

I just set mine up and so far it seems to be working but I’m sure it’ll need some more work.

1 Like

Hello FFV21!

Thank you very much for your answer… it’s not the busiest thread… :wink:

How do you do that, where can you set a remote server address in the controller?

Haha, indeed!

In a browser go to the controller’s local IP address (user&password is ‘admin’ by default).
Under the Serial Port settings you can change the remote server address.

Alternatively use the piece of software and instructions found here; iPool REMOTE change address - Aseko Pool Technology

It’s for Aseko products but it uses the same module.

I haven’t had too much time to mess around with this so haven’t made much progress.

Found that I can intercept and forward the messages the controller sends to the cloud. From those can read water temp, level etc.
The ‘Pool Control’ app also updates with that information but what I can’t get working yet is sending commands from the app back to the controller.

1 Like

Amazing! That is f*** awesome!

Here’s how the controller web frontend looks like:
2025-01-30 17_53_10-USR-K5 - Iron

Luckily I have already a NodeRed server running in my home network. How do I receive the messages sent from the controller? I have these options:

Below the NR flow I threw together (it’s very much work in progress though).

I’m still working on my actual pool. Once that’s done I should have more time to play around with this.

Hope it helps

[
    {
        "id": "42ee5a36741cb37c",
        "type": "tab",
        "label": "Pool Controller Proxy",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "773a16a4ce035840",
        "type": "tcp in",
        "z": "42ee5a36741cb37c",
        "name": "Data from Pool Controller",
        "server": "server",
        "host": "",
        "port": "52278",
        "datamode": "stream",
        "datatype": "buffer",
        "newline": "",
        "topic": "",
        "trim": false,
        "base64": false,
        "tls": "",
        "x": 130,
        "y": 100,
        "wires": [
            [
                "4a16f0e5ce20b2ac",
                "dc34c83da125021e",
                "2310fccf092aa725",
                "bc03f7706d64105c"
            ]
        ]
    },
    {
        "id": "4a16f0e5ce20b2ac",
        "type": "tcp out",
        "z": "42ee5a36741cb37c",
        "name": "Send Data to remote.poolcontrol.be",
        "host": "remote.poolcontrol.be",
        "port": "52278",
        "beserver": "client",
        "base64": false,
        "end": false,
        "tls": "",
        "x": 420,
        "y": 20,
        "wires": []
    },
    {
        "id": "2310fccf092aa725",
        "type": "buffer-parser",
        "z": "42ee5a36741cb37c",
        "name": "WaterTemp",
        "data": "payload",
        "dataType": "msg",
        "specification": "spec",
        "specificationType": "ui",
        "items": [
            {
                "type": "string",
                "name": "WaterTemp",
                "offset": 15,
                "length": 3,
                "offsetbit": 0,
                "scale": "0.1",
                "mask": ""
            }
        ],
        "swap1": "",
        "swap2": "",
        "swap3": "",
        "swap1Type": "swap",
        "swap2Type": "swap",
        "swap3Type": "swap",
        "msgProperty": "payload",
        "msgPropertyType": "str",
        "resultType": "value",
        "resultTypeType": "return",
        "multipleResult": false,
        "fanOutMultipleResult": false,
        "setTopic": true,
        "outputs": 1,
        "x": 370,
        "y": 100,
        "wires": [
            [
                "ab0bf6eee4d3eb62"
            ]
        ]
    },
    {
        "id": "e9bd94822ab94334",
        "type": "debug",
        "z": "42ee5a36741cb37c",
        "d": true,
        "name": "buffer output",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1030,
        "y": 80,
        "wires": []
    },
    {
        "id": "dc34c83da125021e",
        "type": "file",
        "z": "42ee5a36741cb37c",
        "d": true,
        "name": "",
        "filename": "/data/poolcontroller/log.txt",
        "filenameType": "str",
        "appendNewline": true,
        "createDir": true,
        "overwriteFile": "false",
        "encoding": "none",
        "x": 410,
        "y": 300,
        "wires": [
            []
        ]
    },
    {
        "id": "82e96725fb67d01a",
        "type": "mqtt out",
        "z": "42ee5a36741cb37c",
        "name": "",
        "topic": "NodeRed/PoolController/WaterTemp",
        "qos": "",
        "retain": "false",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "fc6ed911150d9657",
        "x": 1110,
        "y": 120,
        "wires": []
    },
    {
        "id": "bc03f7706d64105c",
        "type": "buffer-parser",
        "z": "42ee5a36741cb37c",
        "name": "WaterLevel",
        "data": "payload",
        "dataType": "msg",
        "specification": "spec",
        "specificationType": "ui",
        "items": [
            {
                "type": "string",
                "name": "WaterLevel",
                "offset": 24,
                "length": 2,
                "offsetbit": 0,
                "scale": "1",
                "mask": ""
            }
        ],
        "swap1": "",
        "swap2": "",
        "swap3": "",
        "swap1Type": "swap",
        "swap2Type": "swap",
        "swap3Type": "swap",
        "msgProperty": "payload",
        "msgPropertyType": "str",
        "resultType": "value",
        "resultTypeType": "return",
        "multipleResult": false,
        "fanOutMultipleResult": false,
        "setTopic": true,
        "outputs": 1,
        "x": 370,
        "y": 220,
        "wires": [
            [
                "2a86c7c4d64a8563"
            ]
        ]
    },
    {
        "id": "e0e2917c320c3b97",
        "type": "mqtt out",
        "z": "42ee5a36741cb37c",
        "name": "",
        "topic": "NodeRed/PoolController/WaterLevel",
        "qos": "",
        "retain": "false",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "fc6ed911150d9657",
        "x": 970,
        "y": 260,
        "wires": []
    },
    {
        "id": "85e0d31bcd5fec9a",
        "type": "debug",
        "z": "42ee5a36741cb37c",
        "d": true,
        "name": "buffer output",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 890,
        "y": 220,
        "wires": []
    },
    {
        "id": "ab0bf6eee4d3eb62",
        "type": "convert",
        "z": "42ee5a36741cb37c",
        "name": "",
        "convertTo": "number",
        "x": 570,
        "y": 100,
        "wires": [
            [
                "792cdf212118fc15"
            ]
        ]
    },
    {
        "id": "2a86c7c4d64a8563",
        "type": "convert",
        "z": "42ee5a36741cb37c",
        "name": "",
        "convertTo": "number",
        "x": 570,
        "y": 220,
        "wires": [
            [
                "b970544fd39c4edb"
            ]
        ]
    },
    {
        "id": "792cdf212118fc15",
        "type": "switch",
        "z": "42ee5a36741cb37c",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "istype",
                "v": "number",
                "vt": "number"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 730,
        "y": 100,
        "wires": [
            [
                "71f81d2c7b7e6172"
            ]
        ]
    },
    {
        "id": "b970544fd39c4edb",
        "type": "switch",
        "z": "42ee5a36741cb37c",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "istype",
                "v": "number",
                "vt": "number"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 730,
        "y": 220,
        "wires": [
            [
                "85e0d31bcd5fec9a",
                "e0e2917c320c3b97"
            ]
        ]
    },
    {
        "id": "71f81d2c7b7e6172",
        "type": "calculator",
        "z": "42ee5a36741cb37c",
        "name": "",
        "inputMsgField": "payload",
        "outputMsgField": "payload",
        "operation": "div",
        "constant": "10",
        "round": false,
        "truncate": false,
        "decimals": 0,
        "decimals2": 0,
        "x": 850,
        "y": 100,
        "wires": [
            [
                "e9bd94822ab94334",
                "82e96725fb67d01a"
            ]
        ]
    },
    {
        "id": "fc6ed911150d9657",
        "type": "mqtt-broker",
        "name": "Mosquitto",
        "broker": "192.168.100.2",
        "port": 1883,
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": 4,
        "keepalive": 60,
        "cleansession": true,
        "autoUnsubscribe": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthRetain": "false",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closeRetain": "false",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willRetain": "false",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    }
]
1 Like

Thanky you very much! I could import your code to NodeRed. However I’m still not able to receive the packages from the Controller, but I guess this has something to do with my network configuration, which I need to sort out first. Can you tell me: how often is the controller sending a data packet on port 52278?

The controller sends data every ~10-15 seconds it seems.

Did you set the remote server address to the IP address of your Node-Red server?
remoteserveraddresss

If you’re running NR as a docker container don’t forget to add the port 52278.

1 Like

It works now! I had the PoolController in a guest network segment, that’s why I wasn’t able to intercept the messages from the NR server. Now both are in the same segment and it works!

Hey thank you very very much! A software solution is surely so much better than any additional hardware. Please update me if you manage to send commands from NR to the controller! That’s something I want to do as well.

I also added now reading out the air temperature with this node:

[
    {
        "id": "11690b9f3ee3718f",
        "type": "buffer-parser",
        "z": "42ee5a36741cb37c",
        "name": "AirTemp",
        "data": "payload",
        "dataType": "msg",
        "specification": "spec",
        "specificationType": "ui",
        "items": [
            {
                "type": "string",
                "name": "AirTemp",
                "offset": 18,
                "length": 3,
                "offsetbit": 0,
                "scale": "0.1",
                "mask": ""
            }
        ],
        "swap1": "",
        "swap2": "",
        "swap3": "",
        "swap1Type": "swap",
        "swap2Type": "swap",
        "swap3Type": "swap",
        "msgProperty": "payload",
        "msgPropertyType": "str",
        "resultType": "value",
        "resultTypeType": "return",
        "multipleResult": false,
        "fanOutMultipleResult": false,
        "setTopic": true,
        "outputs": 1,
        "x": 340,
        "y": 520,
        "wires": [
            [
                "f88610fe9238df9d"
            ]
        ]
    }
]

Cool!

One thing I was thinking is that currently we’re getting the values as an offset on a string. My water temp is ~4.0 degrees so currently two digits. When it goes up to double digits I’m guessing all the offsets will be incorrect as I’m assuming it will post something like 200 for 20.0 degrees.

This is my first time using Node-Red so I don’t really have any ideas of how to get around this for now.

You know how we can fix that by any chance?

Also, got the position for cover added

[
    {
        "id": "aa97b179b81bbdbc",
        "type": "buffer-parser",
        "z": "42ee5a36741cb37c",
        "name": "CoverPosition",
        "data": "payload",
        "dataType": "msg",
        "specification": "spec",
        "specificationType": "ui",
        "items": [
            {
                "type": "string",
                "name": "CoverPosition",
                "offset": 243,
                "length": 5,
                "offsetbit": 0,
                "scale": "1",
                "mask": ""
            }
        ],
        "swap1": "",
        "swap2": "",
        "swap3": "",
        "swap1Type": "swap",
        "swap2Type": "swap",
        "swap3Type": "swap",
        "msgProperty": "payload",
        "msgPropertyType": "str",
        "resultType": "value",
        "resultTypeType": "return",
        "multipleResult": false,
        "fanOutMultipleResult": false,
        "setTopic": true,
        "outputs": 1,
        "x": 380,
        "y": 340,
        "wires": [
            [
                "c5e8b6484cf3ce1d",
                "bfb8c0fc72fd4f18"
            ]
        ]
    },
    {
        "id": "c5e8b6484cf3ce1d",
        "type": "convert",
        "z": "42ee5a36741cb37c",
        "name": "",
        "convertTo": "number",
        "x": 570,
        "y": 340,
        "wires": [
            [
                "95848c5f6d2695ed"
            ]
        ]
    },
    {
        "id": "95848c5f6d2695ed",
        "type": "switch",
        "z": "42ee5a36741cb37c",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "istype",
                "v": "number",
                "vt": "number"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 730,
        "y": 340,
        "wires": [
            [
                "82e6257df9e3f641"
            ]
        ]
    },
    {
        "id": "23c058813b725fc4",
        "type": "buffer-parser",
        "z": "42ee5a36741cb37c",
        "name": "CoverMax",
        "data": "payload",
        "dataType": "msg",
        "specification": "spec",
        "specificationType": "ui",
        "items": [
            {
                "type": "string",
                "name": "CoverMax",
                "offset": 249,
                "length": 5,
                "offsetbit": 0,
                "scale": "1",
                "mask": ""
            }
        ],
        "swap1": "",
        "swap2": "",
        "swap3": "",
        "swap1Type": "swap",
        "swap2Type": "swap",
        "swap3Type": "swap",
        "msgProperty": "payload",
        "msgPropertyType": "str",
        "resultType": "value",
        "resultTypeType": "return",
        "multipleResult": false,
        "fanOutMultipleResult": false,
        "setTopic": true,
        "outputs": 1,
        "x": 370,
        "y": 300,
        "wires": [
            [
                "edb59ef8df758f08"
            ]
        ]
    },
    {
        "id": "edb59ef8df758f08",
        "type": "convert",
        "z": "42ee5a36741cb37c",
        "name": "",
        "convertTo": "number",
        "x": 570,
        "y": 300,
        "wires": [
            [
                "c0eb76aba2d09b3d"
            ]
        ]
    },
    {
        "id": "c0eb76aba2d09b3d",
        "type": "switch",
        "z": "42ee5a36741cb37c",
        "name": "",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "istype",
                "v": "number",
                "vt": "number"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 730,
        "y": 300,
        "wires": [
            [
                "a11e93a2709d9c39"
            ]
        ]
    },
    {
        "id": "82e6257df9e3f641",
        "type": "mqtt out",
        "z": "42ee5a36741cb37c",
        "name": "",
        "topic": "NodeRed/PoolController/CoverPosition",
        "qos": "",
        "retain": "false",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "fc6ed911150d9657",
        "x": 950,
        "y": 340,
        "wires": []
    },
    {
        "id": "a11e93a2709d9c39",
        "type": "mqtt out",
        "z": "42ee5a36741cb37c",
        "name": "",
        "topic": "NodeRed/PoolController/CoverMax",
        "qos": "",
        "retain": "false",
        "respTopic": "",
        "contentType": "",
        "userProps": "",
        "correl": "",
        "expiry": "",
        "broker": "fc6ed911150d9657",
        "x": 940,
        "y": 300,
        "wires": []
    },
    {
        "id": "fc6ed911150d9657",
        "type": "mqtt-broker",
        "name": "Mosquitto",
        "broker": "192.168.100.2",
        "port": 1883,
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": 4,
        "keepalive": 60,
        "cleansession": true,
        "autoUnsubscribe": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthRetain": "false",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closeRetain": "false",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willRetain": "false",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    }
]

Don’t know how to template in Node-Red so I did that in HA.

The CoverMax is the value (I think rotations of the motor or something) for the cover being closed.

The CoverPosition is the current position. 0 being it is entirely open. If it equals CoverMax it is entirely closed.

1 Like

To control the cover from HA I used a spare Shelly I had lying around and connected it physically to the controller. Works like a charm.

Will do the same with the lights and should also work to turn on/off the pump and heat demand I believe.

I think I found an easy way how to fix this:

Execute the following steps:
-replace all spaces with commas
-split the csv string into columns
-access col3 for water temperature and col4 for air temperature and assign it to the msg.payload
-create the moving average with 60 values cumulative
-round to 1 digit
-and send (I’m using this within my SignalK server)

Through the comma seperation I guess this should work in case of temperatures over 9 degrees for both air and water and below 0 degrees for air temperature.

Flow:

[
    {
        "id": "773a16a4ce035840",
        "type": "tcp in",
        "z": "42ee5a36741cb37c",
        "name": "Data from Pool Controller",
        "server": "server",
        "host": "",
        "port": "52278",
        "datamode": "stream",
        "datatype": "buffer",
        "newline": "",
        "topic": "",
        "trim": false,
        "base64": false,
        "tls": "",
        "x": 150,
        "y": 180,
        "wires": [
            [
                "4a16f0e5ce20b2ac",
                "fdd24d87374e74c6",
                "141da27c3b797260"
            ]
        ]
    },
    {
        "id": "4a16f0e5ce20b2ac",
        "type": "tcp out",
        "z": "42ee5a36741cb37c",
        "name": "Send Data to remote.poolcontrol.be",
        "host": "remote.poolcontrol.be",
        "port": "52278",
        "beserver": "client",
        "base64": false,
        "end": false,
        "tls": "",
        "x": 480,
        "y": 180,
        "wires": []
    },
    {
        "id": "fdd24d87374e74c6",
        "type": "debug",
        "z": "42ee5a36741cb37c",
        "name": "buffer output",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 410,
        "y": 120,
        "wires": []
    },
    {
        "id": "4ed20d7b6fd5da1c",
        "type": "csv",
        "z": "42ee5a36741cb37c",
        "name": "",
        "sep": ",",
        "hdrin": "",
        "hdrout": "none",
        "multi": "one",
        "ret": "\\n",
        "temp": "",
        "skip": "0",
        "strings": true,
        "include_empty_strings": false,
        "include_null_values": false,
        "x": 250,
        "y": 300,
        "wires": [
            [
                "3164962ec12ade63",
                "fd34f5575d29d187"
            ]
        ]
    },
    {
        "id": "fd34f5575d29d187",
        "type": "function",
        "z": "42ee5a36741cb37c",
        "name": "msg t/p",
        "func": "msg.topic = \"environment.pool.temp.air\"\nmsg.payload = msg.payload.col4 / 10\nreturn msg;\n\n\n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 400,
        "y": 340,
        "wires": [
            [
                "c957aef4678c7b46"
            ]
        ]
    },
    {
        "id": "3164962ec12ade63",
        "type": "function",
        "z": "42ee5a36741cb37c",
        "name": "msg t/p",
        "func": "msg.topic = \"environment.pool.temp.water\"\nmsg.payload = msg.payload.col3 / 10 \nreturn msg;\n\n\n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 400,
        "y": 260,
        "wires": [
            [
                "7c6ef8b097302f60"
            ]
        ]
    },
    {
        "id": "1c8b718296aa41c8",
        "type": "signalk-send-pathvalue",
        "z": "42ee5a36741cb37c",
        "name": "send e.p.t.water",
        "source": "",
        "meta": "{}",
        "x": 800,
        "y": 260,
        "wires": []
    },
    {
        "id": "072a8c5e193d40c4",
        "type": "signalk-send-pathvalue",
        "z": "42ee5a36741cb37c",
        "name": "send e.p.t.air",
        "source": "",
        "meta": "{}",
        "x": 790,
        "y": 340,
        "wires": []
    },
    {
        "id": "c957aef4678c7b46",
        "type": "moving-average",
        "z": "42ee5a36741cb37c",
        "name": "avg60",
        "amount": "60",
        "weight": "cumulative",
        "x": 530,
        "y": 340,
        "wires": [
            [
                "47d7faef25e43b26"
            ]
        ]
    },
    {
        "id": "7c6ef8b097302f60",
        "type": "moving-average",
        "z": "42ee5a36741cb37c",
        "name": "avg60",
        "amount": "60",
        "weight": "cumulative",
        "x": 530,
        "y": 260,
        "wires": [
            [
                "f59ab5a99e9f18f4"
            ]
        ]
    },
    {
        "id": "f59ab5a99e9f18f4",
        "type": "calculator",
        "z": "42ee5a36741cb37c",
        "name": "r1",
        "inputMsgField": "payload",
        "outputMsgField": "payload",
        "operation": "rdec",
        "constant": "2",
        "round": true,
        "truncate": false,
        "decimals": "1",
        "decimals2": 0,
        "x": 650,
        "y": 260,
        "wires": [
            [
                "1c8b718296aa41c8"
            ]
        ]
    },
    {
        "id": "47d7faef25e43b26",
        "type": "calculator",
        "z": "42ee5a36741cb37c",
        "name": "r1",
        "inputMsgField": "payload",
        "outputMsgField": "payload",
        "operation": "rdec",
        "constant": "2",
        "round": true,
        "truncate": false,
        "decimals": "1",
        "decimals2": 0,
        "x": 650,
        "y": 340,
        "wires": [
            [
                "072a8c5e193d40c4"
            ]
        ]
    },
    {
        "id": "141da27c3b797260",
        "type": "string",
        "z": "42ee5a36741cb37c",
        "name": "",
        "methods": [
            {
                "name": "replaceAll",
                "params": [
                    {
                        "type": "str",
                        "value": " "
                    },
                    {
                        "type": "str",
                        "value": ","
                    }
                ]
            }
        ],
        "prop": "payload",
        "propout": "payload",
        "object": "msg",
        "objectout": "msg",
        "x": 130,
        "y": 300,
        "wires": [
            [
                "4ed20d7b6fd5da1c"
            ]
        ]
    }
]

Oh nice one! I tried doing something like that yesterday with the split function but didn’t really get anywhere with that.

Thanks for this!

Figured out a few more in case you’re interested;

Column 10: Anti-freeze - 0=on / 1=off
Column 11: ?
Column 12: Pump Speed - 0=off / 1=low / 2=medium / 3=high / 4=overboost
Column 13: Filter Backwash - 0=off / 1=on
Column 14: ?
Column 15: ?
Column 16: Lights - 0=off / 1=on
Column 17: ?
Column 18: Cover Motor running - 0=on / 1=off

The remaining should be for solar / automatic water filling / heating requested / not sure what the last one would be.

Column 88: Position of the Cover - 0 open / value equals column 89 when closed

Thank You, that is good information, too, especially the pump speed.