Skip to content

Commit f3b9bda

Browse files
authored
2 parents 3499ed7 + 3f3aaa2 commit f3b9bda

File tree

37 files changed

+451
-150
lines changed

37 files changed

+451
-150
lines changed

homeassistant/components/asuswrt/bridge.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,17 @@ def get_bridge(
120120

121121
def __init__(self, host: str) -> None:
122122
"""Initialize Bridge."""
123+
self._configuration_url = f"http://{host}"
123124
self._host = host
124125
self._firmware: str | None = None
125126
self._label_mac: str | None = None
126127
self._model: str | None = None
127128

129+
@property
130+
def configuration_url(self) -> str:
131+
"""Return configuration URL."""
132+
return self._configuration_url
133+
128134
@property
129135
def host(self) -> str:
130136
"""Return hostname."""
@@ -359,6 +365,7 @@ async def async_connect(self) -> None:
359365
# get main router properties
360366
if mac := _identity.mac:
361367
self._label_mac = format_mac(mac)
368+
self._configuration_url = self._api.webpanel
362369
self._firmware = str(_identity.firmware)
363370
self._model = _identity.model
364371

homeassistant/components/asuswrt/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77
"integration_type": "hub",
88
"iot_class": "local_polling",
99
"loggers": ["aioasuswrt", "asusrouter", "asyncssh"],
10-
"requirements": ["aioasuswrt==1.4.0", "asusrouter==1.20.1"]
10+
"requirements": ["aioasuswrt==1.4.0", "asusrouter==1.21.0"]
1111
}

homeassistant/components/asuswrt/router.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,11 +388,11 @@ def update_options(self, new_options: Mapping[str, Any]) -> bool:
388388
def device_info(self) -> DeviceInfo:
389389
"""Return the device information."""
390390
info = DeviceInfo(
391+
configuration_url=self._api.configuration_url,
391392
identifiers={(DOMAIN, self._entry.unique_id or "AsusWRT")},
392393
name=self.host,
393394
model=self._api.model or "Asus Router",
394395
manufacturer="Asus",
395-
configuration_url=f"http://{self.host}",
396396
)
397397
if self._api.firmware:
398398
info["sw_version"] = self._api.firmware

homeassistant/components/auth/login_flow.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,11 @@
9292
from homeassistant.components.http.data_validator import RequestDataValidator
9393
from homeassistant.components.http.view import HomeAssistantView
9494
from homeassistant.core import HomeAssistant, callback
95-
from homeassistant.helpers.network import is_cloud_connection
95+
from homeassistant.helpers.network import (
96+
NoURLAvailableError,
97+
get_url,
98+
is_cloud_connection,
99+
)
96100
from homeassistant.util.network import is_local
97101

98102
from . import indieauth
@@ -125,11 +129,18 @@ class WellKnownOAuthInfoView(HomeAssistantView):
125129

126130
async def get(self, request: web.Request) -> web.Response:
127131
"""Return the well known OAuth2 authorization info."""
132+
hass = request.app[KEY_HASS]
133+
# Some applications require absolute urls, so we prefer using the
134+
# current requests url if possible, with fallback to a relative url.
135+
try:
136+
url_prefix = get_url(hass, require_current_request=True)
137+
except NoURLAvailableError:
138+
url_prefix = ""
128139
return self.json(
129140
{
130-
"authorization_endpoint": "/auth/authorize",
131-
"token_endpoint": "/auth/token",
132-
"revocation_endpoint": "/auth/revoke",
141+
"authorization_endpoint": f"{url_prefix}/auth/authorize",
142+
"token_endpoint": f"{url_prefix}/auth/token",
143+
"revocation_endpoint": f"{url_prefix}/auth/revoke",
133144
"response_types_supported": ["code"],
134145
"service_documentation": (
135146
"https://developers.home-assistant.io/docs/auth_api"

homeassistant/components/bluetooth/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"bleak==1.0.1",
1919
"bleak-retry-connector==4.4.3",
2020
"bluetooth-adapters==2.1.0",
21-
"bluetooth-auto-recovery==1.5.2",
21+
"bluetooth-auto-recovery==1.5.3",
2222
"bluetooth-data-tools==1.28.2",
2323
"dbus-fast==2.44.3",
2424
"habluetooth==5.6.4"

homeassistant/components/emoncms/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
"config_flow": true,
66
"documentation": "https://www.home-assistant.io/integrations/emoncms",
77
"iot_class": "local_polling",
8-
"requirements": ["pyemoncms==0.1.2"]
8+
"requirements": ["pyemoncms==0.1.3"]
99
}

homeassistant/components/emoncms_history/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
"documentation": "https://www.home-assistant.io/integrations/emoncms_history",
66
"iot_class": "local_polling",
77
"quality_scale": "legacy",
8-
"requirements": ["pyemoncms==0.1.2"]
8+
"requirements": ["pyemoncms==0.1.3"]
99
}

homeassistant/components/habitica/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77
"iot_class": "cloud_polling",
88
"loggers": ["habiticalib"],
99
"quality_scale": "platinum",
10-
"requirements": ["habiticalib==0.4.3"]
10+
"requirements": ["habiticalib==0.4.5"]
1111
}

