commit
394dafd980
|
@ -10,7 +10,7 @@ on:
|
|||
|
||||
env:
|
||||
BUILD_TYPE: core
|
||||
DEFAULT_PYTHON: "3.12"
|
||||
DEFAULT_PYTHON: "3.12.3"
|
||||
PIP_TIMEOUT: 60
|
||||
UV_HTTP_TIMEOUT: 60
|
||||
UV_SYSTEM_PYTHON: "true"
|
||||
|
|
|
@ -37,8 +37,8 @@ env:
|
|||
UV_CACHE_VERSION: 1
|
||||
MYPY_CACHE_VERSION: 8
|
||||
HA_SHORT_VERSION: "2024.6"
|
||||
DEFAULT_PYTHON: "3.12"
|
||||
ALL_PYTHON_VERSIONS: "['3.12']"
|
||||
DEFAULT_PYTHON: "3.12.3"
|
||||
ALL_PYTHON_VERSIONS: "['3.12.3']"
|
||||
# 10.3 is the oldest supported version
|
||||
# - 10.3.32 is the version currently shipped with Synology (as of 17 Feb 2022)
|
||||
# 10.6 is the current long-term-support
|
||||
|
|
|
@ -10,7 +10,7 @@ on:
|
|||
- "**strings.json"
|
||||
|
||||
env:
|
||||
DEFAULT_PYTHON: "3.11"
|
||||
DEFAULT_PYTHON: "3.12.3"
|
||||
|
||||
jobs:
|
||||
upload:
|
||||
|
|
|
@ -17,7 +17,7 @@ on:
|
|||
- "script/gen_requirements_all.py"
|
||||
|
||||
env:
|
||||
DEFAULT_PYTHON: "3.12"
|
||||
DEFAULT_PYTHON: "3.12.3"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name}}
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
"documentation": "https://www.home-assistant.io/integrations/buienradar",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["buienradar", "vincenty"],
|
||||
"requirements": ["buienradar==1.0.5"]
|
||||
"requirements": ["buienradar==1.0.6"]
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ class Concord232Alarm(AlarmControlPanelEntity):
|
|||
|
||||
self._attr_name = name
|
||||
self._code = code
|
||||
self._alarm_control_panel_option_default_code = code
|
||||
self._mode = mode
|
||||
self._url = url
|
||||
self._alarm = concord232_client.Client(self._url)
|
||||
|
|
|
@ -20,5 +20,5 @@
|
|||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||
"integration_type": "system",
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["home-assistant-frontend==20240610.0"]
|
||||
"requirements": ["home-assistant-frontend==20240610.1"]
|
||||
}
|
||||
|
|
|
@ -13,5 +13,6 @@
|
|||
"dependencies": ["bluetooth_adapters"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/gardena_bluetooth",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["bleak", "bleak_esphome", "gardena_bluetooth"],
|
||||
"requirements": ["gardena-bluetooth==1.4.2"]
|
||||
}
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
"documentation": "https://www.home-assistant.io/integrations/goodwe",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["goodwe"],
|
||||
"requirements": ["goodwe==0.3.5"]
|
||||
"requirements": ["goodwe==0.3.6"]
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
"after_dependencies": [
|
||||
"alarm_control_panel",
|
||||
"climate",
|
||||
"cover",
|
||||
"device_tracker",
|
||||
"lock",
|
||||
"media_player",
|
||||
"person",
|
||||
"plant",
|
||||
"vacuum",
|
||||
|
|
|
@ -9,7 +9,6 @@ from typing import TYPE_CHECKING, Any
|
|||
from icmplib import NameLookupError, async_ping
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import UpdateFailed
|
||||
|
||||
from .const import ICMP_TIMEOUT, PING_TIMEOUT
|
||||
|
||||
|
@ -59,9 +58,10 @@ class PingDataICMPLib(PingData):
|
|||
timeout=ICMP_TIMEOUT,
|
||||
privileged=self._privileged,
|
||||
)
|
||||
except NameLookupError as err:
|
||||
except NameLookupError:
|
||||
_LOGGER.debug("Error resolving host: %s", self.ip_address)
|
||||
self.is_alive = False
|
||||
raise UpdateFailed(f"Error resolving host: {self.ip_address}") from err
|
||||
return
|
||||
|
||||
_LOGGER.debug(
|
||||
"async_ping returned: reachable=%s sent=%i received=%s",
|
||||
|
@ -152,17 +152,22 @@ class PingDataSubProcess(PingData):
|
|||
if TYPE_CHECKING:
|
||||
assert match is not None
|
||||
rtt_min, rtt_avg, rtt_max, rtt_mdev = match.groups()
|
||||
except TimeoutError as err:
|
||||
except TimeoutError:
|
||||
_LOGGER.debug(
|
||||
"Timed out running command: `%s`, after: %s",
|
||||
" ".join(self._ping_cmd),
|
||||
self._count + PING_TIMEOUT,
|
||||
)
|
||||
|
||||
if pinger:
|
||||
with suppress(TypeError):
|
||||
await pinger.kill() # type: ignore[func-returns-value]
|
||||
del pinger
|
||||
|
||||
raise UpdateFailed(
|
||||
f"Timed out running command: `{self._ping_cmd}`, after: {self._count + PING_TIMEOUT}s"
|
||||
) from err
|
||||
return None
|
||||
except AttributeError as err:
|
||||
raise UpdateFailed from err
|
||||
_LOGGER.debug("Error matching ping output: %s", err)
|
||||
return None
|
||||
return {"min": rtt_min, "avg": rtt_avg, "max": rtt_max, "mdev": rtt_mdev}
|
||||
|
||||
async def async_update(self) -> None:
|
||||
|
|
|
@ -116,7 +116,6 @@ async def async_setup_entry(
|
|||
class ReolinkCamera(ReolinkChannelCoordinatorEntity, Camera):
|
||||
"""An implementation of a Reolink IP camera."""
|
||||
|
||||
_attr_supported_features: CameraEntityFeature = CameraEntityFeature.STREAM
|
||||
entity_description: ReolinkCameraEntityDescription
|
||||
|
||||
def __init__(
|
||||
|
@ -130,6 +129,9 @@ class ReolinkCamera(ReolinkChannelCoordinatorEntity, Camera):
|
|||
ReolinkChannelCoordinatorEntity.__init__(self, reolink_data, channel)
|
||||
Camera.__init__(self)
|
||||
|
||||
if "snapshots" not in entity_description.stream:
|
||||
self._attr_supported_features = CameraEntityFeature.STREAM
|
||||
|
||||
if self._host.api.model in DUAL_LENS_MODELS:
|
||||
self._attr_translation_key = (
|
||||
f"{entity_description.translation_key}_lens_{self._channel}"
|
||||
|
|
|
@ -37,7 +37,6 @@ from .const import (
|
|||
CONST_MODE_SMART_SCHEDULE,
|
||||
CONST_OVERLAY_MANUAL,
|
||||
CONST_OVERLAY_TADO_OPTIONS,
|
||||
CONST_OVERLAY_TIMER,
|
||||
DATA,
|
||||
DOMAIN,
|
||||
HA_TERMINATION_DURATION,
|
||||
|
@ -65,7 +64,7 @@ from .const import (
|
|||
TYPE_HEATING,
|
||||
)
|
||||
from .entity import TadoZoneEntity
|
||||
from .helper import decide_overlay_mode
|
||||
from .helper import decide_duration, decide_overlay_mode
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -603,14 +602,12 @@ class TadoClimate(TadoZoneEntity, ClimateEntity):
|
|||
overlay_mode=overlay_mode,
|
||||
zone_id=self.zone_id,
|
||||
)
|
||||
# If we ended up with a timer but no duration, set a default duration
|
||||
if overlay_mode == CONST_OVERLAY_TIMER and duration is None:
|
||||
duration = (
|
||||
int(self._tado_zone_data.default_overlay_termination_duration)
|
||||
if self._tado_zone_data.default_overlay_termination_duration is not None
|
||||
else 3600
|
||||
)
|
||||
|
||||
duration = decide_duration(
|
||||
tado=self._tado,
|
||||
duration=duration,
|
||||
zone_id=self.zone_id,
|
||||
overlay_mode=overlay_mode,
|
||||
)
|
||||
_LOGGER.debug(
|
||||
(
|
||||
"Switching to %s for zone %s (%d) with temperature %s °C and duration"
|
||||
|
|
|
@ -212,3 +212,5 @@ SERVICE_ADD_METER_READING = "add_meter_reading"
|
|||
CONF_CONFIG_ENTRY = "config_entry"
|
||||
CONF_READING = "reading"
|
||||
ATTR_MESSAGE = "message"
|
||||
|
||||
WATER_HEATER_FALLBACK_REPAIR = "water_heater_fallback"
|
||||
|
|
|
@ -29,3 +29,23 @@ def decide_overlay_mode(
|
|||
)
|
||||
|
||||
return overlay_mode
|
||||
|
||||
|
||||
def decide_duration(
|
||||
tado: TadoConnector,
|
||||
duration: int | None,
|
||||
zone_id: int,
|
||||
overlay_mode: str | None = None,
|
||||
) -> None | int:
|
||||
"""Return correct duration based on the selected overlay mode/duration and tado config."""
|
||||
# If we ended up with a timer but no duration, set a default duration
|
||||
# If we ended up with a timer but no duration, set a default duration
|
||||
if overlay_mode == CONST_OVERLAY_TIMER and duration is None:
|
||||
duration = (
|
||||
int(tado.data["zone"][zone_id].default_overlay_termination_duration)
|
||||
if tado.data["zone"][zone_id].default_overlay_termination_duration
|
||||
is not None
|
||||
else 3600
|
||||
)
|
||||
|
||||
return duration
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
"""Repair implementations."""
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
|
||||
from .const import (
|
||||
CONST_OVERLAY_MANUAL,
|
||||
CONST_OVERLAY_TADO_DEFAULT,
|
||||
DOMAIN,
|
||||
WATER_HEATER_FALLBACK_REPAIR,
|
||||
)
|
||||
|
||||
|
||||
def manage_water_heater_fallback_issue(
|
||||
hass: HomeAssistant,
|
||||
water_heater_entities: list,
|
||||
integration_overlay_fallback: str | None,
|
||||
) -> None:
|
||||
"""Notify users about water heater respecting fallback setting."""
|
||||
if (
|
||||
integration_overlay_fallback
|
||||
in [CONST_OVERLAY_TADO_DEFAULT, CONST_OVERLAY_MANUAL]
|
||||
and len(water_heater_entities) > 0
|
||||
):
|
||||
for water_heater_entity in water_heater_entities:
|
||||
ir.async_create_issue(
|
||||
hass=hass,
|
||||
domain=DOMAIN,
|
||||
issue_id=f"{WATER_HEATER_FALLBACK_REPAIR}_{water_heater_entity.zone_name}",
|
||||
is_fixable=False,
|
||||
is_persistent=False,
|
||||
severity=ir.IssueSeverity.WARNING,
|
||||
translation_key=WATER_HEATER_FALLBACK_REPAIR,
|
||||
)
|
|
@ -165,6 +165,10 @@
|
|||
"import_failed_invalid_auth": {
|
||||
"title": "Failed to import, invalid credentials",
|
||||
"description": "Failed to import the configuration for the Tado Device Tracker, due to invalid credentials. Please fix the YAML configuration and restart Home Assistant. Alternatively you can use the UI to configure Tado. Don't forget to delete the YAML configuration, once the import is successful."
|
||||
},
|
||||
"water_heater_fallback": {
|
||||
"title": "Tado Water Heater entities now support fallback options",
|
||||
"description": "Due to added support for water heaters entities, these entities may use different overlay. Please configure integration entity and tado app water heater zone overlay options."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@ from .const import (
|
|||
TYPE_HOT_WATER,
|
||||
)
|
||||
from .entity import TadoZoneEntity
|
||||
from .helper import decide_overlay_mode
|
||||
from .helper import decide_duration, decide_overlay_mode
|
||||
from .repairs import manage_water_heater_fallback_issue
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -80,6 +81,12 @@ async def async_setup_entry(
|
|||
|
||||
async_add_entities(entities, True)
|
||||
|
||||
manage_water_heater_fallback_issue(
|
||||
hass=hass,
|
||||
water_heater_entities=entities,
|
||||
integration_overlay_fallback=tado.fallback,
|
||||
)
|
||||
|
||||
|
||||
def _generate_entities(tado: TadoConnector) -> list[WaterHeaterEntity]:
|
||||
"""Create all water heater entities."""
|
||||
|
@ -283,7 +290,12 @@ class TadoWaterHeater(TadoZoneEntity, WaterHeaterEntity):
|
|||
duration=duration,
|
||||
zone_id=self.zone_id,
|
||||
)
|
||||
|
||||
duration = decide_duration(
|
||||
tado=self._tado,
|
||||
duration=duration,
|
||||
zone_id=self.zone_id,
|
||||
overlay_mode=overlay_mode,
|
||||
)
|
||||
_LOGGER.debug(
|
||||
"Switching to %s for zone %s (%d) with temperature %s",
|
||||
self._current_tado_hvac_mode,
|
||||
|
|
|
@ -54,6 +54,10 @@ SCAN_INTERVAL = timedelta(seconds=DEFAULT_SCAN_INTERVAL)
|
|||
|
||||
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
|
||||
|
||||
EARLY_ACCESS_URL = (
|
||||
"https://www.home-assistant.io/integrations/unifiprotect#software-support"
|
||||
)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up the UniFi Protect."""
|
||||
|
@ -122,8 +126,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
DOMAIN,
|
||||
"ea_channel_warning",
|
||||
is_fixable=True,
|
||||
is_persistent=True,
|
||||
learn_more_url="https://www.home-assistant.io/integrations/unifiprotect#about-unifi-early-access",
|
||||
is_persistent=False,
|
||||
learn_more_url=EARLY_ACCESS_URL,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="ea_channel_warning",
|
||||
translation_placeholders={"version": str(nvr_info.version)},
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
"integration_type": "hub",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["uiprotect", "unifi_discovery"],
|
||||
"requirements": ["uiprotect==0.4.1", "unifi-discovery==1.1.8"],
|
||||
"requirements": ["uiprotect==1.7.2", "unifi-discovery==1.1.8"],
|
||||
"ssdp": [
|
||||
{
|
||||
"manufacturer": "Ubiquiti Networks",
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
"all_updates": "Realtime metrics (WARNING: Greatly increases CPU usage)",
|
||||
"override_connection_host": "Override Connection Host",
|
||||
"max_media": "Max number of event to load for Media Browser (increases RAM usage)",
|
||||
"allow_ea": "Allow Early Access versions of Protect (WARNING: Will mark your integration as unsupported)"
|
||||
"allow_ea_channel": "Allow Early Access versions of Protect (WARNING: Will mark your integration as unsupported)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,7 @@
|
|||
"step": {
|
||||
"start": {
|
||||
"title": "UniFi Protect Early Access enabled",
|
||||
"description": "You are either running an Early Access version of UniFi Protect (v{version}) or opt-ed into a release channel that is not the Official Release Channel. [Home Assistant does not support Early Access versions](https://www.home-assistant.io/integrations/unifiprotect#about-unifi-early-access), so you should immediately switch to the Official Release Channel. Accidentally upgrading to an Early Access version can break your UniFi Protect integration.\n\nBy submitting this form, you have switched back to the Official Release Channel or agree to run an unsupported version of UniFi Protect, which may break your Home Assistant integration at any time."
|
||||
"description": "You are either running an Early Access version of UniFi Protect (v{version}) or opt-ed into a release channel that is not the Official Release Channel.\n\nAs these Early Access releases may not be tested yet, using it may cause the UniFi Protect integration to behave unexpectedly. [Read more about Early Access and Home Assistant]({learn_more}).\n\nSubmit to dismiss this message."
|
||||
},
|
||||
"confirm": {
|
||||
"title": "[%key:component::unifiprotect::issues::ea_channel_warning::fix_flow::step::start::title%]",
|
||||
|
|
|
@ -89,10 +89,8 @@ def async_get_devices_by_type(
|
|||
bootstrap: Bootstrap, device_type: ModelType
|
||||
) -> dict[str, ProtectAdoptableDeviceModel]:
|
||||
"""Get devices by type."""
|
||||
|
||||
devices: dict[str, ProtectAdoptableDeviceModel] = getattr(
|
||||
bootstrap, f"{device_type.value}s"
|
||||
)
|
||||
devices: dict[str, ProtectAdoptableDeviceModel]
|
||||
devices = getattr(bootstrap, device_type.devices_key)
|
||||
return devices
|
||||
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ async def _async_validate_country_and_province(
|
|||
DOMAIN,
|
||||
"bad_country",
|
||||
is_fixable=True,
|
||||
is_persistent=True,
|
||||
is_persistent=False,
|
||||
severity=IssueSeverity.ERROR,
|
||||
translation_key="bad_country",
|
||||
translation_placeholders={"title": entry.title},
|
||||
|
@ -59,7 +59,7 @@ async def _async_validate_country_and_province(
|
|||
DOMAIN,
|
||||
"bad_province",
|
||||
is_fixable=True,
|
||||
is_persistent=True,
|
||||
is_persistent=False,
|
||||
severity=IssueSeverity.ERROR,
|
||||
translation_key="bad_province",
|
||||
translation_placeholders={
|
||||
|
|
|
@ -21,11 +21,11 @@
|
|||
"universal_silabs_flasher"
|
||||
],
|
||||
"requirements": [
|
||||
"bellows==0.39.0",
|
||||
"bellows==0.39.1",
|
||||
"pyserial==3.5",
|
||||
"zha-quirks==0.0.116",
|
||||
"zigpy-deconz==0.23.1",
|
||||
"zigpy==0.64.0",
|
||||
"zigpy==0.64.1",
|
||||
"zigpy-xbee==0.20.1",
|
||||
"zigpy-zigate==0.12.0",
|
||||
"zigpy-znp==0.12.1",
|
||||
|
|
|
@ -24,7 +24,7 @@ if TYPE_CHECKING:
|
|||
APPLICATION_NAME: Final = "HomeAssistant"
|
||||
MAJOR_VERSION: Final = 2024
|
||||
MINOR_VERSION: Final = 6
|
||||
PATCH_VERSION: Final = "2"
|
||||
PATCH_VERSION: Final = "3"
|
||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 12, 0)
|
||||
|
|
|
@ -1362,6 +1362,8 @@ class IntentResponse:
|
|||
|
||||
if self.reprompt:
|
||||
response_dict["reprompt"] = self.reprompt
|
||||
if self.speech_slots:
|
||||
response_dict["speech_slots"] = self.speech_slots
|
||||
|
||||
response_data: dict[str, Any] = {}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ habluetooth==3.1.1
|
|||
hass-nabucasa==0.81.1
|
||||
hassil==1.7.1
|
||||
home-assistant-bluetooth==1.12.0
|
||||
home-assistant-frontend==20240610.0
|
||||
home-assistant-frontend==20240610.1
|
||||
home-assistant-intents==2024.6.5
|
||||
httpx==0.27.0
|
||||
ifaddr==0.2.0
|
||||
|
|
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||
|
||||
[project]
|
||||
name = "homeassistant"
|
||||
version = "2024.6.2"
|
||||
version = "2024.6.3"
|
||||
license = {text = "Apache-2.0"}
|
||||
description = "Open-source home automation platform running on Python 3."
|
||||
readme = "README.rst"
|
||||
|
|
|
@ -547,7 +547,7 @@ beautifulsoup4==4.12.3
|
|||
# beewi-smartclim==0.0.10
|
||||
|
||||
# homeassistant.components.zha
|
||||
bellows==0.39.0
|
||||
bellows==0.39.1
|
||||
|
||||
# homeassistant.components.bmw_connected_drive
|
||||
bimmer-connected[china]==0.15.3
|
||||
|
@ -634,7 +634,7 @@ bthomehub5-devicelist==0.1.1
|
|||
btsmarthub-devicelist==0.2.3
|
||||
|
||||
# homeassistant.components.buienradar
|
||||
buienradar==1.0.5
|
||||
buienradar==1.0.6
|
||||
|
||||
# homeassistant.components.dhcp
|
||||
cached_ipaddress==0.3.0
|
||||
|
@ -961,7 +961,7 @@ glances-api==0.8.0
|
|||
goalzero==0.2.2
|
||||
|
||||
# homeassistant.components.goodwe
|
||||
goodwe==0.3.5
|
||||
goodwe==0.3.6
|
||||
|
||||
# homeassistant.components.google_mail
|
||||
# homeassistant.components.google_tasks
|
||||
|
@ -1087,7 +1087,7 @@ hole==0.8.0
|
|||
holidays==0.50
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20240610.0
|
||||
home-assistant-frontend==20240610.1
|
||||
|
||||
# homeassistant.components.conversation
|
||||
home-assistant-intents==2024.6.5
|
||||
|
@ -2779,7 +2779,7 @@ twitchAPI==4.0.0
|
|||
uasiren==0.0.1
|
||||
|
||||
# homeassistant.components.unifiprotect
|
||||
uiprotect==0.4.1
|
||||
uiprotect==1.7.2
|
||||
|
||||
# homeassistant.components.landisgyr_heat_meter
|
||||
ultraheat-api==0.5.7
|
||||
|
@ -2981,7 +2981,7 @@ zigpy-zigate==0.12.0
|
|||
zigpy-znp==0.12.1
|
||||
|
||||
# homeassistant.components.zha
|
||||
zigpy==0.64.0
|
||||
zigpy==0.64.1
|
||||
|
||||
# homeassistant.components.zoneminder
|
||||
zm-py==0.5.4
|
||||
|
|
|
@ -472,7 +472,7 @@ base36==0.1.1
|
|||
beautifulsoup4==4.12.3
|
||||
|
||||
# homeassistant.components.zha
|
||||
bellows==0.39.0
|
||||
bellows==0.39.1
|
||||
|
||||
# homeassistant.components.bmw_connected_drive
|
||||
bimmer-connected[china]==0.15.3
|
||||
|
@ -536,7 +536,7 @@ brunt==1.2.0
|
|||
bthome-ble==3.8.1
|
||||
|
||||
# homeassistant.components.buienradar
|
||||
buienradar==1.0.5
|
||||
buienradar==1.0.6
|
||||
|
||||
# homeassistant.components.dhcp
|
||||
cached_ipaddress==0.3.0
|
||||
|
@ -790,7 +790,7 @@ glances-api==0.8.0
|
|||
goalzero==0.2.2
|
||||
|
||||
# homeassistant.components.goodwe
|
||||
goodwe==0.3.5
|
||||
goodwe==0.3.6
|
||||
|
||||
# homeassistant.components.google_mail
|
||||
# homeassistant.components.google_tasks
|
||||
|
@ -889,7 +889,7 @@ hole==0.8.0
|
|||
holidays==0.50
|
||||
|
||||
# homeassistant.components.frontend
|
||||
home-assistant-frontend==20240610.0
|
||||
home-assistant-frontend==20240610.1
|
||||
|
||||
# homeassistant.components.conversation
|
||||
home-assistant-intents==2024.6.5
|
||||
|
@ -2153,7 +2153,7 @@ twitchAPI==4.0.0
|
|||
uasiren==0.0.1
|
||||
|
||||
# homeassistant.components.unifiprotect
|
||||
uiprotect==0.4.1
|
||||
uiprotect==1.7.2
|
||||
|
||||
# homeassistant.components.landisgyr_heat_meter
|
||||
ultraheat-api==0.5.7
|
||||
|
@ -2322,7 +2322,7 @@ zigpy-zigate==0.12.0
|
|||
zigpy-znp==0.12.1
|
||||
|
||||
# homeassistant.components.zha
|
||||
zigpy==0.64.0
|
||||
zigpy==0.64.1
|
||||
|
||||
# homeassistant.components.zwave_js
|
||||
zwave-js-server-python==0.56.0
|
||||
|
|
|
@ -9,7 +9,7 @@ from homeassistant.components.tado.const import (
|
|||
CONST_OVERLAY_TADO_MODE,
|
||||
CONST_OVERLAY_TIMER,
|
||||
)
|
||||
from homeassistant.components.tado.helper import decide_overlay_mode
|
||||
from homeassistant.components.tado.helper import decide_duration, decide_overlay_mode
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
|
||||
|
@ -21,7 +21,7 @@ def dummy_tado_connector(hass: HomeAssistant, fallback) -> TadoConnector:
|
|||
async def test_overlay_mode_duration_set(hass: HomeAssistant) -> None:
|
||||
"""Test overlay method selection when duration is set."""
|
||||
tado = dummy_tado_connector(hass=hass, fallback=CONST_OVERLAY_TADO_MODE)
|
||||
overlay_mode = decide_overlay_mode(tado=tado, duration="01:00:00", zone_id=1)
|
||||
overlay_mode = decide_overlay_mode(tado=tado, duration=3600, zone_id=1)
|
||||
# Must select TIMER overlay
|
||||
assert overlay_mode == CONST_OVERLAY_TIMER
|
||||
|
||||
|
@ -52,3 +52,36 @@ async def test_overlay_mode_tado_default_fallback(hass: HomeAssistant) -> None:
|
|||
overlay_mode = decide_overlay_mode(tado=tado, duration=None, zone_id=zone_id)
|
||||
# Must fallback to zone setting
|
||||
assert overlay_mode == zone_fallback
|
||||
|
||||
|
||||
async def test_duration_enabled_without_tado_default(hass: HomeAssistant) -> None:
|
||||
"""Test duration decide method when overlay is timer and duration is set."""
|
||||
overlay = CONST_OVERLAY_TIMER
|
||||
expected_duration = 600
|
||||
tado = dummy_tado_connector(hass=hass, fallback=CONST_OVERLAY_MANUAL)
|
||||
duration = decide_duration(
|
||||
tado=tado, duration=expected_duration, overlay_mode=overlay, zone_id=0
|
||||
)
|
||||
# Should return the same duration value
|
||||
assert duration == expected_duration
|
||||
|
||||
|
||||
async def test_duration_enabled_with_tado_default(hass: HomeAssistant) -> None:
|
||||
"""Test overlay method selection when ended up with timer overlay and None duration."""
|
||||
zone_fallback = CONST_OVERLAY_TIMER
|
||||
expected_duration = 45000
|
||||
tado = dummy_tado_connector(hass=hass, fallback=zone_fallback)
|
||||
|
||||
class MockZoneData:
|
||||
def __init__(self) -> None:
|
||||
self.default_overlay_termination_duration = expected_duration
|
||||
|
||||
zone_id = 1
|
||||
|
||||
zone_data = {"zone": {zone_id: MockZoneData()}}
|
||||
with patch.dict(tado.data, zone_data):
|
||||
duration = decide_duration(
|
||||
tado=tado, duration=None, zone_id=zone_id, overlay_mode=zone_fallback
|
||||
)
|
||||
# Must fallback to zone timer setting
|
||||
assert duration == expected_duration
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
"""Repair tests."""
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.tado.const import (
|
||||
CONST_OVERLAY_MANUAL,
|
||||
CONST_OVERLAY_TADO_DEFAULT,
|
||||
CONST_OVERLAY_TADO_MODE,
|
||||
DOMAIN,
|
||||
WATER_HEATER_FALLBACK_REPAIR,
|
||||
)
|
||||
from homeassistant.components.tado.repairs import manage_water_heater_fallback_issue
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
|
||||
|
||||
class MockWaterHeater:
|
||||
"""Mock Water heater entity."""
|
||||
|
||||
def __init__(self, zone_name) -> None:
|
||||
"""Init mock entity class."""
|
||||
self.zone_name = zone_name
|
||||
|
||||
|
||||
async def test_manage_water_heater_fallback_issue_not_created(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
) -> None:
|
||||
"""Test water heater fallback issue is not needed."""
|
||||
zone_name = "Hot Water"
|
||||
expected_issue_id = f"{WATER_HEATER_FALLBACK_REPAIR}_{zone_name}"
|
||||
water_heater_entities = [MockWaterHeater(zone_name)]
|
||||
manage_water_heater_fallback_issue(
|
||||
water_heater_entities=water_heater_entities,
|
||||
integration_overlay_fallback=CONST_OVERLAY_TADO_MODE,
|
||||
hass=hass,
|
||||
)
|
||||
assert (
|
||||
issue_registry.async_get_issue(issue_id=expected_issue_id, domain=DOMAIN)
|
||||
is None
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"integration_overlay_fallback", [CONST_OVERLAY_TADO_DEFAULT, CONST_OVERLAY_MANUAL]
|
||||
)
|
||||
async def test_manage_water_heater_fallback_issue_created(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
integration_overlay_fallback: str,
|
||||
) -> None:
|
||||
"""Test water heater fallback issue created cases."""
|
||||
zone_name = "Hot Water"
|
||||
expected_issue_id = f"{WATER_HEATER_FALLBACK_REPAIR}_{zone_name}"
|
||||
water_heater_entities = [MockWaterHeater(zone_name)]
|
||||
manage_water_heater_fallback_issue(
|
||||
water_heater_entities=water_heater_entities,
|
||||
integration_overlay_fallback=integration_overlay_fallback,
|
||||
hass=hass,
|
||||
)
|
||||
assert (
|
||||
issue_registry.async_get_issue(issue_id=expected_issue_id, domain=DOMAIN)
|
||||
is not None
|
||||
)
|
|
@ -61,7 +61,7 @@ async def test_ea_warning_ignore(
|
|||
|
||||
flow_id = data["flow_id"]
|
||||
assert data["description_placeholders"] == {
|
||||
"learn_more": "https://www.home-assistant.io/integrations/unifiprotect#about-unifi-early-access",
|
||||
"learn_more": "https://www.home-assistant.io/integrations/unifiprotect#software-support",
|
||||
"version": str(version),
|
||||
}
|
||||
assert data["step_id"] == "start"
|
||||
|
@ -73,7 +73,7 @@ async def test_ea_warning_ignore(
|
|||
|
||||
flow_id = data["flow_id"]
|
||||
assert data["description_placeholders"] == {
|
||||
"learn_more": "https://www.home-assistant.io/integrations/unifiprotect#about-unifi-early-access",
|
||||
"learn_more": "https://www.home-assistant.io/integrations/unifiprotect#software-support",
|
||||
"version": str(version),
|
||||
}
|
||||
assert data["step_id"] == "confirm"
|
||||
|
@ -123,7 +123,7 @@ async def test_ea_warning_fix(
|
|||
|
||||
flow_id = data["flow_id"]
|
||||
assert data["description_placeholders"] == {
|
||||
"learn_more": "https://www.home-assistant.io/integrations/unifiprotect#about-unifi-early-access",
|
||||
"learn_more": "https://www.home-assistant.io/integrations/unifiprotect#software-support",
|
||||
"version": str(version),
|
||||
}
|
||||
assert data["step_id"] == "start"
|
||||
|
|
|
@ -149,8 +149,13 @@ async def test_assist_api(
|
|||
|
||||
assert test_context.json_fragment # To reproduce an error case in tracing
|
||||
intent_response = intent.IntentResponse("*")
|
||||
intent_response.matched_states = [State("light.matched", "on")]
|
||||
intent_response.unmatched_states = [State("light.unmatched", "on")]
|
||||
intent_response.async_set_states(
|
||||
[State("light.matched", "on")], [State("light.unmatched", "on")]
|
||||
)
|
||||
intent_response.async_set_speech("Some speech")
|
||||
intent_response.async_set_card("Card title", "card content")
|
||||
intent_response.async_set_speech_slots({"hello": 1})
|
||||
intent_response.async_set_reprompt("Do it again")
|
||||
tool_input = llm.ToolInput(
|
||||
tool_name="test_intent",
|
||||
tool_args={"area": "kitchen", "floor": "ground_floor"},
|
||||
|
@ -181,8 +186,22 @@ async def test_assist_api(
|
|||
"success": [],
|
||||
"targets": [],
|
||||
},
|
||||
"reprompt": {
|
||||
"plain": {
|
||||
"extra_data": None,
|
||||
"reprompt": "Do it again",
|
||||
},
|
||||
},
|
||||
"response_type": "action_done",
|
||||
"speech": {},
|
||||
"speech": {
|
||||
"plain": {
|
||||
"extra_data": None,
|
||||
"speech": "Some speech",
|
||||
},
|
||||
},
|
||||
"speech_slots": {
|
||||
"hello": 1,
|
||||
},
|
||||
}
|
||||
|
||||
# Call with a device/area/floor
|
||||
|
@ -227,7 +246,21 @@ async def test_assist_api(
|
|||
"targets": [],
|
||||
},
|
||||
"response_type": "action_done",
|
||||
"speech": {},
|
||||
"reprompt": {
|
||||
"plain": {
|
||||
"extra_data": None,
|
||||
"reprompt": "Do it again",
|
||||
},
|
||||
},
|
||||
"speech": {
|
||||
"plain": {
|
||||
"extra_data": None,
|
||||
"speech": "Some speech",
|
||||
},
|
||||
},
|
||||
"speech_slots": {
|
||||
"hello": 1,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue