pull/116507/head 2024.6.3
Franck Nijhof 2024-06-15 21:05:26 +02:00 committed by GitHub
commit 394dafd980
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 281 additions and 66 deletions

View File

@ -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"

View File

@ -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

View File

@ -10,7 +10,7 @@ on:
- "**strings.json"
env:
DEFAULT_PYTHON: "3.11"
DEFAULT_PYTHON: "3.12.3"
jobs:
upload:

View File

@ -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}}

View File

@ -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"]
}

View File

@ -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)

View File

@ -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"]
}

View File

@ -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"]
}

View File

@ -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"]
}

View File

@ -4,7 +4,10 @@
"after_dependencies": [
"alarm_control_panel",
"climate",
"cover",
"device_tracker",
"lock",
"media_player",
"person",
"plant",
"vacuum",

View File

@ -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:

View File

@ -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}"

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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,
)

View File

@ -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."
}
}
}

View File

@ -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,

View File

@ -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)},

View File

@ -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",

View File

@ -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%]",

View File

@ -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

View File

@ -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={

View File

@ -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",

View File

@ -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)

View File

@ -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] = {}

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
)

View File

@ -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"

View File

@ -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,
},
}