Skip to content

Commit 5940811

Browse files
authored
Merge pull request #19 from rhammen/main
Several enhancements
2 parents 99bf92d + 0762c7e commit 5940811

File tree

9 files changed

+174
-48
lines changed

9 files changed

+174
-48
lines changed

custom_components/luxtronik/climate.py

+34-20
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,28 @@
2828
CONF_HA_SENSOR_INDOOR_TEMPERATURE,
2929
CONF_LANGUAGE_SENSOR_NAMES, CONF_PARAMETERS,
3030
CONF_VISIBILITIES, DEFAULT_TOLERANCE, DOMAIN, LOGGER,
31+
3132
LUX_SENSOR_DOMESTIC_WATER_CURRENT_TEMPERATURE,
3233
LUX_SENSOR_DOMESTIC_WATER_TARGET_TEMPERATURE,
33-
LUX_SENSOR_MODE_DOMESTIC_WATER, LUX_SENSOR_MODE_HEATING,
34+
LUX_SENSOR_HEATING_TEMPERATURE_CORRECTION,
35+
LUX_SENSOR_COOLING_TARGET,
36+
LUX_SENSOR_COOLING_THRESHOLD,
37+
LUX_SENSOR_OUTDOOR_TEMPERATURE,
38+
39+
LUX_SENSOR_MODE_DOMESTIC_WATER,
40+
LUX_SENSOR_MODE_HEATING,
41+
LUX_SENSOR_MODE_COOLING,
42+
3443
LUX_SENSOR_STATUS, LUX_SENSOR_STATUS1, LUX_SENSOR_STATUS3,
3544
LUX_STATUS1_WORKAROUND, LUX_STATUS3_WORKAROUND,
3645
LUX_STATUS_COOLING, LUX_STATUS_DEFROST,
37-
LUX_STATUS_DOMESTIC_WATER, LUX_STATUS_EVU,
38-
LUX_STATUS_HEATING, LUX_STATUS_HEATING_EXTERNAL_SOURCE,
46+
LUX_STATUS_DOMESTIC_WATER,
47+
LUX_STATUS_EVU,
48+
LUX_STATUS_HEATING,
49+
LUX_STATUS_HEATING_EXTERNAL_SOURCE,
3950
LUX_STATUS_NO_REQUEST, LUX_STATUS_SWIMMING_POOL_SOLAR,
40-
PRESET_SECOND_HEATSOURCE, LuxMode)
51+
PRESET_SECOND_HEATSOURCE, PRESET_AUTO,
52+
LuxMode)
4153
from .helpers.helper import get_sensor_text
4254

