Skip to content

Commit 0cda883

Browse files
authored
2 parents 220c233 + ae58e63 commit 0cda883

File tree

31 files changed

+500
-56
lines changed

31 files changed

+500
-56
lines changed

homeassistant/components/bmw_connected_drive/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
"documentation": "https://www.home-assistant.io/integrations/bmw_connected_drive",
77
"iot_class": "cloud_polling",
88
"loggers": ["bimmer_connected"],
9-
"requirements": ["bimmer-connected[china]==0.17.2"]
9+
"requirements": ["bimmer-connected[china]==0.17.3"]
1010
}

homeassistant/components/conversation/default_agent.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
)
3636
from hassil.string_matcher import UnmatchedRangeEntity, UnmatchedTextEntity
3737
from hassil.trie import Trie
38-
from hassil.util import merge_dict
38+
from hassil.util import merge_dict, remove_punctuation
3939
from home_assistant_intents import (
4040
ErrorKey,
4141
FuzzyConfig,
@@ -327,12 +327,10 @@ async def async_recognize_intent(
327327

328328
if self._exposed_names_trie is not None:
329329
# Filter by input string
330-
text_lower = user_input.text.strip().lower()
330+
text = remove_punctuation(user_input.text).strip().lower()
331331
slot_lists["name"] = TextSlotList(
332332
name="name",
333-
values=[
334-
result[2] for result in self._exposed_names_trie.find(text_lower)
335-
],
333+
values=[result[2] for result in self._exposed_names_trie.find(text)],
336334
)
337335

338336
start = time.monotonic()
@@ -1263,7 +1261,7 @@ async def _make_slot_lists(self) -> dict[str, SlotList]:
12631261
name_list = TextSlotList.from_tuples(exposed_entity_names, allow_template=False)
12641262
for name_value in name_list.values:
12651263
assert isinstance(name_value.text_in, TextChunk)
1266-
name_text = name_value.text_in.text.strip().lower()
1264+
name_text = remove_punctuation(name_value.text_in.text).strip().lower()
12671265
self._exposed_names_trie.insert(name_text, name_value)
12681266

12691267
self._slot_lists = {

homeassistant/components/fan/strings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
"toggle": "[%key:common::device_automation::action_type::toggle%]",
1515
"turn_on": "[%key:common::device_automation::action_type::turn_on%]",
1616
"turn_off": "[%key:common::device_automation::action_type::turn_off%]"
17+
},
18+
"extra_fields": {
19+
"for": "[%key:common::device_automation::extra_fields::for%]"
1720
}
1821
},
1922
"entity_component": {

homeassistant/components/fritz/strings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,8 @@
183183
"description": "Sets a new password for the guest Wi-Fi. The password must be between 8 and 63 characters long. If no additional parameter is set, the password will be auto-generated with a length of 12 characters.",
184184
"fields": {
185185
"device_id": {
186-
"name": "Fritz!Box Device",
187-
"description": "Select the Fritz!Box to configure."
186+
"name": "FRITZ!Box Device",
187+
"description": "Select the FRITZ!Box to configure."
188188
},
189189
"password": {
190190
"name": "[%key:common::config_flow::data::password%]",

homeassistant/components/frontend/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@
2020
"documentation": "https://www.home-assistant.io/integrations/frontend",
2121
"integration_type": "system",
2222
"quality_scale": "internal",
23-
"requirements": ["home-assistant-frontend==20250903.2"]
23+
"requirements": ["home-assistant-frontend==20250903.3"]
2424
}

homeassistant/components/hassio/ingress.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,9 +303,9 @@ async def _websocket_forward(
303303
elif msg.type is aiohttp.WSMsgType.BINARY:
304304
await ws_to.send_bytes(msg.data)
305305
elif msg.type is aiohttp.WSMsgType.PING:
306-
await ws_to.ping()
306+
await ws_to.ping(msg.data)
307307
elif msg.type is aiohttp.WSMsgType.PONG:
308-
await ws_to.pong()
308+
await ws_to.pong(msg.data)
309309
elif ws_to.closed:
310310
await ws_to.close(code=ws_to.close_code, message=msg.extra) # type: ignore[arg-type]
311311
except RuntimeError:

homeassistant/components/hue/config_flow.py

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import aiohttp
1010
from aiohue import LinkButtonNotPressed, create_app_key
1111
from aiohue.discovery import DiscoveredHueBridge, discover_bridge, discover_nupnp
12+
from aiohue.errors import AiohueException
1213
from aiohue.util import normalize_bridge_id
14+
from aiohue.v2 import HueBridgeV2
1315
import slugify as unicode_slug
1416
import voluptuous as vol
1517

@@ -40,6 +42,9 @@
4042
HUE_IGNORED_BRIDGE_NAMES = ["Home Assistant Bridge", "Espalexa"]
4143
HUE_MANUAL_BRIDGE_ID = "manual"
4244

45+
BSB002_MODEL_ID = "BSB002"
46+
BSB003_MODEL_ID = "BSB003"
47+
4348

4449
class HueFlowHandler(ConfigFlow, domain=DOMAIN):
4550
"""Handle a Hue config flow."""
@@ -74,7 +79,14 @@ async def _get_bridge(
7479
"""Return a DiscoveredHueBridge object."""
7580
try:
7681
bridge = await discover_bridge(
77-
host, websession=aiohttp_client.async_get_clientsession(self.hass)
82+
host,
83+
websession=aiohttp_client.async_get_clientsession(
84+
# NOTE: we disable SSL verification for now due to the fact that the (BSB003)
85+
# Hue bridge uses a certificate from a on-bridge root authority.
86+
# We need to specifically handle this case in a follow-up update.
87+
self.hass,
88+
verify_ssl=False,
89+
),
7890
)
7991
except aiohttp.ClientError as err:
8092
LOGGER.warning(
@@ -110,7 +122,9 @@ async def async_step_init(
110122
try:
111123
async with asyncio.timeout(5):
112124
bridges = await discover_nupnp(
113-
websession=aiohttp_client.async_get_clientsession(self.hass)
125+
websession=aiohttp_client.async_get_clientsession(
126+
self.hass, verify_ssl=False
127+
)
114128
)
115129
except TimeoutError:
116130
bridges = []
@@ -178,7 +192,9 @@ async def async_step_link(
178192
app_key = await create_app_key(
179193
bridge.host,
180194
f"home-assistant#{device_name}",
181-
websession=aiohttp_client.async_get_clientsession(self.hass),
195+
websession=aiohttp_client.async_get_clientsession(
196+
self.hass, verify_ssl=False
197+
),
182198
)
183199
except LinkButtonNotPressed:
184200
errors["base"] = "register_failed"
@@ -228,14 +244,21 @@ async def async_step_zeroconf(
228244
self._abort_if_unique_id_configured(
229245
updates={CONF_HOST: discovery_info.host}, reload_on_update=True
230246
)
231-
232247
# we need to query the other capabilities too
233248
bridge = await self._get_bridge(
234249
discovery_info.host, discovery_info.properties["bridgeid"]
235250
)
236251
if bridge is None:
237252
return self.async_abort(reason="cannot_connect")
238253
self.bridge = bridge
254+
if (
255+
bridge.supports_v2
256+
and discovery_info.properties.get("modelid") == BSB003_MODEL_ID
257+
):
258+
# try to handle migration of BSB002 --> BSB003
259+
if await self._check_migrated_bridge(bridge):
260+
return self.async_abort(reason="migrated_bridge")
261+
239262
return await self.async_step_link()
240263

241264
async def async_step_homekit(
@@ -272,6 +295,55 @@ async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResu
272295
self.bridge = bridge
273296
return await self.async_step_link()
274297

298+
async def _check_migrated_bridge(self, bridge: DiscoveredHueBridge) -> bool:
299+
"""Check if the discovered bridge is a migrated bridge."""
300+
# Try to handle migration of BSB002 --> BSB003.
301+
# Once we detect a BSB003 bridge on the network which has not yet been
302+
# configured in HA (otherwise we would have had a unique id match),
303+
# we check if we have any existing (BSB002) entries and if we can connect to the
304+
# new bridge with our previously stored api key.
305+
# If that succeeds, we migrate the entry to the new bridge.
306+
for conf_entry in self.hass.config_entries.async_entries(
307+
DOMAIN, include_ignore=False, include_disabled=False
308+
):
309+
if conf_entry.data[CONF_API_VERSION] != 2:
310+
continue
311+
if conf_entry.data[CONF_HOST] == bridge.host:
312+
continue
313+
# found an existing (BSB002) bridge entry,
314+
# check if we can connect to the new BSB003 bridge using the old credentials
315+
api = HueBridgeV2(bridge.host, conf_entry.data[CONF_API_KEY])
316+
try:
317+
await api.fetch_full_state()
318+
except (AiohueException, aiohttp.ClientError):
319+
continue
320+
old_bridge_id = conf_entry.unique_id
321+
assert old_bridge_id is not None
322+
# found a matching entry, migrate it
323+
self.hass.config_entries.async_update_entry(
324+
conf_entry,
325+
data={
326+
**conf_entry.data,
327+
CONF_HOST: bridge.host,
328+
},
329+
unique_id=bridge.id,
330+
)
331+
# also update the bridge device
332+
dev_reg = dr.async_get(self.hass)
333+
if bridge_device := dev_reg.async_get_device(
334+
identifiers={(DOMAIN, old_bridge_id)}
335+
):
336+
dev_reg.async_update_device(
337+
bridge_device.id,
338+
# overwrite identifiers with new bridge id
339+
new_identifiers={(DOMAIN, bridge.id)},
340+
# overwrite mac addresses with empty set to drop the old (incorrect) addresses
341+
# this will be auto corrected once the integration is loaded
342+
new_connections=set(),
343+
)
344+
return True
345+
return False
346+
275347

276348
class HueV1OptionsFlowHandler(OptionsFlow):
277349
"""Handle Hue options for V1 implementation."""

homeassistant/components/hue/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
"integration_type": "hub",
1111
"iot_class": "local_push",
1212
"loggers": ["aiohue"],
13-
"requirements": ["aiohue==4.7.4"],
13+
"requirements": ["aiohue==4.7.5"],
1414
"zeroconf": ["_hue._tcp.local."]
1515
}

homeassistant/components/imeon_inverter/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"integration_type": "device",
88
"iot_class": "local_polling",
99
"quality_scale": "bronze",
10-
"requirements": ["imeon_inverter_api==0.3.14"],
10+
"requirements": ["imeon_inverter_api==0.3.16"],
1111
"ssdp": [
1212
{
1313
"manufacturer": "IMEON",

homeassistant/components/intent/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response
615615
intent_result = await intent.async_handle(
616616
hass, DOMAIN, intent_name, slots, "", self.context(request)
617617
)
618-
except intent.IntentHandleError as err:
618+
except (intent.IntentHandleError, intent.MatchFailedError) as err:
619619
intent_result = intent.IntentResponse(language=language)
620620
intent_result.async_set_speech(str(err))
621621

0 commit comments

Comments
 (0)