Merge branch 'dev' into copilot/fix-149693

This commit is contained in:
Michael
2025-07-31 19:54:30 +02:00
committed by GitHub
50 changed files with 1541 additions and 121 deletions

View File

@@ -159,7 +159,7 @@ jobs:
sed -i "/uv/d" requirements_diff.txt
- name: Build wheels
uses: home-assistant/wheels@2025.03.0
uses: home-assistant/wheels@2025.07.0
with:
abi: ${{ matrix.abi }}
tag: musllinux_1_2
@@ -219,7 +219,7 @@ jobs:
sed -i "/uv/d" requirements_diff.txt
- name: Build wheels
uses: home-assistant/wheels@2025.03.0
uses: home-assistant/wheels@2025.07.0
with:
abi: ${{ matrix.abi }}
tag: musllinux_1_2

View File

@@ -33,7 +33,10 @@ class AuthFlowContext(FlowContext, total=False):
redirect_uri: str
AuthFlowResult = FlowResult[AuthFlowContext, tuple[str, str]]
class AuthFlowResult(FlowResult[AuthFlowContext, tuple[str, str]], total=False):
"""Typed result dict for auth flow."""
result: Credentials # Only present if type is CREATE_ENTRY
@attr.s(slots=True)

View File

@@ -268,7 +268,7 @@ class LoginFlowBaseView(HomeAssistantView):
result.pop("data")
result.pop("context")
result_obj: Credentials = result.pop("result")
result_obj = result.pop("result")
# Result can be None if credential was never linked to a user before.
user = await hass.auth.async_get_user_by_credentials(result_obj)
@@ -281,7 +281,8 @@ class LoginFlowBaseView(HomeAssistantView):
)
process_success_login(request)
result["result"] = self._store_result(client_id, result_obj)
# We overwrite the Credentials object with the string code to retrieve it.
result["result"] = self._store_result(client_id, result_obj) # type: ignore[typeddict-item]
return self.json(result)

View File

@@ -1119,7 +1119,7 @@ class BackupManager:
)
if unavailable_agents:
LOGGER.warning(
"Backup agents %s are not available, will backupp to %s",
"Backup agents %s are not available, will backup to %s",
unavailable_agents,
available_agents,
)

View File

@@ -146,8 +146,9 @@ def _prepare_config_flow_result_json(
return prepare_result_json(result)
data = result.copy()
entry: config_entries.ConfigEntry = data["result"]
data["result"] = entry.as_json_fragment
entry: config_entries.ConfigEntry = data["result"] # type: ignore[typeddict-item]
# We overwrite the ConfigEntry object with its json representation.
data["result"] = entry.as_json_fragment # type: ignore[typeddict-unknown-key]
data.pop("data")
data.pop("context")
return data

View File

@@ -316,10 +316,11 @@ class EsphomeFlowHandler(ConfigFlow, domain=DOMAIN):
# Don't call _fetch_device_info() for ignored entries
raise AbortFlow("already_configured")
configured_host: str | None = entry.data.get(CONF_HOST)
configured_port: int | None = entry.data.get(CONF_PORT)
if configured_host == host and configured_port == port:
configured_port: int = entry.data.get(CONF_PORT, DEFAULT_PORT)
# When port is None (from DHCP discovery), only compare hosts
if configured_host == host and (port is None or configured_port == port):
# Don't probe to verify the mac is correct since
# the host and port matches.
# the host matches (and port matches if provided).
raise AbortFlow("already_configured")
configured_psk: str | None = entry.data.get(CONF_NOISE_PSK)
await self._fetch_device_info(host, port or configured_port, configured_psk)

View File

@@ -17,7 +17,7 @@
"mqtt": ["esphome/discover/#"],
"quality_scale": "platinum",
"requirements": [
"aioesphomeapi==37.1.5",
"aioesphomeapi==37.2.0",
"esphome-dashboard-api==1.3.0",
"bleak-esphome==3.1.0"
],

View File

@@ -20,5 +20,5 @@
"documentation": "https://www.home-assistant.io/integrations/frontend",
"integration_type": "system",
"quality_scale": "internal",
"requirements": ["home-assistant-frontend==20250730.0"]
"requirements": ["home-assistant-frontend==20250731.0"]
}

View File

@@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/growatt_server",
"iot_class": "cloud_polling",
"loggers": ["growattServer"],
"requirements": ["growattServer==1.6.0"]
"requirements": ["growattServer==1.7.1"]
}

View File

