Skip to content

Commit

Permalink
Merge branch 'dev' into ecobee-deprecate-aux-heat
Browse files Browse the repository at this point in the history
  • Loading branch information
bjpetit committed May 7, 2024
2 parents cfc78d9 + 5db8082 commit 8f25ede
Show file tree
Hide file tree
Showing 423 changed files with 6,518 additions and 4,850 deletions.
2 changes: 1 addition & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ omit =
homeassistant/components/alarmdecoder/sensor.py
homeassistant/components/alpha_vantage/sensor.py
homeassistant/components/amazon_polly/*
homeassistant/components/ambiclimate/climate.py
homeassistant/components/ambient_station/__init__.py
homeassistant/components/ambient_station/binary_sensor.py
homeassistant/components/ambient_station/entity.py
Expand Down Expand Up @@ -519,6 +518,7 @@ omit =
homeassistant/components/guardian/util.py
homeassistant/components/guardian/valve.py
homeassistant/components/habitica/__init__.py
homeassistant/components/habitica/coordinator.py
homeassistant/components/habitica/sensor.py
homeassistant/components/harman_kardon_avr/media_player.py
homeassistant/components/harmony/data.py
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.2
rev: v0.4.3
hooks:
- id: ruff
args:
Expand Down
1 change: 0 additions & 1 deletion .strict-typing
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ homeassistant.components.alexa.*
homeassistant.components.alpha_vantage.*
homeassistant.components.amazon_polly.*
homeassistant.components.amberelectric.*
homeassistant.components.ambiclimate.*
homeassistant.components.ambient_network.*
homeassistant.components.ambient_station.*
homeassistant.components.amcrest.*
Expand Down
4 changes: 2 additions & 2 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ build.json @home-assistant/supervisor
/tests/components/alexa/ @home-assistant/cloud @ochlocracy @jbouwh
/homeassistant/components/amberelectric/ @madpilot
/tests/components/amberelectric/ @madpilot
/homeassistant/components/ambiclimate/ @danielhiversen
/tests/components/ambiclimate/ @danielhiversen
/homeassistant/components/ambient_network/ @thomaskistler
/tests/components/ambient_network/ @thomaskistler
/homeassistant/components/ambient_station/ @bachya
Expand Down Expand Up @@ -692,6 +690,8 @@ build.json @home-assistant/supervisor
/homeassistant/components/iqvia/ @bachya
/tests/components/iqvia/ @bachya
/homeassistant/components/irish_rail_transport/ @ttroy50
/homeassistant/components/isal/ @bdraco
/tests/components/isal/ @bdraco
/homeassistant/components/islamic_prayer_times/ @engrbm87 @cpfair
/tests/components/islamic_prayer_times/ @engrbm87 @cpfair
/homeassistant/components/iss/ @DurgNomis-drol
Expand Down
41 changes: 28 additions & 13 deletions homeassistant/auth/auth_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import hmac
import itertools
from logging import getLogger
import time
from typing import Any

from homeassistant.core import HomeAssistant, callback
Expand Down Expand Up @@ -62,6 +63,7 @@ def __init__(self, hass: HomeAssistant) -> None:
self._store = Store[dict[str, list[dict[str, Any]]]](
hass, STORAGE_VERSION, STORAGE_KEY, private=True, atomic_writes=True
)
self._token_id_to_user_id: dict[str, str] = {}

async def async_get_groups(self) -> list[models.Group]:
"""Retrieve all users."""
Expand Down Expand Up @@ -135,7 +137,10 @@ async def async_link_user(

async def async_remove_user(self, user: models.User) -> None:
"""Remove a user."""
self._users.pop(user.id)
user = self._users.pop(user.id)
for refresh_token_id in user.refresh_tokens:
del self._token_id_to_user_id[refresh_token_id]
user.refresh_tokens.clear()
self._async_schedule_save()

async def async_update_user(
Expand Down Expand Up @@ -218,27 +223,27 @@ async def async_create_refresh_token(
kwargs["client_icon"] = client_icon

refresh_token = models.RefreshToken(**kwargs)
user.refresh_tokens[refresh_token.id] = refresh_token
token_id = refresh_token.id
user.refresh_tokens[token_id] = refresh_token
self._token_id_to_user_id[token_id] = user.id

self._async_schedule_save()
return refresh_token

@callback
def async_remove_refresh_token(self, refresh_token: models.RefreshToken) -> None:
"""Remove a refresh token."""
for user in self._users.values():
if user.refresh_tokens.pop(refresh_token.id, None):
self._async_schedule_save()
break
refresh_token_id = refresh_token.id
if user_id := self._token_id_to_user_id.get(refresh_token_id):
del self._users[user_id].refresh_tokens[refresh_token_id]
del self._token_id_to_user_id[refresh_token_id]
self._async_schedule_save()

@callback
def async_get_refresh_token(self, token_id: str) -> models.RefreshToken | None:
"""Get refresh token by id."""
for user in self._users.values():
refresh_token = user.refresh_tokens.get(token_id)
if refresh_token is not None:
return refresh_token

if user_id := self._token_id_to_user_id.get(token_id):
return self._users[user_id].refresh_tokens.get(token_id)
return None

@callback
Expand Down Expand Up @@ -290,7 +295,7 @@ async def async_load(self) -> None: # noqa: C901
perm_lookup = PermissionLookup(ent_reg, dev_reg)
self._perm_lookup = perm_lookup

now_ts = dt_util.utcnow().timestamp()
now_ts = time.time()

if data is None or not isinstance(data, dict):
self._set_defaults()
Expand Down Expand Up @@ -478,9 +483,18 @@ async def async_load(self) -> None: # noqa: C901

self._groups = groups
self._users = users

self._build_token_id_to_user_id()
self._async_schedule_save(INITIAL_LOAD_SAVE_DELAY)

@callback
def _build_token_id_to_user_id(self) -> None:
"""Build a map of token id to user id."""
self._token_id_to_user_id = {
token_id: user_id
for user_id, user in self._users.items()
for token_id in user.refresh_tokens
}

@callback
def _async_schedule_save(self, delay: float = DEFAULT_SAVE_DELAY) -> None:
"""Save users."""
Expand Down Expand Up @@ -574,6 +588,7 @@ def _set_defaults(self) -> None:
read_only_group = _system_read_only_group()
groups[read_only_group.id] = read_only_group
self._groups = groups
self._build_token_id_to_user_id()


def _system_admin_group() -> models.Group:
Expand Down
12 changes: 6 additions & 6 deletions homeassistant/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
template,
translation,
)
from .helpers.dispatcher import async_dispatcher_send
from .helpers.dispatcher import async_dispatcher_send_internal
from .helpers.storage import get_internal_store_manager
from .helpers.system_info import async_get_system_info
from .helpers.typing import ConfigType
Expand Down Expand Up @@ -680,7 +680,7 @@ def _async_watch(self) -> None:

if remaining_with_setup_started:
_LOGGER.debug("Integration remaining: %s", remaining_with_setup_started)
elif waiting_tasks := self._hass._active_tasks: # pylint: disable=protected-access
elif waiting_tasks := self._hass._active_tasks: # noqa: SLF001
_LOGGER.debug("Waiting on tasks: %s", waiting_tasks)
self._async_dispatch(remaining_with_setup_started)
if (
Expand All @@ -700,7 +700,7 @@ def _async_watch(self) -> None:
def _async_dispatch(self, remaining_with_setup_started: dict[str, float]) -> None:
"""Dispatch the signal."""
if remaining_with_setup_started or not self._previous_was_empty:
async_dispatcher_send(
async_dispatcher_send_internal(
self._hass, SIGNAL_BOOTSTRAP_INTEGRATIONS, remaining_with_setup_started
)
self._previous_was_empty = not remaining_with_setup_started
Expand Down Expand Up @@ -984,7 +984,7 @@ async def _async_set_up_integrations(
except TimeoutError:
_LOGGER.warning(
"Setup timed out for stage 1 waiting on %s - moving forward",
hass._active_tasks, # pylint: disable=protected-access
hass._active_tasks, # noqa: SLF001
)

# Add after dependencies when setting up stage 2 domains
Expand All @@ -1000,7 +1000,7 @@ async def _async_set_up_integrations(
except TimeoutError:
_LOGGER.warning(
"Setup timed out for stage 2 waiting on %s - moving forward",
hass._active_tasks, # pylint: disable=protected-access
hass._active_tasks, # noqa: SLF001
)

# Wrap up startup
Expand All @@ -1011,7 +1011,7 @@ async def _async_set_up_integrations(
except TimeoutError:
_LOGGER.warning(
"Setup timed out for bootstrap waiting on %s - moving forward",
hass._active_tasks, # pylint: disable=protected-access
hass._active_tasks, # noqa: SLF001
)

watcher.async_stop()
Expand Down
25 changes: 9 additions & 16 deletions homeassistant/components/accuweather/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ class AccuWeatherData:
coordinator_daily_forecast: AccuWeatherDailyForecastDataUpdateCoordinator


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
AccuWeatherConfigEntry = ConfigEntry[AccuWeatherData]


async def async_setup_entry(hass: HomeAssistant, entry: AccuWeatherConfigEntry) -> bool:
"""Set up AccuWeather as config entry."""
api_key: str = entry.data[CONF_API_KEY]
name: str = entry.data[CONF_NAME]
Expand Down Expand Up @@ -64,9 +67,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await coordinator_observation.async_config_entry_first_refresh()
await coordinator_daily_forecast.async_config_entry_first_refresh()

entry.async_on_unload(entry.add_update_listener(update_listener))

hass.data.setdefault(DOMAIN, {})[entry.entry_id] = AccuWeatherData(
entry.runtime_data = AccuWeatherData(
coordinator_observation=coordinator_observation,
coordinator_daily_forecast=coordinator_daily_forecast,
)
Expand All @@ -84,16 +85,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_unload_entry(
hass: HomeAssistant, entry: AccuWeatherConfigEntry
) -> bool:
"""Unload a config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)

return unload_ok


async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Update listener."""
await hass.config_entries.async_reload(entry.entry_id)
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
8 changes: 3 additions & 5 deletions homeassistant/components/accuweather/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,19 @@
from typing import Any

from homeassistant.components.diagnostics import async_redact_data
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE
from homeassistant.core import HomeAssistant

from . import AccuWeatherData
from .const import DOMAIN
from . import AccuWeatherConfigEntry, AccuWeatherData

TO_REDACT = {CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE}


async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry
hass: HomeAssistant, config_entry: AccuWeatherConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
accuweather_data: AccuWeatherData = hass.data[DOMAIN][config_entry.entry_id]
accuweather_data: AccuWeatherData = config_entry.runtime_data

return {
"config_entry_data": async_redact_data(dict(config_entry.data), TO_REDACT),
Expand Down
15 changes: 6 additions & 9 deletions homeassistant/components/accuweather/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONCENTRATION_PARTS_PER_CUBIC_METER,
PERCENTAGE,
Expand All @@ -28,7 +27,7 @@
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from . import AccuWeatherData
from . import AccuWeatherConfigEntry
from .const import (
API_METRIC,
ATTR_CATEGORY,
Expand All @@ -38,7 +37,6 @@
ATTR_SPEED,
ATTR_VALUE,
ATTRIBUTION,
DOMAIN,
MAX_FORECAST_DAYS,
)
from .coordinator import (
Expand Down Expand Up @@ -458,17 +456,16 @@ class AccuWeatherForecastSensorDescription(AccuWeatherSensorDescription):


async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
hass: HomeAssistant,
entry: AccuWeatherConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Add AccuWeather entities from a config_entry."""

accuweather_data: AccuWeatherData = hass.data[DOMAIN][entry.entry_id]

observation_coordinator: AccuWeatherObservationDataUpdateCoordinator = (
accuweather_data.coordinator_observation
entry.runtime_data.coordinator_observation
)
forecast_daily_coordinator: AccuWeatherDailyForecastDataUpdateCoordinator = (
accuweather_data.coordinator_daily_forecast
entry.runtime_data.coordinator_daily_forecast
)

sensors: list[AccuWeatherSensor | AccuWeatherForecastSensor] = [
Expand Down
9 changes: 6 additions & 3 deletions homeassistant/components/accuweather/system_health.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from homeassistant.components import system_health
from homeassistant.core import HomeAssistant, callback

from . import AccuWeatherConfigEntry
from .const import DOMAIN


Expand All @@ -22,9 +23,11 @@ def async_register(

async def system_health_info(hass: HomeAssistant) -> dict[str, Any]:
"""Get info for the info page."""
remaining_requests = list(hass.data[DOMAIN].values())[
0
].coordinator_observation.accuweather.requests_remaining
config_entry: AccuWeatherConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]

remaining_requests = (
config_entry.runtime_data.coordinator_observation.accuweather.requests_remaining
)

return {
"can_reach_server": system_health.async_check_can_reach_url(hass, ENDPOINT),
Expand Down
15 changes: 5 additions & 10 deletions homeassistant/components/accuweather/weather.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
Forecast,
WeatherEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
UnitOfLength,
UnitOfPrecipitationDepth,
Expand All @@ -31,18 +30,16 @@
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import TimestampDataUpdateCoordinator
from homeassistant.util.dt import utc_from_timestamp

from . import AccuWeatherData
from . import AccuWeatherConfigEntry, AccuWeatherData
from .const import (
API_METRIC,
ATTR_DIRECTION,
ATTR_SPEED,
ATTR_VALUE,
ATTRIBUTION,
CONDITION_MAP,
DOMAIN,
)
from .coordinator import (
AccuWeatherDailyForecastDataUpdateCoordinator,
Expand All @@ -53,20 +50,18 @@


async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
hass: HomeAssistant,
entry: AccuWeatherConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Add a AccuWeather weather entity from a config_entry."""
accuweather_data: AccuWeatherData = hass.data[DOMAIN][entry.entry_id]

async_add_entities([AccuWeatherEntity(accuweather_data)])
async_add_entities([AccuWeatherEntity(entry.runtime_data)])


class AccuWeatherEntity(
CoordinatorWeatherEntity[
AccuWeatherObservationDataUpdateCoordinator,
AccuWeatherDailyForecastDataUpdateCoordinator,
TimestampDataUpdateCoordinator,
TimestampDataUpdateCoordinator,
]
):
"""Define an AccuWeather entity."""
Expand Down

0 comments on commit 8f25ede

Please sign in to comment.