4355
# endregion Imports
@@ -98,13 +110,11 @@ async def async_setup_entry(
98110

99111
deviceInfoCooling = hass.data[f"{DOMAIN}_DeviceInfo_Cooling"]
100112
if deviceInfoCooling is not None:
101-
# Future use: cooling
102-
# text_cooling = get_sensor_text(lang, 'cooling')
113+
text_cooling = get_sensor_text(lang, 'cooling')
103114
entities += [
104-
# TODO:
105-
# LuxtronikCoolingThermostat(hass, luxtronik, deviceInfoCooling, name=text_cooling,
106-
# control_mode_home_assistant=control_mode_home_assistant,
107-
# current_temperature_sensor=LUX_SENSOR_DOMESTIC_WATER_CURRENT_TEMPERATURE, entity_category=None)
115+
LuxtronikCoolingThermostat(
116+
hass, luxtronik, deviceInfoCooling, name=text_cooling, control_mode_home_assistant=control_mode_home_assistant,
117+
current_temperature_sensor=LUX_SENSOR_OUTDOOR_TEMPERATURE, entity_category=None)
108118
]
109119

110120
async_add_entities(entities)
@@ -132,7 +142,7 @@ class LuxtronikThermostat(ClimateEntity, RestoreEntity):
132142
_status_sensor: Final = LUX_SENSOR_STATUS
133143
_target_temperature_sensor: str = None
134144

135-
_heat_status = [LUX_STATUS_HEATING, LUX_STATUS_DOMESTIC_WATER]
145+
_heat_status = [LUX_STATUS_HEATING, LUX_STATUS_DOMESTIC_WATER, LUX_STATUS_COOLING]
136146

137147
_cold_tolerance = DEFAULT_TOLERANCE
138148
_hot_tolerance = DEFAULT_TOLERANCE
@@ -367,7 +377,9 @@ class LuxtronikDomesticWaterThermostat(LuxtronikThermostat):
367377
_attr_icon = 'mdi:water-boiler'
368378
_attr_device_class: Final = f"{DOMAIN}__{_attr_unique_id}"
369379

370-
_attr_target_temperature_step = 2.5
380+
_attr_target_temperature_step = 1.0
381+
_attr_min_temp = 40.0
382+
_attr_max_temp = 58.0
371383

372384
_target_temperature_sensor: Final = LUX_SENSOR_DOMESTIC_WATER_TARGET_TEMPERATURE
373385
_heater_sensor: Final = LUX_SENSOR_MODE_DOMESTIC_WATER
@@ -379,23 +391,25 @@ class LuxtronikHeatingThermostat(LuxtronikThermostat):
379391
_attr_icon = 'mdi:radiator'
380392
_attr_device_class: Final = f"{DOMAIN}__{_attr_unique_id}"
381393

382-
_attr_target_temperature = 20.5
383-
_attr_target_temperature_step = 0.1
384-
_attr_min_temp = 18.0
385-
_attr_max_temp = 23.0
394+
#_attr_target_temperature = 20.5
395+
_attr_target_temperature_step = 0.5
396+
_attr_min_temp = -5.0
397+
_attr_max_temp = +5.0
386398

399+
_target_temperature_sensor: Final = LUX_SENSOR_HEATING_TEMPERATURE_CORRECTION
387400
_heater_sensor: Final = LUX_SENSOR_MODE_HEATING
388-
401+
_heat_status: Final = [LUX_STATUS_HEATING]
389402

390403
class LuxtronikCoolingThermostat(LuxtronikThermostat):
391404
_attr_unique_id = 'cooling'
392405
_attr_icon = 'mdi:snowflake'
393406
_attr_device_class: Final = f"{DOMAIN}__{_attr_unique_id}"
394407

395-
_attr_target_temperature = 20.5
408+
_target_temperature_sensor = LUX_SENSOR_COOLING_THRESHOLD
396409
_attr_target_temperature_step = 0.5
397410
_attr_min_temp = 18.0
398411
_attr_max_temp = 30.0
412+
_attr_preset_modes = [PRESET_NONE]
399413

400414
# _heater_sensor: Final = LUX_SENSOR_MODE_HEATING
401415

@@ -410,5 +424,5 @@ class LuxtronikCoolingThermostat(LuxtronikThermostat):
410424
# parameters.ID_Einst_Kuhl_Zeit_Aus_akt
411425
# stop cooling after this timeout
412426
# 12.0
413-
_heater_sensor = 'calculations.ID_WEB_FreigabKuehl'
414-
_heat_status = ['cooling']
427+
_heater_sensor = LUX_SENSOR_MODE_COOLING
428+
_heat_status = [LUX_STATUS_COOLING]

custom_components/luxtronik/const.py

+23-9
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
CONF_LOCK_TIMEOUT: Final = "lock_timeout"
4949
CONF_UPDATE_IMMEDIATELY_AFTER_WRITE: Final = "update_immediately_after_write"
5050

51-
CONF_PARAMETERS: Final = "parameters"
51+
CONF_PARAMETERS: Final = "parameters"
5252
CONF_CALCULATIONS: Final = "calculations"
5353
CONF_VISIBILITIES: Final = "visibilities"
5454

@@ -109,7 +109,7 @@ class LuxtronikSensorEntityDescription(SensorEntityDescription):
109109

110110
MIN_TIME_BETWEEN_UPDATES: Final = timedelta(seconds=10)
111111

112-
112+
PRESET_AUTO: Final = 'automatic'
113113
PRESET_SECOND_HEATSOURCE: Final = "second_heatsource"
114114

115115
# region Lux Modes
@@ -137,6 +137,7 @@ class LuxMode(Enum):
137137
LUX_STATUS_NO_REQUEST: Final = "no request" # 5
138138
LUX_STATUS_HEATING_EXTERNAL_SOURCE: Final = "heating external source" # 6
139139
LUX_STATUS_COOLING: Final = "cooling" # 7
140+
LUX_STATUS_THERMAL_DESINFECTION: Final = "thermal desinfection"
140141

141142
LUX_STATUS_NONE: Final = "None"
142143
LUX_STATUS_UNKNOWN: Final = "unknown"
@@ -190,20 +191,25 @@ class LuxMode(Enum):
190191

191192
# region Luxtronik Sensor ids
192193
LUX_SENSOR_DETECT_COOLING: Final = "calculations.ID_WEB_FreigabKuehl"
193-
LUX_SENSOR_STATUS: Final = "calculations.ID_WEB_WP_BZ_akt"
194+
LUX_SENSOR_STATUS: Final = "calculations.ID_WEB_WP_BZ_akt"
194195
LUX_SENSOR_STATUS1: Final = "calculations.ID_WEB_HauptMenuStatus_Zeile1"
195196
LUX_SENSOR_STATUS3: Final = "calculations.ID_WEB_HauptMenuStatus_Zeile3"
196197

197198
LUX_SENSOR_REMOTE_MAINTENANCE: Final = "parameters.ID_Einst_Fernwartung_akt"
198199

199-
LUX_SENSOR_HEATING_TEMPERATURE_CORRECTION: Final = "parameters.ID_Einst_WK_akt"
200-
LUX_SENSOR_HEATING_THRESHOLD: Final = "parameters.ID_Einst_Heizgrenze"
201-
LUX_SENSOR_HEATING_THRESHOLD_TEMPERATURE: Final = "parameters.ID_Einst_Heizgrenze_Temp"
200+
LUX_SENSOR_OUTDOOR_TEMPERATURE: Final = "calculations.ID_WEB_Temperatur_TA"
201+
202+
LUX_SENSOR_HEATING_TEMPERATURE_CORRECTION: Final = "parameters.ID_Einst_WK_akt"
203+
LUX_SENSOR_HEATING_THRESHOLD: Final = "parameters.ID_Einst_Heizgrenze"
204+
LUX_SENSOR_HEATING_THRESHOLD_TEMPERATURE: Final = "parameters.ID_Einst_Heizgrenze_Temp"
202205
LUX_SENSOR_HEATING_MIN_FLOW_OUT_TEMPERATURE: Final = "parameters.ID_Einst_Minimale_Ruecklaufsolltemperatur"
203-
LUX_SENSOR_MODE_HEATING: Final = "parameters.ID_Ba_Hz_akt"
206+
LUX_SENSOR_MODE_HEATING: Final = "parameters.ID_Ba_Hz_akt"
204207

205-
LUX_SENSOR_COOLING_THRESHOLD: Final = "parameters.ID_Einst_KuehlFreig_akt"
206-
LUX_SENSOR_MODE_COOLING: Final = "parameters.ID_Ba_Hz_akt"
208+
LUX_SENSOR_COOLING_THRESHOLD: Final = "parameters.ID_Einst_KuehlFreig_akt"
209+
LUX_SENSOR_COOLING_START_DELAY: Final = "parameters.ID_Einst_Kuhl_Zeit_Ein_akt"
210+
LUX_SENSOR_COOLING_STOP_DELAY: Final = "parameters.ID_Einst_Kuhl_Zeit_Aus_akt"
211+
LUX_SENSOR_COOLING_TARGET: Final = "parameters.ID_Sollwert_KuCft2_akt"
212+
LUX_SENSOR_MODE_COOLING: Final = "parameters.ID_Einst_BA_Kuehl_akt"
207213
# Future use:
208214
# LUX_SENSOR_MODE_COOLING: Final = 'parameters.ID_Einst_BA_Kuehl_akt'
209215

@@ -295,6 +301,14 @@ class LuxMode(Enum):
295301
# unit_of_measurement=TEMP_CELSIUS,
296302
sensor_key="calculations.ID_WEB_Temperatur_TA",
297303
),
304+
LuxtronikSensorEntityDescription(
305+
key="indoor_RBE_temperature",
306+
# name=f"{text_outdoor} {text_temp}",
307+
device_class=DEVICE_CLASS_TEMPERATURE,
308+
state_class=STATE_CLASS_MEASUREMENT,
309+
# unit_of_measurement=TEMP_CELSIUS,
310+
sensor_key="calculations.ID_WEB_RBE_RT_Ist",
311+
),
298312
LuxtronikSensorEntityDescription(
299313
key="outdoor_temperature_average",
300314
# name=f"{text_average} {text_outdoor} {text_temp}",

custom_components/luxtronik/number.py

+40-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
STATE_CLASS_MEASUREMENT)
99
from homeassistant.config_entries import ConfigEntry
1010
from homeassistant.const import (DEVICE_CLASS_TEMPERATURE, ENTITY_CATEGORIES,
11-
TEMP_CELSIUS)
11+
TEMP_CELSIUS,
12+
TIME_HOURS)
1213
from homeassistant.core import HomeAssistant
1314
from homeassistant.helpers.entity import DeviceInfo, EntityCategory
1415
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@@ -18,6 +19,9 @@
1819
from . import LuxtronikDevice
1920
from .const import (CONF_LANGUAGE_SENSOR_NAMES, DOMAIN, LOGGER,
2021
LUX_SENSOR_COOLING_THRESHOLD,
22+
LUX_SENSOR_COOLING_START_DELAY,
23+
LUX_SENSOR_COOLING_STOP_DELAY,
24+
LUX_SENSOR_COOLING_TARGET,
2125
LUX_SENSOR_DOMESTIC_WATER_TARGET_TEMPERATURE,
2226
LUX_SENSOR_HEATING_MIN_FLOW_OUT_TEMPERATURE,
2327
LUX_SENSOR_HEATING_TEMPERATURE_CORRECTION,
@@ -87,17 +91,48 @@ async def async_setup_entry(
8791
hass, luxtronik, deviceInfoDomesticWater,
8892
number_key=LUX_SENSOR_DOMESTIC_WATER_TARGET_TEMPERATURE,
8993
unique_id='domestic_water_target_temperature', name=f"{text_domestic_water} {text_target} {text_temp}",
90-
icon='mdi:water-boiler', unit_of_measurement=TEMP_CELSIUS, min_value=40.0, max_value=60.0, step=2.5, mode=MODE_BOX)
94+
icon='mdi:water-boiler', unit_of_measurement=TEMP_CELSIUS, min_value=40.0, max_value=60.0, step=1.0, mode=MODE_BOX)
9195
]
9296