@@ -12,6 +12,7 @@ from ha_silabs_firmware_client import (
ManifestMissing,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
@@ -24,13 +25,20 @@ FIRMWARE_REFRESH_INTERVAL = timedelta(hours=8)
class FirmwareUpdateCoordinator(DataUpdateCoordinator[FirmwareManifest]):
"""Coordinator to manage firmware updates."""
def __init__(self, hass: HomeAssistant, session: ClientSession, url: str) -> None:
def __init__(
self,
hass: HomeAssistant,
config_entry: ConfigEntry,
session: ClientSession,
url: str,
) -> None:
"""Initialize the firmware update coordinator."""
super().__init__(
hass,
_LOGGER,
name="firmware update coordinator",
update_interval=FIRMWARE_REFRESH_INTERVAL,
config_entry=config_entry,
)
self.hass = hass
self.session = session

View File

@@ -124,6 +124,7 @@ def _async_create_update_entity(
config_entry=config_entry,
update_coordinator=FirmwareUpdateCoordinator(
hass,
config_entry,
session,
NABU_CASA_FIRMWARE_RELEASES_URL,
),

View File

@@ -129,6 +129,7 @@ def _async_create_update_entity(
config_entry=config_entry,
update_coordinator=FirmwareUpdateCoordinator(
hass,
config_entry,
session,
NABU_CASA_FIRMWARE_RELEASES_URL,
),

View File

@@ -99,7 +99,7 @@ class OptionsFlowHandler(OptionsFlowWithReload):
),
}
)
self.add_suggested_values_to_schema(
data_schema = self.add_suggested_values_to_schema(
data_schema,
{"section_1": {"int": self.config_entry.options.get(CONF_INT, 10)}},
)

View File

@@ -431,6 +431,16 @@ DISHWASHER_PROGRAM_ID: dict[int, str] = {
38: "quick_power_wash",
42: "tall_items",
44: "power_wash",
200: "eco",
202: "automatic",
203: "comfort_wash",
204: "power_wash",
205: "intensive",
207: "extra_quiet",
209: "comfort_wash_plus",
210: "gentle",
214: "maintenance",
215: "rinse_salt",
}
TUMBLE_DRYER_PROGRAM_ID: dict[int, str] = {
-1: "no_program", # Extrapolated from other device types.

View File

@@ -731,7 +731,7 @@ class MielePlateSensor(MieleSensor):
)
).name
if self.device.state_plate_step
else PlatePowerStep.plate_step_0
else PlatePowerStep.plate_step_0.name
)

View File

@@ -203,7 +203,7 @@ async def get_programs(call: ServiceCall) -> ServiceResponse:
else {}
),
}
if item["parameters"]
if item.get("parameters")
else {}
),
}

View File

@@ -485,6 +485,8 @@
"cook_bacon": "Cook bacon",
"biscuits_short_crust_pastry_1_tray": "Biscuits, short crust pastry (1 tray)",
"biscuits_short_crust_pastry_2_trays": "Biscuits, short crust pastry (2 trays)",
"comfort_wash": "Comfort wash",
"comfort_wash_plus": "Comfort wash plus",
"cool_air": "Cool air",
"corn_on_the_cob": "Corn on the cob",
"cottons": "Cottons",
@@ -827,6 +829,7 @@
"rice_pudding_steam_cooking": "Rice pudding (steam cooking)",
"rinse": "Rinse",
"rinse_out_lint": "Rinse out lint",
"rinse_salt": "Rinse salt",
"risotto": "Risotto",
"ristretto": "Ristretto",
"roast_beef_low_temperature_cooking": "Roast beef (low temperature cooking)",

View File

@@ -802,15 +802,15 @@
"data": {
"max_humidity": "Maximum humidity",
"min_humidity": "Minimum humidity",
"target_humidity_command_template": "Humidity command template",
"target_humidity_command_topic": "Humidity command topic",
"target_humidity_state_template": "Humidity state template",
"target_humidity_state_topic": "Humidity state topic"
"target_humidity_command_template": "Target humidity command template",
"target_humidity_command_topic": "Target humidity command topic",
"target_humidity_state_template": "Target humidity state template",
"target_humidity_state_topic": "Target humidity state topic"
},
"data_description": {
"max_humidity": "The maximum target humidity that can be set.",
"min_humidity": "The minimum target humidity that can be set.",
"target_humidity_command_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to compose the payload to be published at the humidity command topic.",
"target_humidity_command_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt) to compose the payload to be published at the target humidity command topic.",
"target_humidity_command_topic": "The MQTT topic to publish commands to change the climate target humidity. [Learn more.]({url}#humidity_command_topic)",
"target_humidity_state_template": "A [template](https://www.home-assistant.io/docs/configuration/templating/#using-value-templates-with-mqtt) to render the value received on the target humidity state topic with.",
"target_humidity_state_topic": "The MQTT topic to subscribe for changes of the target humidity. [Learn more.]({url}#humidity_state_topic)"
@@ -838,7 +838,7 @@
"temperature_low_state_topic": "Lower temperature state topic"
},
"data_description": {
"initial": "The climate initalizes with this target temperature.",
"initial": "The climate initializes with this target temperature.",
"max_temp": "The maximum target temperature that can be set.",
"min_temp": "The minimum target temperature that can be set.",
"precision": "The precision in degrees the thermostat is working at.",

View File

@@ -19,5 +19,5 @@
"iot_class": "local_push",
"loggers": ["reolink_aio"],
"quality_scale": "platinum",
"requirements": ["reolink-aio==0.14.4"]
"requirements": ["reolink-aio==0.14.5"]
}

View File

