WindHager integration

There is one problem left. Think it has to do with the fact that my Heating System is Mulitwin but not Biowin:

File “/config/custom_components/windhager/init.py”, line 36, in async_update_data
return await httpClient.fetch_all()
File “/config/custom_components/windhager/client.py”, line 391, in fetch_all
ret[“oids”][oid] = json[“value”]
KeyError: ‘value’

Can you help me to trace this one? Maybe it is because I do not get any heater info so some of the OIDs are NULL.

It is more a timeout issue…I changed the update interval value in init.py to 90 and the problems seems to occur at least, less often!

I think I should add error handling in the module, and reduce the number of requests. (Maybe I can group requests, I need to check the API). I’ll try to look it up today or in the week-end !

This what I’ve done so far!
I spent some time to have a closer look why sometimes the entities get unavailable and it seems that sometimes API read requests stuck at the rc7030.

Below you can see the error:

return await httpClient.fetch_all()
File “/config/custom_components/windhager/client.py”, line 391, in fetch_all
ret[“oids”][oid] = json[“value”]
KeyError: ‘value’
2023-04-29 11:59:09.693 ERROR (MainThread) [custom_components.windhager] Timeout fetching sensor data.

but definitly setting the update interval to 90 seconds reduced the number of time it occurs.

I’m not sure which HA version made the change, but it seems the integration is not updateing data automatically. Only if I change a setting (for example heating program) the values are updated. Is anyone expierencing the same behaviour?

Dear vermi0ffh,

I have a BioWin 2 Touch and want to integrate it into HA. The BW2 has an LAN-interface built in making the hardware-interfacing quite easy.
Regarding the integration into HA I am still a bit unsure if I should use your repository or for instance GitHub - sessl3r/windhager: Windhager BioWin102 + InfoWin Touch (needs a separate VM to translate the data as mqtt for HA) or the one from sarabanjina GitHub - sarabanjina/mycomfortclient: Windhager myComfort Python client for Home Assistant (@sarabanjina maybe you can also comment on this).

Why are there so many separate repos? Where are the main differences? Is it possible to unify/combine to reduce errors and problems for new users like me? BTW I am willing to test and give feedback but am currently not sure where to start and I do not want to test all possible project after another.

Thanks in advance.

I just started the heater this season, with 2023.11, and everything seems to work. Do you still have issues ?

Hi, I think you can give it a try with. When I connected mine to HA there was no integrations at all. So I made mine for my needs. I try to keep it alive for my use, but I don’t really have time to improve it.
Maybe in a few months, with a older Kids and whole nights of sleep :sweat_smile:

1 Like

Dear vermi0ffh,
I managed to install your integration using HACS.

How to set e.g. the ip of the heater?
Thanks in advance,
HoWil

I found it. these were the man points (@vermi0ffh maybe you can use this as a starting point for your documentation on the Github page =) ):

Install HAC

See User Documentation | HACS

Is during initial configuration “Enable experimental features” necessary? I used it.
Do we need to restart HA after the installation of HAC? I did it.

Add vermi0ffh/ha-windhager in HACS

Add “Custom repositories” in HACS (from the left panel entry) via the top right menu.GitHub - vermi0ffh/ha-windhager: Windhager integration in home assistant

Add the heating

In HA go to ‘Settings’ → ‘Integration’ → ‘ADD INTEGRATION’ → ‘Windhager heating’ → Set IP and password of your heating.

How to add new entries like ‘Running time until cleaning’ ‘Laufzeit bis zur Reinigung’ "BioWin2 - BioWin2 - 98 - 8 20:061 " or more interesting for me signals for the pumps to distinguish where the produced heat is going to (Underfloor heating or hot water).

I added the simple doc in the readme (thank you). Here is a list of improvments I’ll try to make :

  1. Add Devices to easily regroup entities
  2. Add some sensors (like running time until cleanup as you asked).
  3. Add translations (because it contains texts in french only for now)

I just added a develop branch to add those step by step without breaking everything !

