mirror of
https://github.com/home-assistant/core.git
synced 2025-08-31 02:11:32 +02:00
Merge branch 'dev' into copilot/fix-149693
This commit is contained in:
4
.github/workflows/wheels.yml
vendored
4
.github/workflows/wheels.yml
vendored
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -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,
|
||||
)
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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"
|
||||
],
|
||||
|
@@ -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"]
|
||||
}
|
||||
|
@@ -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"]
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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,
|
||||
),
|
||||
|
@@ -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,
|
||||
),
|
||||
|
@@ -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)}},
|
||||
)
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
)
|
||||
|
||||
|
||||
|
@@ -203,7 +203,7 @@ async def get_programs(call: ServiceCall) -> ServiceResponse:
|
||||
else {}
|
||||
),
|
||||
}
|
||||
if item["parameters"]
|
||||
if item.get("parameters")
|
||||
else {}
|
||||
),
|
||||
}
|
||||
|
@@ -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)",
|
||||
|
@@ -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.",
|
||||
|
@@ -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"]
|
||||
}
|
||||
|
@@ -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
|
||||
|
||||
|
||||
|
@@ -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 haven’t 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 select’s current value.",
|
||||
"select_option": "Defines actions to run when an `option` from the `options` list is selected. Receives variable `option`.",
|
||||
"options": "Template for the select’s 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%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@@ -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,
|
||||
|
@@ -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"]
|
||||
}
|
||||
|
@@ -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(
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
@@ -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()
|
||||
|
@@ -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:
|
||||
|
@@ -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
10
requirements_all.txt
generated
@@ -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
|
||||
|
10
requirements_test_all.txt
generated
10
requirements_test_all.txt
generated
@@ -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
|
||||
|
@@ -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 = (
|
||||
|
@@ -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(
|
||||
|
@@ -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"
|
||||
|
@@ -15,7 +15,6 @@
|
||||
# ---
|
||||
# name: test_options[create_entry]
|
||||
FlowResultSnapshot({
|
||||
'result': True,
|
||||
'type': <FlowResultType.CREATE_ENTRY: 'create_entry'>,
|
||||
})
|
||||
# ---
|
||||
|
@@ -39,7 +39,6 @@
|
||||
# ---
|
||||
# name: test_options[create_entry]
|
||||
FlowResultSnapshot({
|
||||
'result': True,
|
||||
'type': <FlowResultType.CREATE_ENTRY: 'create_entry'>,
|
||||
})
|
||||
# ---
|
||||
|
@@ -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,
|
||||
}
|
||||
|
||||
|
@@ -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()
|
||||
|
@@ -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,
|
||||
),
|
||||
|
@@ -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",
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
@@ -30,5 +30,9 @@
|
||||
"mandatory": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"programId": 24000,
|
||||
"program": "Ristretto"
|
||||
}
|
||||
]
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -43,6 +43,12 @@
|
||||
'program': 'Fan plus',
|
||||
'program_id': 13,
|
||||
}),
|
||||
dict({
|
||||
'parameters': dict({
|
||||
}),
|
||||
'program': 'Ristretto',
|
||||
'program_id': 24000,
|
||||
}),
|
||||
]),
|
||||
})
|
||||
# ---
|
||||
|
@@ -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)
|
||||
|
@@ -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"})
|
||||
|
@@ -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 }}",
|
||||
|
@@ -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",
|
||||
|
@@ -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."""
|
||||
|
Reference in New Issue
Block a user