Skip to content

Commit

Permalink
* Optimize solar detection
Browse files Browse the repository at this point in the history
* Add diagnostics with all current sensor values
* Trim recorder data
  • Loading branch information
BenPru committed Jan 5, 2023
1 parent 87dc883 commit 28c4e5f
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 11 deletions.
4 changes: 2 additions & 2 deletions custom_components/luxtronik/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
CONF_VISIBILITIES, DEFAULT_DEVICE_CLASS, DEVICE_CLASSES,
DOMAIN, LOGGER,
LUX_BINARY_SENSOR_ADDITIONAL_CIRCULATION_PUMP,
LUX_BINARY_SENSOR_DOMESTIC_WATER_RECIRCULATION_PUMP,
LUX_BINARY_SENSOR_CIRCULATION_PUMP_HEATING,
LUX_BINARY_SENSOR_DOMESTIC_WATER_RECIRCULATION_PUMP,
LUX_BINARY_SENSOR_EVU_UNLOCKED,
LUX_BINARY_SENSOR_SOLAR_PUMP)
from .helpers.helper import get_sensor_text
Expand Down Expand Up @@ -253,7 +253,6 @@ async def async_setup_entry(

deviceInfoDomesticWater = hass.data[f"{DOMAIN}_DeviceInfo_Domestic_Water"]
if deviceInfoDomesticWater is not None:
text_solar_pump = get_sensor_text(lang, "solar_pump")
if luxtronik.has_domestic_water_circulation_pump:
circulation_pump_unique_id = 'domestic_water_circulation_pump'
text_domestic_water_circulation_pump = text_circulation_pump
Expand Down Expand Up @@ -282,6 +281,7 @@ async def async_setup_entry(
]
solar_present = luxtronik.detect_solar_present()
if solar_present:
text_solar_pump = get_sensor_text(lang, "solar_pump")
entities += [
LuxtronikBinarySensor(
luxtronik=luxtronik,
Expand Down
2 changes: 1 addition & 1 deletion custom_components/luxtronik/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ class LuxMode(Enum):
]
# endregion Luxtronik Sensor ids

LUX_DETECT_SOLAR_SENSOR: Final = "parameters.ID_BSTD_Solar"
LUX_DETECT_SOLAR_SENSOR: Final = "visibilities.ID_Visi_Solar"
LUX_MK_SENSORS = ['parameters.ID_Einst_MK1Typ_akt',
'parameters.ID_Einst_MK2Typ_akt',
'parameters.ID_Einst_MK3Typ_akt']
Expand Down
84 changes: 84 additions & 0 deletions custom_components/luxtronik/diagnostics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""Diagnostics support for Luxtronik."""
from __future__ import annotations

from functools import partial
from ipaddress import IPv6Address, ip_address

from async_timeout import timeout
from getmac import get_mac_address
from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (CONF_HOST, CONF_PASSWORD, CONF_PORT,
CONF_USERNAME)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry
from luxtronik import Luxtronik as Lux

from .const import CONF_COORDINATOR, DOMAIN

TO_REDACT = {CONF_USERNAME, CONF_PASSWORD}


async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: ConfigEntry
) -> dict:
"""Return diagnostics for a config entry."""
data: dict = entry.data
client = Lux(data[CONF_HOST], data[CONF_PORT], True)
client.read()

mac = ""
async with timeout(10):
mac = await _async_get_mac_address(hass, data[CONF_HOST])
mac = mac[:9] + '*'

entry_data = async_redact_data(entry.as_dict(), TO_REDACT)
if "data" not in entry_data:
entry_data["data"] = {}
entry_data["data"]["mac"] = mac
diag_data = {
"entry": entry_data,
"parameters": _dump_items(client.parameters.parameters),
"calculations": _dump_items(client.calculations.calculations),
"visibilities": _dump_items(client.visibilities.visibilities),
}
return diag_data


def _dump_items(items: dict) -> dict:
dump = dict()
for index, item in items.items():
dump[f"{index:<4d} {item.name:<60}"] = f"{items.get(index)}"
return dump


async def _async_get_mac_address(hass: HomeAssistant, host: str) -> str | None:
"""Get mac address from host name, IPv4 address, or IPv6 address."""
# Help mypy, which has trouble with the async_add_executor_job + partial call
mac_address: str | None
# getmac has trouble using IPv6 addresses as the "hostname" parameter so
# assume host is an IP address, then handle the case it's not.
try:
ip_addr = ip_address(host)
except ValueError:
mac_address = await hass.async_add_executor_job(
partial(get_mac_address, hostname=host)
)
else:
if ip_addr.version == 4:
mac_address = await hass.async_add_executor_job(
partial(get_mac_address, ip=host)
)
else:
# Drop scope_id from IPv6 address by converting via int
ip_addr = IPv6Address(int(ip_addr))
mac_address = await hass.async_add_executor_job(
partial(get_mac_address, ip6=str(ip_addr))
)

if not mac_address:
return None

return device_registry.format_mac(mac_address)


5 changes: 4 additions & 1 deletion custom_components/luxtronik/luxtronik_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,10 @@ def detect_cooling_Mk(self):

def detect_solar_present(self):
sensor_value = self.get_value(LUX_DETECT_SOLAR_SENSOR)
SolarPresent = (sensor_value > 0.01)
solar_koll = self.get_value("visibilities.ID_Visi_Temp_Solarkoll")
solar_buffer = self.get_value("visibilities.ID_Visi_Temp_Solarsp")
working_hours = self.get_value("parameters.ID_BSTD_Solar")
SolarPresent = (sensor_value > 0 or working_hours > 0.01 or solar_koll > 0 or solar_buffer > 0)
LOGGER.info(f"SolarPresent = {SolarPresent}")
return SolarPresent

Expand Down
4 changes: 2 additions & 2 deletions custom_components/luxtronik/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"domain": "luxtronik2",
"name": "Luxtronik",
"version": "2022.12.30",
"version": "2023.01.05",
"integration_type": "hub",
"config_flow": true,
"iot_class": "local_polling",
Expand All @@ -10,7 +10,7 @@
"dependencies": [],
"after_dependencies": ["http"],
"codeowners": ["@bouni", "@benpru"],
"requirements": ["luxtronik>=0.3.14"],
"requirements": ["luxtronik>=0.3.14", "getmac>=0.8.2"],
"homeassistant": "2022.9.0",
"dhcp": [
{
Expand Down
37 changes: 37 additions & 0 deletions custom_components/luxtronik/recorder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""Integration platform for recorder."""
from __future__ import annotations

from homeassistant.core import HomeAssistant, callback

from .const import (ATTR_EXTRA_STATE_ATTRIBUTE_LAST_THERMAL_DESINFECTION,
ATTR_STATUS_TEXT, DOMAIN)


@callback
def exclude_attributes(hass: HomeAssistant) -> set[str]:
"""Exclude attributes from being recorded in the database."""
return {
ATTR_STATUS_TEXT,
ATTR_EXTRA_STATE_ATTRIBUTE_LAST_THERMAL_DESINFECTION,
'WP Seit (ID_WEB_Time_WPein_akt)',
'ZWE1 seit (ID_WEB_Time_ZWE1_akt)',
'ZWE2 seit (ID_WEB_Time_ZWE2_akt)',
'Netzeinschaltv. (ID_WEB_Timer_EinschVerz)',
'Schaltspielsperre SSP-Aus-Zeit (ID_WEB_Time_SSPAUS_akt)',
'Schaltspielsperre SSP-Ein-Zeit (ID_WEB_Time_SSPEIN_akt)',
'VD-Stand (ID_WEB_Time_VDStd_akt)',
'Heizungsregler Mehr-Zeit HRM-Zeit (ID_WEB_Time_HRM_akt)',
'Heizungsregler Weniger-Zeit HRW-Stand (ID_WEB_Time_HRW_akt)',
'ID_WEB_Time_LGS_akt',
'Sperre WW? ID_WEB_Time_SBW_akt',
'Abtauen in ID_WEB_Time_AbtIn',
'ID_WEB_Time_Heissgas',
'switch_gap',
f"sensor.{DOMAIN}_status_time",
'status raw',
'EVU first start time',
'EVU first end time',
'EVU second start time',
'EVU second end time',
'EVU minutes until next event',
}
29 changes: 24 additions & 5 deletions custom_components/luxtronik/sensor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Luxtronik heatpump sensor."""
# region Imports
from typing import Any
from datetime import datetime, time
from typing import Any

from homeassistant.components.sensor import (ENTITY_ID_FORMAT,
STATE_CLASS_MEASUREMENT,
Expand Down Expand Up @@ -588,7 +588,6 @@ async def async_setup_entry(
text_operation_hours_domestic_water = get_sensor_text(
lang, "operation_hours_domestic_water"
)
text_operation_hours_solar = get_sensor_text(lang, "operation_hours_solar")
text_heat_amount_domestic_water = get_sensor_text(
lang, "heat_amount_domestic_water"
)
Expand Down Expand Up @@ -630,8 +629,22 @@ async def async_setup_entry(
),
]

solar_present = luxtronik.detect_solar_present()
if solar_present:
if luxtronik.get_value("visibilities.ID_Visi_Temp_Solarkoll") > 0:
entities += [
LuxtronikSensor(
luxtronik,
device_info_domestic_water,
"calculations.ID_WEB_Temperatur_TSK",
"solar_collector_temperature",
f"Solar {text_collector}",
"mdi:solar-panel-large",
entity_category=None,
),
]
# Temp. disabled:
# solar_present = luxtronik.detect_solar_present()
# if solar_present:
if luxtronik.get_value("visibilities.ID_Visi_Temp_Solarkoll") > 0:
entities += [
LuxtronikSensor(
luxtronik,
Expand All @@ -642,6 +655,9 @@ async def async_setup_entry(
"mdi:solar-panel-large",
entity_category=None,
),
]
if luxtronik.get_value("visibilities.ID_Visi_Temp_Solarsp") > 0:
entities += [
LuxtronikSensor(
luxtronik,
device_info_domestic_water,
Expand All @@ -651,6 +667,10 @@ async def async_setup_entry(
"mdi:propane-tank-outline",
entity_category=None,
),
]
if luxtronik.get_value("parameters.ID_BSTD_Solar") > 0:
text_operation_hours_solar = get_sensor_text(lang, "operation_hours_solar")
entities += [
LuxtronikSensor(
luxtronik,
device_info_domestic_water,
Expand All @@ -664,7 +684,6 @@ async def async_setup_entry(
entity_category=EntityCategory.DIAGNOSTIC,
factor=SECOUND_TO_HOUR_FACTOR,
),

]

deviceInfoCooling = hass.data[f"{DOMAIN}_DeviceInfo_Cooling"]
Expand Down

0 comments on commit 28c4e5f

Please sign in to comment.