forked from home-assistant/core
Compare commits
174 Commits
Swamp-Ig-p
...
2023.3.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca5a88342b | ||
|
|
117113cdfc | ||
|
|
174342860b | ||
|
|
a7b5a0297e | ||
|
|
406e92511b | ||
|
|
146347e31a | ||
|
|
3747fd5dcb | ||
|
|
53d400ca96 | ||
|
|
2a18261efb | ||
|
|
1f71068740 | ||
|
|
92fb978a03 | ||
|
|
127f2289a1 | ||
|
|
de6f55dcfb | ||
|
|
713d3025f2 | ||
|
|
1e03ff68a2 | ||
|
|
a5aa5c0c01 | ||
|
|
b6d001bfe6 | ||
|
|
7e18e15cac | ||
|
|
e651ca747b | ||
|
|
9fa73fe3a9 | ||
|
|
abda7b8a5b | ||
|
|
90a4afb6fa | ||
|
|
52981699cf | ||
|
|
c3d7696c2e | ||
|
|
f120bac17f | ||
|
|
02738fb9d4 | ||
|
|
a9a6ff50cc | ||
|
|
fdd9c5383f | ||
|
|
d084e70aff | ||
|
|
69582b7ecb | ||
|
|
160518350f | ||
|
|
daa5718a80 | ||
|
|
f5562e93ac | ||
|
|
d2f90236d1 | ||
|
|
65c614421a | ||
|
|
22922da607 | ||
|
|
ca0304ffc4 | ||
|
|
950a1f6e9e | ||
|
|
1e7f58d859 | ||
|
|
7cb4620671 | ||
|
|
8c2569d2ce | ||
|
|
6ebd493c4d | ||
|
|
990ecbba72 | ||
|
|
ddde17606d | ||
|
|
3fba181e7b | ||
|
|
da79bf8534 | ||
|
|
83e2cc32b7 | ||
|
|
c7fb404a17 | ||
|
|
f1e114380a | ||
|
|
04e4a644cb | ||
|
|
e606c2e227 | ||
|
|
ebf95feff3 | ||
|
|
3dca4c2f23 | ||
|
|
3f8f38f2df | ||
|
|
0844a0b269 | ||
|
|
b65180d20a | ||
|
|
7f8a9697f0 | ||
|
|
563bd4a0dd | ||
|
|
29b5ef31c1 | ||
|
|
863f8b727d | ||
|
|
83ed8cf689 | ||
|
|
52cd2f9429 | ||
|
|
74d3b2374b | ||
|
|
f982af2412 | ||
|
|
0b5ddd9cbf | ||
|
|
8d1aa0132e | ||
|
|
d737b97c91 | ||
|
|
0fac12866d | ||
|
|
e3fe71f76e | ||
|
|
eba1bfad51 | ||
|
|
1a0a385e03 | ||
|
|
c9999cd08c | ||
|
|
8252aeead2 | ||
|
|
c27a69ef85 | ||
|
|
d4c28a1f4a | ||
|
|
322eb4bd83 | ||
|
|
f0f12fd14a | ||
|
|
1836e35717 | ||
|
|
4eb55146be | ||
|
|
b1ee6e304e | ||
|
|
d0b195516b | ||
|
|
a867f1d3c8 | ||
|
|
f7eaeb7a39 | ||
|
|
3e961d3e17 | ||
|
|
c28e16fa8b | ||
|
|
e2e8d74aa6 | ||
|
|
8a9fbd650a | ||
|
|
243725efe3 | ||
|
|
8d59489da8 | ||
|
|
c146413a1a | ||
|
|
a46d63a11b | ||
|
|
db4f6fb94d | ||
|
|
c50c920589 | ||
|
|
fe22aa0b4b | ||
|
|
a0162e4986 | ||
|
|
62c5cf51f5 | ||
|
|
89aebba3ab | ||
|
|
6c73b9024b | ||
|
|
59a9ace171 | ||
|
|
e751948bc8 | ||
|
|
702646427d | ||
|
|
8a605b1377 | ||
|
|
8eb8415d3f | ||
|
|
9f3f71d0c3 | ||
|
|
b82da9418d | ||
|
|
38cf725075 | ||
|
|
04cedab8d4 | ||
|
|
2238a3f201 | ||
|
|
f58ca17926 | ||
|
|
d5e517b874 | ||
|
|
f9eeb4f4d8 | ||
|
|
86d5e4aaa8 | ||
|
|
a56935ed7c | ||
|
|
fc56c958c3 | ||
|
|
a8e1dc8962 | ||
|
|
32b138b6c6 | ||
|
|
2112c66804 | ||
|
|
72c0526d87 | ||
|
|
9ed4e01e94 | ||
|
|
dcf1ecfeb5 | ||
|
|
b72224ceff | ||
|
|
96ad5c9666 | ||
|
|
00b59c142a | ||
|
|
b054c81e13 | ||
|
|
b0cbcad440 | ||
|
|
bafe552af6 | ||
|
|
d399855e50 | ||
|
|
d26f430766 | ||
|
|
f2e4943a53 | ||
|
|
6512cd901f | ||
|
|
fbe1524f6c | ||
|
|
95e337277c | ||
|
|
1503674bd6 | ||
|
|
ab6bd75b70 | ||
|
|
2fff836bd4 | ||
|
|
d8850758f1 | ||
|
|
0449856064 | ||
|
|
e48089e0c9 | ||
|
|
a7e081f70d | ||
|
|
fe181425d8 | ||
|
|
8c7b29db25 | ||
|
|
aaa5bb9f86 | ||
|
|
5b78e0c4ff | ||
|
|
2063dbf00d | ||
|
|
91a03ab83d | ||
|
|
ed8f538890 | ||
|
|
6196607c5d | ||
|
|
833ccafb76 | ||
|
|
ca539d0a09 | ||
|
|
0e3e954000 | ||
|
|
4ef96c76e4 | ||
|
|
d5b0c1faa0 | ||
|
|
2405908cdd | ||
|
|
b6e50135f5 | ||
|
|
64197aa5f5 | ||
|
|
5a2d7a5dd4 | ||
|
|
2d6f84b2a8 | ||
|
|
0c6a469218 | ||
|
|
e69271cb46 | ||
|
|
02bd3f897d | ||
|
|
64ad5326dd | ||
|
|
74696a3fac | ||
|
|
70e1d14da0 | ||
|
|
25f066d476 | ||
|
|
5adf1dcc90 | ||
|
|
0fb28dcf9e | ||
|
|
2fddbcedcf | ||
|
|
951df3df57 | ||
|
|
35142e456a | ||
|
|
cfaba87dd6 | ||
|
|
2db8d4b73a | ||
|
|
0d2006bf33 | ||
|
|
45547d226e | ||
|
|
cebc6dd096 |
@@ -639,10 +639,6 @@ omit =
|
||||
homeassistant/components/linode/*
|
||||
homeassistant/components/linux_battery/sensor.py
|
||||
homeassistant/components/lirc/*
|
||||
homeassistant/components/livisi/__init__.py
|
||||
homeassistant/components/livisi/climate.py
|
||||
homeassistant/components/livisi/coordinator.py
|
||||
homeassistant/components/livisi/switch.py
|
||||
homeassistant/components/llamalab_automate/notify.py
|
||||
homeassistant/components/logi_circle/__init__.py
|
||||
homeassistant/components/logi_circle/camera.py
|
||||
@@ -807,9 +803,7 @@ omit =
|
||||
homeassistant/components/nuki/sensor.py
|
||||
homeassistant/components/nx584/alarm_control_panel.py
|
||||
homeassistant/components/oasa_telematics/sensor.py
|
||||
homeassistant/components/obihai/__init__.py
|
||||
homeassistant/components/obihai/connectivity.py
|
||||
homeassistant/components/obihai/sensor.py
|
||||
homeassistant/components/obihai/*
|
||||
homeassistant/components/octoprint/__init__.py
|
||||
homeassistant/components/oem/climate.py
|
||||
homeassistant/components/ohmconnect/sensor.py
|
||||
@@ -1369,6 +1363,7 @@ omit =
|
||||
homeassistant/components/verisure/sensor.py
|
||||
homeassistant/components/verisure/switch.py
|
||||
homeassistant/components/versasense/*
|
||||
homeassistant/components/vesync/__init__.py
|
||||
homeassistant/components/vesync/common.py
|
||||
homeassistant/components/vesync/fan.py
|
||||
homeassistant/components/vesync/light.py
|
||||
|
||||
6
.github/workflows/ci.yaml
vendored
6
.github/workflows/ci.yaml
vendored
@@ -31,7 +31,7 @@ env:
|
||||
CACHE_VERSION: 5
|
||||
PIP_CACHE_VERSION: 4
|
||||
MYPY_CACHE_VERSION: 4
|
||||
HA_SHORT_VERSION: 2023.4
|
||||
HA_SHORT_VERSION: 2023.3
|
||||
DEFAULT_PYTHON: "3.10"
|
||||
ALL_PYTHON_VERSIONS: "['3.10', '3.11']"
|
||||
# 10.3 is the oldest supported version
|
||||
@@ -1073,10 +1073,10 @@ jobs:
|
||||
ffmpeg \
|
||||
postgresql-server-dev-14
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v3.3.0
|
||||
uses: actions/checkout@v3.1.0
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.5.0
|
||||
uses: actions/setup-python@v4.3.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: true
|
||||
|
||||
@@ -186,7 +186,6 @@ homeassistant.components.ld2410_ble.*
|
||||
homeassistant.components.lidarr.*
|
||||
homeassistant.components.lifx.*
|
||||
homeassistant.components.light.*
|
||||
homeassistant.components.litejet.*
|
||||
homeassistant.components.litterrobot.*
|
||||
homeassistant.components.local_ip.*
|
||||
homeassistant.components.lock.*
|
||||
|
||||
14
CODEOWNERS
14
CODEOWNERS
@@ -659,8 +659,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/litejet/ @joncar
|
||||
/homeassistant/components/litterrobot/ @natekspencer @tkdrob
|
||||
/tests/components/litterrobot/ @natekspencer @tkdrob
|
||||
/homeassistant/components/livisi/ @StefanIacobLivisi @planbnet
|
||||
/tests/components/livisi/ @StefanIacobLivisi @planbnet
|
||||
/homeassistant/components/livisi/ @StefanIacobLivisi
|
||||
/tests/components/livisi/ @StefanIacobLivisi
|
||||
/homeassistant/components/local_calendar/ @allenporter
|
||||
/tests/components/local_calendar/ @allenporter
|
||||
/homeassistant/components/local_ip/ @issacg
|
||||
@@ -825,8 +825,7 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/nws/ @MatthewFlamm @kamiyo
|
||||
/homeassistant/components/nzbget/ @chriscla
|
||||
/tests/components/nzbget/ @chriscla
|
||||
/homeassistant/components/obihai/ @dshokouhi @ejpenney
|
||||
/tests/components/obihai/ @dshokouhi @ejpenney
|
||||
/homeassistant/components/obihai/ @dshokouhi
|
||||
/homeassistant/components/octoprint/ @rfleming71
|
||||
/tests/components/octoprint/ @rfleming71
|
||||
/homeassistant/components/ohmconnect/ @robbiet480
|
||||
@@ -1101,6 +1100,7 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/smhi/ @gjohansson-ST
|
||||
/tests/components/smhi/ @gjohansson-ST
|
||||
/homeassistant/components/sms/ @ocalvo
|
||||
/homeassistant/components/snapcast/ @luar123
|
||||
/homeassistant/components/snooz/ @AustinBrunkhorst
|
||||
/tests/components/snooz/ @AustinBrunkhorst
|
||||
/homeassistant/components/solaredge/ @frenck
|
||||
@@ -1139,8 +1139,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/starline/ @anonym-tsk
|
||||
/homeassistant/components/starlink/ @boswelja
|
||||
/tests/components/starlink/ @boswelja
|
||||
/homeassistant/components/statistics/ @ThomDietrich
|
||||
/tests/components/statistics/ @ThomDietrich
|
||||
/homeassistant/components/statistics/ @fabaff @ThomDietrich
|
||||
/tests/components/statistics/ @fabaff @ThomDietrich
|
||||
/homeassistant/components/steam_online/ @tkdrob
|
||||
/tests/components/steam_online/ @tkdrob
|
||||
/homeassistant/components/steamist/ @bdraco
|
||||
@@ -1213,6 +1213,8 @@ build.json @home-assistant/supervisor
|
||||
/homeassistant/components/thethingsnetwork/ @fabaff
|
||||
/homeassistant/components/thread/ @home-assistant/core
|
||||
/tests/components/thread/ @home-assistant/core
|
||||
/homeassistant/components/threshold/ @fabaff
|
||||
/tests/components/threshold/ @fabaff
|
||||
/homeassistant/components/tibber/ @danielhiversen
|
||||
/tests/components/tibber/ @danielhiversen
|
||||
/homeassistant/components/tile/ @bachya
|
||||
|
||||
@@ -6,12 +6,15 @@ from typing import TYPE_CHECKING
|
||||
import attr
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers import (
|
||||
device_registry as dev_reg,
|
||||
entity_registry as ent_reg,
|
||||
)
|
||||
|
||||
|
||||
@attr.s(slots=True)
|
||||
class PermissionLookup:
|
||||
"""Class to hold data for permission lookups."""
|
||||
|
||||
entity_registry: er.EntityRegistry = attr.ib()
|
||||
device_registry: dr.DeviceRegistry = attr.ib()
|
||||
entity_registry: ent_reg.EntityRegistry = attr.ib()
|
||||
device_registry: dev_reg.DeviceRegistry = attr.ib()
|
||||
|
||||
@@ -68,7 +68,6 @@ SENSOR_TYPES: list[AirQEntityDescription] = [
|
||||
AirQEntityDescription(
|
||||
key="co",
|
||||
name="CO",
|
||||
device_class=SensorDeviceClass.CO,
|
||||
native_unit_of_measurement=CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("co"),
|
||||
@@ -289,7 +288,6 @@ SENSOR_TYPES: list[AirQEntityDescription] = [
|
||||
AirQEntityDescription(
|
||||
key="tvoc",
|
||||
name="VOC",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("tvoc"),
|
||||
@@ -297,7 +295,6 @@ SENSOR_TYPES: list[AirQEntityDescription] = [
|
||||
AirQEntityDescription(
|
||||
key="tvoc_ionsc",
|
||||
name="VOC (Industrial)",
|
||||
device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value=lambda data: data.get("tvoc_ionsc"),
|
||||
|
||||
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Mapping
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from AIOAladdinConnect import AladdinConnectClient
|
||||
@@ -19,6 +20,8 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import CLIENT_ID, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
STEP_USER_DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_USERNAME): str,
|
||||
@@ -131,6 +134,12 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
|
||||
)
|
||||
|
||||
async def async_step_import(
|
||||
self, import_data: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Import Aladin Connect config from configuration.yaml."""
|
||||
return await self.async_step_user(import_data)
|
||||
|
||||
|
||||
class InvalidAuth(HomeAssistantError):
|
||||
"""Error to indicate there is invalid auth."""
|
||||
|
||||
@@ -2,24 +2,63 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
from typing import Any
|
||||
import logging
|
||||
from typing import Any, Final
|
||||
|
||||
from AIOAladdinConnect import AladdinConnectClient
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.cover import CoverDeviceClass, CoverEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_CLOSED, STATE_CLOSING, STATE_OPENING
|
||||
from homeassistant.components.cover import (
|
||||
PLATFORM_SCHEMA as BASE_PLATFORM_SCHEMA,
|
||||
CoverDeviceClass,
|
||||
CoverEntity,
|
||||
)
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_PASSWORD,
|
||||
CONF_USERNAME,
|
||||
STATE_CLOSED,
|
||||
STATE_CLOSING,
|
||||
STATE_OPENING,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
from .const import DOMAIN, STATES_MAP, SUPPORTED_FEATURES
|
||||
from .model import DoorDevice
|
||||
|
||||
_LOGGER: Final = logging.getLogger(__name__)
|
||||
|
||||
PLATFORM_SCHEMA: Final = BASE_PLATFORM_SCHEMA.extend(
|
||||
{vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string}
|
||||
)
|
||||
SCAN_INTERVAL = timedelta(seconds=300)
|
||||
|
||||
|
||||
async def async_setup_platform(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up Aladdin Connect devices yaml depreciated."""
|
||||
_LOGGER.warning(
|
||||
"Configuring Aladdin Connect through yaml is deprecated. Please remove it from"
|
||||
" your configuration as it has already been imported to a config entry"
|
||||
)
|
||||
await hass.async_create_task(
|
||||
hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
data=config,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
|
||||
@@ -21,7 +21,7 @@ from homeassistant.const import (
|
||||
SERVICE_ALARM_TRIGGER,
|
||||
)
|
||||
from homeassistant.core import Context, HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import get_supported_features
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
@@ -57,11 +57,11 @@ async def async_get_actions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device actions for Alarm control panel devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
actions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -21,11 +21,7 @@ from homeassistant.const import (
|
||||
STATE_ALARM_TRIGGERED,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import (
|
||||
condition,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
|
||||
from homeassistant.helpers.entity import get_supported_features
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
@@ -68,11 +64,11 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Alarm control panel devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
conditions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ from homeassistant.const import (
|
||||
STATE_ALARM_TRIGGERED,
|
||||
)
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.entity import get_supported_features
|
||||
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
@@ -57,11 +57,11 @@ async def async_get_triggers(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device triggers for Alarm control panel devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
triggers: list[dict[str, str]] = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import asyncio
|
||||
from http import HTTPStatus
|
||||
import json
|
||||
import logging
|
||||
from typing import cast
|
||||
|
||||
import aiohttp
|
||||
import async_timeout
|
||||
@@ -16,7 +15,6 @@ from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.event import async_track_state_change
|
||||
from homeassistant.helpers.significant_change import create_checker
|
||||
import homeassistant.util.dt as dt_util
|
||||
from homeassistant.util.json import JsonObjectType, json_loads_object
|
||||
|
||||
from .const import API_CHANGE, DATE_FORMAT, DOMAIN, Cause
|
||||
from .entities import ENTITY_ADAPTERS, AlexaEntity, generate_alexa_id
|
||||
@@ -164,10 +162,9 @@ async def async_send_changereport_message(
|
||||
if response.status == HTTPStatus.ACCEPTED:
|
||||
return
|
||||
|
||||
response_json = json_loads_object(response_text)
|
||||
response_payload = cast(JsonObjectType, response_json["payload"])
|
||||
response_json = json.loads(response_text)
|
||||
|
||||
if response_payload["code"] == "INVALID_ACCESS_TOKEN_EXCEPTION":
|
||||
if response_json["payload"]["code"] == "INVALID_ACCESS_TOKEN_EXCEPTION":
|
||||
if invalidate_access_token:
|
||||
# Invalidate the access token and try again
|
||||
config.async_invalidate_access_token()
|
||||
@@ -183,8 +180,8 @@ async def async_send_changereport_message(
|
||||
_LOGGER.error(
|
||||
"Error when sending ChangeReport for %s to Alexa: %s: %s",
|
||||
alexa_entity.entity_id,
|
||||
response_payload["code"],
|
||||
response_payload["description"],
|
||||
response_json["payload"]["code"],
|
||||
response_json["payload"]["description"],
|
||||
)
|
||||
|
||||
|
||||
@@ -302,12 +299,11 @@ async def async_send_doorbell_event_message(hass, config, alexa_entity):
|
||||
if response.status == HTTPStatus.ACCEPTED:
|
||||
return
|
||||
|
||||
response_json = json_loads_object(response_text)
|
||||
response_payload = cast(JsonObjectType, response_json["payload"])
|
||||
response_json = json.loads(response_text)
|
||||
|
||||
_LOGGER.error(
|
||||
"Error when sending DoorbellPress event for %s to Alexa: %s: %s",
|
||||
alexa_entity.entity_id,
|
||||
response_payload["code"],
|
||||
response_payload["description"],
|
||||
response_json["payload"]["code"],
|
||||
response_json["payload"]["description"],
|
||||
)
|
||||
|
||||
@@ -20,12 +20,13 @@ from homeassistant.components.camera import (
|
||||
from homeassistant.components.ffmpeg import FFmpegManager, get_ffmpeg_manager
|
||||
from homeassistant.const import ATTR_ENTITY_ID, CONF_NAME, STATE_OFF, STATE_ON
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
from homeassistant.helpers.aiohttp_client import (
|
||||
async_aiohttp_proxy_stream,
|
||||
async_aiohttp_proxy_web,
|
||||
async_get_clientsession,
|
||||
)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
@@ -145,7 +146,7 @@ async def async_setup_platform(
|
||||
# with this version, update the old entity with the new unique id.
|
||||
serial_number = await device.api.async_serial_number
|
||||
serial_number = serial_number.strip()
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
entity_id = registry.async_get_entity_id(CAMERA_DOMAIN, DOMAIN, serial_number)
|
||||
if entity_id is not None:
|
||||
_LOGGER.debug("Updating unique id for camera %s", entity_id)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Rest API for Home Assistant."""
|
||||
import asyncio
|
||||
from functools import lru_cache
|
||||
from http import HTTPStatus
|
||||
import logging
|
||||
|
||||
@@ -350,6 +351,12 @@ class APIComponentsView(HomeAssistantView):
|
||||
return self.json(request.app["hass"].config.components)
|
||||
|
||||
|
||||
@lru_cache
|
||||
def _cached_template(template_str: str, hass: ha.HomeAssistant) -> template.Template:
|
||||
"""Return a cached template."""
|
||||
return template.Template(template_str, hass)
|
||||
|
||||
|
||||
class APITemplateView(HomeAssistantView):
|
||||
"""View to handle Template requests."""
|
||||
|
||||
@@ -362,7 +369,7 @@ class APITemplateView(HomeAssistantView):
|
||||
raise Unauthorized()
|
||||
try:
|
||||
data = await request.json()
|
||||
tpl = template.Template(data["template"], request.app["hass"])
|
||||
tpl = _cached_template(data["template"], request.app["hass"])
|
||||
return tpl.async_render(variables=data.get("variables"), parse_result=False)
|
||||
except (ValueError, TemplateError) as ex:
|
||||
return self.json_message(
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/apprise",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["apprise"],
|
||||
"requirements": ["apprise==1.3.0"]
|
||||
"requirements": ["apprise==1.2.1"]
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ from homeassistant.const import (
|
||||
CONF_TYPE,
|
||||
)
|
||||
from homeassistant.core import CALLBACK_TYPE, Event, HassJob, HomeAssistant, callback
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
@@ -32,11 +32,11 @@ async def async_get_triggers(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device triggers for Arcam FMJ Receiver control devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
triggers = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain == "media_player":
|
||||
triggers.append(
|
||||
{
|
||||
|
||||
@@ -180,7 +180,7 @@ class ArestData:
|
||||
self._resource = resource
|
||||
self._pin = pin
|
||||
self.data = {}
|
||||
self._attr_available = True
|
||||
self.available = True
|
||||
|
||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||
def update(self):
|
||||
@@ -201,7 +201,7 @@ class ArestData:
|
||||
f"{self._resource}/digital/{self._pin}", timeout=10
|
||||
)
|
||||
self.data = {"value": response.json()["return_value"]}
|
||||
self._attr_available = True
|
||||
self.available = True
|
||||
except requests.exceptions.ConnectionError:
|
||||
_LOGGER.error("No route to device %s", self._resource)
|
||||
self._attr_available = False
|
||||
self.available = False
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Support for collecting data from the ARWN project."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from homeassistant.components import mqtt
|
||||
@@ -10,7 +11,6 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
from homeassistant.util import slugify
|
||||
from homeassistant.util.json import json_loads_object
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -102,7 +102,7 @@ async def async_setup_platform(
|
||||
"""Set up the ARWN platform."""
|
||||
|
||||
@callback
|
||||
def async_sensor_event_received(msg: mqtt.ReceiveMessage) -> None:
|
||||
def async_sensor_event_received(msg):
|
||||
"""Process events as sensors.
|
||||
|
||||
When a new event on our topic (arwn/#) is received we map it
|
||||
@@ -115,7 +115,7 @@ async def async_setup_platform(
|
||||
This lets us dynamically incorporate sensors without any
|
||||
configuration on our side.
|
||||
"""
|
||||
event = json_loads_object(msg.payload)
|
||||
event = json.loads(msg.payload)
|
||||
sensors = discover_sensors(msg.topic, event)
|
||||
if not sensors:
|
||||
return
|
||||
|
||||
@@ -28,5 +28,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/august",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["pubnub", "yalexs"],
|
||||
"requirements": ["yalexs==1.2.7", "yalexs_ble==2.0.4"]
|
||||
"requirements": ["yalexs==1.2.7", "yalexs-ble==2.1.1"]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""Support for Aurora Forecast sensor."""
|
||||
from homeassistant.components.sensor import SensorEntity, SensorStateClass
|
||||
from homeassistant.components.sensor import SensorEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import PERCENTAGE
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -28,7 +28,6 @@ class AuroraSensor(AuroraEntity, SensorEntity):
|
||||
"""Implementation of an aurora sensor."""
|
||||
|
||||
_attr_native_unit_of_measurement = PERCENTAGE
|
||||
_attr_state_class = SensorStateClass.MEASUREMENT
|
||||
|
||||
@property
|
||||
def native_value(self):
|
||||
|
||||
@@ -60,7 +60,7 @@ from .const import (
|
||||
DEFAULT_PROBABILITY_THRESHOLD,
|
||||
)
|
||||
from .helpers import Observation
|
||||
from .repairs import raise_mirrored_entries, raise_no_prob_given_false
|
||||
from .issues import raise_mirrored_entries, raise_no_prob_given_false
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""Helpers for generating repairs."""
|
||||
"""Helpers for generating issues."""
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
from homeassistant.helpers import issue_registry
|
||||
|
||||
from . import DOMAIN
|
||||
from .helpers import Observation
|
||||
@@ -15,13 +15,13 @@ def raise_mirrored_entries(
|
||||
if len(observations) != 2:
|
||||
return
|
||||
if observations[0].is_mirror(observations[1]):
|
||||
ir.async_create_issue(
|
||||
issue_registry.async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"mirrored_entry/" + text,
|
||||
breaks_in_ha_version="2022.10.0",
|
||||
is_fixable=False,
|
||||
severity=ir.IssueSeverity.WARNING,
|
||||
severity=issue_registry.IssueSeverity.WARNING,
|
||||
translation_key="manual_migration",
|
||||
translation_placeholders={"entity": text},
|
||||
learn_more_url="https://github.com/home-assistant/core/pull/67631",
|
||||
@@ -31,13 +31,13 @@ def raise_mirrored_entries(
|
||||
# Should deprecate in some future version (2022.10 at time of writing) & make prob_given_false required in schemas.
|
||||
def raise_no_prob_given_false(hass: HomeAssistant, text: str) -> None:
|
||||
"""In previous 2022.9 and earlier, prob_given_false was optional and had a default version."""
|
||||
ir.async_create_issue(
|
||||
issue_registry.async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
f"no_prob_given_false/{text}",
|
||||
breaks_in_ha_version="2022.10.0",
|
||||
is_fixable=False,
|
||||
severity=ir.IssueSeverity.ERROR,
|
||||
severity=issue_registry.IssueSeverity.ERROR,
|
||||
translation_key="no_prob_given_false",
|
||||
translation_placeholders={"entity": text},
|
||||
learn_more_url="https://github.com/home-assistant/core/pull/67631",
|
||||
@@ -227,20 +227,21 @@ class BaseHaRemoteScanner(BaseHaScanner):
|
||||
self.hass, self._async_expire_devices, timedelta(seconds=30)
|
||||
)
|
||||
cancel_stop = self.hass.bus.async_listen(
|
||||
EVENT_HOMEASSISTANT_STOP, self._save_history
|
||||
EVENT_HOMEASSISTANT_STOP, self._async_save_history
|
||||
)
|
||||
self._async_setup_scanner_watchdog()
|
||||
|
||||
@hass_callback
|
||||
def _cancel() -> None:
|
||||
self._save_history()
|
||||
self._async_save_history()
|
||||
self._async_stop_scanner_watchdog()
|
||||
cancel_track()
|
||||
cancel_stop()
|
||||
|
||||
return _cancel
|
||||
|
||||
def _save_history(self, event: Event | None = None) -> None:
|
||||
@hass_callback
|
||||
def _async_save_history(self, event: Event | None = None) -> None:
|
||||
"""Save the history."""
|
||||
self._storage.async_set_advertisement_history(
|
||||
self.source,
|
||||
@@ -252,6 +253,7 @@ class BaseHaRemoteScanner(BaseHaScanner):
|
||||
),
|
||||
)
|
||||
|
||||
@hass_callback
|
||||
def _async_expire_devices(self, _datetime: datetime.datetime) -> None:
|
||||
"""Expire old devices."""
|
||||
now = MONOTONIC_TIME()
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["bond_async"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["bond-async==0.1.22"],
|
||||
"requirements": ["bond-async==0.1.23"],
|
||||
"zeroconf": ["_bond._tcp.local."]
|
||||
}
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
"dependencies": ["bluetooth_adapters"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/bthome",
|
||||
"iot_class": "local_push",
|
||||
"requirements": ["bthome-ble==2.7.0"]
|
||||
"requirements": ["bthome-ble==2.5.2"]
|
||||
}
|
||||
|
||||
@@ -119,16 +119,6 @@ SENSOR_DESCRIPTIONS = {
|
||||
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
),
|
||||
# Gas (m3)
|
||||
(
|
||||
BTHomeSensorDeviceClass.GAS,
|
||||
Units.VOLUME_CUBIC_METERS,
|
||||
): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.GAS}_{Units.VOLUME_CUBIC_METERS}",
|
||||
device_class=SensorDeviceClass.GAS,
|
||||
native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
),
|
||||
# Humidity in (percent)
|
||||
(BTHomeSensorDeviceClass.HUMIDITY, Units.PERCENTAGE): SensorEntityDescription(
|
||||
key=f"{BTHomeSensorDeviceClass.HUMIDITY}_{Units.PERCENTAGE}",
|
||||
|
||||
@@ -11,7 +11,7 @@ from homeassistant.const import (
|
||||
CONF_TYPE,
|
||||
)
|
||||
from homeassistant.core import Context, HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
|
||||
@@ -31,7 +31,7 @@ async def async_get_actions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device actions for button devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
return [
|
||||
{
|
||||
CONF_DEVICE_ID: device_id,
|
||||
@@ -39,7 +39,7 @@ async def async_get_actions(
|
||||
CONF_ENTITY_ID: entry.entity_id,
|
||||
CONF_TYPE: "press",
|
||||
}
|
||||
for entry in er.async_entries_for_device(registry, device_id)
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id)
|
||||
if entry.domain == DOMAIN
|
||||
]
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ from homeassistant.const import (
|
||||
CONF_TYPE,
|
||||
)
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
@@ -36,7 +36,7 @@ async def async_get_triggers(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device triggers for button devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
return [
|
||||
{
|
||||
CONF_PLATFORM: "device",
|
||||
@@ -45,7 +45,7 @@ async def async_get_triggers(
|
||||
CONF_ENTITY_ID: entry.entity_id,
|
||||
CONF_TYPE: "pressed",
|
||||
}
|
||||
for entry in er.async_entries_for_device(registry, device_id)
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id)
|
||||
if entry.domain == DOMAIN
|
||||
]
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import Context, HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import get_capability, get_supported_features
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
@@ -44,11 +44,11 @@ async def async_get_actions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device actions for Climate devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
actions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -13,11 +13,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import (
|
||||
condition,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
|
||||
from homeassistant.helpers.entity import get_capability, get_supported_features
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
@@ -49,11 +45,11 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Climate devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
conditions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ from homeassistant.const import (
|
||||
PERCENTAGE,
|
||||
)
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
@@ -62,11 +62,11 @@ async def async_get_triggers(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device triggers for Climate devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
triggers = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ from coinbase.wallet.error import AuthenticationError
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_API_KEY, CONF_API_TOKEN, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
from .const import (
|
||||
@@ -70,8 +71,10 @@ async def update_listener(hass: HomeAssistant, config_entry: ConfigEntry) -> Non
|
||||
|
||||
await hass.config_entries.async_reload(config_entry.entry_id)
|
||||
|
||||
registry = er.async_get(hass)
|
||||
entities = er.async_entries_for_config_entry(registry, config_entry.entry_id)
|
||||
registry = entity_registry.async_get(hass)
|
||||
entities = entity_registry.async_entries_for_config_entry(
|
||||
registry, config_entry.entry_id
|
||||
)
|
||||
|
||||
# Remove orphaned entities
|
||||
for entity in entities:
|
||||
|
||||
@@ -8,7 +8,7 @@ from homeassistant.components.automation.config import (
|
||||
)
|
||||
from homeassistant.config import AUTOMATION_CONFIG_PATH
|
||||
from homeassistant.const import CONF_ID, SERVICE_RELOAD
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry
|
||||
|
||||
from . import ACTION_DELETE, EditIdBasedConfigView
|
||||
|
||||
@@ -23,7 +23,7 @@ async def async_setup(hass):
|
||||
if action != ACTION_DELETE:
|
||||
return
|
||||
|
||||
ent_reg = er.async_get(hass)
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
|
||||
entity_id = ent_reg.async_get_entity_id(DOMAIN, DOMAIN, config_key)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ from homeassistant.components.scene import DOMAIN, PLATFORM_SCHEMA
|
||||
from homeassistant.config import SCENE_CONFIG_PATH
|
||||
from homeassistant.const import CONF_ID, SERVICE_RELOAD
|
||||
from homeassistant.core import DOMAIN as HA_DOMAIN
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry
|
||||
|
||||
from . import ACTION_DELETE, EditIdBasedConfigView
|
||||
|
||||
@@ -19,7 +19,7 @@ async def async_setup(hass):
|
||||
await hass.services.async_call(DOMAIN, SERVICE_RELOAD)
|
||||
return
|
||||
|
||||
ent_reg = er.async_get(hass)
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
|
||||
entity_id = ent_reg.async_get_entity_id(DOMAIN, HA_DOMAIN, config_key)
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
DOMAIN = "conversation"
|
||||
|
||||
DEFAULT_EXPOSED_DOMAINS = {
|
||||
"binary_sensor",
|
||||
"climate",
|
||||
"cover",
|
||||
"fan",
|
||||
@@ -17,5 +16,3 @@ DEFAULT_EXPOSED_DOMAINS = {
|
||||
"vacuum",
|
||||
"water_heater",
|
||||
}
|
||||
|
||||
DEFAULT_EXPOSED_ATTRIBUTES = {"device_class"}
|
||||
|
||||
@@ -18,9 +18,9 @@ import yaml
|
||||
|
||||
from homeassistant import core, setup
|
||||
from homeassistant.helpers import (
|
||||
area_registry as ar,
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
area_registry,
|
||||
device_registry,
|
||||
entity_registry,
|
||||
intent,
|
||||
template,
|
||||
translation,
|
||||
@@ -28,7 +28,7 @@ from homeassistant.helpers import (
|
||||
from homeassistant.util.json import JsonObjectType, json_loads_object
|
||||
|
||||
from .agent import AbstractConversationAgent, ConversationInput, ConversationResult
|
||||
from .const import DEFAULT_EXPOSED_ATTRIBUTES, DEFAULT_EXPOSED_DOMAINS, DOMAIN
|
||||
from .const import DEFAULT_EXPOSED_DOMAINS, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_DEFAULT_ERROR_TEXT = "Sorry, I couldn't understand that"
|
||||
@@ -95,12 +95,12 @@ class DefaultAgent(AbstractConversationAgent):
|
||||
self._config_intents = config_intents
|
||||
|
||||
self.hass.bus.async_listen(
|
||||
ar.EVENT_AREA_REGISTRY_UPDATED,
|
||||
area_registry.EVENT_AREA_REGISTRY_UPDATED,
|
||||
self._async_handle_area_registry_changed,
|
||||
run_immediately=True,
|
||||
)
|
||||
self.hass.bus.async_listen(
|
||||
er.EVENT_ENTITY_REGISTRY_UPDATED,
|
||||
entity_registry.EVENT_ENTITY_REGISTRY_UPDATED,
|
||||
self._async_handle_entity_registry_changed,
|
||||
run_immediately=True,
|
||||
)
|
||||
@@ -471,20 +471,14 @@ class DefaultAgent(AbstractConversationAgent):
|
||||
states = [
|
||||
state for state in self.hass.states.async_all() if is_entity_exposed(state)
|
||||
]
|
||||
entities = er.async_get(self.hass)
|
||||
devices = dr.async_get(self.hass)
|
||||
entities = entity_registry.async_get(self.hass)
|
||||
devices = device_registry.async_get(self.hass)
|
||||
|
||||
# Gather exposed entity names
|
||||
entity_names = []
|
||||
for state in states:
|
||||
# Checked against "requires_context" and "excludes_context" in hassil
|
||||
context = {"domain": state.domain}
|
||||
if state.attributes:
|
||||
# Include some attributes
|
||||
for attr_key, attr_value in state.attributes.items():
|
||||
if attr_key not in DEFAULT_EXPOSED_ATTRIBUTES:
|
||||
continue
|
||||
context[attr_key] = attr_value
|
||||
|
||||
entity = entities.async_get(state.entity_id)
|
||||
if entity is not None:
|
||||
@@ -512,7 +506,7 @@ class DefaultAgent(AbstractConversationAgent):
|
||||
entity_names.append((state.name, state.name, context))
|
||||
|
||||
# Gather areas from exposed entities
|
||||
areas = ar.async_get(self.hass)
|
||||
areas = area_registry.async_get(self.hass)
|
||||
area_names = []
|
||||
for area_id in area_ids_with_entities:
|
||||
area = areas.async_get_area(area_id)
|
||||
@@ -524,9 +518,6 @@ class DefaultAgent(AbstractConversationAgent):
|
||||
for alias in area.aliases:
|
||||
area_names.append((alias, area.id))
|
||||
|
||||
_LOGGER.debug("Exposed areas: %s", area_names)
|
||||
_LOGGER.debug("Exposed entities: %s", entity_names)
|
||||
|
||||
self._slot_lists = {
|
||||
"area": TextSlotList.from_tuples(area_names, allow_template=False),
|
||||
"name": TextSlotList.from_tuples(entity_names, allow_template=False),
|
||||
|
||||
@@ -8,11 +8,7 @@ import coronavirus
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import (
|
||||
aiohttp_client,
|
||||
entity_registry as er,
|
||||
update_coordinator,
|
||||
)
|
||||
from homeassistant.helpers import aiohttp_client, entity_registry, update_coordinator
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from .const import DOMAIN
|
||||
@@ -35,14 +31,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_migrator(entity_entry: er.RegistryEntry):
|
||||
def _async_migrator(entity_entry: entity_registry.RegistryEntry):
|
||||
"""Migrate away from unstable ID."""
|
||||
country, info_type = entity_entry.unique_id.rsplit("-", 1)
|
||||
if not country.isnumeric():
|
||||
return None
|
||||
return {"new_unique_id": f"{entry.title}-{info_type}"}
|
||||
|
||||
await er.async_migrate_entries(hass, entry.entry_id, _async_migrator)
|
||||
await entity_registry.async_migrate_entries(
|
||||
hass, entry.entry_id, _async_migrator
|
||||
)
|
||||
|
||||
if not entry.unique_id:
|
||||
hass.config_entries.async_update_entry(entry, unique_id=entry.data["country"])
|
||||
|
||||
@@ -18,7 +18,7 @@ from homeassistant.const import (
|
||||
SERVICE_STOP_COVER,
|
||||
)
|
||||
from homeassistant.core import Context, HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import get_supported_features
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
@@ -63,11 +63,11 @@ async def async_get_actions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device actions for Cover devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
actions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -18,11 +18,7 @@ from homeassistant.const import (
|
||||
STATE_OPENING,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import (
|
||||
condition,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
|
||||
from homeassistant.helpers.entity import get_supported_features
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
@@ -70,11 +66,11 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Cover devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
conditions: list[dict[str, str]] = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ from homeassistant.const import (
|
||||
STATE_OPENING,
|
||||
)
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.entity import get_supported_features
|
||||
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
@@ -71,11 +71,11 @@ async def async_get_triggers(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device triggers for Cover devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
triggers = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["pydeconz"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["pydeconz==108"],
|
||||
"requirements": ["pydeconz==110"],
|
||||
"ssdp": [
|
||||
{
|
||||
"manufacturer": "Royal Philips Electronics",
|
||||
|
||||
@@ -14,7 +14,7 @@ from homeassistant.components.sensor import (
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_IDLE, Platform, UnitOfDataRate
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers import entity_platform
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from . import DelugeEntity
|
||||
@@ -71,7 +71,9 @@ SENSOR_TYPES: tuple[DelugeSensorEntityDescription, ...] = (
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: entity_platform.AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Deluge sensor."""
|
||||
async_add_entities(
|
||||
|
||||
@@ -7,7 +7,7 @@ from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers import entity_platform
|
||||
|
||||
from . import DelugeEntity
|
||||
from .const import DOMAIN
|
||||
@@ -15,7 +15,9 @@ from .coordinator import DelugeDataUpdateCoordinator
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: entity_platform.AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Deluge switch."""
|
||||
async_add_entities([DelugeSwitch(hass.data[DOMAIN][entry.entry_id])])
|
||||
|
||||
@@ -8,7 +8,6 @@ import voluptuous as vol
|
||||
from homeassistant.const import CONF_DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.condition import ConditionProtocol, trace_condition_function
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from . import DeviceAutomationType, async_get_device_automation_platform
|
||||
@@ -18,13 +17,24 @@ if TYPE_CHECKING:
|
||||
from homeassistant.helpers import condition
|
||||
|
||||
|
||||
class DeviceAutomationConditionProtocol(ConditionProtocol, Protocol):
|
||||
class DeviceAutomationConditionProtocol(Protocol):
|
||||
"""Define the format of device_condition modules.
|
||||
|
||||
Each module must define either CONDITION_SCHEMA or async_validate_condition_config
|
||||
from ConditionProtocol.
|
||||
Each module must define either CONDITION_SCHEMA or async_validate_condition_config.
|
||||
"""
|
||||
|
||||
CONDITION_SCHEMA: vol.Schema
|
||||
|
||||
async def async_validate_condition_config(
|
||||
self, hass: HomeAssistant, config: ConfigType
|
||||
) -> ConfigType:
|
||||
"""Validate config."""
|
||||
|
||||
def async_condition_from_config(
|
||||
self, hass: HomeAssistant, config: ConfigType
|
||||
) -> condition.ConditionCheckerType:
|
||||
"""Evaluate state based on configuration."""
|
||||
|
||||
async def async_get_condition_capabilities(
|
||||
self, hass: HomeAssistant, config: ConfigType
|
||||
) -> dict[str, vol.Schema]:
|
||||
@@ -52,4 +62,4 @@ async def async_condition_from_config(
|
||||
platform = await async_get_device_automation_platform(
|
||||
hass, config[CONF_DOMAIN], DeviceAutomationType.CONDITION
|
||||
)
|
||||
return trace_condition_function(platform.async_condition_from_config(hass, config))
|
||||
return platform.async_condition_from_config(hass, config)
|
||||
|
||||
@@ -13,11 +13,7 @@ from homeassistant.const import (
|
||||
STATE_HOME,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import (
|
||||
condition,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
|
||||
@@ -37,11 +33,11 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Device tracker devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
conditions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ from homeassistant.const import (
|
||||
CONF_ZONE,
|
||||
)
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
@@ -38,11 +38,11 @@ async def async_get_triggers(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device triggers for Device Tracker devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
triggers = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from homeassistant.components.device_tracker import (
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import STATE_UNKNOWN, UnitOfFrequency
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
CoordinatorEntity,
|
||||
@@ -30,7 +30,7 @@ async def async_setup_entry(
|
||||
coordinators: dict[
|
||||
str, DataUpdateCoordinator[list[ConnectedStationInfo]]
|
||||
] = hass.data[DOMAIN][entry.entry_id]["coordinators"]
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
tracked = set()
|
||||
|
||||
@callback
|
||||
@@ -53,7 +53,9 @@ async def async_setup_entry(
|
||||
def restore_entities() -> None:
|
||||
"""Restore clients that are not a part of active clients list."""
|
||||
missing = []
|
||||
for entity in er.async_entries_for_config_entry(registry, entry.entry_id):
|
||||
for entity in entity_registry.async_entries_for_config_entry(
|
||||
registry, entry.entry_id
|
||||
):
|
||||
if (
|
||||
entity.platform == DOMAIN
|
||||
and entity.domain == DEVICE_TRACKER_DOMAIN
|
||||
|
||||
@@ -21,7 +21,8 @@ from homeassistant.const import CONF_DEVICE_ID, CONF_HOST, CONF_MAC, CONF_TYPE,
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.exceptions import IntegrationError
|
||||
from homeassistant.helpers import config_validation as cv, device_registry as dr
|
||||
from homeassistant.helpers import device_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from .const import (
|
||||
CONF_BROWSE_UNFILTERED,
|
||||
@@ -500,4 +501,4 @@ async def _async_get_mac_address(hass: HomeAssistant, host: str) -> str | None:
|
||||
if not mac_address:
|
||||
return None
|
||||
|
||||
return dr.format_mac(mac_address)
|
||||
return device_registry.format_mac(mac_address)
|
||||
|
||||
@@ -29,7 +29,7 @@ from homeassistant.components.media_player import (
|
||||
)
|
||||
from homeassistant.const import CONF_DEVICE_ID, CONF_MAC, CONF_TYPE, CONF_URL
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers import device_registry, entity_registry
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import (
|
||||
@@ -363,21 +363,21 @@ class DlnaDmrEntity(MediaPlayerEntity):
|
||||
# device's UDN. They may be the same, if the DMR is the root device.
|
||||
connections.add(
|
||||
(
|
||||
dr.CONNECTION_UPNP,
|
||||
device_registry.CONNECTION_UPNP,
|
||||
self._device.profile_device.root_device.udn,
|
||||
)
|
||||
)
|
||||
connections.add((dr.CONNECTION_UPNP, self._device.udn))
|
||||
connections.add((device_registry.CONNECTION_UPNP, self._device.udn))
|
||||
|
||||
if self.mac_address:
|
||||
# Connection based on MAC address, if known
|
||||
connections.add(
|
||||
# Device MAC is obtained from the config entry, which uses getmac
|
||||
(dr.CONNECTION_NETWORK_MAC, self.mac_address)
|
||||
(device_registry.CONNECTION_NETWORK_MAC, self.mac_address)
|
||||
)
|
||||
|
||||
# Create linked HA DeviceEntry now the information is known.
|
||||
dev_reg = dr.async_get(self.hass)
|
||||
dev_reg = device_registry.async_get(self.hass)
|
||||
device_entry = dev_reg.async_get_or_create(
|
||||
config_entry_id=self.registry_entry.config_entry_id,
|
||||
connections=connections,
|
||||
@@ -388,7 +388,7 @@ class DlnaDmrEntity(MediaPlayerEntity):
|
||||
)
|
||||
|
||||
# Update entity registry to link to the device
|
||||
ent_reg = er.async_get(self.hass)
|
||||
ent_reg = entity_registry.async_get(self.hass)
|
||||
ent_reg.async_get_or_create(
|
||||
self.registry_entry.domain,
|
||||
self.registry_entry.platform,
|
||||
|
||||
@@ -45,9 +45,10 @@ BINARY_SENSOR_DESCRIPTIONS = (
|
||||
),
|
||||
DormakabaDkeyBinarySensorDescription(
|
||||
key="security_locked",
|
||||
name="Dead bolt",
|
||||
name="Deadbolt",
|
||||
device_class=BinarySensorDeviceClass.LOCK,
|
||||
is_on=lambda state: state.unlock_status != UnlockStatus.SECURITY_LOCKED,
|
||||
is_on=lambda state: state.unlock_status
|
||||
not in (UnlockStatus.SECURITY_LOCKED, UnlockStatus.UNLOCKED_SECURITY_LOCKED),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -11,5 +11,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/dormakaba_dkey",
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_polling",
|
||||
"requirements": ["py-dormakaba-dkey==1.0.3"]
|
||||
"requirements": ["py-dormakaba-dkey==1.0.4"]
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/easyenergy",
|
||||
"iot_class": "cloud_polling",
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["easyenergy==0.1.2"]
|
||||
"requirements": ["easyenergy==0.2.2"]
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ from homeassistant.components.sensor import (
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import UnitOfEnergy, UnitOfPower
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers import entity_platform
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from . import EfergyEntity
|
||||
@@ -104,7 +104,9 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: entity_platform.AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Efergy sensors."""
|
||||
api: Efergy = hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
@@ -15,10 +15,7 @@ from homeassistant.components.sensor import (
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import PERCENTAGE, UnitOfTemperature
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddEntitiesCallback,
|
||||
async_get_current_platform,
|
||||
)
|
||||
from homeassistant.helpers import entity_platform as ep
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from . import EightSleepBaseEntity, EightSleepConfigEntryData
|
||||
@@ -71,7 +68,7 @@ SERVICE_EIGHT_SCHEMA = {
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: ep.AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up the eight sleep sensors."""
|
||||
config_entry_data: EightSleepConfigEntryData = hass.data[DOMAIN][entry.entry_id]
|
||||
@@ -98,7 +95,7 @@ async def async_setup_entry(
|
||||
|
||||
async_add_entities(all_sensors)
|
||||
|
||||
platform = async_get_current_platform()
|
||||
platform = ep.async_get_current_platform()
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_HEAT_SET,
|
||||
SERVICE_EIGHT_SCHEMA,
|
||||
|
||||
@@ -9,7 +9,8 @@ import voluptuous as vol
|
||||
from homeassistant.components.switch import PLATFORM_SCHEMA, SwitchEntity
|
||||
from homeassistant.const import CONF_ID, CONF_NAME, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
@@ -37,7 +38,7 @@ def _migrate_to_new_unique_id(hass: HomeAssistant, dev_id, channel) -> None:
|
||||
"""Migrate old unique ids to new unique ids."""
|
||||
old_unique_id = f"{combine_hex(dev_id)}"
|
||||
|
||||
ent_reg = er.async_get(hass)
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
entity_id = ent_reg.async_get_entity_id(Platform.SWITCH, DOMAIN, old_unique_id)
|
||||
|
||||
if entity_id is not None:
|
||||
|
||||
@@ -130,10 +130,15 @@ class RuntimeEntryData:
|
||||
)
|
||||
self.ble_connections_free = free
|
||||
self.ble_connections_limit = limit
|
||||
if free:
|
||||
for fut in self._ble_connection_free_futures:
|
||||
if not free:
|
||||
return
|
||||
for fut in self._ble_connection_free_futures:
|
||||
# If wait_for_ble_connections_free gets cancelled, it will
|
||||
# leave a future in the list. We need to check if it's done
|
||||
# before setting the result.
|
||||
if not fut.done():
|
||||
fut.set_result(free)
|
||||
self._ble_connection_free_futures.clear()
|
||||
self._ble_connection_free_futures.clear()
|
||||
|
||||
async def wait_for_ble_connections_free(self) -> int:
|
||||
"""Wait until there are free BLE connections."""
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["aioesphomeapi", "noiseprotocol"],
|
||||
"requirements": ["aioesphomeapi==13.4.1", "esphome-dashboard-api==1.2.3"],
|
||||
"requirements": ["aioesphomeapi==13.5.1", "esphome-dashboard-api==1.2.3"],
|
||||
"zeroconf": ["_esphomelib._tcp.local."]
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@ from homeassistant.config_entries import (
|
||||
)
|
||||
from homeassistant.const import CONF_IP_ADDRESS, CONF_PASSWORD, CONF_USERNAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, discovery_flow
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddEntitiesCallback,
|
||||
async_get_current_platform,
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
discovery_flow,
|
||||
entity_platform,
|
||||
)
|
||||
|
||||
from .const import (
|
||||
@@ -53,7 +53,9 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: entity_platform.AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up EZVIZ cameras based on a config entry."""
|
||||
|
||||
@@ -130,7 +132,7 @@ async def async_setup_entry(
|
||||
|
||||
async_add_entities(camera_entities)
|
||||
|
||||
platform = async_get_current_platform()
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_PTZ,
|
||||
|
||||
@@ -14,11 +14,7 @@ from homeassistant.const import (
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import (
|
||||
condition,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
|
||||
@@ -38,11 +34,11 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Fan devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
conditions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -94,9 +94,9 @@ class FibaroCover(FibaroDevice, CoverEntity):
|
||||
"""Return if the cover is closed."""
|
||||
if self._is_open_close_only():
|
||||
state = self.fibaro_device.state
|
||||
if not state.has_value or state.str_value.lower() == "unknown":
|
||||
if not state.has_value or state.str_value().lower() == "unknown":
|
||||
return None
|
||||
return state.str_value.lower() == "closed"
|
||||
return state.str_value().lower() == "closed"
|
||||
|
||||
if self.current_cover_position is None:
|
||||
return None
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"integration_type": "hub",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["pyfibaro"],
|
||||
"requirements": ["pyfibaro==0.6.8"]
|
||||
"requirements": ["pyfibaro==0.6.9"]
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ from homeassistant.helpers.icon import icon_for_battery_level
|
||||
from homeassistant.helpers.json import save_json
|
||||
from homeassistant.helpers.network import NoURLAvailableError, get_url
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
from homeassistant.util.json import load_json_object
|
||||
from homeassistant.util.json import load_json
|
||||
from homeassistant.util.unit_system import METRIC_SYSTEM
|
||||
|
||||
from .const import (
|
||||
@@ -85,7 +85,7 @@ def request_app_setup(
|
||||
"""Handle configuration updates."""
|
||||
config_path = hass.config.path(FITBIT_CONFIG_FILE)
|
||||
if os.path.isfile(config_path):
|
||||
config_file = load_json_object(config_path)
|
||||
config_file = load_json(config_path)
|
||||
if config_file == DEFAULT_CONFIG:
|
||||
error_msg = (
|
||||
f"You didn't correctly modify {FITBIT_CONFIG_FILE}, please try"
|
||||
@@ -161,7 +161,7 @@ def setup_platform(
|
||||
"""Set up the Fitbit sensor."""
|
||||
config_path = hass.config.path(FITBIT_CONFIG_FILE)
|
||||
if os.path.isfile(config_path):
|
||||
config_file = load_json_object(config_path)
|
||||
config_file: ConfigType = cast(ConfigType, load_json(config_path))
|
||||
if config_file == DEFAULT_CONFIG:
|
||||
request_app_setup(
|
||||
hass, config, add_entities, config_path, discovery_info=None
|
||||
@@ -175,10 +175,13 @@ def setup_platform(
|
||||
if "fitbit" in _CONFIGURING:
|
||||
configurator.request_done(hass, _CONFIGURING.pop("fitbit"))
|
||||
|
||||
access_token: str | None = config_file.get(ATTR_ACCESS_TOKEN)
|
||||
refresh_token: str | None = config_file.get(ATTR_REFRESH_TOKEN)
|
||||
expires_at: int | None = config_file.get(ATTR_LAST_SAVED_AT)
|
||||
if (
|
||||
(access_token := config_file.get(ATTR_ACCESS_TOKEN)) is not None
|
||||
and (refresh_token := config_file.get(ATTR_REFRESH_TOKEN)) is not None
|
||||
and (expires_at := config_file.get(ATTR_LAST_SAVED_AT)) is not None
|
||||
access_token is not None
|
||||
and refresh_token is not None
|
||||
and expires_at is not None
|
||||
):
|
||||
authd_client = Fitbit(
|
||||
config_file.get(CONF_CLIENT_ID),
|
||||
@@ -189,7 +192,7 @@ def setup_platform(
|
||||
refresh_cb=lambda x: None,
|
||||
)
|
||||
|
||||
if int(time.time()) - cast(int, expires_at) > 3600:
|
||||
if int(time.time()) - expires_at > 3600:
|
||||
authd_client.client.refresh_token()
|
||||
|
||||
user_profile = authd_client.user_profile_get()["user"]
|
||||
|
||||
@@ -77,7 +77,6 @@ class FreeboxFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
# Check permissions
|
||||
await fbx.system.get_config()
|
||||
await fbx.lan.get_hosts_list()
|
||||
await self.hass.async_block_till_done()
|
||||
|
||||
# Close connection
|
||||
await fbx.close()
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||
"integration_type": "system",
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["home-assistant-frontend==20230227.0"]
|
||||
"requirements": ["home-assistant-frontend==20230309.1"]
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ async def async_setup_platform(
|
||||
[
|
||||
GeniusClimateZone(broker, z)
|
||||
for z in broker.client.zone_objs
|
||||
if z.data["type"] in GH_ZONES
|
||||
if z.data.get("type") in GH_ZONES
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ async def async_setup_platform(
|
||||
[
|
||||
GeniusSwitch(broker, z)
|
||||
for z in broker.client.zone_objs
|
||||
if z.data["type"] == GH_ON_OFF_ZONE
|
||||
if z.data.get("type") == GH_ON_OFF_ZONE
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ async def async_setup_platform(
|
||||
[
|
||||
GeniusWaterHeater(broker, z)
|
||||
for z in broker.client.zone_objs
|
||||
if z.data["type"] in GH_HEATERS
|
||||
if z.data.get("type") in GH_HEATERS
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from homeassistant.components.device_tracker import SourceType, TrackerEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_LATITUDE, ATTR_LONGITUDE
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers import device_registry
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
@@ -34,7 +34,7 @@ async def async_setup_entry(
|
||||
] = async_dispatcher_connect(hass, TRACKER_UPDATE, _receive_data)
|
||||
|
||||
# Restore previously loaded devices
|
||||
dev_reg = dr.async_get(hass)
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
dev_ids = {
|
||||
identifier[1]
|
||||
for device in dev_reg.devices.values()
|
||||
|
||||
@@ -21,7 +21,7 @@ from homeassistant.const import (
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
@@ -257,7 +257,7 @@ async def async_setup_entry(
|
||||
hass: HomeAssistant, old_unique_id: str, new_key: str
|
||||
) -> None:
|
||||
"""Migrate unique IDs to the new format."""
|
||||
ent_reg = er.async_get(hass)
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
|
||||
if entity_id := ent_reg.async_get_entity_id(
|
||||
Platform.SENSOR, DOMAIN, old_unique_id
|
||||
|
||||
@@ -22,12 +22,7 @@ from homeassistant.const import (
|
||||
STATE_UNAVAILABLE,
|
||||
)
|
||||
from homeassistant.core import Context, HomeAssistant, State, callback
|
||||
from homeassistant.helpers import (
|
||||
area_registry as ar,
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
start,
|
||||
)
|
||||
from homeassistant.helpers import area_registry, device_registry, entity_registry, start
|
||||
from homeassistant.helpers.event import async_call_later
|
||||
from homeassistant.helpers.network import get_url
|
||||
from homeassistant.helpers.storage import Store
|
||||
@@ -57,11 +52,15 @@ LOCAL_SDK_MIN_VERSION = AwesomeVersion("2.1.5")
|
||||
@callback
|
||||
def _get_registry_entries(
|
||||
hass: HomeAssistant, entity_id: str
|
||||
) -> tuple[er.RegistryEntry | None, dr.DeviceEntry | None, ar.AreaEntry | None,]:
|
||||
) -> tuple[
|
||||
entity_registry.RegistryEntry | None,
|
||||
device_registry.DeviceEntry | None,
|
||||
area_registry.AreaEntry | None,
|
||||
]:
|
||||
"""Get registry entries."""
|
||||
ent_reg = er.async_get(hass)
|
||||
dev_reg = dr.async_get(hass)
|
||||
area_reg = ar.async_get(hass)
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
area_reg = area_registry.async_get(hass)
|
||||
|
||||
if (entity_entry := ent_reg.async_get(entity_id)) and entity_entry.device_id:
|
||||
device_entry = dev_reg.devices.get(entity_entry.device_id)
|
||||
|
||||
@@ -8,7 +8,7 @@ from homeassistant.const import (
|
||||
ATTR_LONGITUDE,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers import device_registry
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
@@ -44,7 +44,7 @@ async def async_setup_entry(
|
||||
] = async_dispatcher_connect(hass, TRACKER_UPDATE, _receive_data)
|
||||
|
||||
# Restore previously loaded devices
|
||||
dev_reg = dr.async_get(hass)
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
dev_ids = {
|
||||
identifier[1]
|
||||
for device in dev_reg.devices.values()
|
||||
|
||||
@@ -342,12 +342,14 @@ def get_next_departure(
|
||||
origin_stop_time.departure_time
|
||||
LIMIT :limit
|
||||
"""
|
||||
result = schedule.engine.execute(
|
||||
result = schedule.engine.connect().execute(
|
||||
text(sql_query),
|
||||
origin_station_id=start_station_id,
|
||||
end_station_id=end_station_id,
|
||||
today=now_date,
|
||||
limit=limit,
|
||||
{
|
||||
"origin_station_id": start_station_id,
|
||||
"end_station_id": end_station_id,
|
||||
"today": now_date,
|
||||
"limit": limit,
|
||||
},
|
||||
)
|
||||
|
||||
# Create lookup timetable for today and possibly tomorrow, taking into
|
||||
@@ -357,7 +359,8 @@ def get_next_departure(
|
||||
yesterday_start = today_start = tomorrow_start = None
|
||||
yesterday_last = today_last = ""
|
||||
|
||||
for row in result:
|
||||
for row_cursor in result:
|
||||
row = row_cursor._asdict()
|
||||
if row["yesterday"] == 1 and yesterday_date >= row["start_date"]:
|
||||
extras = {"day": "yesterday", "first": None, "last": False}
|
||||
if yesterday_start is None:
|
||||
@@ -800,7 +803,10 @@ class GTFSDepartureSensor(SensorEntity):
|
||||
@staticmethod
|
||||
def dict_for_table(resource: Any) -> dict:
|
||||
"""Return a dictionary for the SQLAlchemy resource given."""
|
||||
return {col: getattr(resource, col) for col in resource.__table__.columns}
|
||||
_dict = {}
|
||||
for column in resource.__table__.columns:
|
||||
_dict[column.name] = str(getattr(resource, column.name))
|
||||
return _dict
|
||||
|
||||
def append_keys(self, resource: dict, prefix: str | None = None) -> None:
|
||||
"""Properly format key val pairs to append to attributes."""
|
||||
|
||||
@@ -12,7 +12,7 @@ from aioguardian.errors import GuardianError
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
@@ -41,7 +41,7 @@ def async_finish_entity_domain_replacements(
|
||||
entity_replacement_strategies: Iterable[EntityDomainReplacementStrategy],
|
||||
) -> None:
|
||||
"""Remove old entities and create a repairs issue with info on their replacement."""
|
||||
ent_reg = er.async_get(hass)
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
for strategy in entity_replacement_strategies:
|
||||
try:
|
||||
[registry_entry] = [
|
||||
|
||||
@@ -5,7 +5,7 @@ from homeassistant.components.remote import ATTR_ACTIVITY, ATTR_DELAY_SECS
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, CONF_NAME, EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
|
||||
from .const import (
|
||||
@@ -60,7 +60,7 @@ async def _migrate_old_unique_ids(
|
||||
names_to_ids = {activity["label"]: activity["id"] for activity in data.activities}
|
||||
|
||||
@callback
|
||||
def _async_migrator(entity_entry: er.RegistryEntry):
|
||||
def _async_migrator(entity_entry: entity_registry.RegistryEntry):
|
||||
# Old format for switches was {remote_unique_id}-{activity_name}
|
||||
# New format is activity_{activity_id}
|
||||
parts = entity_entry.unique_id.split("-", 1)
|
||||
@@ -78,7 +78,7 @@ async def _migrate_old_unique_ids(
|
||||
|
||||
return None
|
||||
|
||||
await er.async_migrate_entries(hass, entry_id, _async_migrator)
|
||||
await entity_registry.async_migrate_entries(hass, entry_id, _async_migrator)
|
||||
|
||||
|
||||
@callback
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/harmony",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["aioharmony", "slixmpp"],
|
||||
"requirements": ["aioharmony==0.2.9"],
|
||||
"requirements": ["aioharmony==0.2.10"],
|
||||
"ssdp": [
|
||||
{
|
||||
"manufacturer": "Logitech",
|
||||
|
||||
@@ -96,7 +96,7 @@ from .handler import ( # noqa: F401
|
||||
)
|
||||
from .http import HassIOView
|
||||
from .ingress import async_setup_ingress_view
|
||||
from .repairs import SupervisorRepairs
|
||||
from .issues import SupervisorIssues
|
||||
from .websocket_api import async_load_websocket_api
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -123,7 +123,7 @@ DATA_SUPERVISOR_INFO = "hassio_supervisor_info"
|
||||
DATA_ADDONS_CHANGELOGS = "hassio_addons_changelogs"
|
||||
DATA_ADDONS_INFO = "hassio_addons_info"
|
||||
DATA_ADDONS_STATS = "hassio_addons_stats"
|
||||
DATA_SUPERVISOR_REPAIRS = "supervisor_repairs"
|
||||
DATA_SUPERVISOR_ISSUES = "supervisor_issues"
|
||||
HASSIO_UPDATE_INTERVAL = timedelta(minutes=5)
|
||||
|
||||
ADDONS_COORDINATOR = "hassio_addons_coordinator"
|
||||
@@ -581,9 +581,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # noqa:
|
||||
hass.config_entries.flow.async_init(DOMAIN, context={"source": "system"})
|
||||
)
|
||||
|
||||
# Start listening for problems with supervisor and making repairs
|
||||
hass.data[DATA_SUPERVISOR_REPAIRS] = repairs = SupervisorRepairs(hass, hassio)
|
||||
await repairs.setup()
|
||||
# Start listening for problems with supervisor and making issues
|
||||
hass.data[DATA_SUPERVISOR_ISSUES] = issues = SupervisorIssues(hass, hassio)
|
||||
await issues.setup()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ X_AUTH_TOKEN = "X-Supervisor-Token"
|
||||
X_INGRESS_PATH = "X-Ingress-Path"
|
||||
X_HASS_USER_ID = "X-Hass-User-ID"
|
||||
X_HASS_IS_ADMIN = "X-Hass-Is-Admin"
|
||||
X_HASS_SOURCE = "X-Hass-Source"
|
||||
|
||||
WS_TYPE = "type"
|
||||
WS_ID = "id"
|
||||
|
||||
@@ -17,7 +17,7 @@ from homeassistant.const import SERVER_PORT
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.loader import bind_hass
|
||||
|
||||
from .const import ATTR_DISCOVERY, DOMAIN
|
||||
from .const import ATTR_DISCOVERY, DOMAIN, X_HASS_SOURCE
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -445,6 +445,8 @@ class HassIO:
|
||||
payload=None,
|
||||
timeout=10,
|
||||
return_text=False,
|
||||
*,
|
||||
source="core.handler",
|
||||
):
|
||||
"""Send API command to Hass.io.
|
||||
|
||||
@@ -458,7 +460,8 @@ class HassIO:
|
||||
headers={
|
||||
aiohttp.hdrs.AUTHORIZATION: (
|
||||
f"Bearer {os.environ.get('SUPERVISOR_TOKEN', '')}"
|
||||
)
|
||||
),
|
||||
X_HASS_SOURCE: source,
|
||||
},
|
||||
timeout=aiohttp.ClientTimeout(total=timeout),
|
||||
)
|
||||
|
||||
@@ -6,6 +6,7 @@ from http import HTTPStatus
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from urllib.parse import quote, unquote
|
||||
|
||||
import aiohttp
|
||||
from aiohttp import web
|
||||
@@ -19,13 +20,16 @@ from aiohttp.hdrs import (
|
||||
TRANSFER_ENCODING,
|
||||
)
|
||||
from aiohttp.web_exceptions import HTTPBadGateway
|
||||
from multidict import istr
|
||||
|
||||
from homeassistant.components.http import KEY_AUTHENTICATED, HomeAssistantView
|
||||
from homeassistant.components.http import (
|
||||
KEY_AUTHENTICATED,
|
||||
KEY_HASS_USER,
|
||||
HomeAssistantView,
|
||||
)
|
||||
from homeassistant.components.onboarding import async_is_onboarded
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import X_HASS_IS_ADMIN, X_HASS_USER_ID
|
||||
from .const import X_HASS_SOURCE
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -34,23 +38,53 @@ MAX_UPLOAD_SIZE = 1024 * 1024 * 1024
|
||||
# pylint: disable=implicit-str-concat
|
||||
NO_TIMEOUT = re.compile(
|
||||
r"^(?:"
|
||||
r"|homeassistant/update"
|
||||
r"|hassos/update"
|
||||
r"|hassos/update/cli"
|
||||
r"|supervisor/update"
|
||||
r"|addons/[^/]+/(?:update|install|rebuild)"
|
||||
r"|backups/.+/full"
|
||||
r"|backups/.+/partial"
|
||||
r"|backups/[^/]+/(?:upload|download)"
|
||||
r")$"
|
||||
)
|
||||
|
||||
NO_AUTH_ONBOARDING = re.compile(r"^(?:" r"|supervisor/logs" r"|backups/[^/]+/.+" r")$")
|
||||
# fmt: off
|
||||
# Onboarding can upload backups and restore it
|
||||
PATHS_NOT_ONBOARDED = re.compile(
|
||||
r"^(?:"
|
||||
r"|backups/[a-f0-9]{8}(/info|/new/upload|/download|/restore/full|/restore/partial)?"
|
||||
r"|backups/new/upload"
|
||||
r")$"
|
||||
)
|
||||
|
||||
NO_AUTH = re.compile(r"^(?:" r"|app/.*" r"|[store\/]*addons/[^/]+/(logo|icon)" r")$")
|
||||
# Authenticated users manage backups + download logs, changelog and documentation
|
||||
PATHS_ADMIN = re.compile(
|
||||
r"^(?:"
|
||||
r"|backups/[a-f0-9]{8}(/info|/download|/restore/full|/restore/partial)?"
|
||||
r"|backups/new/upload"
|
||||
r"|audio/logs"
|
||||
r"|cli/logs"
|
||||
r"|core/logs"
|
||||
r"|dns/logs"
|
||||
r"|host/logs"
|
||||
r"|multicast/logs"
|
||||
r"|observer/logs"
|
||||
r"|supervisor/logs"
|
||||
r"|addons/[^/]+/(changelog|documentation|logs)"
|
||||
r")$"
|
||||
)
|
||||
|
||||
NO_STORE = re.compile(r"^(?:" r"|app/entrypoint.js" r")$")
|
||||
# Unauthenticated requests come in for Supervisor panel + add-on images
|
||||
PATHS_NO_AUTH = re.compile(
|
||||
r"^(?:"
|
||||
r"|app/.*"
|
||||
r"|(store/)?addons/[^/]+/(logo|icon)"
|
||||
r")$"
|
||||
)
|
||||
|
||||
NO_STORE = re.compile(
|
||||
r"^(?:"
|
||||
r"|app/entrypoint.js"
|
||||
r")$"
|
||||
)
|
||||
# pylint: enable=implicit-str-concat
|
||||
# fmt: on
|
||||
|
||||
|
||||
class HassIOView(HomeAssistantView):
|
||||
@@ -65,38 +99,66 @@ class HassIOView(HomeAssistantView):
|
||||
self._host = host
|
||||
self._websession = websession
|
||||
|
||||
async def _handle(
|
||||
self, request: web.Request, path: str
|
||||
) -> web.Response | web.StreamResponse:
|
||||
"""Route data to Hass.io."""
|
||||
hass = request.app["hass"]
|
||||
if _need_auth(hass, path) and not request[KEY_AUTHENTICATED]:
|
||||
return web.Response(status=HTTPStatus.UNAUTHORIZED)
|
||||
|
||||
return await self._command_proxy(path, request)
|
||||
|
||||
delete = _handle
|
||||
get = _handle
|
||||
post = _handle
|
||||
|
||||
async def _command_proxy(
|
||||
self, path: str, request: web.Request
|
||||
) -> web.StreamResponse:
|
||||
async def _handle(self, request: web.Request, path: str) -> web.StreamResponse:
|
||||
"""Return a client request with proxy origin for Hass.io supervisor.
|
||||
|
||||
This method is a coroutine.
|
||||
Use cases:
|
||||
- Onboarding allows restoring backups
|
||||
- Load Supervisor panel and add-on logo unauthenticated
|
||||
- User upload/restore backups
|
||||
"""
|
||||
headers = _init_header(request)
|
||||
if path == "backups/new/upload":
|
||||
# We need to reuse the full content type that includes the boundary
|
||||
headers[
|
||||
CONTENT_TYPE
|
||||
] = request._stored_content_type # pylint: disable=protected-access
|
||||
# No bullshit
|
||||
if path != unquote(path):
|
||||
return web.Response(status=HTTPStatus.BAD_REQUEST)
|
||||
|
||||
hass: HomeAssistant = request.app["hass"]
|
||||
is_admin = request[KEY_AUTHENTICATED] and request[KEY_HASS_USER].is_admin
|
||||
authorized = is_admin
|
||||
|
||||
if is_admin:
|
||||
allowed_paths = PATHS_ADMIN
|
||||
|
||||
elif not async_is_onboarded(hass):
|
||||
allowed_paths = PATHS_NOT_ONBOARDED
|
||||
|
||||
# During onboarding we need the user to manage backups
|
||||
authorized = True
|
||||
|
||||
else:
|
||||
# Either unauthenticated or not an admin
|
||||
allowed_paths = PATHS_NO_AUTH
|
||||
|
||||
no_auth_path = PATHS_NO_AUTH.match(path)
|
||||
headers = {
|
||||
X_HASS_SOURCE: "core.http",
|
||||
}
|
||||
|
||||
if no_auth_path:
|
||||
if request.method != "GET":
|
||||
return web.Response(status=HTTPStatus.METHOD_NOT_ALLOWED)
|
||||
|
||||
else:
|
||||
if not allowed_paths.match(path):
|
||||
return web.Response(status=HTTPStatus.UNAUTHORIZED)
|
||||
|
||||
if authorized:
|
||||
headers[
|
||||
AUTHORIZATION
|
||||
] = f"Bearer {os.environ.get('SUPERVISOR_TOKEN', '')}"
|
||||
|
||||
if request.method == "POST":
|
||||
headers[CONTENT_TYPE] = request.content_type
|
||||
# _stored_content_type is only computed once `content_type` is accessed
|
||||
if path == "backups/new/upload":
|
||||
# We need to reuse the full content type that includes the boundary
|
||||
headers[
|
||||
CONTENT_TYPE
|
||||
] = request._stored_content_type # pylint: disable=protected-access
|
||||
|
||||
try:
|
||||
client = await self._websession.request(
|
||||
method=request.method,
|
||||
url=f"http://{self._host}/{path}",
|
||||
url=f"http://{self._host}/{quote(path)}",
|
||||
params=request.query,
|
||||
data=request.content,
|
||||
headers=headers,
|
||||
@@ -123,20 +185,8 @@ class HassIOView(HomeAssistantView):
|
||||
|
||||
raise HTTPBadGateway()
|
||||
|
||||
|
||||
def _init_header(request: web.Request) -> dict[istr, str]:
|
||||
"""Create initial header."""
|
||||
headers = {
|
||||
AUTHORIZATION: f"Bearer {os.environ.get('SUPERVISOR_TOKEN', '')}",
|
||||
CONTENT_TYPE: request.content_type,
|
||||
}
|
||||
|
||||
# Add user data
|
||||
if request.get("hass_user") is not None:
|
||||
headers[istr(X_HASS_USER_ID)] = request["hass_user"].id
|
||||
headers[istr(X_HASS_IS_ADMIN)] = str(int(request["hass_user"].is_admin))
|
||||
|
||||
return headers
|
||||
get = _handle
|
||||
post = _handle
|
||||
|
||||
|
||||
def _response_header(response: aiohttp.ClientResponse, path: str) -> dict[str, str]:
|
||||
@@ -164,12 +214,3 @@ def _get_timeout(path: str) -> ClientTimeout:
|
||||
if NO_TIMEOUT.match(path):
|
||||
return ClientTimeout(connect=10, total=None)
|
||||
return ClientTimeout(connect=10, total=300)
|
||||
|
||||
|
||||
def _need_auth(hass: HomeAssistant, path: str) -> bool:
|
||||
"""Return if a path need authentication."""
|
||||
if not async_is_onboarded(hass) and NO_AUTH_ONBOARDING.match(path):
|
||||
return False
|
||||
if NO_AUTH.match(path):
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -3,20 +3,22 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Iterable
|
||||
from functools import lru_cache
|
||||
from ipaddress import ip_address
|
||||
import logging
|
||||
import os
|
||||
from urllib.parse import quote
|
||||
|
||||
import aiohttp
|
||||
from aiohttp import ClientTimeout, hdrs, web
|
||||
from aiohttp.web_exceptions import HTTPBadGateway, HTTPBadRequest
|
||||
from multidict import CIMultiDict
|
||||
from yarl import URL
|
||||
|
||||
from homeassistant.components.http import HomeAssistantView
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import X_AUTH_TOKEN, X_INGRESS_PATH
|
||||
from .const import X_HASS_SOURCE, X_INGRESS_PATH
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -42,9 +44,19 @@ class HassIOIngress(HomeAssistantView):
|
||||
self._host = host
|
||||
self._websession = websession
|
||||
|
||||
@lru_cache
|
||||
def _create_url(self, token: str, path: str) -> str:
|
||||
"""Create URL to service."""
|
||||
return f"http://{self._host}/ingress/{token}/{path}"
|
||||
base_path = f"/ingress/{token}/"
|
||||
url = f"http://{self._host}{base_path}{quote(path)}"
|
||||
|
||||
try:
|
||||
if not URL(url).path.startswith(base_path):
|
||||
raise HTTPBadRequest()
|
||||
except ValueError as err:
|
||||
raise HTTPBadRequest() from err
|
||||
|
||||
return url
|
||||
|
||||
async def _handle(
|
||||
self, request: web.Request, token: str, path: str
|
||||
@@ -185,10 +197,8 @@ def _init_header(request: web.Request, token: str) -> CIMultiDict | dict[str, st
|
||||
continue
|
||||
headers[name] = value
|
||||
|
||||
# Inject token / cleanup later on Supervisor
|
||||
headers[X_AUTH_TOKEN] = os.environ.get("SUPERVISOR_TOKEN", "")
|
||||
|
||||
# Ingress information
|
||||
headers[X_HASS_SOURCE] = "core.ingress"
|
||||
headers[X_INGRESS_PATH] = f"/api/hassio_ingress/{token}"
|
||||
|
||||
# Set X-Forwarded-For
|
||||
|
||||
@@ -70,11 +70,11 @@ UNHEALTHY_REASONS = {
|
||||
}
|
||||
|
||||
|
||||
class SupervisorRepairs:
|
||||
"""Create repairs from supervisor events."""
|
||||
class SupervisorIssues:
|
||||
"""Create issues from supervisor events."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, client: HassIO) -> None:
|
||||
"""Initialize supervisor repairs."""
|
||||
"""Initialize supervisor issues."""
|
||||
self._hass = hass
|
||||
self._client = client
|
||||
self._unsupported_reasons: set[str] = set()
|
||||
@@ -87,7 +87,7 @@ class SupervisorRepairs:
|
||||
|
||||
@unhealthy_reasons.setter
|
||||
def unhealthy_reasons(self, reasons: set[str]) -> None:
|
||||
"""Set unhealthy reasons. Create or delete repairs as necessary."""
|
||||
"""Set unhealthy reasons. Create or delete issues as necessary."""
|
||||
for unhealthy in reasons - self.unhealthy_reasons:
|
||||
if unhealthy in UNHEALTHY_REASONS:
|
||||
translation_key = f"unhealthy_{unhealthy}"
|
||||
@@ -119,7 +119,7 @@ class SupervisorRepairs:
|
||||
|
||||
@unsupported_reasons.setter
|
||||
def unsupported_reasons(self, reasons: set[str]) -> None:
|
||||
"""Set unsupported reasons. Create or delete repairs as necessary."""
|
||||
"""Set unsupported reasons. Create or delete issues as necessary."""
|
||||
for unsupported in reasons - UNSUPPORTED_SKIP_REPAIR - self.unsupported_reasons:
|
||||
if unsupported in UNSUPPORTED_REASONS:
|
||||
translation_key = f"unsupported_{unsupported}"
|
||||
@@ -149,18 +149,18 @@ class SupervisorRepairs:
|
||||
await self.update()
|
||||
|
||||
async_dispatcher_connect(
|
||||
self._hass, EVENT_SUPERVISOR_EVENT, self._supervisor_events_to_repairs
|
||||
self._hass, EVENT_SUPERVISOR_EVENT, self._supervisor_events_to_issues
|
||||
)
|
||||
|
||||
async def update(self) -> None:
|
||||
"""Update repairs from Supervisor resolution center."""
|
||||
"""Update issuess from Supervisor resolution center."""
|
||||
data = await self._client.get_resolution_info()
|
||||
self.unhealthy_reasons = set(data[ATTR_UNHEALTHY])
|
||||
self.unsupported_reasons = set(data[ATTR_UNSUPPORTED])
|
||||
|
||||
@callback
|
||||
def _supervisor_events_to_repairs(self, event: dict[str, Any]) -> None:
|
||||
"""Create repairs from supervisor events."""
|
||||
def _supervisor_events_to_issues(self, event: dict[str, Any]) -> None:
|
||||
"""Create issues from supervisor events."""
|
||||
if ATTR_WS_EVENT not in event:
|
||||
return
|
||||
|
||||
@@ -116,6 +116,7 @@ async def websocket_supervisor_api(
|
||||
method=msg[ATTR_METHOD],
|
||||
timeout=msg.get(ATTR_TIMEOUT, 10),
|
||||
payload=msg.get(ATTR_DATA, {}),
|
||||
source="core.websocket_api",
|
||||
)
|
||||
|
||||
if result.get(ATTR_RESULT) == "error":
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""Config flow for HLK-SW16."""
|
||||
import asyncio
|
||||
|
||||
import async_timeout
|
||||
from hlk_sw16 import create_hlk_sw16_connection
|
||||
import voluptuous as vol
|
||||
|
||||
@@ -36,8 +35,7 @@ async def connect_client(hass, user_input):
|
||||
reconnect_interval=DEFAULT_RECONNECT_INTERVAL,
|
||||
keep_alive_interval=DEFAULT_KEEP_ALIVE_INTERVAL,
|
||||
)
|
||||
async with async_timeout.timeout(CONNECTION_TIMEOUT):
|
||||
return await client_aw
|
||||
return await asyncio.wait_for(client_aw, timeout=CONNECTION_TIMEOUT)
|
||||
|
||||
|
||||
async def validate_input(hass: HomeAssistant, user_input):
|
||||
|
||||
@@ -50,12 +50,8 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import CoreState, HomeAssistant, ServiceCall, State, callback
|
||||
from homeassistant.exceptions import HomeAssistantError, Unauthorized
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
instance_id,
|
||||
)
|
||||
from homeassistant.helpers import device_registry, entity_registry, instance_id
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entityfilter import (
|
||||
BASE_FILTER_SCHEMA,
|
||||
FILTER_SCHEMA,
|
||||
@@ -435,19 +431,20 @@ def _async_register_events_and_services(hass: HomeAssistant) -> None:
|
||||
async def async_handle_homekit_unpair(service: ServiceCall) -> None:
|
||||
"""Handle unpair HomeKit service call."""
|
||||
referenced = async_extract_referenced_entity_ids(hass, service)
|
||||
dev_reg = dr.async_get(hass)
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
for device_id in referenced.referenced_devices:
|
||||
if not (dev_reg_ent := dev_reg.async_get(device_id)):
|
||||
raise HomeAssistantError(f"No device found for device id: {device_id}")
|
||||
macs = [
|
||||
cval
|
||||
for ctype, cval in dev_reg_ent.connections
|
||||
if ctype == dr.CONNECTION_NETWORK_MAC
|
||||
if ctype == device_registry.CONNECTION_NETWORK_MAC
|
||||
]
|
||||
matching_instances = [
|
||||
homekit
|
||||
for homekit in _async_all_homekit_instances(hass)
|
||||
if homekit.driver and dr.format_mac(homekit.driver.state.mac) in macs
|
||||
if homekit.driver
|
||||
and device_registry.format_mac(homekit.driver.state.mac) in macs
|
||||
]
|
||||
if not matching_instances:
|
||||
raise HomeAssistantError(
|
||||
@@ -701,7 +698,7 @@ class HomeKit:
|
||||
return False
|
||||
|
||||
def add_bridge_triggers_accessory(
|
||||
self, device: dr.DeviceEntry, device_triggers: list[dict[str, Any]]
|
||||
self, device: device_registry.DeviceEntry, device_triggers: list[dict[str, Any]]
|
||||
) -> None:
|
||||
"""Add device automation triggers to the bridge."""
|
||||
if self._would_exceed_max_devices(device.name):
|
||||
@@ -737,8 +734,8 @@ class HomeKit:
|
||||
|
||||
async def async_configure_accessories(self) -> list[State]:
|
||||
"""Configure accessories for the included states."""
|
||||
dev_reg = dr.async_get(self.hass)
|
||||
ent_reg = er.async_get(self.hass)
|
||||
dev_reg = device_registry.async_get(self.hass)
|
||||
ent_reg = entity_registry.async_get(self.hass)
|
||||
device_lookup = ent_reg.async_get_device_class_lookup(
|
||||
{
|
||||
(BINARY_SENSOR_DOMAIN, BinarySensorDeviceClass.BATTERY_CHARGING),
|
||||
@@ -833,8 +830,8 @@ class HomeKit:
|
||||
def _async_register_bridge(self) -> None:
|
||||
"""Register the bridge as a device so homekit_controller and exclude it from discovery."""
|
||||
assert self.driver is not None
|
||||
dev_reg = dr.async_get(self.hass)
|
||||
formatted_mac = dr.format_mac(self.driver.state.mac)
|
||||
dev_reg = device_registry.async_get(self.hass)
|
||||
formatted_mac = device_registry.format_mac(self.driver.state.mac)
|
||||
# Connections and identifiers are both used here.
|
||||
#
|
||||
# connections exists so homekit_controller can know the
|
||||
@@ -847,7 +844,7 @@ class HomeKit:
|
||||
# because this was the way you had to fix homekit when pairing
|
||||
# failed.
|
||||
#
|
||||
connection = (dr.CONNECTION_NETWORK_MAC, formatted_mac)
|
||||
connection = (device_registry.CONNECTION_NETWORK_MAC, formatted_mac)
|
||||
identifier = (DOMAIN, self._entry_id, BRIDGE_SERIAL_NUMBER)
|
||||
self._async_purge_old_bridges(dev_reg, identifier, connection)
|
||||
is_accessory_mode = self._homekit_mode == HOMEKIT_MODE_ACCESSORY
|
||||
@@ -861,13 +858,13 @@ class HomeKit:
|
||||
manufacturer=MANUFACTURER,
|
||||
name=accessory_friendly_name(self._entry_title, self.driver.accessory),
|
||||
model=f"HomeKit {hk_mode_name}",
|
||||
entry_type=dr.DeviceEntryType.SERVICE,
|
||||
entry_type=device_registry.DeviceEntryType.SERVICE,
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_purge_old_bridges(
|
||||
self,
|
||||
dev_reg: dr.DeviceRegistry,
|
||||
dev_reg: device_registry.DeviceRegistry,
|
||||
identifier: tuple[str, str, str],
|
||||
connection: tuple[str, str],
|
||||
) -> None:
|
||||
@@ -923,7 +920,7 @@ class HomeKit:
|
||||
|
||||
async def _async_add_trigger_accessories(self) -> None:
|
||||
"""Add devices with triggers to the bridge."""
|
||||
dev_reg = dr.async_get(self.hass)
|
||||
dev_reg = device_registry.async_get(self.hass)
|
||||
valid_device_ids = []
|
||||
for device_id in self._devices:
|
||||
if not dev_reg.async_get(device_id):
|
||||
@@ -992,7 +989,7 @@ class HomeKit:
|
||||
@callback
|
||||
def _async_configure_linked_sensors(
|
||||
self,
|
||||
ent_reg_ent: er.RegistryEntry,
|
||||
ent_reg_ent: entity_registry.RegistryEntry,
|
||||
device_lookup: dict[str, dict[tuple[str, str | None], str]],
|
||||
state: State,
|
||||
) -> None:
|
||||
@@ -1054,8 +1051,8 @@ class HomeKit:
|
||||
|
||||
async def _async_set_device_info_attributes(
|
||||
self,
|
||||
ent_reg_ent: er.RegistryEntry,
|
||||
dev_reg: dr.DeviceRegistry,
|
||||
ent_reg_ent: entity_registry.RegistryEntry,
|
||||
dev_reg: device_registry.DeviceRegistry,
|
||||
entity_id: str,
|
||||
) -> None:
|
||||
"""Set attributes that will be used for homekit device info."""
|
||||
@@ -1073,7 +1070,7 @@ class HomeKit:
|
||||
ent_cfg[ATTR_INTEGRATION] = ent_reg_ent.platform
|
||||
|
||||
def _fill_config_from_device_registry_entry(
|
||||
self, device_entry: dr.DeviceEntry, config: dict[str, Any]
|
||||
self, device_entry: device_registry.DeviceEntry, config: dict[str, Any]
|
||||
) -> None:
|
||||
"""Populate a config dict from the registry."""
|
||||
if device_entry.manufacturer:
|
||||
|
||||
@@ -28,11 +28,8 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback, split_entity_id
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
)
|
||||
from homeassistant.helpers import device_registry, entity_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entityfilter import (
|
||||
CONF_EXCLUDE_DOMAINS,
|
||||
CONF_EXCLUDE_ENTITIES,
|
||||
@@ -633,7 +630,7 @@ async def _async_get_supported_devices(hass: HomeAssistant) -> dict[str, str]:
|
||||
results = await device_automation.async_get_device_automations(
|
||||
hass, device_automation.DeviceAutomationType.TRIGGER
|
||||
)
|
||||
dev_reg = dr.async_get(hass)
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
unsorted: dict[str, str] = {}
|
||||
for device_id in results:
|
||||
entry = dev_reg.async_get(device_id)
|
||||
@@ -642,7 +639,7 @@ async def _async_get_supported_devices(hass: HomeAssistant) -> dict[str, str]:
|
||||
|
||||
|
||||
def _exclude_by_entity_registry(
|
||||
ent_reg: er.EntityRegistry,
|
||||
ent_reg: entity_registry.EntityRegistry,
|
||||
entity_id: str,
|
||||
include_entity_category: bool,
|
||||
include_hidden: bool,
|
||||
@@ -664,7 +661,7 @@ def _async_get_matching_entities(
|
||||
include_hidden: bool = False,
|
||||
) -> dict[str, str]:
|
||||
"""Fetch all entities or entities in the given domains."""
|
||||
ent_reg = er.async_get(hass)
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
return {
|
||||
state.entity_id: (
|
||||
f"{state.attributes.get(ATTR_FRIENDLY_NAME, state.entity_id)} ({state.entity_id})"
|
||||
|
||||
@@ -7,7 +7,7 @@ from typing import Any
|
||||
from pyhap.const import CATEGORY_SENSOR
|
||||
|
||||
from homeassistant.core import CALLBACK_TYPE, Context
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
from homeassistant.helpers.trigger import async_initialize_triggers
|
||||
|
||||
from .accessories import TYPES, HomeAccessory
|
||||
@@ -42,7 +42,7 @@ class DeviceTriggerAccessory(HomeAccessory):
|
||||
self._remove_triggers: CALLBACK_TYPE | None = None
|
||||
self.triggers = []
|
||||
assert device_triggers is not None
|
||||
ent_reg = er.async_get(self.hass)
|
||||
ent_reg = entity_registry.async_get(self.hass)
|
||||
for idx, trigger in enumerate(device_triggers):
|
||||
type_: str = trigger["type"]
|
||||
subtype: str | None = trigger.get("subtype")
|
||||
|
||||
@@ -14,7 +14,6 @@ PLATFORMS = [
|
||||
Platform.CLIMATE,
|
||||
Platform.COVER,
|
||||
Platform.LIGHT,
|
||||
Platform.LOCK,
|
||||
Platform.SENSOR,
|
||||
Platform.SWITCH,
|
||||
Platform.WEATHER,
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
"""Helper functions for Homematicip Cloud Integration."""
|
||||
|
||||
from functools import wraps
|
||||
import json
|
||||
import logging
|
||||
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
from . import HomematicipGenericEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def is_error_response(response) -> bool:
|
||||
"""Response from async call contains errors or not."""
|
||||
if isinstance(response, dict):
|
||||
return response.get("errorCode") not in ("", None)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def handle_errors(func):
|
||||
"""Handle async errors."""
|
||||
|
||||
@wraps(func)
|
||||
async def inner(self: HomematicipGenericEntity) -> None:
|
||||
"""Handle errors from async call."""
|
||||
result = await func(self)
|
||||
if is_error_response(result):
|
||||
_LOGGER.error(
|
||||
"Error while execute function %s: %s",
|
||||
__name__,
|
||||
json.dumps(result),
|
||||
)
|
||||
raise HomeAssistantError(
|
||||
f"Error while execute function {func.__name__}: {result.get('errorCode')}. See log for more information."
|
||||
)
|
||||
|
||||
return inner
|
||||
@@ -1,95 +0,0 @@
|
||||
"""Support for HomematicIP Cloud lock devices."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from homematicip.aio.device import AsyncDoorLockDrive
|
||||
from homematicip.base.enums import LockState, MotorState
|
||||
|
||||
from homeassistant.components.lock import LockEntity, LockEntityFeature
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericEntity
|
||||
from .helpers import handle_errors
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTR_AUTO_RELOCK_DELAY = "auto_relock_delay"
|
||||
ATTR_DOOR_HANDLE_TYPE = "door_handle_type"
|
||||
ATTR_DOOR_LOCK_DIRECTION = "door_lock_direction"
|
||||
ATTR_DOOR_LOCK_NEUTRAL_POSITION = "door_lock_neutral_position"
|
||||
ATTR_DOOR_LOCK_TURNS = "door_lock_turns"
|
||||
|
||||
DEVICE_DLD_ATTRIBUTES = {
|
||||
"autoRelockDelay": ATTR_AUTO_RELOCK_DELAY,
|
||||
"doorHandleType": ATTR_DOOR_HANDLE_TYPE,
|
||||
"doorLockDirection": ATTR_DOOR_LOCK_DIRECTION,
|
||||
"doorLockNeutralPosition": ATTR_DOOR_LOCK_NEUTRAL_POSITION,
|
||||
"doorLockTurns": ATTR_DOOR_LOCK_TURNS,
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the HomematicIP locks from a config entry."""
|
||||
hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id]
|
||||
|
||||
async_add_entities(
|
||||
HomematicipDoorLockDrive(hap, device)
|
||||
for device in hap.home.devices
|
||||
if isinstance(device, AsyncDoorLockDrive)
|
||||
)
|
||||
|
||||
|
||||
class HomematicipDoorLockDrive(HomematicipGenericEntity, LockEntity):
|
||||
"""Representation of the HomematicIP DoorLockDrive."""
|
||||
|
||||
_attr_supported_features = LockEntityFeature.OPEN
|
||||
|
||||
@property
|
||||
def is_locked(self) -> bool | None:
|
||||
"""Return true if device is locked."""
|
||||
return (
|
||||
self._device.lockState == LockState.LOCKED
|
||||
and self._device.motorState == MotorState.STOPPED
|
||||
)
|
||||
|
||||
@property
|
||||
def is_locking(self) -> bool:
|
||||
"""Return true if device is locking."""
|
||||
return self._device.motorState == MotorState.CLOSING
|
||||
|
||||
@property
|
||||
def is_unlocking(self) -> bool:
|
||||
"""Return true if device is unlocking."""
|
||||
return self._device.motorState == MotorState.OPENING
|
||||
|
||||
@handle_errors
|
||||
async def async_lock(self, **kwargs: Any) -> None:
|
||||
"""Lock the device."""
|
||||
return await self._device.set_lock_state(LockState.LOCKED)
|
||||
|
||||
@handle_errors
|
||||
async def async_unlock(self, **kwargs: Any) -> None:
|
||||
"""Unlock the device."""
|
||||
return await self._device.set_lock_state(LockState.UNLOCKED)
|
||||
|
||||
@handle_errors
|
||||
async def async_open(self, **kwargs: Any) -> None:
|
||||
"""Open the door latch."""
|
||||
return await self._device.set_lock_state(LockState.OPEN)
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the state attributes of the device."""
|
||||
return super().extra_state_attributes | {
|
||||
attr_key: attr_value
|
||||
for attr, attr_key in DEVICE_DLD_ATTRIBUTES.items()
|
||||
if (attr_value := getattr(self._device, attr, None)) is not None
|
||||
}
|
||||
@@ -60,9 +60,7 @@ def async_sign_path(
|
||||
|
||||
url = URL(path)
|
||||
now = dt_util.utcnow()
|
||||
params = dict(sorted(url.query.items()))
|
||||
for param in SAFE_QUERY_PARAMS:
|
||||
params.pop(param, None)
|
||||
params = [itm for itm in url.query.items() if itm[0] not in SAFE_QUERY_PARAMS]
|
||||
encoded = jwt.encode(
|
||||
{
|
||||
"iss": refresh_token_id,
|
||||
@@ -75,7 +73,7 @@ def async_sign_path(
|
||||
algorithm="HS256",
|
||||
)
|
||||
|
||||
params[SIGN_QUERY_PARAM] = encoded
|
||||
params.append((SIGN_QUERY_PARAM, encoded))
|
||||
url = url.with_query(params)
|
||||
return f"{url.path}?{url.query_string}"
|
||||
|
||||
@@ -184,10 +182,11 @@ async def async_setup_auth(hass: HomeAssistant, app: Application) -> None:
|
||||
if claims["path"] != request.path:
|
||||
return False
|
||||
|
||||
params = dict(sorted(request.query.items()))
|
||||
del params[SIGN_QUERY_PARAM]
|
||||
for param in SAFE_QUERY_PARAMS:
|
||||
params.pop(param, None)
|
||||
params = [
|
||||
list(itm) # claims stores tuples as lists
|
||||
for itm in request.query.items()
|
||||
if itm[0] not in SAFE_QUERY_PARAMS and itm[0] != SIGN_QUERY_PARAM
|
||||
]
|
||||
if claims["params"] != params:
|
||||
return False
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
discovery,
|
||||
entity_registry as er,
|
||||
entity_registry,
|
||||
)
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send
|
||||
from homeassistant.helpers.entity import DeviceInfo, Entity
|
||||
@@ -359,8 +359,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
# Transitional from < 2021.8: update None config entry and entity unique ids
|
||||
if router_info and (serial_number := router_info.get("SerialNumber")):
|
||||
hass.config_entries.async_update_entry(entry, unique_id=serial_number)
|
||||
ent_reg = er.async_get(hass)
|
||||
for entity_entry in er.async_entries_for_config_entry(
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
for entity_entry in entity_registry.async_entries_for_config_entry(
|
||||
ent_reg, entry.entry_id
|
||||
):
|
||||
if not entity_entry.unique_id.startswith("None-"):
|
||||
|
||||
@@ -15,7 +15,7 @@ from homeassistant.components.device_tracker import (
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
@@ -66,7 +66,7 @@ async def async_setup_entry(
|
||||
|
||||
# Initialize already tracked entities
|
||||
tracked: set[str] = set()
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
known_entities: list[Entity] = []
|
||||
track_wired_clients = router.config_entry.options.get(
|
||||
CONF_TRACK_WIRED_CLIENTS, DEFAULT_TRACK_WIRED_CLIENTS
|
||||
|
||||
@@ -18,11 +18,8 @@ from homeassistant.components import zeroconf
|
||||
from homeassistant.const import CONF_API_KEY, CONF_HOST
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers import (
|
||||
aiohttp_client,
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
)
|
||||
from homeassistant.helpers import aiohttp_client, device_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.util.network import is_ipv6_address
|
||||
|
||||
from .const import (
|
||||
@@ -309,8 +306,10 @@ class HueV2OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
|
||||
# create a list of Hue device ID's that the user can select
|
||||
# to ignore availability status
|
||||
dev_reg = dr.async_get(self.hass)
|
||||
entries = dr.async_entries_for_config_entry(dev_reg, self.config_entry.entry_id)
|
||||
dev_reg = device_registry.async_get(self.hass)
|
||||
entries = device_registry.async_entries_for_config_entry(
|
||||
dev_reg, self.config_entry.entry_id
|
||||
)
|
||||
dev_ids = {
|
||||
identifier[1]: entry.name
|
||||
for entry in entries
|
||||
|
||||
@@ -13,12 +13,9 @@ import voluptuous as vol
|
||||
from homeassistant.components.scene import ATTR_TRANSITION, Scene as SceneEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_platform
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddEntitiesCallback,
|
||||
async_get_current_platform,
|
||||
)
|
||||
|
||||
from .bridge import HueBridge
|
||||
from .const import DOMAIN
|
||||
@@ -34,7 +31,7 @@ ATTR_BRIGHTNESS = "brightness"
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
async_add_entities: entity_platform.AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up scene platform from Hue group scenes."""
|
||||
bridge: HueBridge = hass.data[DOMAIN][config_entry.entry_id]
|
||||
@@ -65,7 +62,7 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
# add platform service to turn_on/activate scene with advanced options
|
||||
platform = async_get_current_platform()
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_ACTIVATE_SCENE,
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ from homeassistant.const import (
|
||||
ATTR_VIA_DEVICE,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers import device_registry
|
||||
|
||||
from ..const import DOMAIN
|
||||
|
||||
@@ -29,11 +29,11 @@ async def async_setup_devices(bridge: "HueBridge"):
|
||||
entry = bridge.config_entry
|
||||
hass = bridge.hass
|
||||
api: HueBridgeV2 = bridge.api # to satisfy typing
|
||||
dev_reg = dr.async_get(hass)
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
dev_controller = api.devices
|
||||
|
||||
@callback
|
||||
def add_device(hue_device: Device) -> dr.DeviceEntry:
|
||||
def add_device(hue_device: Device) -> device_registry.DeviceEntry:
|
||||
"""Register a Hue device in device registry."""
|
||||
model = f"{hue_device.product_data.product_name} ({hue_device.product_data.model_id})"
|
||||
params = {
|
||||
@@ -51,7 +51,9 @@ async def async_setup_devices(bridge: "HueBridge"):
|
||||
params[ATTR_VIA_DEVICE] = (DOMAIN, api.config.bridge_device.id)
|
||||
zigbee = dev_controller.get_zigbee_connectivity(hue_device.id)
|
||||
if zigbee and zigbee.mac_address:
|
||||
params[ATTR_CONNECTIONS] = {(dr.CONNECTION_NETWORK_MAC, zigbee.mac_address)}
|
||||
params[ATTR_CONNECTIONS] = {
|
||||
(device_registry.CONNECTION_NETWORK_MAC, zigbee.mac_address)
|
||||
}
|
||||
|
||||
return dev_reg.async_get_or_create(config_entry_id=entry.entry_id, **params)
|
||||
|
||||
@@ -75,7 +77,9 @@ async def async_setup_devices(bridge: "HueBridge"):
|
||||
known_devices = [add_device(hue_device) for hue_device in dev_controller]
|
||||
|
||||
# Check for nodes that no longer exist and remove them
|
||||
for device in dr.async_entries_for_config_entry(dev_reg, entry.entry_id):
|
||||
for device in device_registry.async_entries_for_config_entry(
|
||||
dev_reg, entry.entry_id
|
||||
):
|
||||
if device not in known_devices:
|
||||
# handle case where a virtual device was created for a Hue group
|
||||
hue_dev_id = next(x[1] for x in device.identifiers if x[0] == DOMAIN)
|
||||
|
||||
@@ -9,7 +9,7 @@ from aiohue.v2.models.relative_rotary import RelativeRotary
|
||||
|
||||
from homeassistant.const import CONF_DEVICE_ID, CONF_ID, CONF_TYPE, CONF_UNIQUE_ID
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers import device_registry
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from ..const import ATTR_HUE_EVENT, CONF_SUBTYPE, DOMAIN
|
||||
@@ -29,7 +29,7 @@ async def async_setup_hue_events(bridge: "HueBridge"):
|
||||
hass = bridge.hass
|
||||
api: HueBridgeV2 = bridge.api # to satisfy typing
|
||||
conf_entry = bridge.config_entry
|
||||
dev_reg = dr.async_get(hass)
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
|
||||
btn_controller = api.sensors.button
|
||||
rotary_controller = api.sensors.relative_rotary
|
||||
|
||||
@@ -8,10 +8,14 @@ from energyflip.const import (
|
||||
SOURCE_TYPE_GAS,
|
||||
)
|
||||
|
||||
from homeassistant.const import UnitOfTime, UnitOfVolume
|
||||
|
||||
DATA_COORDINATOR = "coordinator"
|
||||
|
||||
DOMAIN = "huisbaasje"
|
||||
|
||||
FLOW_CUBIC_METERS_PER_HOUR = f"{UnitOfVolume.CUBIC_METERS}/{UnitOfTime.HOURS}"
|
||||
|
||||
"""Interval in seconds between polls to huisbaasje."""
|
||||
POLLING_INTERVAL = 20
|
||||
|
||||
|
||||
@@ -21,13 +21,7 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_ID,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfVolume,
|
||||
UnitOfVolumeFlowRate,
|
||||
)
|
||||
from homeassistant.const import CONF_ID, UnitOfEnergy, UnitOfPower, UnitOfVolume
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
@@ -38,6 +32,7 @@ from homeassistant.helpers.update_coordinator import (
|
||||
from .const import (
|
||||
DATA_COORDINATOR,
|
||||
DOMAIN,
|
||||
FLOW_CUBIC_METERS_PER_HOUR,
|
||||
SENSOR_TYPE_RATE,
|
||||
SENSOR_TYPE_THIS_DAY,
|
||||
SENSOR_TYPE_THIS_MONTH,
|
||||
@@ -184,7 +179,7 @@ SENSORS_INFO = [
|
||||
),
|
||||
HuisbaasjeSensorEntityDescription(
|
||||
name="Huisbaasje Current Gas",
|
||||
native_unit_of_measurement=UnitOfVolumeFlowRate.CUBIC_METERS_PER_HOUR,
|
||||
native_unit_of_measurement=FLOW_CUBIC_METERS_PER_HOUR,
|
||||
sensor_type=SENSOR_TYPE_RATE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
key=SOURCE_TYPE_GAS,
|
||||
|
||||
@@ -14,7 +14,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import Context, HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import entity_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entity import get_capability, get_supported_features
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
@@ -48,11 +48,11 @@ async def async_get_actions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device actions for Humidifier devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
actions = await toggle_entity.async_get_actions(hass, device_id, DOMAIN)
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -15,11 +15,7 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import (
|
||||
condition,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
||||
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
|
||||
from homeassistant.helpers.entity import get_capability, get_supported_features
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
@@ -45,11 +41,11 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Humidifier devices."""
|
||||
registry = er.async_get(hass)
|
||||
registry = entity_registry.async_get(hass)
|
||||
conditions = await toggle_entity.async_get_conditions(hass, device_id, DOMAIN)
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user