Skip to content

Commit

Permalink
* Optimize socket reconnect
Browse files Browse the repository at this point in the history
* Remove to many log messages
* Code cleanup
* Improvements
  • Loading branch information
BenPru committed Oct 30, 2023
1 parent 3c40dca commit c81bc1d
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 56 deletions.
13 changes: 8 additions & 5 deletions custom_components/luxtronik/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ async def async_setup_entry(
await coordinator.async_config_entry_first_refresh()

async_add_entities(
LuxtronikBinarySensorEntity(
hass, entry, coordinator, description, description.device_key
)
for description in BINARY_SENSORS
if coordinator.entity_active(description)
(
LuxtronikBinarySensorEntity(
hass, entry, coordinator, description, description.device_key
)
for description in BINARY_SENSORS
if coordinator.entity_active(description)
),
True,
)


Expand Down
33 changes: 21 additions & 12 deletions custom_components/luxtronik/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,12 @@ async def async_setup_entry(
await coordinator.async_config_entry_first_refresh()

async_add_entities(
LuxtronikThermostat(hass, entry, coordinator, description)
for description in THERMOSTATS
if coordinator.entity_active(description)
(
LuxtronikThermostat(hass, entry, coordinator, description)
for description in THERMOSTATS
if coordinator.entity_active(description)
),
True,
)


Expand All @@ -179,6 +182,7 @@ def as_dict(self) -> dict[str, Any]:
class LuxtronikThermostat(LuxtronikEntity, ClimateEntity, RestoreEntity):
"""The thermostat class for Luxtronik thermostats."""

# region Attributes
entity_description: LuxtronikClimateDescription

_last_hvac_mode_before_preset: str | None = None
Expand All @@ -194,6 +198,7 @@ class LuxtronikThermostat(LuxtronikEntity, ClimateEntity, RestoreEntity):
_attr_preset_mode: str | None = None

_attr_current_lux_operation = LuxOperationMode.no_request
# endregion Attributes

def __init__(
self,
Expand Down Expand Up @@ -265,11 +270,11 @@ def _handle_coordinator_update(
correction_factor = get_sensor_data(
data, self.entity_description.luxtronik_key_correction_factor.value, False
)
#LOGGER.info(f"self._attr_target_temperature={self._attr_target_temperature}")
#LOGGER.info(f"self._attr_current_temperature={self._attr_current_temperature}")
#LOGGER.info(f"correction_factor={correction_factor}")
#LOGGER.info(f"lux_action={lux_action}")
#LOGGER.info(f"_attr_hvac_action={self._attr_hvac_action}")
# LOGGER.info(f"self._attr_target_temperature={self._attr_target_temperature}")
# LOGGER.info(f"self._attr_current_temperature={self._attr_current_temperature}")
# LOGGER.info(f"correction_factor={correction_factor}")
# LOGGER.info(f"lux_action={lux_action}")
# LOGGER.info(f"_attr_hvac_action={self._attr_hvac_action}")
if (
self._attr_target_temperature is not None
and self._attr_current_temperature is not None # noqa: W503
Expand All @@ -284,10 +289,10 @@ def _handle_coordinator_update(
self.entity_description.luxtronik_key_correction_target.value
)
correction_current = get_sensor_data(data, key_correction_target)
#LOGGER.info(f"correction_current={correction_current}")
#LOGGER.info(f"correction={correction}")
# LOGGER.info(f"correction_current={correction_current}")
# LOGGER.info(f"correction={correction}")
if correction_current is None or correction_current != correction:
#LOGGER.info(f'key_correction_target={key_correction_target.split(".")[1]}')
# LOGGER.info(f'key_correction_target={key_correction_target.split(".")[1]}')
_ = self.coordinator.write(
key_correction_target.split(".")[1], correction
) # mypy: allow-unused-coroutine
Expand All @@ -307,6 +312,7 @@ async def async_set_temperature(self, **kwargs: Any) -> None:

async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
"""Set new target hvac mode."""
self._attr_hvac_mode = hvac_mode
lux_mode = [
k
for k, v in self.entity_description.hvac_mode_mapping.items()
Expand All @@ -316,7 +322,8 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:

async def async_set_preset_mode(self, preset_mode: str) -> None:
"""Set new preset mode."""
if preset_mode == PRESET_COMFORT:
self._attr_preset_mode = preset_mode
if preset_mode in [PRESET_COMFORT]:
lux_mode = LuxMode.automatic
elif preset_mode != PRESET_NONE:
lux_mode = [k for k, v in HVAC_PRESET_MAPPING.items() if v == preset_mode][
Expand All @@ -333,12 +340,14 @@ async def async_set_preset_mode(self, preset_mode: str) -> None:

async def async_turn_aux_heat_on(self) -> None:
"""Turn auxiliary heater on."""
self._attr_is_aux_heat = True
if self._last_hvac_mode_before_preset is None:
self._last_hvac_mode_before_preset = self._attr_hvac_mode
await self._async_set_lux_mode(LuxMode.second_heatsource.value)

async def async_turn_aux_heat_off(self) -> None:
"""Turn auxiliary heater off."""
self._attr_is_aux_heat = False
if (self._last_hvac_mode_before_preset is None) or (
not self._last_hvac_mode_before_preset in HVAC_PRESET_MAPPING
):
Expand Down
4 changes: 3 additions & 1 deletion custom_components/luxtronik/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
def get_sensor_data(
sensors: LuxtronikCoordinatorData,
luxtronik_key: str | LP | LC | LV,
warn_unset = True,
warn_unset=True,
) -> Any:
"""Get sensor data."""
if luxtronik_key is None or "." not in luxtronik_key:
Expand All @@ -39,6 +39,8 @@ def get_sensor_data(
"Function get_sensor_data luxtronik_key %s is None", luxtronik_key
)
return None
elif "{" in luxtronik_key:
return None
key = luxtronik_key.split(".")
group: str = key[0]
sensor_id: str = key[1]
Expand Down
10 changes: 4 additions & 6 deletions custom_components/luxtronik/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ async def _async_has_devices(hass: HomeAssistant) -> bool:
class LuxtronikFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a Luxtronik heatpump controller config flow."""

VERSION = 5
VERSION = 7
_hassio_discovery = None
_discovery_host = None
_discovery_port = None
Expand Down Expand Up @@ -307,7 +307,7 @@ def async_get_options_flow(
return LuxtronikOptionsFlowHandler(config_entry)


class LuxtronikOptionsFlowHandler(config_entries.OptionsFlow):
class LuxtronikOptionsFlowHandler(config_entries.OptionsFlowWithConfigEntry):
"""Handle a Luxtronik options flow."""

_sensor_prefix = DOMAIN
Expand All @@ -318,9 +318,7 @@ def __init__(self, config_entry):

def _get_value(self, key: str, default=None):
"""Return a value from Luxtronik."""
return self.config_entry.options.get(
key, self.config_entry.data.get(key, default)
)
return self.options.get(key, self.config_entry.data.get(key, default))

# def _get_options_schema(self):
# """Return a schema for Luxtronik configuration options."""
Expand Down Expand Up @@ -354,7 +352,7 @@ async def async_step_user(self, user_input=None) -> FlowResult:
self.hass.config_entries.async_update_entry(
self.config_entry,
data=self.config_entry.data | user_input,
options=self.config_entry.options,
options=self.options,
)
# Store empty options because we have store it in data:
return self.async_create_entry(title="", data={})
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 @@ -6,7 +6,7 @@
import logging
from typing import Final

from homeassistant.backports.enum import StrEnum
from enum import StrEnum
from homeassistant.const import Platform
from homeassistant.helpers.typing import StateType

Expand Down
25 changes: 24 additions & 1 deletion custom_components/luxtronik/lux_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,13 @@ def get_manufacturer_firmware_url_by_model(model: str) -> str:


def _is_socket_closed(sock: socket.socket) -> bool:
try:
if sock.fileno() < 0:
return True
except Exception as err: # pylint: disable=broad-except
LOGGER.exception(
"Unexpected exception when checking if a socket is closed", exc_info=err
)
try:
# this will try to read bytes without blocking and also without removing them from buffer (peek only)
last_timeout = sock.gettimeout()
Expand Down Expand Up @@ -189,6 +196,9 @@ def __init__(

def __del__(self):
"""Luxtronik helper descructor."""
self._disconnect()

def _disconnect(self):
if self._socket is not None:
if not _is_socket_closed(self._socket):
self._socket.close()
Expand All @@ -215,7 +225,17 @@ def _read_write(self, write=False):
socket.SOCK_STREAM,
)
if is_none or _is_socket_closed(self._socket):
self._socket.connect((self._host, self._port))
try:
self._socket.connect((self._host, self._port))
except OSError as err:
if err.errno == 9: # Bad file descr.
self._disconnect()
return
elif err.errno == 106:
self._socket.close()
self._socket.connect((self._host, self._port))
else:
raise err
self._socket.settimeout(self._socket_timeout)
LOGGER.info(
"Connected to Luxtronik heatpump %s:%s with timeout %ss",
Expand Down Expand Up @@ -312,6 +332,9 @@ def _read_visibilities(self):
self._max_data_length,
)
return
elif length <= 0:
# Force reconnect for the next readout
self._disconnect()
LOGGER.debug("Length %s", length)
for _ in range(0, length):
try:
Expand Down
2 changes: 1 addition & 1 deletion custom_components/luxtronik/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"after_dependencies": [],
"codeowners": ["@BenPru"],
"iot_class": "local_polling",
"version": "2023.10.29",
"version": "2023.10.30",
"homeassistant": "2023.1.0",
"dhcp": [
{ "macaddress": "000E8C*" },
Expand Down
13 changes: 8 additions & 5 deletions custom_components/luxtronik/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,14 @@ async def async_setup_entry(
await coordinator.async_config_entry_first_refresh()

async_add_entities(
LuxtronikNumberEntity(
hass, entry, coordinator, description, description.device_key
)
for description in NUMBER_SENSORS
if coordinator.entity_active(description)
(
LuxtronikNumberEntity(
hass, entry, coordinator, description, description.device_key
)
for description in NUMBER_SENSORS
if coordinator.entity_active(description)
),
True,
)


Expand Down
39 changes: 24 additions & 15 deletions custom_components/luxtronik/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,36 @@ async def async_setup_entry(
await coordinator.async_config_entry_first_refresh()

async_add_entities(
LuxtronikSensorEntity(
hass, entry, coordinator, description, description.device_key
)
for description in SENSORS
if coordinator.entity_active(description)
(
LuxtronikSensorEntity(
hass, entry, coordinator, description, description.device_key
)
for description in SENSORS
if coordinator.entity_active(description)
),
True,
)

async_add_entities(
LuxtronikStatusSensorEntity(
hass, entry, coordinator, description, description.device_key
)
for description in SENSORS_STATUS
if coordinator.entity_active(description)
(
LuxtronikStatusSensorEntity(
hass, entry, coordinator, description, description.device_key
)
for description in SENSORS_STATUS
if coordinator.entity_active(description)
),
True,
)

async_add_entities(
LuxtronikIndexSensor(
hass, entry, coordinator, description, description.device_key
)
for description in SENSORS_INDEX
if coordinator.entity_active(description)
(
LuxtronikIndexSensor(
hass, entry, coordinator, description, description.device_key
)
for description in SENSORS_INDEX
if coordinator.entity_active(description)
),
True,
)


Expand Down
13 changes: 8 additions & 5 deletions custom_components/luxtronik/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ async def async_setup_entry(
await coordinator.async_config_entry_first_refresh()

async_add_entities(
LuxtronikSwitchEntity(
hass, entry, coordinator, description, description.device_key
)
for description in SWITCHES
if coordinator.entity_active(description)
(
LuxtronikSwitchEntity(
hass, entry, coordinator, description, description.device_key
)
for description in SWITCHES
if coordinator.entity_active(description)
),
True,
)


Expand Down
2 changes: 1 addition & 1 deletion custom_components/luxtronik/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ async def async_setup_entry(
)
entities = [update_entity]

async_add_entities(entities)
async_add_entities(entities, True)


class LuxtronikUpdateEntity(LuxtronikEntity, UpdateEntity):
Expand Down
9 changes: 6 additions & 3 deletions custom_components/luxtronik/water_heater.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,12 @@ async def async_setup_entry(
await coordinator.async_config_entry_first_refresh()

async_add_entities(
LuxtronikWaterHeater(hass, config_entry, coordinator, description)
for description in WATER_HEATERS
if coordinator.entity_active(description)
(
LuxtronikWaterHeater(hass, config_entry, coordinator, description)
for description in WATER_HEATERS
if coordinator.entity_active(description)
),
True,
)


Expand Down

0 comments on commit c81bc1d

Please sign in to comment.