mirror of
https://github.com/home-assistant/core.git
synced 2026-09-24 23:41:48 -05:00
Bump python-duco-connectivity to 0.14.0 (#180964)
This commit is contained in:
@@ -10,7 +10,6 @@ from duco_connectivity.exceptions import (
|
||||
DucoConnectionError,
|
||||
DucoError,
|
||||
DucoResponseError,
|
||||
DucoUnsupportedCapabilityError,
|
||||
)
|
||||
from duco_connectivity.models import (
|
||||
BoardInfo,
|
||||
@@ -53,8 +52,6 @@ class DucoCoordinator(DataUpdateCoordinator[DucoData]):
|
||||
config_entry: DucoConfigEntry
|
||||
board_info: BoardInfo
|
||||
_supports_time_filter_remain: bool
|
||||
_supports_ventilation_temperatures: bool
|
||||
_supports_bypass_supply_temperature_targets: bool
|
||||
_configured_node_names: dict[int, str]
|
||||
|
||||
def __init__(
|
||||
@@ -74,8 +71,6 @@ class DucoCoordinator(DataUpdateCoordinator[DucoData]):
|
||||
self.client = client
|
||||
self._configured_node_names = {}
|
||||
self._supports_time_filter_remain = True
|
||||
self._supports_ventilation_temperatures = True
|
||||
self._supports_bypass_supply_temperature_targets = True
|
||||
|
||||
async def _async_load_node_names(self) -> None:
|
||||
"""Load configured Duco node names during setup."""
|
||||
@@ -193,38 +188,28 @@ class DucoCoordinator(DataUpdateCoordinator[DucoData]):
|
||||
ventilation_temperatures = (
|
||||
self.data.ventilation_temperatures if self.data else None
|
||||
)
|
||||
if self._supports_ventilation_temperatures:
|
||||
try:
|
||||
ventilation_temperatures = (
|
||||
await self.client.async_get_ventilation_temperature_info()
|
||||
)
|
||||
except DucoUnsupportedCapabilityError:
|
||||
ventilation_temperatures = None
|
||||
self._supports_ventilation_temperatures = False
|
||||
except DucoError as err:
|
||||
_LOGGER.debug(
|
||||
"Could not fetch Duco ventilation temperatures", exc_info=err
|
||||
)
|
||||
try:
|
||||
ventilation_temperatures = (
|
||||
await self.client.async_get_ventilation_temperature_info()
|
||||
)
|
||||
except DucoError as err:
|
||||
_LOGGER.debug("Could not fetch Duco ventilation temperatures", exc_info=err)
|
||||
|
||||
bypass_supply_temperature_targets: dict[int, BypassSupplyTemperatureTarget] = {}
|
||||
if self._supports_bypass_supply_temperature_targets:
|
||||
try:
|
||||
bypass_supply_temperature_targets = (
|
||||
await self.client.async_get_bypass_supply_temperature_targets()
|
||||
)
|
||||
except DucoUnsupportedCapabilityError:
|
||||
bypass_supply_temperature_targets = {}
|
||||
self._supports_bypass_supply_temperature_targets = False
|
||||
except DucoConnectionError as err:
|
||||
raise UpdateFailed(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="cannot_connect",
|
||||
) from err
|
||||
except DucoError as err:
|
||||
raise UpdateFailed(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="api_error",
|
||||
) from err
|
||||
try:
|
||||
bypass_supply_temperature_targets = (
|
||||
await self.client.async_get_bypass_supply_temperature_targets()
|
||||
)
|
||||
except DucoConnectionError as err:
|
||||
raise UpdateFailed(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="cannot_connect",
|
||||
) from err
|
||||
except DucoError as err:
|
||||
raise UpdateFailed(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="api_error",
|
||||
) from err
|
||||
|
||||
return DucoData(
|
||||
nodes={node.node_id: node for node in nodes},
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["duco_connectivity"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["python-duco-connectivity==0.13.1"],
|
||||
"requirements": ["python-duco-connectivity==0.14.0"],
|
||||
"zeroconf": [
|
||||
{
|
||||
"name": "duco [[][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][]].*",
|
||||
|
||||
@@ -56,14 +56,6 @@ async def async_setup_entry(
|
||||
if (description.key, zone_id) in known_entities:
|
||||
continue
|
||||
|
||||
# Skip incomplete metadata because guessing valid limits would expose an invalid control.
|
||||
if (
|
||||
target.minimum is None
|
||||
or target.maximum is None
|
||||
or target.increment is None
|
||||
):
|
||||
continue
|
||||
|
||||
known_entities.add((description.key, zone_id))
|
||||
new_entities.append(
|
||||
DucoBypassSupplyTemperatureTargetNumber(
|
||||
|
||||
Generated
+1
-1
@@ -2702,7 +2702,7 @@ python-digitalocean==1.13.2
|
||||
python-dropbox-api==0.1.4
|
||||
|
||||
# homeassistant.components.duco
|
||||
python-duco-connectivity==0.13.1
|
||||
python-duco-connectivity==0.14.0
|
||||
|
||||
# homeassistant.components.ecobee
|
||||
python-ecobee-api==0.4.1
|
||||
|
||||
@@ -13,7 +13,6 @@ from duco_connectivity import (
|
||||
DucoConnectionError,
|
||||
DucoError,
|
||||
DucoResponseError,
|
||||
DucoUnsupportedCapabilityError,
|
||||
LanInfo,
|
||||
Node,
|
||||
NodeListActionItemList,
|
||||
@@ -268,20 +267,18 @@ async def test_setup_entry_retries_on_bypass_temperature_failure(
|
||||
assert mock_config_entry.error_reason_translation_placeholders is None
|
||||
|
||||
|
||||
async def test_unsupported_bypass_temperature_capability_is_not_repolled(
|
||||
async def test_empty_bypass_temperature_targets_are_retried(
|
||||
hass: HomeAssistant,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
mock_bypass_supply_temperature_targets: dict[int, BypassSupplyTemperatureTarget],
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_duco_client: AsyncMock,
|
||||
) -> None:
|
||||
"""Test an unsupported bulk bypass target endpoint is not polled again."""
|
||||
mock_duco_client.async_get_bypass_supply_temperature_targets.side_effect = (
|
||||
DucoUnsupportedCapabilityError(
|
||||
400,
|
||||
"/config",
|
||||
'{"Code":3,"Result":"FAILED"}',
|
||||
)
|
||||
)
|
||||
"""Test empty bypass targets are retried and can later create entities."""
|
||||
mock_duco_client.async_get_bypass_supply_temperature_targets.side_effect = [
|
||||
{},
|
||||
mock_bypass_supply_temperature_targets.copy(),
|
||||
]
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
@@ -296,7 +293,9 @@ async def test_unsupported_bypass_temperature_capability_is_not_repolled(
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
mock_duco_client.async_get_bypass_supply_temperature_targets.assert_awaited_once_with()
|
||||
assert mock_duco_client.async_get_bypass_supply_temperature_targets.await_count == 2
|
||||
assert hass.states.get("number.living_bypass_target_1") is not None
|
||||
assert hass.states.get("number.living_bypass_target_2") is not None
|
||||
|
||||
|
||||
async def test_missing_bypass_temperature_targets_are_retried(
|
||||
|
||||
@@ -92,32 +92,6 @@ async def test_bypass_supply_temperature_targets_missing_skips_number_creation(
|
||||
assert hass.states.get(_ZONE_2_ENTITY_ID) is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"field",
|
||||
[
|
||||
pytest.param("minimum", id="missing_minimum"),
|
||||
pytest.param("maximum", id="missing_maximum"),
|
||||
pytest.param("increment", id="missing_increment"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("mock_duco_client")
|
||||
async def test_bypass_supply_temperature_target_incomplete_metadata_skips_number_creation(
|
||||
hass: HomeAssistant,
|
||||
mock_bypass_supply_temperature_targets: dict[int, BypassSupplyTemperatureTarget],
|
||||
mock_config_entry: MockConfigEntry,
|
||||
field: str,
|
||||
) -> None:
|
||||
"""Test incomplete target metadata does not expose an invalid control."""
|
||||
mock_bypass_supply_temperature_targets[1] = replace(
|
||||
mock_bypass_supply_temperature_targets[1], **{field: None}
|
||||
)
|
||||
|
||||
await setup_platform_integration(hass, mock_config_entry, [Platform.NUMBER])
|
||||
|
||||
assert hass.states.get(_ZONE_1_ENTITY_ID) is None
|
||||
assert hass.states.get(_ZONE_2_ENTITY_ID) is not None
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("init_integration")
|
||||
async def test_set_bypass_supply_temperature_target(
|
||||
hass: HomeAssistant,
|
||||
|
||||
@@ -7,7 +7,6 @@ from unittest.mock import AsyncMock
|
||||
from duco_connectivity import (
|
||||
DucoConnectionError,
|
||||
DucoError,
|
||||
DucoUnsupportedCapabilityError,
|
||||
Node,
|
||||
NodeGeneralInfo,
|
||||
NodeSensorInfo,
|
||||
@@ -277,15 +276,15 @@ async def test_time_filter_remaining_missing_skips_sensor_creation(
|
||||
assert hass.states.get(FILTER_REMAINING_ENTITY_ID) is None
|
||||
|
||||
|
||||
async def test_ventilation_temperatures_missing_skip_sensor_creation(
|
||||
async def test_empty_ventilation_temperatures_are_retried(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_duco_client: AsyncMock,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test unsupported ventilation temperatures never expose temperature states."""
|
||||
"""Test empty ventilation temperatures are retried and can appear later."""
|
||||
mock_duco_client.async_get_ventilation_temperature_info.side_effect = [
|
||||
DucoUnsupportedCapabilityError(400, "/info", '{"Code":3,"Result":"FAILED"}'),
|
||||
VentilationTemperatureInfo(),
|
||||
VentilationTemperatureInfo(temp_oda=5.5),
|
||||
]
|
||||
|
||||
@@ -298,8 +297,10 @@ async def test_ventilation_temperatures_missing_skip_sensor_creation(
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
for entity_id in VENTILATION_TEMPERATURE_ENTITY_IDS:
|
||||
assert hass.states.get(entity_id) is None
|
||||
assert mock_duco_client.async_get_ventilation_temperature_info.await_count == 2
|
||||
state = hass.states.get("sensor.living_outdoor_air_temperature")
|
||||
assert state is not None
|
||||
assert state.state == "5.5"
|
||||
|
||||
|
||||
async def test_partial_ventilation_temperatures_only_expose_available_sensor_values(
|
||||
|
||||
Reference in New Issue
Block a user