AquaForte DM Vario S 20000 Wifi

AquaForte DM Vario S 20000 pond pump with Wi-Fi - AquaForte Reliable and Innovative (Swimming) Pond Products (aqua-forte.com)

App: AQUA FORTE – Aplikácie v službe Google Play

I plan to buy this pump with regulation.
The application is aqaforte
Can it be integrated into Home assistant?

I was looking for the same, but there are Zero informations about the Pump or API. Was expecting they use the Tuya Ecosystem, but seems it’s a very own totally closed app and Pump Controller.

Good news guys, I’m in progress of integrating it into my home assistant.

It uses a known framework that someone all ready reverse engineered.

I’m doing the first tests, so I’ll keep you updated when I’ve got something working

Hello, very interested also. Do you have any update ?

Any news about this?

Yeah, i have a reverse engineerd and MQTT python program running.

it works with auto discovery of Aquaforte pumps on the network and had local push communication with the pump controller.

I’m going to try and create a home assistant addon of this. But this is my first one so it will take some time.

What pumps are you guys running, as i think they might work different.
I’d like to get some info on different versions.

Please run this code and post the discoverd product key:

import socket
import struct
import asyncio
import json

# AquaForte constants
AQUAFORTE_UDP_PORT = 12414
DISCOVERY_REQUEST = 0x03
DISCOVERY_RESPONSE = 0x04
DISCOVERY_TIME = 2

def read_uint32_be(data, offset):
    return struct.unpack_from('>I', data, offset)[0], offset + 4

def read_varint(data, offset):
    result = 0
    shift = 0
    while True:
        byte = data[offset]
        offset += 1
        result |= (byte & 0x7F) << shift
        if (byte & 0x80) == 0:
            break
        shift += 7
    return result, offset

def read_int8(data, offset):
    return struct.unpack_from('>b', data, offset)[0], offset + 1

def read_int16_be(data, offset):
    return struct.unpack_from('>h', data, offset)[0], offset + 2

def read_string(data, offset, length=None):
    if length is not None:
        return data[offset:offset + length].decode('ascii'), offset + length
    else:
        end = offset
        while end < len(data) and data[end] != 0:
            end += 1
        return data[offset:end].decode('ascii'), end + 1

def read_bytes(data, offset, length):
    return data[offset:offset + length], offset + length

class AquaForteDiscovery:
    def __init__(self):
        self.socket = None
        self.loop = asyncio.get_event_loop()
        self.discovered_devices = []

    async def discover(self):
        print('Starting discovery process...')
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self.socket.bind(('0.0.0.0', AQUAFORTE_UDP_PORT))

        self.loop.add_reader(self.socket, self._handle_response)

        print('Sending discovery message...')
        DISCOVERY_MESSAGE = b'\x00\x00\x00\x03\x03\x00\x00\x03'
        self.socket.sendto(DISCOVERY_MESSAGE, ('255.255.255.255', AQUAFORTE_UDP_PORT))

        # Give some time to receive responses
        await asyncio.sleep(DISCOVERY_TIME)

        self.loop.remove_reader(self.socket)
        if self.socket:
            self.socket.close()
            self.socket = None

        print('Discovery process completed.')
        return self.discovered_devices

    def _handle_response(self):
        message, remote = self.socket.recvfrom(1024)
        self._parse_response(message, remote)

    def _parse_response(self, message, remote):
        offset = 0
        try:
            prefix, offset = read_uint32_be(message, offset)
            if prefix != 0x00000003:
                return
        except Exception:
            return

        try:
            data_length, offset = read_varint(message, offset)
        except Exception:
            return

        try:
            flag, offset = read_int8(message, offset)
        except Exception:
            return

        try:
            message_type, offset = read_int16_be(message, offset)
        except Exception:
            return

        if message_type == DISCOVERY_RESPONSE:
            self._handle_reply_broadcast(remote, message, offset)

    def _handle_reply_broadcast(self, remote, message, offset):
        try:
            device_id_len, offset = read_int16_be(message, offset)
            device_id, offset = read_string(message, offset, length=device_id_len)
            mac_len, offset = read_int16_be(message, offset)
            mac, offset = read_bytes(message, offset, length=mac_len)
            wifi_ver_len, offset = read_int16_be(message, offset)
            wifi_ver, offset = read_bytes(message, offset, length=wifi_ver_len)
            prod_key_len, offset = read_int16_be(message, offset)
            prod_key, offset = read_string(message, offset, length=prod_key_len)

            print(f"Discovered Device - IP: {remote[0]}, Product Key: {prod_key}")

        except Exception:
            return

async def main():
    discovery = AquaForteDiscovery()
    await discovery.discover()

if __name__ == "__main__":
    asyncio.run(main())

Also please let me know what model you have.
@izo @daemonenstall @hwinkel @Laco_Jurdik

1 Like

Looks promising :blush:

At the moment I don’t have such a pump. I’m thinking about purchasing one, but this depends on the possibility to integrate it into HASS. I don’t want to mess around with another app for the pump. Then I prefer a stupid pump just controlled by a relay.

I am also looking to buy the Aquaforte pool heater.
Would love to hear more if you have been able to integrate it to HA.

If all goes well, you’ll have full control over the pump, timers and speed

1 Like

That I don’t know, I don’t have such a device and there might be a small chance it works. Just run the same script as above, if it is discovered chances are pretty good it would work

Hello, I also tried to communicate with my pump.
In the past I was able to use the cloud interface but with the new app version it seems not to work.
Can you explain how/what you can send commands to the pump (via websocket?)

(The broadcast discovery did not work for me, but sending the message directly to the pump’s ip address resulted in the correct data)

I was sniffing the traffic and saw that the pump was accessing a web addres. I traced that back and discovered the pump controller usses a framework called Gizwits. The framework works on the local netwerk and on the cloud.

Next I found someone who reverse engineered the protocol: Apollon77/node-ph803w

I converted the code to python and started to implement the framework to match the pump, and reverse engineered the ways to send commands.

Currently i’m getting started with the local commands to MQTT, and implementing the autodiscovery in home assistant.

I’m not a very eperience developer, so if someone wants to contribute to getting the addon polished that would be nice.

At some point i will publish the addon in hacs or just my own repo.

I have a WiFi 20000 Running as well

Please run the discovery script above and send me the numbers it outputs

Please post the output of the discovery script and let me know what pump you have

Can you teach me to run the script? I have a Prime Vario 20000.

it is a python script, You should be able to find a lot on how to run a python script on you computer

I have installed VS Code created a pythin folder and file and VS Code asked me to install the Python Plugin, which makes it easy to run the scripts