Skip to content

Commit

Permalink
Bugfix:
Browse files Browse the repository at this point in the history
* The luxtronik status text attribute is now in german if german is selected in the configuration. The last release have always used english.

Feature:
* Added device urls: local heatpump, heatpump24 and firmware download
* Added new attribute 'Luxtronik Key' in binary_sensors, numbers, sensors and switchs with the source luxtronik key. E.g. calculations.ID_WEB_ZIPout
* The luxtronik status sensor has now the attribute 'Status raw' to provide the raw luxtronik status.
* The luxtronik status sensor has now the attributes 'EVU first start time', 'EVU first end time', 'EVU second start time' and 'EVU second end time'.
  They log the last detected EVU event time with format 'HH:MM'. After a home assistant restart they are restored.
* The luxtronik status sensor has now the attribute 'EVU minutes until next event' to provide a value with minutes until the next EVU event should raise.
* The heatpump models enum was extended with MODELS_Other = ['CB','CI','CN','CS']

Changed:
* Changed device for circulation_pump_domestic_water (calculations.ID_WEB_BUPout)	from heatpump to domestic water
* Changed device for circulation_pump_heating (calculations.ID_WEB_HUPout)		from heatpump to heating
* Fix binary sensor names and text:
  * circulating_pump_domestic_water	--> circulation_pump (calculations.ID_WEB_ZIPout)
  * circulating_pump_heating		--> additional_circulation_pump (calculations.ID_WEB_ZUPout)
  * circulating_pump_water		--> circulation_pump_domestic_water (calculations.ID_WEB_BUPout)
  * unloading_pump			--> circulation_pump_heating (calculations.ID_WEB_HUPout)
  • Loading branch information