I think the problem is that my Windhager configuration is so different from your’s. It is a gas heater with a water buffer storage. I’m using an automation to update every 5 minutes. I also use some rest API’s to get the needed info from my buffer storage, like top and bottom water temperature. I also changed the code to reflect my heating modes which are different from yours. So I’m fine. As you said below: It is not perfect but much better than nothing. Thank you very much for your effort to build this integration.

I think it should not be very difficul to add it to the integration, but without proper testing, it will take some try/retry.

For heating modes, I think I could load them from the header directly, it should be better

EDIT:
Dear @vermi0ffh, I have a suggestion:

Warm water usage - DHW

I changed client.py to also include data from my Solar-Registerboiler (hot-water-boiler) and all pumps. since not every installation will have this elements it would be good to have them optional (if it not already is).
I added:

  • DHW temperatures - Actual
  • Circulation pump active
  • Circulation pump, heating
  • Mixing valve heating circuit
  • Circulation pump DHW
  • Charging pump DHW
  • DHW temperatures - Actual

Adopted code of client.py

import aiohttp
import logging
from .aiohelper import DigestAuth

_LOGGER = logging.getLogger(__name__)


class WindhagerHttpClient:
    """Raw API HTTP requests"""

    def __init__(self, host, password) -> None:
        self.host = host
        self.password = password
        self.oids = None
        self.devices = []

    async def fetch(self, url):
        client = aiohttp.ClientSession()
        auth = DigestAuth("USER", self.password, client)
        ret = await auth.request("GET", "http://" + self.host + "/api/1.0/lookup" + url)
        json = await ret.json()
        await client.close()
        return json

    async def update(self, oid, value):
        client = aiohttp.ClientSession()
        auth = DigestAuth("USER", self.password, client)
        await auth.request(
            "PUT",
            "http://" + self.host + "/api/1.0/datapoint",
            data=bytes('{"OID":"' + oid + '","value":"' + value + '"}', "utf-8"),
        )
        await client.close()

    async def fetch_all(self):
        if self.oids is None:
            self.oids = set()
            # Fetch all devices on the network
            json_devices = await self.fetch("/1")

            # Add devices
            for device in json_devices:
                device_id = "/1/" + str(device["nodeId"])

                if "functions" not in device:
                    continue

                # Filter climate controls
                functions = list(
                    filter(
                        lambda f: (f["fctType"] == 14 and f["lock"] is False),
                        device["functions"],
                    )
                )
                if len(functions) > 0:
                    fct_id = "/" + str(functions[0]["fctId"])

                    # Climate control
                    self.devices.append(
                        {
                            "id": (self.host + device_id)
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"],
                            "type": "climate",
                            "prefix": device_id,
                            "oids": [
                                fct_id + "/0/1/0",
                                fct_id + "/1/1/0",
                                fct_id + "/3/50/0",
                                fct_id + "/2/10/0",
                                fct_id + "/3/58/0",
                            ],
                            "device_id": (self.host + device_id)
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )
                    self.oids.update(
                        [
                            # Current temperature
                            device_id + fct_id + "/0/1/0",
                            # Target temperature
                            device_id + fct_id + "/1/1/0",
                            # Current selected mode
                            device_id + fct_id + "/3/50/0",
                            # Duration of custom temperature (in minutes)
                            device_id + fct_id + "/2/10/0",
                            # Outside temperature
                            device_id + fct_id + "/0/0/0",
                            # Temp confort correction
                            device_id + fct_id + "/3/58/0",
                            # Tempe correction
                            device_id + fct_id + "/3/7/0",
                            # Circulation pump active
                            device_id + fct_id + "/5/6/0",
                            # Circuit pump, heating
                            device_id + fct_id + "/1/20/0",
                            # Mixing valve heating circuit
                            device_id + fct_id + "/1/21/0",
                            # Circulation pump DHW
                            device_id + fct_id + "/1/65/0",
                            # Charging pump DHW
                            device_id + fct_id + "/1/66/0",             
                            
                            # DHW temperatures - Actual
                            device_id + fct_id + "/0/04/0",

                            
                        ]
                    )

                    # Current temperature
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/0/1/0"
                                + "/3/58/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Current Temperature",
                            "type": "temperature",
                            "correction_oid": device_id + fct_id + "/3/58/0",
                            "oid": device_id + fct_id + "/0/1/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )

                    # Current temperature (real)
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/0/1/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"]
                            + " Current Temperature real",
                            "type": "temperature",
                            "oid": device_id + fct_id + "/0/1/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )

                    # Comfort Temperature correction
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/3/58/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"]
                            + " Comfort Temperature Correction",
                            "type": "sensor",
                            "device_class": None,
                            "state_class": None,
                            "unit": "K",
                            "oid": device_id + fct_id + "/3/58/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )
                    # Current Temperature correction
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/3/7/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"]
                            + " Current Temperature Correction",
                            "type": "sensor",
                            "device_class": None,
                            "state_class": None,
                            "unit": "K",
                            "oid": device_id + fct_id + "/3/7/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )
                    # Target temperature
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/1/1/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Target Temperature",
                            "type": "temperature",
                            "correction_oid": device_id + fct_id + "/3/58/0",
                            "oid": device_id + fct_id + "/1/1/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )
                    # Outside temperature
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/0/0/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Outside Temperature",
                            "type": "temperature",
                            "oid": device_id + fct_id + "/0/0/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )
                    # Circulation pump active, Minimal value 0, Maximal value 3, Step 1
                    # (15) UMUMLZ / (0) UMLZ (1) / (05:06) Zirkulationspumpe (/1/15/0   /5/6/0)
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/5/6/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Circulation pump active",
                            "type": "sensor",
                            "oid": device_id + fct_id + "/5/6/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )
                    # ID 01:020; Name Circuit pump, heating; Value 0
                    # Circulation pump
                    # DE: (122) Unbekannte Ebene (0) 01:020 Heizkreispumpe
                    # (15) UMUMLZ / (0) UMLZ (1) / (01:20) Heizkreispumpe (/1/15/0/1/20/0)
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/1/20/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Circulation pump, heating",
                            "type": "sensor",
                            "oid": device_id + fct_id + "/1/20/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )                   
                    # ID 01:021; Name Mixing valve heating circuit; Value 0 %
                    # DE (122) Unbekannte Ebene (1) 01:021 Mischer
                    # (15) UMUMLZ / (0) UMLZ (1) / (01:21) Mischer (/1/15/0/1/21/0)
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/1/21/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Mixing valve heating circuit",
                            "type": "sensor",
                            "unit": "%",
                            "oid": device_id + fct_id + "/1/21/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )                    
                    # ID 01:065;
                    # (15) UMUMLZ / (0) UMLZ (1) / (01:65) Warmwasser Zirkulationspumpe (/1/15/0/1/65/0)
                    # DE: (122) Unbekannte Ebene (3) 01:065 Warmwasser Zirkulationspumpe
                    #ID 01:065; Name Circulation pump DHW; Value 0 
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/1/65/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Circulation pump DHW",
                            "type": "sensor",
                            "oid": device_id + fct_id + "/1/65/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )                    
                    # EN:ID 01:066 ; Name Charging pump DHW; Value 0 
                    # DE: (122) Unbekannte Ebene (2) 01:066 Warmwasser Ladepumpe
                    # (15) UMUMLZ / (0) UMLZ (1) / (01:66) Warmwasser Ladepumpe (/1/15/0/1/66/0)
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/1/66/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Charging pump DHW",
                            "type": "sensor",
                            "oid": device_id + fct_id + "/1/66/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )                    
                    # EN: (114) DHW temperatures ID 00:004; Name Actual; Value 62.1 °C  
                    # DE: (114) Warmwassertemperatur (0) 00:004 Aktueller Wert
                    # (15) UMUMLZ / (0) UMLZ (1) / (00:004) DHW temperatures - Actual (/1/15/0/0/04/0)
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/0/04/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " DHW temperatures - Actual ",
                            "type": "temperature",
                            "oid": device_id + fct_id + "/0/04/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )     
                    
                    
                    


                # Filter heaters
                functions = list(
                    filter(
                        lambda f: (f["fctType"] == 9 and f["lock"] is False),
                        device["functions"],
                    )
                )
                if len(functions) > 0:
                    fct_id = "/" + str(functions[0]["fctId"])

                    self.oids.update(
                        [
                            # Heater power (percent)
                            device_id + fct_id + "/0/9/0",
                            # Fumes temperature
                            device_id + fct_id + "/0/11/0",
                            # Heater temperature
                            device_id + fct_id + "/0/7/0",
                            # Combusion chamber temperature
                            device_id + fct_id + "/0/45/0",
                            # Heater status
                            device_id + fct_id + "/2/1/0",
                            # Pellet consumption
                            device_id + fct_id + "/23/100/0",
                            device_id + fct_id + "/23/103/0",
                            # Cleaning
                            device_id + fct_id + "/20/61/0",
                            device_id + fct_id + "/20/62/0"
                        ]
                    )

                    # Heater current power factor
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/0/9/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Power factor",
                            "type": "sensor",
                            "device_class": "power_factor",
                            "state_class": None,
                            "unit": "%",
                            "oid": device_id + fct_id + "/0/9/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )
                    # Fumes temperature
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/0/11/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Fumes Temperature",
                            "type": "temperature",
                            "oid": device_id + fct_id + "/0/11/0",
                            "device_id": (self.host + str(device["nodeId"]))
                                .replace(".", "-")
                                .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )
                    # Heater temperature
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/0/7/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Heater Temperature",
                            "type": "temperature",
                            "oid": device_id + fct_id + "/0/7/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )
                    # Combustion chamber temperature
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/0/45/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"]
                            + " Combustion chamber Temperature",
                            "type": "temperature",
                            "oid": device_id + fct_id + "/0/45/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )
                    # Heater status 
                    # (1) System (15) UMUMLZ (60) BioWIN 2 (0) BioWIN 2(100) unknown section (3) 02:001 Betriebsphasen (/1/60/0/2/1/0)
                    options_EN = ["0: Burner locked", "1: Self-test", 
                                  "2: Switch-off heat gener.", "3: Stand-by", 
                                  "4: Burner OFF", "5: Purging", 
                                  "6: Ignition phase", "7: Flame stabilisation", 
                                  "8: Modulation mode", "9: Boiler locked", 
                                  "10: Stand-by off period", "11: Fan OFF", 
                                  "12: Cladding door open", "13: Ignition ready", 
                                  "14: Cancel ignition phase", "15: Start procedure"]
                    options_FR = ["0: Brûleur bloqué", "1: Autotest", 
                                  "2: Eteindre gén. chaleur", "3: Veille", 
                                  "4: Brûleur ARRET", "5: Prérinçage", 
                                  "6: Phase d'allumage", "7: Stabilisation flamme", 
                                  "8: Modulation mode", "9: Chaudière bloqué", 
                                "10: Veille temps différé", "11: Ventilateur Arrêté", 
                                "12: Porte de revêtement ouverte", "13: Allumage prêt", 
                                "14: Annuler phase d'allumage", "15: Préchauffage en cours"]
                    options_DE = ["0: Brenner gesperrt", "1: Selbsttest", 
                                  "2: WE ausschalten", "3: Standby", 
                                  "4: Brenner AUS", "5: Vorspülen", 
                                  "6: Vorspülen", "7: Flammenstabilisierung", 
                                  "8: Modulationsbetrieb", "9: Kessel gesperrt", 
                                "10: Standby Sperrzeit", "11: Gebläse AUS", 
                                "12: Verkleidungstür offen", "13: Zündung bereit", 
                                "14: Abbruch Zündphase", "15: Anheizvorgang"]
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/2/1/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Heater status",
                            "options": options_EN,
                            "type": "select",
                            "oid": device_id + fct_id + "/2/1/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )
                    # Pellet consumption
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/23/100/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"] + " Pellet consumption",
                            "type": "total",
                            "oid": device_id + fct_id + "/23/100/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )
                    # Total pellet consumption
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/23/103/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"]
                            + " Total Pellet consumption",
                            "type": "total_increasing",
                            "oid": device_id + fct_id + "/23/103/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )

                    # Running time until stage 1 cleaning
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/20/61/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"]
                            + " Running time until stage 1 cleaning",
                            "type": "sensor",
                            "device_class": "duration",
                            "state_class": None,
                            "unit": "h",
                            "oid": device_id + fct_id + "/20/61/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )

                    # Running time until stage 2 cleaning
                    self.devices.append(
                        {
                            "id": (
                                self.host
                                + "/1/"
                                + str(device["nodeId"])
                                + fct_id
                                + "/20/62/0"
                            )
                            .replace(".", "-")
                            .replace("/", "-"),
                            "name": functions[0]["name"]
                            + " Running time until stage 2 cleaning",
                            "type": "sensor",
                            "device_class": "duration",
                            "state_class": None,
                            "unit": "h",
                            "oid": device_id + fct_id + "/20/62/0",
                            "device_id": (self.host + str(device["nodeId"]))
                            .replace(".", "-")
                            .replace("/", "-"),
                            "device_name": functions[0]["name"],
                        }
                    )

        ret = {
            "devices": self.devices,
            "oids": {},
        }

        # Lecture de tous les OIDs trouvés
        for oid in self.oids:
            json = await self.fetch(oid)
            ret["oids"][oid] = json["value"]

        return ret