9397
deviceInfoCooling = hass.data[f"{DOMAIN}_DeviceInfo_Cooling"]
9498
if deviceInfoCooling is not None:
9599
text_cooling_threshold_temperature = get_sensor_text(
96100
lang, 'cooling_threshold_temperature')
101+
text_cooling_start_delay_hours = get_sensor_text(
102+
lang, 'cooling_start_delay_hours')
103+
text_cooling_stop_delay_hours = get_sensor_text(
104+
lang, 'cooling_stop_delay_hours')
105+
text_cooling_target_temperature = get_sensor_text(
106+
lang, 'cooling_target_temperature')
97107
entities += [
98-
LuxtronikNumber(hass, luxtronik, deviceInfoCooling, number_key=LUX_SENSOR_COOLING_THRESHOLD,
99-
unique_id='cooling_threshold_temperature', name=f"{text_cooling_threshold_temperature}",
100-
icon='mdi:upload-outline', unit_of_measurement=TEMP_CELSIUS, min_value=18.0, max_value=30.0, step=0.5, mode=MODE_BOX)
108+
LuxtronikNumber(hass, luxtronik, deviceInfoCooling,
109+
number_key=LUX_SENSOR_COOLING_THRESHOLD,
110+
unique_id='cooling_threshold_temperature',
111+
name=f"{text_cooling_threshold_temperature}",
112+
icon='mdi:sun-thermometer',
113+
unit_of_measurement=TEMP_CELSIUS,
114+
min_value=18.0, max_value=30.0, step=0.5, mode=MODE_BOX),
115+
LuxtronikNumber(hass, luxtronik, deviceInfoCooling,
116+
number_key=LUX_SENSOR_COOLING_TARGET,
117+
unique_id='cooling_target_temperature',
118+
name=f"{text_cooling_target_temperature}",
119+
icon='mdi:snowflake-thermometer',
120+
unit_of_measurement=TEMP_CELSIUS,
121+
min_value=18.0, max_value=25.0, step=1.0, mode=MODE_BOX),
122+
LuxtronikNumber(hass, luxtronik, deviceInfoCooling,
123+
number_key=LUX_SENSOR_COOLING_START_DELAY,
124+
unique_id='cooling_start_delay_hours',
125+
name=f"{text_cooling_start_delay_hours}",
126+
icon='mdi:clock-start',
127+
unit_of_measurement=TIME_HOURS,
128+
min_value=0.0, max_value=12.0, step=0.5, mode=MODE_BOX),
129+
LuxtronikNumber(hass, luxtronik, deviceInfoCooling,
130+
number_key=LUX_SENSOR_COOLING_STOP_DELAY,
131+
unique_id='cooling_stop_delay_hours',
132+
name=f"{text_cooling_stop_delay_hours}",
133+
icon='mdi:clock-end',
134+
unit_of_measurement=TIME_HOURS,
135+
min_value=0.0, max_value=12.0, step=0.5, mode=MODE_BOX),
101136
]
102137