@@ -89,8 +89,6 @@ class RepairsFlowManager(data_entry_flow.FlowManager):
"""
if result.get("type") != data_entry_flow.FlowResultType.ABORT:
ir.async_delete_issue(self.hass, flow.handler, flow.init_data["issue_id"])
if "result" not in result:
result["result"] = None
return result

View File

@@ -2,6 +2,7 @@
"common": {
"advanced_options": "Advanced options",
"availability": "Availability template",
"availability_description": "Defines a template to get the `available` state of the entity. If the template either fails to render or returns `True`, `\"1\"`, `\"true\"`, `\"yes\"`, `\"on\"`, `\"enable\"`, or a non-zero number, the entity will be `available`. If the template returns any other value, the entity will be `unavailable`. If not configured, the entity will always be `available`. Note that the string comparison is not case sensitive; `\"TrUe\"` and `\"yEs\"` are allowed.",
"code_format": "Code format",
"device_class": "Device class",
"device_id_description": "Select a device to link to this entity.",
@@ -28,13 +29,26 @@
"code_format": "[%key:component::template::common::code_format%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"value_template": "Defines a template to set the state of the alarm panel. Valid output values from the template are `armed_away`, `armed_home`, `armed_night`, `armed_vacation`, `arming`, `disarmed`, `pending`, and `triggered`.",
"disarm": "Defines actions to run when the alarm control panel is disarmed. Receives variable `code`.",
"arm_away": "Defines actions to run when the alarm control panel is armed to `arm_away`. Receives variable `code`.",
"arm_custom_bypass": "Defines actions to run when the alarm control panel is armed to `arm_custom_bypass`. Receives variable `code`.",
"arm_home": "Defines actions to run when the alarm control panel is armed to `arm_home`. Receives variable `code`.",
"arm_night": "Defines actions to run when the alarm control panel is armed to `arm_night`. Receives variable `code`.",
"arm_vacation": "Defines actions to run when the alarm control panel is armed to `arm_vacation`. Receives variable `code`.",
"trigger": "Defines actions to run when the alarm control panel is triggered. Receives variable `code`.",
"code_arm_required": "If true, the code is required to arm the alarm.",
"code_format": "One of `number`, `text` or `no_code`. Format for the code used to arm/disarm the alarm."
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -48,13 +62,17 @@
"state": "[%key:component::template::common::state%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "The sensor is `on` if the template evaluates as `True`, `yes`, `on`, `enable` or a positive number. Any other value will render it as `off`."
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -68,13 +86,17 @@
"press": "Actions on press"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"press": "Defines actions to run when button is pressed."
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -99,13 +121,16 @@
"close_cover": "Defines actions to run when the cover is closed.",
"stop_cover": "Defines actions to run when the cover is stopped.",
"position": "Defines a template to get the position of the cover. Value values are numbers between `0` (`closed`) and `100` (`open`).",
"set_cover_position": "Defines actions to run when the cover is given a `set_cover_position` command."
"set_cover_position": "Defines actions to run when the cover is given a `set_cover_position` command. Receives variable `position`."
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -124,11 +149,11 @@
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "Defines a template to get the state of the fan. Valid values: `on`, `off`.",
"state": "The fan is `on` if the template evaluates as `True`, `yes`, `on`, `enable` or a positive number. Any other value will render it as `off`.",
"turn_off": "Defines actions to run when the fan is turned off.",
"turn_on": "Defines actions to run when the fan is turned on.",
"turn_on": "Defines actions to run when the fan is turned on. Receives variables `percentage` and/or `preset_mode`.",
"percentage": "Defines a template to get the speed percentage of the fan.",
"set_percentage": "Defines actions to run when the fan is given a speed percentage command.",
"set_percentage": "Defines actions to run when the fan is given a speed percentage command. Receives variable `percentage`.",
"speed_count": "The number of speeds the fan supports. Used to calculate the percentage step for the `fan.increase_speed` and `fan.decrease_speed` actions."
},
"sections": {
@@ -136,6 +161,9 @@
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -149,13 +177,18 @@
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"url": "Defines a template to get the URL on which the image is served.",
"verify_ssl": "Enable or disable SSL certificate verification. Disable to use an http URL, or if you have a self-signed SSL certificate and havent installed the CA certificate to enable verification."
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -176,13 +209,25 @@
"set_temperature": "Actions on set color temperature"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "The light is `on` if the template evaluates as `True`, `yes`, `on`, `enable` or a positive number. Any other value will render it as `off`.",
"turn_off": "Defines actions to run when the light is turned off.",
"turn_on": "Defines actions to run when the light is turned on.",
"level": "Defines a template to get the brightness of the light. Valid values are 0 to 255.",
"set_level": "Defines actions to run when the light is given a brightness command. The script will only be called if the `turn_on` call only has `brightness`, and optionally `transition`. Receives variables `brightness` and, optionally, `transition`.",
"hs": "Defines a template to get the HS color of the light. Must render a tuple (hue, saturation).",
"set_hs": "Defines actions to run when the light is given a hs color command. Available variables: `hs` as a tuple, `h` and `s`.",
"temperature": "Defines a template to get the color temperature of the light.",
"set_temperature": "Defines actions to run when the light is given a color temperature command. Receives variable `color_temp_kelvin`. May also receive variables `brightness` and/or `transition`."
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -199,13 +244,21 @@
"open": "Actions on open"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "Defines a template to set the state of the lock. The lock is locked if the template evaluates to `True`, `true`, `on`, or `locked`. The lock is unlocked if the template evaluates to `False`, `false`, `off`, or `unlocked`. Other valid states are `jammed`, `opening`, `locking`, `open`, and `unlocking`.",
"lock": "Defines actions to run when the lock is locked.",
"unlock": "Defines actions to run when the lock is unlocked.",
"code_format": "Defines a template to get the `code_format` attribute of the lock.",
"open": "Defines actions to run when the lock is opened."
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -223,13 +276,22 @@
"unit_of_measurement": "[%key:component::template::common::unit_of_measurement%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "Template for the number's current value.",
"step": "Template for the number's increment/decrement step.",
"set_value": "Defines actions to run when the number is set to a value. Receives variable `value`.",
"max": "Template for the number's maximum value.",
"min": "Template for the number's minimum value.",
"unit_of_measurement": "Defines the unit of measurement of the number, if any."
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -244,13 +306,19 @@
"options": "Available options"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "Template for the selects current value.",
"select_option": "Defines actions to run when an `option` from the `options` list is selected. Receives variable `option`.",
"options": "Template for the selects available options."
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -266,13 +334,18 @@
"unit_of_measurement": "[%key:component::template::common::unit_of_measurement%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "Defines a template to get the state of the sensor. If the sensor is numeric, i.e. it has a `state_class` or a `unit_of_measurement`, the state template must render to a number or to `none`. The state template must not render to a string, including `unknown` or `unavailable`. An `availability` template may be defined to suppress rendering of the state template.",
"unit_of_measurement": "Defines the unit of measurement for the sensor, if any. This will also display the value based on the number format setting in the user profile and influence the graphical presentation in the history visualization as a continuous value."
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -307,13 +380,18 @@
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]",
"value_template": "Defines a template to set the state of the switch. If not defined, the switch will optimistically assume all commands are successful."
"value_template": "Defines a template to set the state of the switch. If not defined, the switch will optimistically assume all commands are successful.",
"turn_off": "Defines actions to run when the switch is turned off.",
"turn_on": "Defines actions to run when the switch is turned on."
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -324,24 +402,37 @@
"device_id": "[%key:common::config_flow::data::device%]",
"name": "[%key:common::config_flow::data::name%]",
"state": "[%key:component::template::common::state%]",
"start": "Actions on turn off",
"start": "Actions on start",
"fan_speed": "Fan speed",
"fan_speeds": "Fan speeds",
"set_fan_speed": "Actions on set fan speed",
"stop": "Actions on stop",
"pause": "Actions on pause",
"return_to_base": "Actions on return to base",
"return_to_base": "Actions on return to dock",
"clean_spot": "Actions on clean spot",
"locate": "Actions on locate"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "Defines a template to get the state of the vacuum. Valid values are `cleaning`, `docked`, `idle`, `paused`, `returning`, and `error`.",
"start": "Defines actions to run when the vacuum is started.",
"fan_speed": "Defines a template to get the fan speed of the vacuum.",
"fan_speeds": "List of fan speeds supported by the vacuum.",
"set_fan_speed": "Defines actions to run when the vacuum is given a command to set the fan speed. Receives variable `fan_speed`.",
"stop": "Defines actions to run when the vacuum is stopped.",
"pause": "Defines actions to run when the vacuum is paused.",
"return_to_base": "Defines actions to run when the vacuum is given a 'Return to dock' command.",
"clean_spot": "Defines actions to run when the vacuum is given a 'Clean spot' command.",
"locate": "Defines actions to run when the vacuum is given a 'Locate' command."
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -366,13 +457,26 @@
"code_format": "[%key:component::template::common::code_format%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"value_template": "[%key:component::template::config::step::alarm_control_panel::data_description::value_template%]",
"disarm": "[%key:component::template::config::step::alarm_control_panel::data_description::disarm%]",
"arm_away": "[%key:component::template::config::step::alarm_control_panel::data_description::arm_away%]",
"arm_custom_bypass": "[%key:component::template::config::step::alarm_control_panel::data_description::arm_custom_bypass%]",
"arm_home": "[%key:component::template::config::step::alarm_control_panel::data_description::arm_home%]",
"arm_night": "[%key:component::template::config::step::alarm_control_panel::data_description::arm_night%]",
"arm_vacation": "[%key:component::template::config::step::alarm_control_panel::data_description::arm_vacation%]",
"trigger": "[%key:component::template::config::step::alarm_control_panel::data_description::trigger%]",
"code_arm_required": "[%key:component::template::config::step::alarm_control_panel::data_description::code_arm_required%]",
"code_format": "[%key:component::template::config::step::alarm_control_panel::data_description::code_format%]"
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -384,13 +488,17 @@
"state": "[%key:component::template::common::state%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "[%key:component::template::config::step::binary_sensor::data_description::state%]"
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -402,13 +510,17 @@
"press": "[%key:component::template::config::step::button::data::press%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"press": "[%key:component::template::config::step::button::data_description::press%]"
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -439,6 +551,9 @@
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -468,6 +583,9 @@
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -480,13 +598,18 @@
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"url": "[%key:component::template::config::step::image::data_description::url%]",
"verify_ssl": "[%key:component::template::config::step::image::data_description::verify_ssl%]"
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -507,13 +630,25 @@
"set_temperature": "[%key:component::template::config::step::light::data::set_temperature%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "[%key:component::template::config::step::light::data_description::state%]",
"turn_off": "[%key:component::template::config::step::light::data_description::turn_off%]",
"turn_on": "[%key:component::template::config::step::light::data_description::turn_on%]",
"level": "[%key:component::template::config::step::light::data_description::level%]",
"set_level": "[%key:component::template::config::step::light::data_description::set_level%]",
"hs": "[%key:component::template::config::step::light::data_description::hs%]",
"set_hs": "[%key:component::template::config::step::light::data_description::set_hs%]",
"temperature": "[%key:component::template::config::step::light::data_description::temperature%]",
"set_temperature": "[%key:component::template::config::step::light::data_description::set_temperature%]"
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -529,13 +664,21 @@
"open": "[%key:component::template::config::step::lock::data::open%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "[%key:component::template::config::step::lock::data_description::state%]",
"lock": "[%key:component::template::config::step::lock::data_description::lock%]",
"unlock": "[%key:component::template::config::step::lock::data_description::unlock%]",
"code_format": "[%key:component::template::config::step::lock::data_description::code_format%]",
"open": "[%key:component::template::config::step::lock::data_description::open%]"
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -552,13 +695,21 @@
"min": "[%key:component::template::config::step::number::data::min%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "[%key:component::template::config::step::number::data_description::state%]",
"step": "[%key:component::template::config::step::number::data_description::step%]",
"set_value": "[%key:component::template::config::step::number::data_description::set_value%]",
"max": "[%key:component::template::config::step::number::data_description::max%]",
"min": "[%key:component::template::config::step::number::data_description::min%]"
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -573,13 +724,19 @@
"options": "[%key:component::template::config::step::select::data::options%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "[%key:component::template::config::step::select::data_description::state%]",
"select_option": "[%key:component::template::config::step::select::data_description::select_option%]",
"options": "[%key:component::template::config::step::select::data_description::options%]"
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -594,13 +751,18 @@
"unit_of_measurement": "[%key:component::template::common::unit_of_measurement%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "[%key:component::template::config::step::sensor::data_description::state%]",
"unit_of_measurement": "[%key:component::template::config::step::sensor::data_description::state%]"
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -616,13 +778,18 @@
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]",
"value_template": "[%key:component::template::config::step::switch::data_description::value_template%]"
"value_template": "[%key:component::template::config::step::switch::data_description::value_template%]",
"turn_off": "[%key:component::template::config::step::switch::data_description::turn_off%]",
"turn_on": "[%key:component::template::config::step::switch::data_description::turn_on%]"
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
@@ -644,17 +811,30 @@
"locate": "[%key:component::template::config::step::vacuum::data::locate%]"
},
"data_description": {
"device_id": "[%key:component::template::common::device_id_description%]"
"device_id": "[%key:component::template::common::device_id_description%]",
"state": "[%key:component::template::config::step::vacuum::data_description::state%]",
"start": "[%key:component::template::config::step::vacuum::data_description::start%]",
"fan_speed": "[%key:component::template::config::step::vacuum::data_description::fan_speed%]",
"fan_speeds": "[%key:component::template::config::step::vacuum::data_description::fan_speeds%]",
"set_fan_speed": "[%key:component::template::config::step::vacuum::data_description::set_fan_speed%]",
"stop": "[%key:component::template::config::step::vacuum::data_description::stop%]",
"pause": "[%key:component::template::config::step::vacuum::data_description::pause%]",
"return_to_base": "[%key:component::template::config::step::vacuum::data_description::return_to_base%]",
"clean_spot": "[%key:component::template::config::step::vacuum::data_description::clean_spot%]",
"locate": "[%key:component::template::config::step::vacuum::data_description::locate%]"
},
"sections": {
"advanced_options": {
"name": "[%key:component::template::common::advanced_options%]",
"data": {
"availability": "[%key:component::template::common::availability%]"
},
"data_description": {
"availability": "[%key:component::template::common::availability_description%]"
}
}
},
"title": "Template vacuum"
"title": "[%key:component::template::config::step::vacuum::title%]"
}
}
},

View File

@@ -34,6 +34,7 @@ from homeassistant.components.weather import (
from homeassistant.const import (
CONF_NAME,
CONF_TEMPERATURE_UNIT,
CONF_UNIQUE_ID,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
)
@@ -151,6 +152,7 @@ PLATFORM_SCHEMA = vol.Schema(
vol.Optional(CONF_PRESSURE_UNIT): vol.In(PressureConverter.VALID_UNITS),
vol.Required(CONF_TEMPERATURE_TEMPLATE): cv.template,
vol.Optional(CONF_TEMPERATURE_UNIT): vol.In(TemperatureConverter.VALID_UNITS),
vol.Optional(CONF_UNIQUE_ID): cv.string,
vol.Optional(CONF_VISIBILITY_TEMPLATE): cv.template,
vol.Optional(CONF_VISIBILITY_UNIT): vol.In(DistanceConverter.VALID_UNITS),
vol.Optional(CONF_WIND_BEARING_TEMPLATE): cv.template,

View File

@@ -24,5 +24,5 @@
"dependencies": ["bluetooth_adapters"],
"documentation": "https://www.home-assistant.io/integrations/xiaomi_ble",
"iot_class": "local_push",
"requirements": ["xiaomi-ble==1.1.0"]
"requirements": ["xiaomi-ble==1.2.0"]
}

View File

@@ -298,8 +298,10 @@ class ConfigFlowContext(FlowContext, total=False):
class ConfigFlowResult(FlowResult[ConfigFlowContext, str], total=False):
"""Typed result dict for config flow."""
# Extra keys, only present if type is CREATE_ENTRY
minor_version: int
options: Mapping[str, Any]
result: ConfigEntry
subentries: Iterable[ConfigSubentryData]
version: int
@@ -3345,7 +3347,6 @@ class ConfigSubentryFlowManager(
),
)
result["result"] = True
return result
@@ -3508,7 +3509,6 @@ class OptionsFlowManager(
):
self.hass.config_entries.async_schedule_reload(entry.entry_id)
result["result"] = True
return result
async def _async_setup_preview(

View File

@@ -142,7 +142,6 @@ class FlowResult(TypedDict, Generic[_FlowContextT, _HandlerT], total=False):
progress_task: asyncio.Task[Any] | None
reason: str
required: bool
result: Any
step_id: str
title: str
translation_domain: str
@@ -706,10 +705,7 @@ class FlowHandler(Generic[_FlowContextT, _FlowResultT, _HandlerT]):
last_step: bool | None = None,
preview: str | None = None,
) -> _FlowResultT:
"""Return the definition of a form to gather user input.
The step_id parameter is deprecated and will be removed in a future release.
"""
"""Return the definition of a form to gather user input."""
flow_result = self._flow_result(
type=FlowResultType.FORM,
flow_id=self.flow_id,
@@ -771,10 +767,7 @@ class FlowHandler(Generic[_FlowContextT, _FlowResultT, _HandlerT]):
url: str,
description_placeholders: Mapping[str, str] | None = None,
) -> _FlowResultT:
"""Return the definition of an external step for the user to take.
The step_id parameter is deprecated and will be removed in a future release.
"""
"""Return the definition of an external step for the user to take."""
flow_result = self._flow_result(
type=FlowResultType.EXTERNAL_STEP,
flow_id=self.flow_id,
@@ -805,10 +798,7 @@ class FlowHandler(Generic[_FlowContextT, _FlowResultT, _HandlerT]):
description_placeholders: Mapping[str, str] | None = None,
progress_task: asyncio.Task[Any] | None = None,
) -> _FlowResultT:
"""Show a progress message to the user, without user input allowed.
The step_id parameter is deprecated and will be removed in a future release.
"""
"""Show a progress message to the user, without user input allowed."""
if progress_task is None and not self.__no_progress_task_reported:
self.__no_progress_task_reported = True
cls = self.__class__
@@ -868,7 +858,6 @@ class FlowHandler(Generic[_FlowContextT, _FlowResultT, _HandlerT]):
"""Show a navigation menu to the user.
Options dict maps step_id => i18n label
The step_id parameter is deprecated and will be removed in a future release.
"""
flow_result = self._flow_result(
type=FlowResultType.MENU,

View File

@@ -35,7 +35,7 @@ class _BaseFlowManagerView(HomeAssistantView, Generic[_FlowManagerT]):
"""Convert result to JSON."""
if result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY:
data = result.copy()
data.pop("result")
assert "result" not in result
data.pop("data")
data.pop("context")
return data

View File

@@ -156,7 +156,7 @@ class _EventDeviceRegistryUpdatedData_Remove(TypedDict):
action: Literal["remove"]
device_id: str
device: DeviceEntry
device: dict[str, Any]
class _EventDeviceRegistryUpdatedData_Update(TypedDict):
@@ -1319,7 +1319,7 @@ class DeviceRegistry(BaseRegistry[dict[str, list[dict[str, Any]]]]):
self.hass.bus.async_fire_internal(
EVENT_DEVICE_REGISTRY_UPDATED,
_EventDeviceRegistryUpdatedData_Remove(
action="remove", device_id=device_id, device=device
action="remove", device_id=device_id, device=device.dict_repr
),
)
self.async_schedule_save()

View File

@@ -1103,13 +1103,13 @@ class EntityRegistry(BaseRegistry):
entities = async_entries_for_device(
self, event.data["device_id"], include_disabled_entities=True
)
removed_device = event.data["device"]
removed_device_dict = event.data["device"]
for entity in entities:
config_entry_id = entity.config_entry_id
if (
config_entry_id in removed_device.config_entries
config_entry_id in removed_device_dict["config_entries"]
and entity.config_subentry_id
in removed_device.config_entries_subentries[config_entry_id]
in removed_device_dict["config_entries_subentries"][config_entry_id]
):
self.async_remove(entity.entity_id)
else:

View File

@@ -38,7 +38,7 @@ habluetooth==4.0.1
hass-nabucasa==0.110.0
hassil==2.2.3
home-assistant-bluetooth==1.13.1
home-assistant-frontend==20250730.0
home-assistant-frontend==20250731.0
home-assistant-intents==2025.7.30
httpx==0.28.1
ifaddr==0.2.0
@@ -209,7 +209,6 @@ aiofiles>=24.1.0
# https://github.com/aio-libs/multidict/issues/1131
multidict>=6.4.2
# rpds-py > 0.25.0 requires cargo 1.84.0
# Stable Alpine current only ships cargo 1.83.0
# rpds-py frequently updates cargo causing build failures
# No wheels upstream available for armhf & armv7
rpds-py==0.24.0
rpds-py==0.26.0

10
requirements_all.txt generated
View File

@@ -247,7 +247,7 @@ aioelectricitymaps==0.4.0
aioemonitor==1.0.5
# homeassistant.components.esphome
aioesphomeapi==37.1.5
aioesphomeapi==37.2.0
# homeassistant.components.flo
aioflo==2021.11.0
@@ -1100,7 +1100,7 @@ greenwavereality==0.5.1
gridnet==5.0.1
# homeassistant.components.growatt_server
growattServer==1.6.0
growattServer==1.7.1
# homeassistant.components.google_sheets
gspread==5.5.0
@@ -1174,7 +1174,7 @@ hole==0.9.0
holidays==0.77
# homeassistant.components.frontend
home-assistant-frontend==20250730.0
home-assistant-frontend==20250731.0
# homeassistant.components.conversation
home-assistant-intents==2025.7.30
@@ -2666,7 +2666,7 @@ renault-api==0.3.1
renson-endura-delta==1.7.2
# homeassistant.components.reolink
reolink-aio==0.14.4
reolink-aio==0.14.5
# homeassistant.components.idteck_prox
rfk101py==0.0.1
@@ -3139,7 +3139,7 @@ wyoming==1.7.1
xbox-webapi==2.1.0
# homeassistant.components.xiaomi_ble
xiaomi-ble==1.1.0
xiaomi-ble==1.2.0
# homeassistant.components.knx
xknx==3.8.0

View File

@@ -235,7 +235,7 @@ aioelectricitymaps==0.4.0
aioemonitor==1.0.5
# homeassistant.components.esphome
aioesphomeapi==37.1.5
aioesphomeapi==37.2.0
# homeassistant.components.flo
aioflo==2021.11.0
@@ -961,7 +961,7 @@ greeneye_monitor==3.0.3
gridnet==5.0.1
# homeassistant.components.growatt_server
growattServer==1.6.0
growattServer==1.7.1
# homeassistant.components.google_sheets
gspread==5.5.0
@@ -1023,7 +1023,7 @@ hole==0.9.0
holidays==0.77
# homeassistant.components.frontend
home-assistant-frontend==20250730.0
home-assistant-frontend==20250731.0
# homeassistant.components.conversation
home-assistant-intents==2025.7.30
@@ -2212,7 +2212,7 @@ renault-api==0.3.1
renson-endura-delta==1.7.2
# homeassistant.components.reolink
reolink-aio==0.14.4
reolink-aio==0.14.5
# homeassistant.components.rflink
rflink==0.0.67
@@ -2592,7 +2592,7 @@ wyoming==1.7.1
xbox-webapi==2.1.0
# homeassistant.components.xiaomi_ble
xiaomi-ble==1.1.0
xiaomi-ble==1.2.0
# homeassistant.components.knx
xknx==3.8.0

View File

@@ -235,10 +235,9 @@ aiofiles>=24.1.0
# https://github.com/aio-libs/multidict/issues/1131
multidict>=6.4.2
# rpds-py > 0.25.0 requires cargo 1.84.0
# Stable Alpine current only ships cargo 1.83.0
# rpds-py frequently updates cargo causing build failures
# No wheels upstream available for armhf & armv7
rpds-py==0.24.0
rpds-py==0.26.0
"""
GENERATED_MESSAGE = (

View File

@@ -236,7 +236,6 @@ async def test_legacy_subscription_repair_flow_timeout(
"handler": "cloud",
"reason": "operation_took_too_long",
"description_placeholders": None,
"result": None,
}
assert issue_registry.async_get_issue(

View File

@@ -2485,3 +2485,36 @@ async def test_reconfig_name_conflict_overwrite(
)
is None
)
@pytest.mark.usefixtures("mock_setup_entry")
async def test_discovery_dhcp_no_probe_same_host_port_none(
hass: HomeAssistant, mock_client: APIClient
) -> None:
"""Test dhcp discovery does not probe when host matches and port is None."""
entry = MockConfigEntry(
domain=DOMAIN,
data={CONF_HOST: "192.168.43.183", CONF_PORT: 6053, CONF_PASSWORD: ""},
unique_id="11:22:33:44:55:aa",
)
entry.add_to_hass(hass)
# DHCP discovery with same MAC and host (WiFi device)
service_info = DhcpServiceInfo(
ip="192.168.43.183",
hostname="test8266",
macaddress="11:22:33:44:55:aa", # Same MAC as configured
)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_DHCP}, data=service_info
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured"
# Verify device_info was NOT called (no probing)
mock_client.device_info.assert_not_called()
# Host should remain unchanged
assert entry.data[CONF_HOST] == "192.168.43.183"