I updated to the last version of your repository and since than I see in the ‘Integrations’ view of ‘Windhager heaters’ only ‘no devices or entries’.

I already removed the ‘Windhager heaters’ integration and reinstalled the complete repo in hacs again, but nothing changes.

Any ideas?

EDIT
@vermi0ffh I got this error in the log after updating. Any ideas?

EDIT:
After a system update the entries were found again.

@vermi0ffh

Translations - general and for ‘Heater status’

The values for “Heater status” should also be in English and maybe in German.
Using the “Web developer tools” in Firefox on the web-interface I could extract all options of the corresponding element 02:001 (oids: /1/60/0/2/1/0). I created three lists for French, English and German element-names and selected English in my client.py above:

                    options_EN = ["0: Burner locked", "1: Self-test", 
                                  "2: Switch-off heat gener.", "3: Stand-by", 
                                  "4: Burner OFF", "5: Purging", 
                                  "6: Ignition phase", "7: Flame stabilisation", 
                                  "8: Modulation mode", "9: Boiler locked", 
                                  "10: Stand-by off period", "11: Fan OFF", 
                                  "12: Cladding door open", "13: Ignition ready", 
                                  "14: Cancel ignition phase", "15: Start procedure"]
                    options_FR = ["0: Brûleur bloqué", "1: Autotest", 
                                  "2: Eteindre gén. chaleur", "3: Veille", 
                                  "4: Brûleur ARRET", "5: Prérinçage", 
                                  "6: Phase d'allumage", "7: Stabilisation flamme", 
                                  "8: Modulation mode", "9: Chaudière bloqué", 
                                "10: Veille temps différé", "11: Ventilateur Arrêté", 
                                "12: Porte de revêtement ouverte", "13: Allumage prêt", 
                                "14: Annuler phase d'allumage", "15: Préchauffage en cours"]
                    options_DE = ["0: Brenner gesperrt", "1: Selbsttest", 
                                  "2: WE ausschalten", "3: Standby", 
                                  "4: Brenner AUS", "5: Vorspülen", 
                                  "6: Vorspülen", "7: Flammenstabilisierung", 
                                  "8: Modulationsbetrieb", "9: Kessel gesperrt", 
                                "10: Standby Sperrzeit", "11: Gebläse AUS", 
                                "12: Verkleidungstür offen", "13: Zündung bereit", 
                                "14: Abbruch Zündphase", "15: Anheizvorgang"]

Hi guys,
i have a new Biowin Touch2 and would like to integrate it in the home assistant. I use the mycomfort app…which leads to a automatic update of the local standard password “123”. (according to the windhager technical support ).
How do you get the password? Or is it not possible to user ha-windhager repository in the system?

Hey ! Can you make a pull request with this on github ?

Hi, I got my password from the Biowin touch interface, directly on the boiler. I don’t remember the exact menu sequence. If I can get a little time, I’ll track it and add it to the readme.