103138
async_add_entities(entities)

custom_components/luxtronik/sensor.py

+31-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
LUX_STATUS3_WORKAROUND,
5353
LUX_STATUS_HEATING,
5454
LUX_STATUS_NO_REQUEST,
55+
LUX_STATUS_THERMAL_DESINFECTION,
5556
PLATFORMS,
5657
SECOUND_TO_HOUR_FACTOR,
5758
UNITS,
@@ -161,6 +162,7 @@ async def async_setup_entry(
161162
text_time = get_sensor_text(lang, "time")
162163
text_temp = get_sensor_text(lang, "temperature")
163164
text_external = get_sensor_text(lang, "external")
165+
text_pump = get_sensor_text(lang, "pump")
164166
text_heat_source_output = get_sensor_text(lang, "heat_source_output")
165167
text_heat_source_input = get_sensor_text(lang, "heat_source_input")
166168
text_outdoor = get_sensor_text(lang, "outdoor")
@@ -322,16 +324,37 @@ async def async_setup_entry(
322324
unit_of_measurement=ENERGY_KILO_WATT_HOUR,
323325
entity_category=EntityCategory.DIAGNOSTIC,
324326
),
327+
LuxtronikSensor(
328+
hass,
329+
luxtronik,
330+
device_info,
331+
"calculations.ID_WEB_Freq_VD",
332+
"pump frequency",
333+
f"{text_pump} Frequency",
334+
entity_category=None,
335+
icon="mdi:sine-wave",
336+
unit_of_measurement='Hz'
337+
),
325338
]
326339