View File

@@ -15,7 +15,6 @@
# ---
# name: test_options[create_entry]
FlowResultSnapshot({
'result': True,
'type': <FlowResultType.CREATE_ENTRY: 'create_entry'>,
})
# ---

View File

@@ -39,7 +39,6 @@
# ---
# name: test_options[create_entry]
FlowResultSnapshot({
'result': True,
'type': <FlowResultType.CREATE_ENTRY: 'create_entry'>,
})
# ---

View File

@@ -471,7 +471,6 @@ async def test_mount_failed_repair_flow_error(
"flow_id": flow_id,
"handler": "hassio",
"reason": "apply_suggestion_fail",
"result": None,
"description_placeholders": None,
}

View File

@@ -13,6 +13,8 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.util import dt as dt_util
from tests.common import MockConfigEntry
async def test_firmware_update_coordinator_fetching(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
@@ -20,6 +22,8 @@ async def test_firmware_update_coordinator_fetching(
"""Test the firmware update coordinator loads manifests."""
session = async_get_clientsession(hass)
mock_config_entry = MockConfigEntry()
manifest = FirmwareManifest(
url=URL("https://example.org/firmware"),
html_url=URL("https://example.org/release_notes"),
@@ -35,7 +39,7 @@ async def test_firmware_update_coordinator_fetching(
return_value=mock_client,
):
coordinator = FirmwareUpdateCoordinator(
hass, session, "https://example.org/firmware"
hass, mock_config_entry, session, "https://example.org/firmware"
)
listener = Mock()

View File

@@ -143,6 +143,7 @@ def _mock_async_create_update_entity(
config_entry=config_entry,
update_coordinator=FirmwareUpdateCoordinator(
hass,
config_entry,
session,
TEST_FIRMWARE_RELEASES_URL,
),
@@ -593,6 +594,7 @@ async def test_update_entity_graceful_firmware_type_callback_errors(
config_entry=update_config_entry,
update_coordinator=FirmwareUpdateCoordinator(
hass,
update_config_entry,
session,
TEST_FIRMWARE_RELEASES_URL,
),

View File

@@ -211,7 +211,6 @@ async def test_options_flow(
)
assert create_result["type"] is FlowResultType.CREATE_ENTRY
assert create_result["result"] is True
assert config_entry.data == {
"firmware": "ezsp",

View File

@@ -406,7 +406,6 @@ async def test_firmware_options_flow(
)
assert create_result["type"] is FlowResultType.CREATE_ENTRY
assert create_result["result"] is True
assert config_entry.data == {
"firmware": fw_type.value,

View File

@@ -110,7 +110,6 @@ async def test_options_reconfigure(
CONF_CANDLE_LIGHT_MINUTES: DEFAULT_CANDLE_LIGHT + 1,
},
)
assert result["result"]
# The value of the "upcoming_shabbat_candle_lighting" sensor should be the new value
assert config_entry.options[CONF_CANDLE_LIGHT_MINUTES] == DEFAULT_CANDLE_LIGHT + 1

View File

@@ -30,5 +30,9 @@
"mandatory": true
}
}
},
{
"programId": 24000,
"program": "Ristretto"
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -43,6 +43,12 @@
'program': 'Fan plus',
'program_id': 13,
}),
dict({
'parameters': dict({
}),
'program': 'Ristretto',
'program_id': 24000,
}),
]),
})
# ---