homeassistant/components/holiday/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
"config_flow": true,
66
"documentation": "https://www.home-assistant.io/integrations/holiday",
77
"iot_class": "local_polling",
8-
"requirements": ["holidays==0.79", "babel==2.15.0"]
8+
"requirements": ["holidays==0.81", "babel==2.15.0"]
99
}

homeassistant/components/homekit_controller/connection.py

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@
5757

5858
RETRY_INTERVAL = 60 # seconds
5959
MAX_POLL_FAILURES_TO_DECLARE_UNAVAILABLE = 3
60-
60+
# HomeKit accessories have varying limits on how many characteristics
61+
# they can handle per request. Since we don't know each device's specific limit,
62+
# we batch requests to a conservative size to avoid overwhelming any device.
63+
MAX_CHARACTERISTICS_PER_REQUEST = 49
6164

6265
BLE_AVAILABILITY_CHECK_INTERVAL = 1800 # seconds
6366

@@ -326,16 +329,20 @@ async def async_setup(self) -> None:
326329
)
327330
entry.async_on_unload(self._async_cancel_subscription_timer)
328331

332+
if transport != Transport.BLE:
333+
# Although async_populate_accessories_state fetched the accessory database,
334+
# the /accessories endpoint may return cached values from the accessory's
335+
# perspective. For example, Ecobee thermostats may report stale temperature
336+
# values (like 100°C) in their /accessories response after restarting.
337+
# We need to explicitly poll characteristics to get fresh sensor readings
338+
# before processing the entity map and creating devices.
339+
# Use poll_all=True since entities haven't registered their characteristics yet.
340+
await self.async_update(poll_all=True)
341+
329342
await self.async_process_entity_map()
330343

331344
if transport != Transport.BLE:
332-
# When Home Assistant starts, we restore the accessory map from storage
333-
# which contains characteristic values from when HA was last running.
334-
# These values are stale and may be incorrect (e.g., Ecobee thermostats
335-
# report 100°C when restarting). We need to poll for fresh values before
336-
# creating entities. Use poll_all=True since entities haven't registered
337-
# their characteristics yet.
338-
await self.async_update(poll_all=True)
345+
# Start regular polling after entity map is processed
339346
self._async_start_polling()
340347

341348
# If everything is up to date, we can create the entities
@@ -938,20 +945,26 @@ async def async_update(
938945
async with self._polling_lock:
939946
_LOGGER.debug("Starting HomeKit device update: %s", self.unique_id)
940947

941-
try:
942-
new_values_dict = await self.get_characteristics(to_poll)
943-
except AccessoryNotFoundError:
944-
# Not only did the connection fail, but also the accessory is not
945-
# visible on the network.
946-
self.async_set_available_state(False)
947-
return
948-
except (AccessoryDisconnectedError, EncryptionError):
949-
# Temporary connection failure. Device may still available but our
950-
# connection was dropped or we are reconnecting
951-
self._poll_failures += 1
952-
if self._poll_failures >= MAX_POLL_FAILURES_TO_DECLARE_UNAVAILABLE:
948+
new_values_dict: dict[tuple[int, int], dict[str, Any]] = {}
949+
to_poll_list = list(to_poll)
950+
951+
for i in range(0, len(to_poll_list), MAX_CHARACTERISTICS_PER_REQUEST):
952+
batch = to_poll_list[i : i + MAX_CHARACTERISTICS_PER_REQUEST]
953+
try:
954+
batch_values = await self.get_characteristics(batch)
955+
new_values_dict.update(batch_values)
956+
except AccessoryNotFoundError:
957+
# Not only did the connection fail, but also the accessory is not
958+
# visible on the network.
953959
self.async_set_available_state(False)
954-
return
960+
return
961+
except (AccessoryDisconnectedError, EncryptionError):
962+
# Temporary connection failure. Device may still available but our
963+
# connection was dropped or we are reconnecting
964+
self._poll_failures += 1
965+
if self._poll_failures >= MAX_POLL_FAILURES_TO_DECLARE_UNAVAILABLE:
966+
self.async_set_available_state(False)
967+
return
955968

956969
self._poll_failures = 0
957970
self.process_new_events(new_values_dict)

0 commit comments

Comments
 (0)