BenPru committed Nov 24, 2022
1 parent 7227b4f commit 3912b8e
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 75 deletions.
14 changes: 10 additions & 4 deletions custom_components/luxtronik/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Support for Luxtronik heatpump controllers."""
# region Imports
from typing import Optional

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP
Expand All @@ -24,7 +23,10 @@
SERVICE_WRITE_SCHEMA,
)
from .helpers.helper import get_sensor_text
from .helpers.lux_helper import get_manufacturer_by_model
from .helpers.lux_helper import (
get_manufacturer_by_model,
get_manufacturer_firmware_url_by_model
)
from .luxtronik_device import LuxtronikDevice

# endregion Imports
Expand Down Expand Up @@ -128,17 +130,19 @@ def setup_internal(hass, data, conf):
model = luxtronik.get_value("calculations.ID_WEB_Code_WP_akt")

hass.data[f"{DOMAIN}_DeviceInfo"] = build_device_info(
luxtronik, serial_number, text_heatpump
luxtronik, serial_number, text_heatpump, data[CONF_HOST]
)
hass.data[f"{DOMAIN}_DeviceInfo_Domestic_Water"] = DeviceInfo(
identifiers={(DOMAIN, "Domestic_Water", serial_number)},
configuration_url="https://www.heatpump24.com/",
default_name=text_domestic_water,
name=text_domestic_water,
manufacturer=get_manufacturer_by_model(model),
model=model,
)
hass.data[f"{DOMAIN}_DeviceInfo_Heating"] = DeviceInfo(
identifiers={(DOMAIN, "Heating", serial_number)},
configuration_url=get_manufacturer_firmware_url_by_model(model),
default_name=text_heating,
name=text_heating,
manufacturer=get_manufacturer_by_model(model),
Expand Down Expand Up @@ -189,17 +193,19 @@ async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
return unload_ok


def build_device_info(luxtronik: LuxtronikDevice, sn: str, name: str) -> DeviceInfo:
def build_device_info(luxtronik: LuxtronikDevice, sn: str, name: str, ip_host: str) -> DeviceInfo:
"""Build luxtronik device info."""
model = luxtronik.get_value("calculations.ID_WEB_Code_WP_akt")
device_info = DeviceInfo(
identifiers={(DOMAIN, "Heatpump", sn)}, # type: ignore
configuration_url=f"http://{ip_host}/",
name=f"{name} S/N {sn}",
default_name=name,
default_manufacturer="Alpha Innotec",
manufacturer=get_manufacturer_by_model(model),
default_model="",
model=model,
suggested_area='Utility room',
sw_version=luxtronik.get_value("calculations.ID_WEB_SoftStand"),
)
LOGGER.debug("build_device_info '%s'", device_info)
Expand Down
83 changes: 43 additions & 40 deletions custom_components/luxtronik/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,18 @@
from homeassistant.helpers.typing import ConfigType
from homeassistant.util import slugify

from .const import (CONF_CALCULATIONS, CONF_GROUP,
CONF_INVERT_STATE,
CONF_LANGUAGE_SENSOR_NAMES,
CONF_PARAMETERS,
CONF_VISIBILITIES,
DEFAULT_DEVICE_CLASS,
DEVICE_CLASSES, DOMAIN, LOGGER,
LUX_BINARY_SENSOR_EVU_UNLOCKED,
LUX_BINARY_SENSOR_SOLAR_PUMP)
from .const import (
ATTR_EXTRA_STATE_ATTRIBUTE_LUXTRONIK_KEY,
CONF_CALCULATIONS, CONF_GROUP,
CONF_INVERT_STATE,
CONF_LANGUAGE_SENSOR_NAMES,
CONF_PARAMETERS,
CONF_VISIBILITIES,
DEFAULT_DEVICE_CLASS,
DEVICE_CLASSES, DOMAIN, LOGGER,
LUX_BINARY_SENSOR_EVU_UNLOCKED,
LUX_BINARY_SENSOR_SOLAR_PUMP
)
from .helpers.helper import get_sensor_text
from .luxtronik_device import LuxtronikDevice

Expand Down Expand Up @@ -149,10 +152,10 @@ async def async_setup_entry(
lang = config_entry.options.get(CONF_LANGUAGE_SENSOR_NAMES)
text_evu_unlocked = get_sensor_text(lang, "evu_unlocked")
text_compressor = get_sensor_text(lang, "compressor")
text_circulating_pump_domestic_water = get_sensor_text(lang, "circulating_pump_domestic_water")
text_circulating_pump_heating = get_sensor_text(lang, "circulating_pump_heating")
text_circulating_pump_water = get_sensor_text(lang, "circulating_pump_water")
text_unloading_pump = get_sensor_text(lang, "unloading_pump")
text_circulation_pump = get_sensor_text(lang, "circulation_pump")
text_additional_circulation_pump = get_sensor_text(lang, "additional_circulation_pump")
text_circulation_pump_domestic_water = get_sensor_text(lang, "circulation_pump_domestic_water")
text_circulation_pump_heating = get_sensor_text(lang, "circulation_pump_heating")
text_pump_flow = get_sensor_text(lang, "pump_flow")
text_compressor_heater = get_sensor_text(lang, "compressor_heater")

Expand Down Expand Up @@ -182,8 +185,8 @@ async def async_setup_entry(
luxtronik=luxtronik,
deviceInfo=deviceInfo,
sensor_key='calculations.ID_WEB_ZIPout',
unique_id="circulating_pump_domestic_water",
name=text_circulating_pump_domestic_water,
unique_id="circulation_pump",
name=text_circulation_pump,
icon="mdi:pump",
device_class=DEVICE_CLASS_RUNNING,
),
Expand All @@ -192,31 +195,11 @@ async def async_setup_entry(
luxtronik=luxtronik,
deviceInfo=deviceInfo,
sensor_key='calculations.ID_WEB_ZUPout',
unique_id="circulating_pump_heating",
name=text_circulating_pump_heating,
icon="mdi:pump",
device_class=DEVICE_CLASS_RUNNING,
),
LuxtronikBinarySensor(
hass=hass,
luxtronik=luxtronik,
deviceInfo=deviceInfo,
sensor_key='calculations.ID_WEB_BUPout',
unique_id="circulating_pump_water",
name=text_circulating_pump_water,
unique_id="additional_circulation_pump",
name=text_additional_circulation_pump,
icon="mdi:pump",
device_class=DEVICE_CLASS_RUNNING,
),
LuxtronikBinarySensor(
hass=hass,
luxtronik=luxtronik,
deviceInfo=deviceInfo,
sensor_key='calculations.ID_WEB_HUPout',
unique_id="unloading_pump",
name=text_unloading_pump,
icon="mdi:car-turbocharger",
device_class=DEVICE_CLASS_RUNNING,
),
# Soleumwälzpumpe
# Umwälzpumpe Ventilator, Brunnen- oder Sole
LuxtronikBinarySensor(
Expand All @@ -240,8 +223,6 @@ async def async_setup_entry(
device_class=DEVICE_CLASS_RUNNING,
),

# ID_WEB_LIN_VDH_out

# calculations.ID_WEB_ASDin Soledruck ausreichend
# calculations.ID_WEB_HDin Hochdruck OK
# calculations.ID_WEB_MOTin Motorschutz OK
Expand All @@ -255,6 +236,16 @@ async def async_setup_entry(
deviceInfoHeating = hass.data[f"{DOMAIN}_DeviceInfo_Heating"]
if deviceInfoHeating is not None:
entities += [
LuxtronikBinarySensor(
hass=hass,
luxtronik=luxtronik,
deviceInfo=deviceInfoHeating,
sensor_key='calculations.ID_WEB_HUPout',
unique_id="circulation_pump_heating",
name=text_circulation_pump_heating,
icon="mdi:car-turbocharger",
device_class=DEVICE_CLASS_RUNNING,
),
]

deviceInfoDomesticWater = hass.data[f"{DOMAIN}_DeviceInfo_Domestic_Water"]
Expand All @@ -271,7 +262,17 @@ async def async_setup_entry(
name=text_solar_pump,
icon="mdi:pump",
device_class=DEVICE_CLASS_RUNNING,
)
),
LuxtronikBinarySensor(
hass=hass,
luxtronik=luxtronik,
deviceInfo=deviceInfoDomesticWater,
sensor_key='calculations.ID_WEB_BUPout',
unique_id="circulation_pump_domestic_water",
name=text_circulation_pump_domestic_water,
icon="mdi:pump",
device_class=DEVICE_CLASS_RUNNING,
),
]

deviceInfoCooling = hass.data[f"{DOMAIN}_DeviceInfo_Cooling"]
Expand Down Expand Up @@ -325,6 +326,8 @@ def __init__(
self._attr_state_class = state_class
self._attr_entity_category = entity_category
self._invert = invert_state
self._attr_extra_state_attributes = { ATTR_EXTRA_STATE_ATTRIBUTE_LUXTRONIK_KEY: sensor_key }


@property
def is_on(self):
Expand Down
4 changes: 2 additions & 2 deletions custom_components/luxtronik/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
SensorDeviceClass,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import (
CONF_HOST,
Expand Down Expand Up @@ -107,6 +105,7 @@ class LuxtronikSensorEntityDescription(SensorEntityDescription):
SECOUND_TO_HOUR_FACTOR: Final = 0.000277777777778

ATTR_STATUS_TEXT: Final = "status_text"
ATTR_EXTRA_STATE_ATTRIBUTE_LUXTRONIK_KEY: Final = "Luxtronik Key"


MIN_TIME_BETWEEN_UPDATES: Final = timedelta(seconds=10)
Expand Down Expand Up @@ -256,6 +255,7 @@ class LuxMkTypes(Enum):

LUX_MODELS_AlphaInnotec = ['LWP','LWV','MSW','SWC','SWP']
LUX_MODELS_Novelan = ['BW','LA','LD','LI','SI','ZLW']
LUX_MODELS_Other = ['CB','CI','CN','CS']

GLOBAL_STATUS_SENSOR_TYPES: tuple[LuxtronikSensorEntityDescription, ...] = (
LuxtronikSensorEntityDescription(
Expand Down
4 changes: 2 additions & 2 deletions custom_components/luxtronik/helpers/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ def get_sensor_value_text(
__content_sensor_default__ = _load_lang_from_file(
f"../translations/{platform}.{LANG_DEFAULT}.json", log_warning=True
)
if lang is None:
lang = LANG_DEFAULT
if __content_sensor_locale__ is None and lang != LANG_DEFAULT:
__content_sensor_locale__ = _load_lang_from_file(
f"../translations/{platform}.{lang}.json", log_warning=False
)
else:
lang = LANG_DEFAULT
content = (
__content_sensor_default__
if lang == LANG_DEFAULT
Expand Down
18 changes: 17 additions & 1 deletion custom_components/luxtronik/helpers/lux_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from ..const import (
LOGGER,
LUX_MODELS_AlphaInnotec,
LUX_MODELS_Novelan
LUX_MODELS_Novelan,
LUX_MODELS_Other
)

def discover():
Expand Down Expand Up @@ -63,3 +64,18 @@ def get_manufacturer_by_model(model: str) -> str:
if model.startswith(tuple(LUX_MODELS_AlphaInnotec)):
return "Alpha Innotec"
return None


def get_manufacturer_firmware_url_by_model(model: str) -> str:
"""Return the manufacturer firmware download url."""
layout_id = 0

if model is None:
layout_id = 0
elif model.startswith(tuple(LUX_MODELS_AlphaInnotec)):
layout_id = 1
elif model.startswith(tuple(LUX_MODELS_Novelan)):
layout_id = 2
elif model.startswith(tuple(LUX_MODELS_Other)):
layout_id = 3
return f"https://www.heatpump24.com/DownloadArea.php?layout={layout_id}"
11 changes: 6 additions & 5 deletions custom_components/luxtronik/luxtronik_device.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
"""Luxtronik device."""
# region Imports
import re
import threading
import time
import re

from luxtronik import Luxtronik as Lux

from homeassistant.util import Throttle
from luxtronik import Luxtronik as Lux

from .const import (
CONF_CALCULATIONS,
CONF_PARAMETERS,
CONF_VISIBILITIES,
LOGGER,
MIN_TIME_BETWEEN_UPDATES,
LUX_MK_SENSORS, LuxMkTypes,
LUX_DETECT_SOLAR_SENSOR
LUX_MK_SENSORS,
LuxMkTypes,
MIN_TIME_BETWEEN_UPDATES,
)
from .helpers.debounce import debounce

Expand Down
12 changes: 7 additions & 5 deletions custom_components/luxtronik/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,21 @@
from homeassistant.helpers.typing import ConfigType

from . import LuxtronikDevice
from .const import (CONF_LANGUAGE_SENSOR_NAMES, DOMAIN, LOGGER,
LUX_SENSOR_COOLING_THRESHOLD,
from .const import (ATTR_EXTRA_STATE_ATTRIBUTE_LUXTRONIK_KEY,
CONF_LANGUAGE_SENSOR_NAMES, DOMAIN, LOGGER,
LUX_SENSOR_COOLING_START_DELAY,
LUX_SENSOR_COOLING_STOP_DELAY,
LUX_SENSOR_COOLING_THRESHOLD,
LUX_SENSOR_DOMESTIC_WATER_TARGET_TEMPERATURE,
LUX_SENSOR_HEATING_CIRCUIT_CURVE1_TEMPERATURE,
LUX_SENSOR_HEATING_CIRCUIT_CURVE2_TEMPERATURE,
LUX_SENSOR_HEATING_CIRCUIT_CURVE_NIGHT_TEMPERATURE,
LUX_SENSOR_HEATING_MIN_FLOW_OUT_TEMPERATURE,
LUX_SENSOR_PUMP_OPTIMIZATION_TIME,
LUX_SENSOR_MAXIMUM_CIRCULATION_PUMP_SPEED,
LUX_SENSOR_HEATING_ROOM_TEMPERATURE_IMPACT_FACTOR,
LUX_SENSOR_HEATING_TARGET_CORRECTION,
LUX_SENSOR_HEATING_THRESHOLD_TEMPERATURE,
LUX_SENSOR_HEATING_ROOM_TEMPERATURE_IMPACT_FACTOR)
LUX_SENSOR_MAXIMUM_CIRCULATION_PUMP_SPEED,
LUX_SENSOR_PUMP_OPTIMIZATION_TIME)
from .helpers.helper import get_sensor_text

# endregion Imports
Expand Down Expand Up @@ -238,6 +239,7 @@ def __init__(
self._attr_native_step = step
self._attr_entity_category = entity_category
self._factor = factor
self._attr_extra_state_attributes = { ATTR_EXTRA_STATE_ATTRIBUTE_LUXTRONIK_KEY: number_key }

@property
def icon(self): # -> str | None:
Expand Down
Loading

0 comments on commit 3912b8e

Please sign in to comment.