View File

@@ -256,3 +256,18 @@ async def test_vacuum_sensor_states(
"""Test robot vacuum cleaner sensor state."""
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)
@pytest.mark.parametrize("load_device_file", ["fan_devices.json"])
@pytest.mark.parametrize("platforms", [(SENSOR_DOMAIN,)])
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_fan_hob_sensor_states(
hass: HomeAssistant,
mock_miele_client: MagicMock,
snapshot: SnapshotAssertion,
entity_registry: er.EntityRegistry,
setup_platform: None,
) -> None:
"""Test robot fan / hob sensor state."""
await snapshot_platform(hass, entity_registry, snapshot, setup_platform.entry_id)

View File

@@ -599,7 +599,6 @@ async def test_fix_issue_aborted(
"handler": "fake_integration",
"reason": "not_given",
"description_placeholders": None,
"result": None,
}
await ws_client.send_json({"id": 4, "type": "repairs/list_issues"})

View File

@@ -132,6 +132,7 @@ async def setup_weather(
{
"platform": "template",
"name": "test",
"unique_id": "abc123",
"attribution_template": "{{ states('sensor.attribution') }}",
"condition_template": "sunny",
"temperature_template": "{{ states('sensor.temperature') | float }}",

View File

@@ -1652,7 +1652,7 @@ async def test_removing_config_entries(
assert update_events[4].data == {
"action": "remove",
"device_id": entry3.id,
"device": entry3,
"device": entry3.dict_repr,
}
@@ -1725,12 +1725,12 @@ async def test_deleted_device_removing_config_entries(
assert update_events[3].data == {
"action": "remove",
"device_id": entry.id,
"device": entry2,
"device": entry2.dict_repr,
}
assert update_events[4].data == {
"action": "remove",
"device_id": entry3.id,
"device": entry3,
"device": entry3.dict_repr,
}
device_registry.async_clear_config_entry(config_entry_1.entry_id)
@@ -1976,7 +1976,7 @@ async def test_removing_config_subentries(
assert update_events[7].data == {
"action": "remove",
"device_id": entry.id,
"device": entry,
"device": entry.dict_repr,
}
@@ -2106,7 +2106,7 @@ async def test_deleted_device_removing_config_subentries(
assert update_events[4].data == {
"action": "remove",
"device_id": entry.id,
"device": entry4,
"device": entry4.dict_repr,
}
device_registry.async_clear_config_subentry(config_entry_1.entry_id, None)
@@ -2930,7 +2930,7 @@ async def test_update_remove_config_entries(
assert update_events[6].data == {
"action": "remove",
"device_id": entry3.id,
"device": entry3,
"device": entry3.dict_repr,
}
@@ -3208,7 +3208,7 @@ async def test_update_remove_config_subentries(
assert update_events[7].data == {
"action": "remove",
"device_id": entry_id,
"device": entry_before_remove,
"device": entry_before_remove.dict_repr,
}
@@ -3551,7 +3551,7 @@ async def test_restore_device(
assert update_events[2].data == {
"action": "remove",
"device_id": entry.id,
"device": entry,
"device": entry.dict_repr,
}
assert update_events[3].data == {
"action": "create",
@@ -3874,7 +3874,7 @@ async def test_restore_shared_device(
assert update_events[3].data == {
"action": "remove",
"device_id": entry.id,
"device": updated_device,
"device": updated_device.dict_repr,
}
assert update_events[4].data == {
"action": "create",
@@ -3883,7 +3883,7 @@ async def test_restore_shared_device(
assert update_events[5].data == {
"action": "remove",
"device_id": entry.id,
"device": entry2,
"device": entry2.dict_repr,
}
assert update_events[6].data == {
"action": "create",

View File

@@ -155,19 +155,23 @@ async def test_form_shows_with_added_suggested_values(manager: MockFlowManager)
async def async_step_init(self, user_input=None):
data_schema = self.add_suggested_values_to_schema(
schema,
{
"username": "doej",
"password": "verySecret1",
"section_1": {"full_name": "John Doe"},
},
user_input,
)
return self.async_show_form(
step_id="init",
data_schema=data_schema,
)
form = await manager.async_init("test")
form = await manager.async_init(
"test",
data={
"username": "doej",
"password": "verySecret1",
"section_1": {"full_name": "John Doe"},
},
)
assert form["type"] == data_entry_flow.FlowResultType.FORM
assert form["data_schema"].schema is not schema.schema
assert form["data_schema"].schema == schema.schema
markers = list(form["data_schema"].schema)
assert len(markers) == 3
@@ -187,6 +191,32 @@ async def test_form_shows_with_added_suggested_values(manager: MockFlowManager)
assert section_markers[0] == "full_name"
assert section_markers[0].description == {"suggested_value": "John Doe"}
# Test again without suggested values to make sure we're not mutating the schema
form = await manager.async_init(
"test",
)
assert form["type"] == data_entry_flow.FlowResultType.FORM
assert form["data_schema"].schema is not schema.schema
assert form["data_schema"].schema == schema.schema
markers = list(form["data_schema"].schema)
assert len(markers) == 3
assert markers[0] == "username"
assert markers[0].description is None
assert markers[1] == "password"
assert markers[1].description is None
assert markers[2] == "section_1"
section_validator = form["data_schema"].schema["section_1"]
assert isinstance(section_validator, data_entry_flow.section)
# The section class was not replaced
assert section_validator is schema.schema["section_1"]
# The section schema was not replaced
assert section_validator.schema is schema.schema["section_1"].schema
section_markers = list(section_validator.schema.schema)
assert len(section_markers) == 1
assert section_markers[0] == "full_name"
# This is a known bug, which needs to be fixed
assert section_markers[0].description == {"suggested_value": "John Doe"}
async def test_abort_removes_instance(manager: MockFlowManager) -> None:
"""Test that abort removes the flow from progress."""