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