327340
device_info_heating = hass.data[f"{DOMAIN}_DeviceInfo_Heating"]
328341
if device_info_heating is not None:
329342
text_flow_in = get_sensor_text(lang, "flow_in")
330343
text_flow_out = get_sensor_text(lang, "flow_out")
344+
text_room = get_sensor_text(lang, "room")
331345
text_target = get_sensor_text(lang, "target")
332346
text_operation_hours_heating = get_sensor_text(lang, "operation_hours_heating")
333347
text_heat_amount_heating = get_sensor_text(lang, "heat_amount_heating")
334348
entities += [
349+
LuxtronikSensor(
350+
hass,
351+
luxtronik,
352+
device_info_heating,
353+
"calculations.ID_WEB_RBE_RT_Ist",
354+
"room_temperature",
355+
f"{text_room} {text_temp}",
356+
entity_category=None,
357+
),
335358
LuxtronikSensor(
336359
hass,
337360
luxtronik,
@@ -585,15 +608,22 @@ def native_value(self): # -> float | int | None:
585608
"""Return the state of the sensor."""
586609
value = self._luxtronik.get_value(self._sensor_key)
587610

611+
if self._sensor_key == LUX_SENSOR_STATUS:
612+
status3 = self._luxtronik.get_value(LUX_SENSOR_STATUS3)
613+
if status3 == LUX_STATUS_THERMAL_DESINFECTION:
614+
# map thermal desinfection to Domestic Water iso Heating
615+
return LUX_STATUS_DOMESTIC_WATER
616+
588617
# region Workaround Luxtronik Bug: Status shows heating but status 3 = no request!
589618
if self._sensor_key == LUX_SENSOR_STATUS and value == LUX_STATUS_HEATING:
590619
status1 = self._luxtronik.get_value(LUX_SENSOR_STATUS1)
591620
status3 = self._luxtronik.get_value(LUX_SENSOR_STATUS3)
592621
if status1 in LUX_STATUS1_WORKAROUND and status3 in LUX_STATUS3_WORKAROUND:
593622
# pump forerun
594623
return LUX_STATUS_NO_REQUEST
595-
# endregion Workaround Luxtronik Bug: Status shows heating but status 3 = no request!
624+
# endregion Workaround Luxtronik Bug: Status shows heating but status 3 = no request!
596625

626+
597627
return value if self._factor is None else round(value * self._factor, 2)
598628

599629
@property

custom_components/luxtronik/switch.py

+18-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
from . import LuxtronikDevice
1414
from .binary_sensor import LuxtronikBinarySensor
1515
from .const import (CONF_LANGUAGE_SENSOR_NAMES, DOMAIN, LOGGER,
16-
LUX_SENSOR_MODE_DOMESTIC_WATER, LUX_SENSOR_MODE_HEATING,
16+
LUX_SENSOR_MODE_DOMESTIC_WATER,
17+
LUX_SENSOR_MODE_HEATING,
18+
LUX_SENSOR_MODE_COOLING,
1719
LuxMode, LUX_SENSOR_HEATING_THRESHOLD, LUX_SENSOR_REMOTE_MAINTENANCE)
1820
from .helpers.helper import get_sensor_text
1921

@@ -85,6 +87,21 @@ async def async_setup_entry(
8587
name=text_domestic_water_mode_auto, icon='mdi:water-boiler',
8688
device_class=DEVICE_CLASS_HEAT)
8789
]
90+
91+
deviceInfoCooling = hass.data[f"{DOMAIN}_DeviceInfo_Cooling"]
92+
if deviceInfoCooling is not None:
93+
text_cooling_mode_auto = get_sensor_text(
94+
lang, 'cooling_mode_auto')
95+
entities += [
96+
LuxtronikSwitch(
97+
on_state=LuxMode.automatic.value, off_state=LuxMode.off.value,
98+
hass=hass, luxtronik=luxtronik,
99+
deviceInfo=deviceInfoCooling,
100+
sensor_key=LUX_SENSOR_MODE_COOLING,
101+
unique_id='cooling',
102+
name=text_cooling_mode_auto, icon='mdi:snowflake',
103+
device_class=DEVICE_CLASS_HEAT)
104+
]
88105

89106
async_add_entities(entities)
90107
# endregion Setup

custom_components/luxtronik/translations/sensor.de.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
},
2323
"luxtronik2__status_line_2": {
2424
"since": "seit",
25-
"in": "in"
25+
"in": "in",
26+
"unknown": "Unbekannt"
2627
},
2728
"luxtronik2__status_line_3": {
2829
"heating": "heizt",

custom_components/luxtronik/translations/sensor.en.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
},
2323
"luxtronik2__status_line_2": {
2424
"since": "since",
25-
"in": "in"
25+
"in": "in",
26+
"unknown": "unknown"
2627
},
2728
"luxtronik2__status_line_3": {
2829
"heating": "heating",

0 commit comments

Comments
 (0)