Compare commits

...

13 Commits

Author SHA1 Message Date
mib1185 c6f70bc101 consider current connection type in reconnect action 2026-06-29 15:33:13 +00:00
Ariel Ebersberger ca7ae00c7e Rename "advanced_settings" section to "additional_settings" in History Stats (#175109) 2026-06-29 14:32:57 +02:00
Ariel Ebersberger ff460901b7 Rename "advanced_options" section to "additional_options" in DNS IP (#175105) 2026-06-29 13:14:58 +02:00
Ariel Ebersberger 30512f08a8 Rename "advanced" step to "additional" in OpenAI Conversation (#175104) 2026-06-29 13:14:19 +02:00
Ariel Ebersberger 9dd1a59d50 Rename "advanced" step to "additional" in Anthropic (#175101) 2026-06-29 13:14:01 +02:00
TrojanHorsePower 91aded4474 Update vsure to 2.8.0 (#175060) 2026-06-29 11:46:21 +02:00
Erwin Douna 543eab3354 Portainer add utility.py for duplicate code (#175082) 2026-06-29 11:04:02 +02:00
Ariel Ebersberger 47b331a869 Rename "Advanced settings" title in OpenAI Conversation (#175096) 2026-06-29 11:00:21 +02:00
Ariel Ebersberger 696dd45803 Rename "Advanced settings" title in Anthropic (#175095) 2026-06-29 10:59:53 +02:00
Ariel Ebersberger f92239877f Rename "Advanced migration/setup" options in ZHA (#175094) 2026-06-29 10:59:35 +02:00
Ariel Ebersberger 45ceb13937 Rename "Advanced settings" sections in Scrape (#175098) 2026-06-29 10:58:26 +02:00
Ariel Ebersberger c5aeee8097 Rename "(advanced)" service name in Music Assistant (#175097) 2026-06-29 10:58:04 +02:00
Erik Montnemery bfc750b608 Tell bots that we like small try-clauses (#174654) 2026-06-29 11:16:46 +03:00
27 changed files with 202 additions and 125 deletions
+1
View File
@@ -54,3 +54,4 @@ This repository contains the core of Home Assistant, a Python 3 based home autom
- Keep comments concise. Prefer one short line stating the non-obvious constraint, or no comment at all.
- Do not add comments that just restate the code on the following line(s) (e.g. `# Check if initialized` above `if self.initialized:`). Comments should only explain why (non-obvious constraints, surprising behavior, or workarounds), never what. Never add comments that justify a change by referencing what the code looked like before.
- Do not add section or divider comments (e.g. `# --- XYZ Triggers ---`) inside or outside of functions, since those can easily become stale and be misleading.
- When catching exceptions, try-clauses should be as small as possible, i.e. avoid wrapping large blocks of code in a try-clause, and avoid catching exceptions from functions that are not expected to raise them.
+1
View File
@@ -43,3 +43,4 @@ This repository contains the core of Home Assistant, a Python 3 based home autom
- Keep comments concise. Prefer one short line stating the non-obvious constraint, or no comment at all.
- Do not add comments that just restate the code on the following line(s) (e.g. `# Check if initialized` above `if self.initialized:`). Comments should only explain why (non-obvious constraints, surprising behavior, or workarounds), never what. Never add comments that justify a change by referencing what the code looked like before.
- Do not add section or divider comments (e.g. `# --- XYZ Triggers ---`) inside or outside of functions, since those can easily become stale and be misleading.
- When catching exceptions, try-clauses should be as small as possible, i.e. avoid wrapping large blocks of code in a try-clause, and avoid catching exceptions from functions that are not expected to raise them.
@@ -298,7 +298,7 @@ class ConversationSubentryFlowHandler(ConfigSubentryFlow):
):
self.options.pop(CONF_LLM_HASS_API)
if not errors:
return await self.async_step_advanced()
return await self.async_step_additional()
return self.async_show_form(
step_id="init",
@@ -308,10 +308,10 @@ class ConversationSubentryFlowHandler(ConfigSubentryFlow):
errors=errors or None,
)
async def async_step_advanced(
async def async_step_additional(
self, user_input: dict[str, Any] | None = None
) -> SubentryFlowResult:
"""Manage advanced options."""
"""Manage additional options."""
errors: dict[str, str] = {}
description_placeholders: dict[str, str] = {}
@@ -360,7 +360,7 @@ class ConversationSubentryFlowHandler(ConfigSubentryFlow):
return await self.async_step_model()
return self.async_show_form(
step_id="advanced",
step_id="additional",
data_schema=self.add_suggested_values_to_schema(
vol.Schema(step_schema), self.options
),
@@ -48,16 +48,16 @@
"user": "Add AI task"
},
"step": {
"advanced": {
"additional": {
"data": {
"chat_model": "[%key:common::generic::model%]",
"prompt_caching": "[%key:component::anthropic::config_subentries::conversation::step::advanced::data::prompt_caching%]"
"prompt_caching": "[%key:component::anthropic::config_subentries::conversation::step::additional::data::prompt_caching%]"
},
"data_description": {
"chat_model": "[%key:component::anthropic::config_subentries::conversation::step::advanced::data_description::chat_model%]",
"prompt_caching": "[%key:component::anthropic::config_subentries::conversation::step::advanced::data_description::prompt_caching%]"
"chat_model": "[%key:component::anthropic::config_subentries::conversation::step::additional::data_description::chat_model%]",
"prompt_caching": "[%key:component::anthropic::config_subentries::conversation::step::additional::data_description::prompt_caching%]"
},
"title": "[%key:component::anthropic::config_subentries::conversation::step::advanced::title%]"
"title": "[%key:component::anthropic::config_subentries::conversation::step::additional::title%]"
},
"init": {
"data": {
@@ -115,7 +115,7 @@
"user": "Add conversation agent"
},
"step": {
"advanced": {
"additional": {
"data": {
"chat_model": "[%key:common::generic::model%]",
"prompt_caching": "Caching strategy"
@@ -124,7 +124,7 @@
"chat_model": "The model to serve the responses.",
"prompt_caching": "Optimize your API cost and response times based on your usage."
},
"title": "Advanced settings"
"title": "Additional settings"
},
"init": {
"data": {
@@ -20,7 +20,7 @@ from homeassistant.data_entry_flow import SectionConfig, section
from homeassistant.helpers import config_validation as cv
from .const import (
CONF_ADVANCED_OPTIONS,
CONF_ADDITIONAL_OPTIONS,
CONF_HOSTNAME,
CONF_IPV4,
CONF_IPV6,
@@ -39,7 +39,7 @@ from .const import (
DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_HOSTNAME, default=DEFAULT_HOSTNAME): cv.string,
vol.Required(CONF_ADVANCED_OPTIONS): section(
vol.Required(CONF_ADDITIONAL_OPTIONS): section(
vol.Schema(
{
vol.Optional(CONF_RESOLVER): cv.string,
@@ -117,13 +117,13 @@ class DnsIPConfigFlow(ConfigFlow, domain=DOMAIN):
if user_input:
hostname = user_input[CONF_HOSTNAME]
name = DEFAULT_NAME if hostname == DEFAULT_HOSTNAME else hostname
advanced_options = user_input[CONF_ADVANCED_OPTIONS]
resolver = advanced_options.get(CONF_RESOLVER, DEFAULT_RESOLVER)
resolver_ipv6 = advanced_options.get(
additional_options = user_input[CONF_ADDITIONAL_OPTIONS]
resolver = additional_options.get(CONF_RESOLVER, DEFAULT_RESOLVER)
resolver_ipv6 = additional_options.get(
CONF_RESOLVER_IPV6, DEFAULT_RESOLVER_IPV6
)
port = advanced_options.get(CONF_PORT, DEFAULT_PORT)
port_ipv6 = advanced_options.get(CONF_PORT_IPV6, DEFAULT_PORT)
port = additional_options.get(CONF_PORT, DEFAULT_PORT)
port_ipv6 = additional_options.get(CONF_PORT_IPV6, DEFAULT_PORT)
validate = await async_validate_hostname(
hostname, resolver, resolver_ipv6, port, port_ipv6
+1 -1
View File
@@ -12,7 +12,7 @@ CONF_PORT_IPV6 = "port_ipv6"
CONF_IPV4 = "ipv4"
CONF_IPV6 = "ipv6"
CONF_IPV6_V4 = "ipv6_v4"
CONF_ADVANCED_OPTIONS = "advanced_options"
CONF_ADDITIONAL_OPTIONS = "additional_options"
DEFAULT_HOSTNAME = "myip.opendns.com"
DEFAULT_IPV6 = False
+9 -9
View File
@@ -15,7 +15,7 @@
"hostname": "The hostname for which to perform the DNS query."
},
"sections": {
"advanced_options": {
"additional_options": {
"data": {
"port": "IPv4 port",
"port_ipv6": "IPv6 port",
@@ -63,16 +63,16 @@
"step": {
"init": {
"data": {
"port": "[%key:component::dnsip::config::step::user::sections::advanced_options::data::port%]",
"port_ipv6": "[%key:component::dnsip::config::step::user::sections::advanced_options::data::port_ipv6%]",
"resolver": "[%key:component::dnsip::config::step::user::sections::advanced_options::data::resolver%]",
"resolver_ipv6": "[%key:component::dnsip::config::step::user::sections::advanced_options::data::resolver_ipv6%]"
"port": "[%key:component::dnsip::config::step::user::sections::additional_options::data::port%]",
"port_ipv6": "[%key:component::dnsip::config::step::user::sections::additional_options::data::port_ipv6%]",
"resolver": "[%key:component::dnsip::config::step::user::sections::additional_options::data::resolver%]",
"resolver_ipv6": "[%key:component::dnsip::config::step::user::sections::additional_options::data::resolver_ipv6%]"
},
"data_description": {
"port": "[%key:component::dnsip::config::step::user::sections::advanced_options::data_description::port%]",
"port_ipv6": "[%key:component::dnsip::config::step::user::sections::advanced_options::data_description::port_ipv6%]",
"resolver": "[%key:component::dnsip::config::step::user::sections::advanced_options::data_description::resolver%]",
"resolver_ipv6": "[%key:component::dnsip::config::step::user::sections::advanced_options::data_description::resolver_ipv6%]"
"port": "[%key:component::dnsip::config::step::user::sections::additional_options::data_description::port%]",
"port_ipv6": "[%key:component::dnsip::config::step::user::sections::additional_options::data_description::port_ipv6%]",
"resolver": "[%key:component::dnsip::config::step::user::sections::additional_options::data_description::resolver%]",
"resolver_ipv6": "[%key:component::dnsip::config::step::user::sections::additional_options::data_description::resolver_ipv6%]"
},
"description": "Optionally change resolvers and ports."
}
+14 -5
View File
@@ -11,7 +11,7 @@ from typing import Any, TypedDict, cast, override
from xml.etree.ElementTree import ParseError
from fritzconnection import FritzConnection
from fritzconnection.core.exceptions import FritzActionError
from fritzconnection.core.exceptions import FritzActionError, FritzConnectionException
from fritzconnection.lib.fritzcall import FritzCall
from fritzconnection.lib.fritzhosts import FritzHosts
from fritzconnection.lib.fritzstatus import FritzStatus
@@ -267,9 +267,7 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
) = self._update_device_info()
if self.fritz_status.has_wan_support:
self.device_conn_type = (
self.fritz_status.get_default_connection_service().connection_service
)
self.device_conn_type = self.fritz_status.connection_service
self.device_is_router = self.fritz_status.has_wan_enabled
self.has_call_deflections = "X_AVM-DE_OnTel1" in self.connection.services
@@ -682,7 +680,18 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]):
async def async_trigger_reconnect(self) -> None:
"""Trigger device reconnect."""
await self.hass.async_add_executor_job(self.connection.reconnect)
try:
await self.hass.async_add_executor_job(
self.connection.call_action,
f"{self.device_conn_type}1",
"ForceTermination",
)
except FritzConnectionException as ex:
# ignore UPnPError:
# errorCode: 707
# errorDescription: DisconnectInProgress
if "disconnectinprogress" not in str(ex).lower():
raise
async def async_trigger_set_guest_password(
self, password: str | None, length: int
@@ -20,7 +20,7 @@ from .const import (
CONF_MIN_STATE_DURATION,
CONF_START,
PLATFORMS,
SECTION_ADVANCED_SETTINGS,
SECTION_ADDITIONAL_SETTINGS,
)
from .coordinator import HistoryStatsUpdateCoordinator
from .data import HistoryStats
@@ -44,8 +44,8 @@ async def async_setup_entry(
min_state_duration: timedelta
if duration_dict := entry.options.get(CONF_DURATION):
duration = timedelta(**duration_dict)
advanced_settings = entry.options.get(SECTION_ADVANCED_SETTINGS, {})
if min_state_duration_dict := advanced_settings.get(CONF_MIN_STATE_DURATION):
additional_settings = entry.options.get(SECTION_ADDITIONAL_SETTINGS, {})
if min_state_duration_dict := additional_settings.get(CONF_MIN_STATE_DURATION):
min_state_duration = timedelta(**min_state_duration_dict)
else:
min_state_duration = timedelta(0)
@@ -121,6 +121,13 @@ async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) ->
hass.config_entries.async_update_entry(
config_entry, options=options, minor_version=3
)
if config_entry.minor_version < 4:
# The "advanced_settings" section was renamed to "additional_settings"
if (additional := options.pop("advanced_settings", None)) is not None:
options[SECTION_ADDITIONAL_SETTINGS] = additional
hass.config_entries.async_update_entry(
config_entry, options=options, minor_version=4
)
_LOGGER.debug(
"Migration to version %s.%s successful",
@@ -44,7 +44,7 @@ from .const import (
CONF_TYPE_TIME,
DEFAULT_NAME,
DOMAIN,
SECTION_ADVANCED_SETTINGS,
SECTION_ADDITIONAL_SETTINGS,
)
from .coordinator import HistoryStatsUpdateCoordinator
from .data import HistoryStats
@@ -149,7 +149,7 @@ def _get_options_schema_with_entity_id(entity_id: str, type: str) -> vol.Schema:
mode=SelectSelectorMode.DROPDOWN,
),
),
vol.Optional(SECTION_ADVANCED_SETTINGS): section(
vol.Optional(SECTION_ADDITIONAL_SETTINGS): section(
vol.Schema(
{
vol.Optional(CONF_MIN_STATE_DURATION): DurationSelector(
@@ -189,7 +189,7 @@ OPTIONS_FLOW = {
class HistoryStatsConfigFlowHandler(SchemaConfigFlowHandler, domain=DOMAIN):
"""Handle a config flow for History stats."""
MINOR_VERSION = 3
MINOR_VERSION = 4
config_flow = CONFIG_FLOW
options_flow = OPTIONS_FLOW
@@ -290,8 +290,8 @@ async def ws_start_preview(
start = validated_data.get(CONF_START)
end = validated_data.get(CONF_END)
duration = validated_data.get(CONF_DURATION)
advanced_settings = validated_data.get(SECTION_ADVANCED_SETTINGS, {})
min_state_duration = advanced_settings.get(CONF_MIN_STATE_DURATION)
additional_settings = validated_data.get(SECTION_ADDITIONAL_SETTINGS, {})
min_state_duration = additional_settings.get(CONF_MIN_STATE_DURATION)
state_class = validated_data.get(CONF_STATE_CLASS)
history_stats = HistoryStats(
@@ -18,4 +18,4 @@ CONF_TYPE_KEYS = [CONF_TYPE_TIME, CONF_TYPE_RATIO, CONF_TYPE_COUNT]
DEFAULT_NAME = "unnamed statistics"
SECTION_ADVANCED_SETTINGS = "advanced_settings"
SECTION_ADDITIONAL_SETTINGS = "additional_settings"
@@ -28,7 +28,7 @@
},
"description": "Read the documentation for further details on how to configure the history stats sensor using these options.",
"sections": {
"advanced_settings": {
"additional_settings": {
"data": { "min_state_duration": "Minimum state duration" },
"data_description": {
"min_state_duration": "The minimum state duration to account for the statistics. Default is 0 seconds."
@@ -93,14 +93,14 @@
},
"description": "[%key:component::history_stats::config::step::options::description%]",
"sections": {
"advanced_settings": {
"additional_settings": {
"data": {
"min_state_duration": "[%key:component::history_stats::config::step::options::sections::advanced_settings::data::min_state_duration%]"
"min_state_duration": "[%key:component::history_stats::config::step::options::sections::additional_settings::data::min_state_duration%]"
},
"data_description": {
"min_state_duration": "[%key:component::history_stats::config::step::options::sections::advanced_settings::data_description::min_state_duration%]"
"min_state_duration": "[%key:component::history_stats::config::step::options::sections::additional_settings::data_description::min_state_duration%]"
},
"name": "[%key:component::history_stats::config::step::options::sections::advanced_settings::name%]"
"name": "[%key:component::history_stats::config::step::options::sections::additional_settings::name%]"
}
}
}
@@ -374,7 +374,7 @@
},
"get_queue": {
"description": "Retrieves the details of the currently active queue of a Music Assistant player.",
"name": "Get playerQueue details (advanced)"
"name": "Get playerQueue details"
},
"play_announcement": {
"description": "Plays an announcement on a Music Assistant player with more fine-grained control options.",
@@ -326,7 +326,7 @@ class OpenAISubentryFlowHandler(ConfigSubentryFlow):
options.update(user_input)
if CONF_LLM_HASS_API in options and CONF_LLM_HASS_API not in user_input:
options.pop(CONF_LLM_HASS_API)
return await self.async_step_advanced()
return await self.async_step_additional()
return self.async_show_form(
step_id="init",
@@ -335,10 +335,10 @@ class OpenAISubentryFlowHandler(ConfigSubentryFlow):
),
)
async def async_step_advanced(
async def async_step_additional(
self, user_input: dict[str, Any] | None = None
) -> SubentryFlowResult:
"""Manage advanced options."""
"""Manage additional options."""
options = self.options
errors: dict[str, str] = {}
@@ -374,7 +374,7 @@ class OpenAISubentryFlowHandler(ConfigSubentryFlow):
return await self.async_step_model()
return self.async_show_form(
step_id="advanced",
step_id="additional",
data_schema=self.add_suggested_values_to_schema(
vol.Schema(step_schema), options
),
@@ -47,18 +47,18 @@
"user": "Add AI task"
},
"step": {
"advanced": {
"additional": {
"data": {
"chat_model": "[%key:common::generic::model%]",
"max_tokens": "[%key:component::openai_conversation::config_subentries::conversation::step::advanced::data::max_tokens%]",
"store_responses": "[%key:component::openai_conversation::config_subentries::conversation::step::advanced::data::store_responses%]",
"temperature": "[%key:component::openai_conversation::config_subentries::conversation::step::advanced::data::temperature%]",
"top_p": "[%key:component::openai_conversation::config_subentries::conversation::step::advanced::data::top_p%]"
"max_tokens": "[%key:component::openai_conversation::config_subentries::conversation::step::additional::data::max_tokens%]",
"store_responses": "[%key:component::openai_conversation::config_subentries::conversation::step::additional::data::store_responses%]",
"temperature": "[%key:component::openai_conversation::config_subentries::conversation::step::additional::data::temperature%]",
"top_p": "[%key:component::openai_conversation::config_subentries::conversation::step::additional::data::top_p%]"
},
"data_description": {
"store_responses": "[%key:component::openai_conversation::config_subentries::conversation::step::advanced::data_description::store_responses%]"
"store_responses": "[%key:component::openai_conversation::config_subentries::conversation::step::additional::data_description::store_responses%]"
},
"title": "[%key:component::openai_conversation::config_subentries::conversation::step::advanced::title%]"
"title": "[%key:component::openai_conversation::config_subentries::conversation::step::additional::title%]"
},
"init": {
"data": {
@@ -109,7 +109,7 @@
"user": "Add conversation agent"
},
"step": {
"advanced": {
"additional": {
"data": {
"chat_model": "[%key:common::generic::model%]",
"max_tokens": "Maximum tokens to return in response",
@@ -120,7 +120,7 @@
"data_description": {
"store_responses": "If enabled, requests and responses are stored by OpenAI and visible in your OpenAI dashboard logs"
},
"title": "Advanced settings"
"title": "Additional settings"
},
"init": {
"data": {
@@ -34,6 +34,7 @@ from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DOMAIN
from .util import sanitize_container_name
type PortainerConfigEntry = ConfigEntry[PortainerCoordinator]
@@ -263,7 +264,7 @@ class PortainerCoordinator(
# Map containers, started and stopped
for container in containers:
container_name = self._get_container_name(container.names[0])
container_name = sanitize_container_name(container.names[0])
prev_container = (
prev_endpoint.containers.get(container_name)
if prev_endpoint
@@ -313,7 +314,7 @@ class PortainerCoordinator(
container_stats = dict(
zip(
(
self._get_container_name(container.names[0])
sanitize_container_name(container.names[0])
for container in active_containers
),
await asyncio.gather(
@@ -431,10 +432,6 @@ class PortainerCoordinator(
for stack_callback in self.new_stacks_callbacks:
stack_callback(new_stack_data)
def _get_container_name(self, container_name: str) -> str:
"""Sanitize to get a proper container name."""
return container_name.replace("/", " ").strip()
class PortainerDockerDiskSpaceCoordinator(
PortainerBaseCoordinator[dict[int, DockerSystemDF]]
+2 -1
View File
@@ -19,6 +19,7 @@ from .coordinator import (
PortainerStackData,
PortainerVolumeData,
)
from .util import sanitize_container_name
class PortainerCoordinatorEntity(CoordinatorEntity[PortainerCoordinator]):
@@ -95,7 +96,7 @@ class PortainerContainerEntity(PortainerCoordinatorEntity):
# According to Docker's API docs, the first name is unique
names = self._device_info.container.names
assert names, "Container names list unexpectedly empty"
self.device_name = names[0].replace("/", " ").strip()
self.device_name = sanitize_container_name(names[0])
self._attr_device_info = DeviceInfo(
identifiers={
@@ -0,0 +1,6 @@
"""Utility functions for the Portainer integration."""
def sanitize_container_name(container_name: str) -> str:
"""Sanitize to get a proper container name."""
return container_name.replace("/", " ").strip()
+4 -4
View File
@@ -32,8 +32,8 @@
"timeout": "Timeout for connection to website.",
"verify_ssl": "Enables/disables verification of SSL/TLS certificate, for example if it is self-signed."
},
"description": "Provide additional advanced settings for the resource.",
"name": "Advanced settings"
"description": "Provide additional settings for the resource.",
"name": "Additional settings"
},
"auth": {
"data": {
@@ -117,8 +117,8 @@
"unit_of_measurement": "Choose unit of measurement or create your own.",
"value_template": "Defines a template to get the state of the sensor."
},
"description": "Provide additional advanced settings for the sensor.",
"name": "Advanced settings"
"description": "Provide additional settings for the sensor.",
"name": "Additional settings"
}
}
}
@@ -12,5 +12,5 @@
"integration_type": "hub",
"iot_class": "cloud_polling",
"loggers": ["verisure"],
"requirements": ["vsure==2.7.1"]
"requirements": ["vsure==2.8.0"]
}
+2 -2
View File
@@ -55,7 +55,7 @@
"migration_strategy_recommended": "This is the quickest option to migrate to a new adapter."
},
"menu_options": {
"migration_strategy_advanced": "Advanced migration",
"migration_strategy_advanced": "Migrate manually",
"migration_strategy_recommended": "Migrate automatically (recommended)"
},
"title": "Migrate to a new adapter"
@@ -74,7 +74,7 @@
"setup_strategy_recommended": "This is the quickest option to create a new network and get started."
},
"menu_options": {
"setup_strategy_advanced": "Advanced setup",
"setup_strategy_advanced": "Set up manually",
"setup_strategy_recommended": "Set up automatically (recommended)"
},
"title": "Set up Zigbee"
+1 -1
View File
@@ -3313,7 +3313,7 @@ volkszaehler==0.4.0
volvocarsapi==0.4.3
# homeassistant.components.verisure
vsure==2.7.1
vsure==2.8.0
# homeassistant.components.vasttrafik
vtjp==0.2.1
+12 -12
View File
@@ -275,9 +275,9 @@ async def test_subentry_options_thinking_budget_more_than_max(
},
)
assert options["type"] is FlowResultType.FORM
assert options["step_id"] == "advanced"
assert options["step_id"] == "additional"
# Configure advanced step
# Configure additional step
options = await hass.config_entries.subentries.async_configure(
options["flow_id"],
{"chat_model": "claude-sonnet-4-5"},
@@ -330,9 +330,9 @@ async def test_subentry_web_search_user_location(
},
)
assert options["type"] is FlowResultType.FORM
assert options["step_id"] == "advanced"
assert options["step_id"] == "additional"
# Configure advanced step
# Configure additional step
options = await hass.config_entries.subentries.async_configure(
options["flow_id"],
{
@@ -424,7 +424,7 @@ async def test_model_list(
},
)
assert options["type"] is FlowResultType.FORM
assert options["step_id"] == "advanced"
assert options["step_id"] == "additional"
assert options["data_schema"].schema["chat_model"].config["options"] == snapshot
@@ -447,9 +447,9 @@ async def test_invalid_model(
},
)
assert options["type"] is FlowResultType.FORM
assert options["step_id"] == "advanced"
assert options["step_id"] == "additional"
# Configure advanced step but with api error
# Configure additional step but with api error
with patch(
"homeassistant.components.anthropic.config_flow.anthropic.resources.models.AsyncModels.retrieve",
new_callable=AsyncMock,
@@ -877,12 +877,12 @@ async def test_ai_task_subentry_not_loaded(
assert result.get("reason") == "entry_not_loaded"
async def test_creating_ai_task_subentry_advanced(
async def test_creating_ai_task_subentry_additional(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_init_component,
) -> None:
"""Test creating an AI task subentry with advanced settings."""
"""Test creating an AI task subentry with additional settings."""
result = await hass.config_entries.subentries.async_init(
(mock_config_entry.entry_id, "ai_task_data"),
context={"source": config_entries.SOURCE_USER},
@@ -891,7 +891,7 @@ async def test_creating_ai_task_subentry_advanced(
assert result.get("type") is FlowResultType.FORM
assert result.get("step_id") == "init"
# Go to advanced settings
# Go to additional settings
result2 = await hass.config_entries.subentries.async_configure(
result["flow_id"],
{
@@ -901,9 +901,9 @@ async def test_creating_ai_task_subentry_advanced(
)
assert result2.get("type") is FlowResultType.FORM
assert result2.get("step_id") == "advanced"
assert result2.get("step_id") == "additional"
# Configure advanced settings
# Configure additional settings
result3 = await hass.config_entries.subentries.async_configure(
result["flow_id"],
{
+6 -6
View File
@@ -8,7 +8,7 @@ import pytest
from homeassistant import config_entries
from homeassistant.components.dnsip.config_flow import DATA_SCHEMA
from homeassistant.components.dnsip.const import (
CONF_ADVANCED_OPTIONS,
CONF_ADDITIONAL_OPTIONS,
CONF_HOSTNAME,
CONF_IPV4,
CONF_IPV6,
@@ -50,7 +50,7 @@ async def test_form(hass: HomeAssistant) -> None:
):
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_HOSTNAME: "home-assistant.io", CONF_ADVANCED_OPTIONS: {}},
{CONF_HOSTNAME: "home-assistant.io", CONF_ADDITIONAL_OPTIONS: {}},
)
await hass.async_block_till_done()
@@ -71,7 +71,7 @@ async def test_form(hass: HomeAssistant) -> None:
assert len(mock_setup_entry.mock_calls) == 1
async def test_form_with_advanced_options(hass: HomeAssistant) -> None:
async def test_form_with_additional_options(hass: HomeAssistant) -> None:
"""Test we can submit the form with custom resolver and port options."""
result = await hass.config_entries.flow.async_init(
@@ -95,7 +95,7 @@ async def test_form_with_advanced_options(hass: HomeAssistant) -> None:
result["flow_id"],
{
CONF_HOSTNAME: "home-assistant.io",
CONF_ADVANCED_OPTIONS: {
CONF_ADDITIONAL_OPTIONS: {
CONF_RESOLVER: "8.8.8.8",
CONF_RESOLVER_IPV6: "2620:119:53::53",
CONF_PORT: 53,
@@ -136,7 +136,7 @@ async def test_form_error(hass: HomeAssistant) -> None:
result["flow_id"],
{
CONF_HOSTNAME: "home-assistant.io",
CONF_ADVANCED_OPTIONS: {},
CONF_ADDITIONAL_OPTIONS: {},
},
)
await hass.async_block_till_done()
@@ -185,7 +185,7 @@ async def test_flow_already_exist(hass: HomeAssistant) -> None:
result["flow_id"],
{
CONF_HOSTNAME: "home-assistant.io",
CONF_ADVANCED_OPTIONS: {},
CONF_ADDITIONAL_OPTIONS: {},
},
)
await hass.async_block_till_done()
+25 -12
View File
@@ -483,31 +483,44 @@ async def test_trigger_methods(
) -> None:
"""Test trigger methods delegate to correct underlying calls."""
# test async_trigger_firmware_update
fritz_tools.connection.call_action = MagicMock(
return_value={"NewX_AVM-DE_UpdateState": True}
)
assert await fritz_tools.async_trigger_firmware_update() is True
# test async_trigger_reboot
fritz_tools.connection.reboot = MagicMock()
fritz_tools.connection.reconnect = MagicMock()
await fritz_tools.async_trigger_reboot()
fritz_tools.connection.reboot.assert_called_once()
# test async_trigger_set_guest_password
fritz_tools.fritz_guest_wifi.set_password = MagicMock()
await fritz_tools.async_trigger_set_guest_password("new-password", 20)
fritz_tools.fritz_guest_wifi.set_password.assert_called_once_with(
"new-password", 20
)
# test async_trigger_reconnect
fritz_tools.connection.call_action = MagicMock(
side_effect=FritzConnectionException(
"UPnPError:\nerrorCode: 707\nerrorDescription: DisconnectInProgress"
)
)
await fritz_tools.async_trigger_reconnect()
fritz_tools.connection.call_action.assert_called_with(
"WANPPPConnection1", "ForceTermination"
)
# test async_trigger_dial
fritz_tools.fritz_call.dial = MagicMock()
fritz_tools.fritz_call.hangup = MagicMock()
assert await fritz_tools.async_trigger_firmware_update() is True
await fritz_tools.async_trigger_reboot()
await fritz_tools.async_trigger_reconnect()
await fritz_tools.async_trigger_set_guest_password("new-password", 20)
with patch(
"homeassistant.components.fritz.coordinator.asyncio.sleep",
new=AsyncMock(),
) as sleep_mock:
await fritz_tools.async_trigger_dial("012345", 1)
fritz_tools.connection.reboot.assert_called_once()
fritz_tools.connection.reconnect.assert_called_once()
fritz_tools.fritz_guest_wifi.set_password.assert_called_once_with(
"new-password", 20
)
fritz_tools.fritz_call.dial.assert_called_once_with("012345")
sleep_mock.assert_awaited_once_with(1)
fritz_tools.fritz_call.hangup.assert_called_once()
@@ -10,9 +10,11 @@ from homeassistant.components.history_stats.config_flow import (
)
from homeassistant.components.history_stats.const import (
CONF_END,
CONF_MIN_STATE_DURATION,
CONF_START,
DEFAULT_NAME,
DOMAIN,
SECTION_ADDITIONAL_SETTINGS,
)
from homeassistant.components.sensor import CONF_STATE_CLASS, SensorStateClass
from homeassistant.config_entries import ConfigEntry, ConfigEntryState
@@ -476,6 +478,46 @@ async def test_migration_1_2(
)
@pytest.mark.usefixtures("recorder_mock")
async def test_migration_1_3(
hass: HomeAssistant,
sensor_entity_entry: er.RegistryEntry,
) -> None:
"""Test migration from v1.3 renames advanced_settings to additional_settings."""
history_stats_config_entry = MockConfigEntry(
data={},
domain=DOMAIN,
options={
CONF_NAME: DEFAULT_NAME,
CONF_ENTITY_ID: sensor_entity_entry.entity_id,
CONF_STATE: ["on"],
CONF_TYPE: "count",
CONF_START: "{{ as_timestamp(utcnow()) - 3600 }}",
CONF_END: "{{ utcnow() }}",
"advanced_settings": {CONF_MIN_STATE_DURATION: {"seconds": 30}},
},
title="My history stats",
version=1,
minor_version=3,
)
history_stats_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(history_stats_config_entry.entry_id)
await hass.async_block_till_done()
assert history_stats_config_entry.state is ConfigEntryState.LOADED
assert "advanced_settings" not in history_stats_config_entry.options
assert history_stats_config_entry.options[SECTION_ADDITIONAL_SETTINGS] == {
CONF_MIN_STATE_DURATION: {"seconds": 30}
}
assert history_stats_config_entry.version == 1
assert (
history_stats_config_entry.minor_version
== HistoryStatsConfigFlowHandler.MINOR_VERSION
)
@pytest.mark.usefixtures("recorder_mock")
async def test_migration_from_future_version(
hass: HomeAssistant,
@@ -246,9 +246,9 @@ async def test_subentry_unsupported_model(
)
await hass.async_block_till_done()
assert subentry_flow["type"] is FlowResultType.FORM
assert subentry_flow["step_id"] == "advanced"
assert subentry_flow["step_id"] == "additional"
# Configure advanced step
# Configure additional step
subentry_flow = await hass.config_entries.subentries.async_configure(
subentry_flow["flow_id"],
{
@@ -300,9 +300,9 @@ async def test_subentry_reasoning_effort_list(
},
)
assert subentry_flow["type"] is FlowResultType.FORM
assert subentry_flow["step_id"] == "advanced"
assert subentry_flow["step_id"] == "additional"
# Configure advanced step
# Configure additional step
subentry_flow = await hass.config_entries.subentries.async_configure(
subentry_flow["flow_id"],
{
@@ -354,9 +354,9 @@ async def test_subentry_reasoning_summary_visibility(
},
)
assert subentry_flow["type"] is FlowResultType.FORM
assert subentry_flow["step_id"] == "advanced"
assert subentry_flow["step_id"] == "additional"
# Configure advanced step
# Configure additional step
subentry_flow = await hass.config_entries.subentries.async_configure(
subentry_flow["flow_id"],
{
@@ -403,7 +403,7 @@ async def test_subentry_reasoning_summary_options(
},
)
assert subentry_flow["type"] is FlowResultType.FORM
assert subentry_flow["step_id"] == "advanced"
assert subentry_flow["step_id"] == "additional"
subentry_flow = await hass.config_entries.subentries.async_configure(
subentry_flow["flow_id"],
@@ -450,7 +450,7 @@ async def test_subentry_reasoning_summary_default_sanitized_on_model_switch(
CONF_LLM_HASS_API: ["assist"],
},
)
assert subentry_flow["step_id"] == "advanced"
assert subentry_flow["step_id"] == "additional"
subentry_flow = await hass.config_entries.subentries.async_configure(
subentry_flow["flow_id"],
@@ -515,9 +515,9 @@ async def test_subentry_service_tier_list(
},
)
assert subentry_flow["type"] is FlowResultType.FORM
assert subentry_flow["step_id"] == "advanced"
assert subentry_flow["step_id"] == "additional"
# Configure advanced step
# Configure additional step
subentry_flow = await hass.config_entries.subentries.async_configure(
subentry_flow["flow_id"],
{
@@ -561,9 +561,9 @@ async def test_subentry_unsupported_reasoning_effort(
},
)
assert subentry_flow["type"] is FlowResultType.FORM
assert subentry_flow["step_id"] == "advanced"
assert subentry_flow["step_id"] == "additional"
# Configure advanced step
# Configure additional step
subentry_flow = await hass.config_entries.subentries.async_configure(
subentry_flow["flow_id"],
{
@@ -1144,9 +1144,9 @@ async def test_subentry_web_search_user_location(
},
)
assert subentry_flow["type"] is FlowResultType.FORM
assert subentry_flow["step_id"] == "advanced"
assert subentry_flow["step_id"] == "additional"
# Configure advanced step
# Configure additional step
subentry_flow = await hass.config_entries.subentries.async_configure(
subentry_flow["flow_id"],
{
@@ -1292,12 +1292,12 @@ async def test_ai_task_subentry_not_loaded(
assert result.get("reason") == "entry_not_loaded"
async def test_creating_ai_task_subentry_advanced(
async def test_creating_ai_task_subentry_additional(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_init_component,
) -> None:
"""Test creating an AI task subentry with advanced settings."""
"""Test creating an AI task subentry with additional settings."""
result = await hass.config_entries.subentries.async_init(
(mock_config_entry.entry_id, "ai_task_data"),
context={"source": config_entries.SOURCE_USER},
@@ -1306,7 +1306,7 @@ async def test_creating_ai_task_subentry_advanced(
assert result.get("type") is FlowResultType.FORM
assert result.get("step_id") == "init"
# Go to advanced settings
# Go to additional settings
result2 = await hass.config_entries.subentries.async_configure(
result["flow_id"],
{
@@ -1316,9 +1316,9 @@ async def test_creating_ai_task_subentry_advanced(
)
assert result2.get("type") is FlowResultType.FORM
assert result2.get("step_id") == "advanced"
assert result2.get("step_id") == "additional"
# Configure advanced settings
# Configure additional settings
result3 = await hass.config_entries.subentries.async_configure(
result["flow_id"],
{