forked from home-assistant/core
Compare commits
176 Commits
2023.3.0b6
...
Swamp-Ig-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c8c3917c3 | ||
|
|
336c17112b | ||
|
|
ee78864b05 | ||
|
|
3818e318db | ||
|
|
12933353b2 | ||
|
|
137d2f0d73 | ||
|
|
79bcdf43f7 | ||
|
|
b84eead3f8 | ||
|
|
d65dff3f9e | ||
|
|
09f1c2318d | ||
|
|
54de16875d | ||
|
|
341d046ba7 | ||
|
|
eae12bd48d | ||
|
|
b94dffb7d3 | ||
|
|
9762b684c2 | ||
|
|
23cdafd12f | ||
|
|
0c66346fb0 | ||
|
|
85f2693353 | ||
|
|
b75879194d | ||
|
|
ab9bd5c29e | ||
|
|
42a69566ac | ||
|
|
fca5cc6ea3 | ||
|
|
29b049fc57 | ||
|
|
6febe00516 | ||
|
|
ed3cdd8fb9 | ||
|
|
1fa3f32474 | ||
|
|
853bd52a22 | ||
|
|
202bed5d51 | ||
|
|
9ab95b6348 | ||
|
|
42b74e7f56 | ||
|
|
f69d76702a | ||
|
|
b3d6f098d2 | ||
|
|
f2b736fad0 | ||
|
|
50f908ce2d | ||
|
|
95dd62186e | ||
|
|
9fc6700c5a | ||
|
|
09d0128601 | ||
|
|
5b49648846 | ||
|
|
3e8716b37e | ||
|
|
c724e7c29f | ||
|
|
246f9784c8 | ||
|
|
ee781e4f49 | ||
|
|
54f709f704 | ||
|
|
1bed5c7775 | ||
|
|
0e4c32efe2 | ||
|
|
6ab0b2751d | ||
|
|
86acc4262e | ||
|
|
39f5f0946e | ||
|
|
8f6cfc25c0 | ||
|
|
e0bdb3ecc3 | ||
|
|
c5e39f7039 | ||
|
|
dccd3e277e | ||
|
|
47a3c27c9a | ||
|
|
ad55a5db11 | ||
|
|
69ce6980d6 | ||
|
|
c444e1c860 | ||
|
|
95ed6fbc08 | ||
|
|
8321443193 | ||
|
|
7bfc7f134c | ||
|
|
ac6bbc2f1c | ||
|
|
ee144d34a9 | ||
|
|
36e6a879ad | ||
|
|
c38df1102a | ||
|
|
f93bd8ef2c | ||
|
|
e74613f8be | ||
|
|
390daf1723 | ||
|
|
a2a23564a4 | ||
|
|
e3e4b44958 | ||
|
|
7b5c978b95 | ||
|
|
1c4aa26ab6 | ||
|
|
f41bec6ba9 | ||
|
|
4d58c9de8d | ||
|
|
b6f66b3568 | ||
|
|
4e66554298 | ||
|
|
bef5fde832 | ||
|
|
d397217b5b | ||
|
|
d2ea773e7f | ||
|
|
07c25b3dd8 | ||
|
|
7b3cab1bfe | ||
|
|
c096ef3fce | ||
|
|
9fed4472f1 | ||
|
|
7a5a882687 | ||
|
|
73c7ee4326 | ||
|
|
79f96fe900 | ||
|
|
7cc8712a0c | ||
|
|
0e8d28dab0 | ||
|
|
fd87748b99 | ||
|
|
00954dfc1f | ||
|
|
e95944bf9f | ||
|
|
ac70612ec5 | ||
|
|
7419a92a1b | ||
|
|
ff4de8cd06 | ||
|
|
bdb9994b7e | ||
|
|
2dcc2f88cc | ||
|
|
db1dd16ab0 | ||
|
|
2c2489284b | ||
|
|
198ebaff6e | ||
|
|
5cc9e7fedd | ||
|
|
76819fbb23 | ||
|
|
aeb6c4f078 | ||
|
|
b25f6e3ffc | ||
|
|
b542f6b3ac | ||
|
|
a8d587bc53 | ||
|
|
fe8f3602ff | ||
|
|
735000475a | ||
|
|
ae3e8746f7 | ||
|
|
10bf910f88 | ||
|
|
b7846de311 | ||
|
|
66b33e1090 | ||
|
|
4fd7ca503f | ||
|
|
33466cdddd | ||
|
|
0d25eef19c | ||
|
|
b5223e1196 | ||
|
|
1d1c553d9b | ||
|
|
f8934175cb | ||
|
|
4898d22960 | ||
|
|
480a495239 | ||
|
|
d219e7c8b1 | ||
|
|
c8fc2dc440 | ||
|
|
9be3f86a4c | ||
|
|
bea81d3f63 | ||
|
|
0f01866508 | ||
|
|
588b51bdfa | ||
|
|
0fb41bdffe | ||
|
|
c9dfa15ed6 | ||
|
|
e00ff54869 | ||
|
|
7c23de469e | ||
|
|
490a0908d4 | ||
|
|
327edabb64 | ||
|
|
b4a3a663cf | ||
|
|
1519a78567 | ||
|
|
57360a7528 | ||
|
|
7b61d3763b | ||
|
|
0f204d6502 | ||
|
|
0a3a8c4b3c | ||
|
|
091305fc57 | ||
|
|
3499d60401 | ||
|
|
f18c0bf626 | ||
|
|
f52a5f6965 | ||
|
|
1edef73c9a | ||
|
|
5a365788b5 | ||
|
|
a60fd18386 | ||
|
|
0223058d25 | ||
|
|
7b2e743a6b | ||
|
|
69a3738bdb | ||
|
|
e69091c6db | ||
|
|
ee7dfdae30 | ||
|
|
fdc06c2fc2 | ||
|
|
ba929dfc79 | ||
|
|
753c790a25 | ||
|
|
ee8f746808 | ||
|
|
84823d2fcf | ||
|
|
0ae2fdc08b | ||
|
|
d90ee85118 | ||
|
|
2f826a6f86 | ||
|
|
af49b98475 | ||
|
|
9575cd9161 | ||
|
|
f0b029c363 | ||
|
|
a71487a42b | ||
|
|
d5f1713498 | ||
|
|
301144993c | ||
|
|
e0601530a0 | ||
|
|
e1e0400b16 | ||
|
|
5739782877 | ||
|
|
6112793b19 | ||
|
|
f8314fe007 | ||
|
|
dac3c7179f | ||
|
|
6511b3f355 | ||
|
|
6474297d1f | ||
|
|
27ebee1501 | ||
|
|
23b52025f9 | ||
|
|
87dc692a20 | ||
|
|
473db48943 | ||
|
|
aa3657e071 | ||
|
|
2a819f23c1 | ||
|
|
c6ff79aa0e |
@@ -639,6 +639,10 @@ 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
|
||||
@@ -803,7 +807,9 @@ omit =
|
||||
homeassistant/components/nuki/sensor.py
|
||||
homeassistant/components/nx584/alarm_control_panel.py
|
||||
homeassistant/components/oasa_telematics/sensor.py
|
||||
homeassistant/components/obihai/*
|
||||
homeassistant/components/obihai/__init__.py
|
||||
homeassistant/components/obihai/connectivity.py
|
||||
homeassistant/components/obihai/sensor.py
|
||||
homeassistant/components/octoprint/__init__.py
|
||||
homeassistant/components/oem/climate.py
|
||||
homeassistant/components/ohmconnect/sensor.py
|
||||
@@ -1363,7 +1369,6 @@ 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.3
|
||||
HA_SHORT_VERSION: 2023.4
|
||||
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.1.0
|
||||
uses: actions/checkout@v3.3.0
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.3.0
|
||||
uses: actions/setup-python@v4.5.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
check-latest: true
|
||||
|
||||
@@ -186,6 +186,7 @@ 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.*
|
||||
|
||||
13
CODEOWNERS
13
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
|
||||
/tests/components/livisi/ @StefanIacobLivisi
|
||||
/homeassistant/components/livisi/ @StefanIacobLivisi @planbnet
|
||||
/tests/components/livisi/ @StefanIacobLivisi @planbnet
|
||||
/homeassistant/components/local_calendar/ @allenporter
|
||||
/tests/components/local_calendar/ @allenporter
|
||||
/homeassistant/components/local_ip/ @issacg
|
||||
@@ -825,7 +825,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/nws/ @MatthewFlamm @kamiyo
|
||||
/homeassistant/components/nzbget/ @chriscla
|
||||
/tests/components/nzbget/ @chriscla
|
||||
/homeassistant/components/obihai/ @dshokouhi
|
||||
/homeassistant/components/obihai/ @dshokouhi @ejpenney
|
||||
/tests/components/obihai/ @dshokouhi @ejpenney
|
||||
/homeassistant/components/octoprint/ @rfleming71
|
||||
/tests/components/octoprint/ @rfleming71
|
||||
/homeassistant/components/ohmconnect/ @robbiet480
|
||||
@@ -1138,8 +1139,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/starline/ @anonym-tsk
|
||||
/homeassistant/components/starlink/ @boswelja
|
||||
/tests/components/starlink/ @boswelja
|
||||
/homeassistant/components/statistics/ @fabaff @ThomDietrich
|
||||
/tests/components/statistics/ @fabaff @ThomDietrich
|
||||
/homeassistant/components/statistics/ @ThomDietrich
|
||||
/tests/components/statistics/ @ThomDietrich
|
||||
/homeassistant/components/steam_online/ @tkdrob
|
||||
/tests/components/steam_online/ @tkdrob
|
||||
/homeassistant/components/steamist/ @bdraco
|
||||
@@ -1212,8 +1213,6 @@ 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,15 +6,12 @@ from typing import TYPE_CHECKING
|
||||
import attr
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from homeassistant.helpers import (
|
||||
device_registry as dev_reg,
|
||||
entity_registry as ent_reg,
|
||||
)
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
|
||||
|
||||
@attr.s(slots=True)
|
||||
class PermissionLookup:
|
||||
"""Class to hold data for permission lookups."""
|
||||
|
||||
entity_registry: ent_reg.EntityRegistry = attr.ib()
|
||||
device_registry: dev_reg.DeviceRegistry = attr.ib()
|
||||
entity_registry: er.EntityRegistry = attr.ib()
|
||||
device_registry: dr.DeviceRegistry = attr.ib()
|
||||
|
||||
5
homeassistant/brands/heltun.json
Normal file
5
homeassistant/brands/heltun.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"domain": "heltun",
|
||||
"name": "HELTUN",
|
||||
"iot_standards": ["zwave"]
|
||||
}
|
||||
@@ -3,7 +3,6 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Mapping
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from AIOAladdinConnect import AladdinConnectClient
|
||||
@@ -20,8 +19,6 @@ 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,
|
||||
@@ -134,12 +131,6 @@ 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,63 +2,24 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Any, Final
|
||||
from typing import Any
|
||||
|
||||
from AIOAladdinConnect import AladdinConnectClient
|
||||
import voluptuous as vol
|
||||
|
||||
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.components.cover import CoverDeviceClass, CoverEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import 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
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
actions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -21,7 +21,11 @@ from homeassistant.const import (
|
||||
STATE_ALARM_TRIGGERED,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
||||
from homeassistant.helpers import (
|
||||
condition,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
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
|
||||
@@ -64,11 +68,11 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Alarm control panel devices."""
|
||||
registry = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
conditions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.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
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
triggers: list[dict[str, str]] = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import asyncio
|
||||
from http import HTTPStatus
|
||||
import json
|
||||
import logging
|
||||
from typing import cast
|
||||
|
||||
import aiohttp
|
||||
import async_timeout
|
||||
@@ -15,6 +16,7 @@ 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
|
||||
@@ -162,9 +164,10 @@ async def async_send_changereport_message(
|
||||
if response.status == HTTPStatus.ACCEPTED:
|
||||
return
|
||||
|
||||
response_json = json.loads(response_text)
|
||||
response_json = json_loads_object(response_text)
|
||||
response_payload = cast(JsonObjectType, response_json["payload"])
|
||||
|
||||
if response_json["payload"]["code"] == "INVALID_ACCESS_TOKEN_EXCEPTION":
|
||||
if response_payload["code"] == "INVALID_ACCESS_TOKEN_EXCEPTION":
|
||||
if invalidate_access_token:
|
||||
# Invalidate the access token and try again
|
||||
config.async_invalidate_access_token()
|
||||
@@ -180,8 +183,8 @@ async def async_send_changereport_message(
|
||||
_LOGGER.error(
|
||||
"Error when sending ChangeReport for %s to Alexa: %s: %s",
|
||||
alexa_entity.entity_id,
|
||||
response_json["payload"]["code"],
|
||||
response_json["payload"]["description"],
|
||||
response_payload["code"],
|
||||
response_payload["description"],
|
||||
)
|
||||
|
||||
|
||||
@@ -299,11 +302,12 @@ async def async_send_doorbell_event_message(hass, config, alexa_entity):
|
||||
if response.status == HTTPStatus.ACCEPTED:
|
||||
return
|
||||
|
||||
response_json = json.loads(response_text)
|
||||
response_json = json_loads_object(response_text)
|
||||
response_payload = cast(JsonObjectType, response_json["payload"])
|
||||
|
||||
_LOGGER.error(
|
||||
"Error when sending DoorbellPress event for %s to Alexa: %s: %s",
|
||||
alexa_entity.entity_id,
|
||||
response_json["payload"]["code"],
|
||||
response_json["payload"]["description"],
|
||||
response_payload["code"],
|
||||
response_payload["description"],
|
||||
)
|
||||
|
||||
@@ -20,13 +20,12 @@ 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 entity_registry
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
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
|
||||
@@ -146,7 +145,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 = entity_registry.async_get(hass)
|
||||
registry = er.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)
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/apprise",
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["apprise"],
|
||||
"requirements": ["apprise==1.2.1"]
|
||||
"requirements": ["apprise==1.3.0"]
|
||||
}
|
||||
|
||||
@@ -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
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
triggers = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
if entry.domain == "media_player":
|
||||
triggers.append(
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""Support for collecting data from the ARWN project."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from homeassistant.components import mqtt
|
||||
@@ -11,6 +10,7 @@ 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):
|
||||
def async_sensor_event_received(msg: mqtt.ReceiveMessage) -> None:
|
||||
"""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(msg.payload)
|
||||
event = json_loads_object(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.2"]
|
||||
"requirements": ["yalexs==1.2.7", "yalexs_ble==2.0.4"]
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/aurora",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["auroranoaa"],
|
||||
"requirements": ["auroranoaa==0.0.2"]
|
||||
"requirements": ["auroranoaa==0.0.3"]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""Support for Aurora Forecast sensor."""
|
||||
from homeassistant.components.sensor import SensorEntity
|
||||
from homeassistant.components.sensor import SensorEntity, SensorStateClass
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import PERCENTAGE
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -28,6 +28,7 @@ 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):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import issue_registry
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
|
||||
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]):
|
||||
issue_registry.async_create_issue(
|
||||
ir.async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"mirrored_entry/" + text,
|
||||
breaks_in_ha_version="2022.10.0",
|
||||
is_fixable=False,
|
||||
severity=issue_registry.IssueSeverity.WARNING,
|
||||
severity=ir.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."""
|
||||
issue_registry.async_create_issue(
|
||||
ir.async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
f"no_prob_given_false/{text}",
|
||||
breaks_in_ha_version="2022.10.0",
|
||||
is_fixable=False,
|
||||
severity=issue_registry.IssueSeverity.ERROR,
|
||||
severity=ir.IssueSeverity.ERROR,
|
||||
translation_key="no_prob_given_false",
|
||||
translation_placeholders={"entity": text},
|
||||
learn_more_url="https://github.com/home-assistant/core/pull/67631",
|
||||
|
||||
@@ -106,6 +106,8 @@ class ActiveBluetoothDataUpdateCoordinator(
|
||||
|
||||
def needs_poll(self, service_info: BluetoothServiceInfoBleak) -> bool:
|
||||
"""Return true if time to try and poll."""
|
||||
if self.hass.is_stopping:
|
||||
return False
|
||||
poll_age: float | None = None
|
||||
if self._last_poll:
|
||||
poll_age = monotonic_time_coarse() - self._last_poll
|
||||
|
||||
@@ -99,6 +99,8 @@ class ActiveBluetoothProcessorCoordinator(
|
||||
|
||||
def needs_poll(self, service_info: BluetoothServiceInfoBleak) -> bool:
|
||||
"""Return true if time to try and poll."""
|
||||
if self.hass.is_stopping:
|
||||
return False
|
||||
poll_age: float | None = None
|
||||
if self._last_poll:
|
||||
poll_age = monotonic_time_coarse() - self._last_poll
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
"dependencies": ["bluetooth_adapters"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/bthome",
|
||||
"iot_class": "local_push",
|
||||
"requirements": ["bthome-ble==2.5.2"]
|
||||
"requirements": ["bthome-ble==2.7.0"]
|
||||
}
|
||||
|
||||
@@ -119,6 +119,16 @@ 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
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.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 entity_registry.async_entries_for_device(registry, device_id)
|
||||
for entry in er.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
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.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 entity_registry.async_entries_for_device(registry, device_id)
|
||||
for entry in er.async_entries_for_device(registry, device_id)
|
||||
if entry.domain == DOMAIN
|
||||
]
|
||||
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/caldav",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["caldav", "vobject"],
|
||||
"requirements": ["caldav==1.1.1"]
|
||||
"requirements": ["caldav==1.2.0"]
|
||||
}
|
||||
|
||||
@@ -66,6 +66,55 @@ SCAN_INTERVAL = datetime.timedelta(seconds=60)
|
||||
# Don't support rrules more often than daily
|
||||
VALID_FREQS = {"DAILY", "WEEKLY", "MONTHLY", "YEARLY"}
|
||||
|
||||
|
||||
def _has_consistent_timezone(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
|
||||
"""Verify that all datetime values have a consistent timezone."""
|
||||
|
||||
def validate(obj: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Test that all keys that are datetime values have the same timezone."""
|
||||
tzinfos = []
|
||||
for key in keys:
|
||||
if not (value := obj.get(key)) or not isinstance(value, datetime.datetime):
|
||||
return obj
|
||||
tzinfos.append(value.tzinfo)
|
||||
uniq_values = groupby(tzinfos)
|
||||
if len(list(uniq_values)) > 1:
|
||||
raise vol.Invalid("Expected all values to have the same timezone")
|
||||
return obj
|
||||
|
||||
return validate
|
||||
|
||||
|
||||
def _as_local_timezone(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
|
||||
"""Convert all datetime values to the local timezone."""
|
||||
|
||||
def validate(obj: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Test that all keys that are datetime values have the same timezone."""
|
||||
for k in keys:
|
||||
if (value := obj.get(k)) and isinstance(value, datetime.datetime):
|
||||
obj[k] = dt.as_local(value)
|
||||
return obj
|
||||
|
||||
return validate
|
||||
|
||||
|
||||
def _is_sorted(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
|
||||
"""Verify that the specified values are sequential."""
|
||||
|
||||
def validate(obj: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Test that all keys in the dict are in order."""
|
||||
values = []
|
||||
for k in keys:
|
||||
if not (value := obj.get(k)):
|
||||
return obj
|
||||
values.append(value)
|
||||
if all(values) and values != sorted(values):
|
||||
raise vol.Invalid(f"Values were not in order: {values}")
|
||||
return obj
|
||||
|
||||
return validate
|
||||
|
||||
|
||||
CREATE_EVENT_SERVICE = "create_event"
|
||||
CREATE_EVENT_SCHEMA = vol.All(
|
||||
cv.has_at_least_one_key(EVENT_START_DATE, EVENT_START_DATETIME, EVENT_IN),
|
||||
@@ -98,6 +147,10 @@ CREATE_EVENT_SCHEMA = vol.All(
|
||||
),
|
||||
},
|
||||
),
|
||||
_has_consistent_timezone(EVENT_START_DATETIME, EVENT_END_DATETIME),
|
||||
_as_local_timezone(EVENT_START_DATETIME, EVENT_END_DATETIME),
|
||||
_is_sorted(EVENT_START_DATE, EVENT_END_DATE),
|
||||
_is_sorted(EVENT_START_DATETIME, EVENT_END_DATETIME),
|
||||
)
|
||||
|
||||
|
||||
@@ -441,36 +494,6 @@ def _has_same_type(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
|
||||
return validate
|
||||
|
||||
|
||||
def _has_consistent_timezone(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
|
||||
"""Verify that all datetime values have a consistent timezone."""
|
||||
|
||||
def validate(obj: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Test that all keys that are datetime values have the same timezone."""
|
||||
values = [obj[k] for k in keys]
|
||||
if all(isinstance(value, datetime.datetime) for value in values):
|
||||
uniq_values = groupby(value.tzinfo for value in values)
|
||||
if len(list(uniq_values)) > 1:
|
||||
raise vol.Invalid(
|
||||
f"Expected all values to have the same timezone: {values}"
|
||||
)
|
||||
return obj
|
||||
|
||||
return validate
|
||||
|
||||
|
||||
def _is_sorted(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
|
||||
"""Verify that the specified values are sequential."""
|
||||
|
||||
def validate(obj: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Test that all keys in the dict are in order."""
|
||||
values = [obj[k] for k in keys]
|
||||
if values != sorted(values):
|
||||
raise vol.Invalid(f"Values were not in order: {values}")
|
||||
return obj
|
||||
|
||||
return validate
|
||||
|
||||
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required("type"): "calendar/event/create",
|
||||
@@ -486,6 +509,7 @@ def _is_sorted(*keys: Any) -> Callable[[dict[str, Any]], dict[str, Any]]:
|
||||
},
|
||||
_has_same_type(EVENT_START, EVENT_END),
|
||||
_has_consistent_timezone(EVENT_START, EVENT_END),
|
||||
_as_local_timezone(EVENT_START, EVENT_END),
|
||||
_is_sorted(EVENT_START, EVENT_END),
|
||||
)
|
||||
),
|
||||
@@ -582,6 +606,7 @@ async def handle_calendar_event_delete(
|
||||
},
|
||||
_has_same_type(EVENT_START, EVENT_END),
|
||||
_has_consistent_timezone(EVENT_START, EVENT_END),
|
||||
_as_local_timezone(EVENT_START, EVENT_END),
|
||||
_is_sorted(EVENT_START, EVENT_END),
|
||||
)
|
||||
),
|
||||
|
||||
@@ -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
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
actions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -13,7 +13,11 @@ 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
|
||||
from homeassistant.helpers import (
|
||||
condition,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
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 +49,11 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Climate devices."""
|
||||
registry = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
conditions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.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
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
triggers = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -10,8 +10,7 @@ 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 entity_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.util import Throttle
|
||||
|
||||
from .const import (
|
||||
@@ -71,10 +70,8 @@ async def update_listener(hass: HomeAssistant, config_entry: ConfigEntry) -> Non
|
||||
|
||||
await hass.config_entries.async_reload(config_entry.entry_id)
|
||||
|
||||
registry = entity_registry.async_get(hass)
|
||||
entities = entity_registry.async_entries_for_config_entry(
|
||||
registry, config_entry.entry_id
|
||||
)
|
||||
registry = er.async_get(hass)
|
||||
entities = er.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
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
|
||||
from . import ACTION_DELETE, EditIdBasedConfigView
|
||||
|
||||
@@ -23,7 +23,7 @@ async def async_setup(hass):
|
||||
if action != ACTION_DELETE:
|
||||
return
|
||||
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
ent_reg = er.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
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
|
||||
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 = entity_registry.async_get(hass)
|
||||
ent_reg = er.async_get(hass)
|
||||
|
||||
entity_id = ent_reg.async_get_entity_id(DOMAIN, HA_DOMAIN, config_key)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
DOMAIN = "conversation"
|
||||
|
||||
DEFAULT_EXPOSED_DOMAINS = {
|
||||
"binary_sensor",
|
||||
"climate",
|
||||
"cover",
|
||||
"fan",
|
||||
@@ -16,3 +17,5 @@ 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,
|
||||
device_registry,
|
||||
entity_registry,
|
||||
area_registry as ar,
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
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_DOMAINS, DOMAIN
|
||||
from .const import DEFAULT_EXPOSED_ATTRIBUTES, 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(
|
||||
area_registry.EVENT_AREA_REGISTRY_UPDATED,
|
||||
ar.EVENT_AREA_REGISTRY_UPDATED,
|
||||
self._async_handle_area_registry_changed,
|
||||
run_immediately=True,
|
||||
)
|
||||
self.hass.bus.async_listen(
|
||||
entity_registry.EVENT_ENTITY_REGISTRY_UPDATED,
|
||||
er.EVENT_ENTITY_REGISTRY_UPDATED,
|
||||
self._async_handle_entity_registry_changed,
|
||||
run_immediately=True,
|
||||
)
|
||||
@@ -227,7 +227,21 @@ class DefaultAgent(AbstractConversationAgent):
|
||||
intent_response: intent.IntentResponse,
|
||||
recognize_result: RecognizeResult,
|
||||
) -> str:
|
||||
all_states = intent_response.matched_states + intent_response.unmatched_states
|
||||
# Make copies of the states here so we can add translated names for responses.
|
||||
matched: list[core.State] = []
|
||||
|
||||
for state in intent_response.matched_states:
|
||||
state_copy = core.State.from_dict(state.as_dict())
|
||||
if state_copy is not None:
|
||||
matched.append(state_copy)
|
||||
|
||||
unmatched: list[core.State] = []
|
||||
for state in intent_response.unmatched_states:
|
||||
state_copy = core.State.from_dict(state.as_dict())
|
||||
if state_copy is not None:
|
||||
unmatched.append(state_copy)
|
||||
|
||||
all_states = matched + unmatched
|
||||
domains = {state.domain for state in all_states}
|
||||
translations = await translation.async_get_translations(
|
||||
self.hass, language, "state", domains
|
||||
@@ -243,9 +257,9 @@ class DefaultAgent(AbstractConversationAgent):
|
||||
# This is available in the response template as "state".
|
||||
state1: core.State | None = None
|
||||
if intent_response.matched_states:
|
||||
state1 = intent_response.matched_states[0]
|
||||
state1 = matched[0]
|
||||
elif intent_response.unmatched_states:
|
||||
state1 = intent_response.unmatched_states[0]
|
||||
state1 = unmatched[0]
|
||||
|
||||
# Render response template
|
||||
speech = response_template.async_render(
|
||||
@@ -262,13 +276,11 @@ class DefaultAgent(AbstractConversationAgent):
|
||||
"query": {
|
||||
# Entity states that matched the query (e.g, "on")
|
||||
"matched": [
|
||||
template.TemplateState(self.hass, state)
|
||||
for state in intent_response.matched_states
|
||||
template.TemplateState(self.hass, state) for state in matched
|
||||
],
|
||||
# Entity states that did not match the query
|
||||
"unmatched": [
|
||||
template.TemplateState(self.hass, state)
|
||||
for state in intent_response.unmatched_states
|
||||
template.TemplateState(self.hass, state) for state in unmatched
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -459,14 +471,20 @@ class DefaultAgent(AbstractConversationAgent):
|
||||
states = [
|
||||
state for state in self.hass.states.async_all() if is_entity_exposed(state)
|
||||
]
|
||||
entities = entity_registry.async_get(self.hass)
|
||||
devices = device_registry.async_get(self.hass)
|
||||
entities = er.async_get(self.hass)
|
||||
devices = dr.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:
|
||||
@@ -494,7 +512,7 @@ class DefaultAgent(AbstractConversationAgent):
|
||||
entity_names.append((state.name, state.name, context))
|
||||
|
||||
# Gather areas from exposed entities
|
||||
areas = area_registry.async_get(self.hass)
|
||||
areas = ar.async_get(self.hass)
|
||||
area_names = []
|
||||
for area_id in area_ids_with_entities:
|
||||
area = areas.async_get_area(area_id)
|
||||
@@ -506,6 +524,9 @@ 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),
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
"integration_type": "system",
|
||||
"iot_class": "local_push",
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["hassil==1.0.5", "home-assistant-intents==2023.2.22"]
|
||||
"requirements": ["hassil==1.0.6", "home-assistant-intents==2023.2.28"]
|
||||
}
|
||||
|
||||
@@ -8,7 +8,11 @@ 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, update_coordinator
|
||||
from homeassistant.helpers import (
|
||||
aiohttp_client,
|
||||
entity_registry as er,
|
||||
update_coordinator,
|
||||
)
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from .const import DOMAIN
|
||||
@@ -31,16 +35,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_migrator(entity_entry: entity_registry.RegistryEntry):
|
||||
def _async_migrator(entity_entry: er.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 entity_registry.async_migrate_entries(
|
||||
hass, entry.entry_id, _async_migrator
|
||||
)
|
||||
await er.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
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
actions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -18,7 +18,11 @@ from homeassistant.const import (
|
||||
STATE_OPENING,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
||||
from homeassistant.helpers import (
|
||||
condition,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
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
|
||||
@@ -66,11 +70,11 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Cover devices."""
|
||||
registry = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
conditions: list[dict[str, str]] = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.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
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
triggers = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -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 import entity_platform
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from . import DelugeEntity
|
||||
@@ -71,9 +71,7 @@ SENSOR_TYPES: tuple[DelugeSensorEntityDescription, ...] = (
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: entity_platform.AddEntitiesCallback,
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: 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 import entity_platform
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import DelugeEntity
|
||||
from .const import DOMAIN
|
||||
@@ -15,9 +15,7 @@ from .coordinator import DelugeDataUpdateCoordinator
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: entity_platform.AddEntitiesCallback,
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up the Deluge switch."""
|
||||
async_add_entities([DelugeSwitch(hass.data[DOMAIN][entry.entry_id])])
|
||||
|
||||
@@ -8,11 +8,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
PLATFORM_SCHEMA,
|
||||
SensorEntity,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
ATTR_UNIT_OF_MEASUREMENT,
|
||||
@@ -135,7 +131,6 @@ class DerivativeSensor(RestoreEntity, SensorEntity):
|
||||
|
||||
_attr_icon = ICON
|
||||
_attr_should_poll = False
|
||||
_attr_state_class = SensorStateClass.MEASUREMENT
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
@@ -8,6 +8,7 @@ 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
|
||||
@@ -17,24 +18,13 @@ if TYPE_CHECKING:
|
||||
from homeassistant.helpers import condition
|
||||
|
||||
|
||||
class DeviceAutomationConditionProtocol(Protocol):
|
||||
class DeviceAutomationConditionProtocol(ConditionProtocol, Protocol):
|
||||
"""Define the format of device_condition modules.
|
||||
|
||||
Each module must define either CONDITION_SCHEMA or async_validate_condition_config.
|
||||
Each module must define either CONDITION_SCHEMA or async_validate_condition_config
|
||||
from ConditionProtocol.
|
||||
"""
|
||||
|
||||
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]:
|
||||
@@ -62,4 +52,4 @@ async def async_condition_from_config(
|
||||
platform = await async_get_device_automation_platform(
|
||||
hass, config[CONF_DOMAIN], DeviceAutomationType.CONDITION
|
||||
)
|
||||
return platform.async_condition_from_config(hass, config)
|
||||
return trace_condition_function(platform.async_condition_from_config(hass, config))
|
||||
|
||||
@@ -13,7 +13,11 @@ from homeassistant.const import (
|
||||
STATE_HOME,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
||||
from homeassistant.helpers import (
|
||||
condition,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
|
||||
@@ -33,11 +37,11 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Device tracker devices."""
|
||||
registry = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
conditions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.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
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
triggers = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.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
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
tracked = set()
|
||||
|
||||
@callback
|
||||
@@ -53,9 +53,7 @@ async def async_setup_entry(
|
||||
def restore_entities() -> None:
|
||||
"""Restore clients that are not a part of active clients list."""
|
||||
missing = []
|
||||
for entity in entity_registry.async_entries_for_config_entry(
|
||||
registry, entry.entry_id
|
||||
):
|
||||
for entity in er.async_entries_for_config_entry(registry, entry.entry_id):
|
||||
if (
|
||||
entity.platform == DOMAIN
|
||||
and entity.domain == DEVICE_TRACKER_DOMAIN
|
||||
|
||||
@@ -21,8 +21,7 @@ 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 device_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers import config_validation as cv, device_registry as dr
|
||||
|
||||
from .const import (
|
||||
CONF_BROWSE_UNFILTERED,
|
||||
@@ -501,4 +500,4 @@ async def _async_get_mac_address(hass: HomeAssistant, host: str) -> str | None:
|
||||
if not mac_address:
|
||||
return None
|
||||
|
||||
return device_registry.format_mac(mac_address)
|
||||
return dr.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, entity_registry
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
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(
|
||||
(
|
||||
device_registry.CONNECTION_UPNP,
|
||||
dr.CONNECTION_UPNP,
|
||||
self._device.profile_device.root_device.udn,
|
||||
)
|
||||
)
|
||||
connections.add((device_registry.CONNECTION_UPNP, self._device.udn))
|
||||
connections.add((dr.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
|
||||
(device_registry.CONNECTION_NETWORK_MAC, self.mac_address)
|
||||
(dr.CONNECTION_NETWORK_MAC, self.mac_address)
|
||||
)
|
||||
|
||||
# Create linked HA DeviceEntry now the information is known.
|
||||
dev_reg = device_registry.async_get(self.hass)
|
||||
dev_reg = dr.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 = entity_registry.async_get(self.hass)
|
||||
ent_reg = er.async_get(self.hass)
|
||||
ent_reg.async_get_or_create(
|
||||
self.registry_entry.domain,
|
||||
self.registry_entry.platform,
|
||||
|
||||
@@ -19,7 +19,7 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda
|
||||
from .const import CONF_ASSOCIATION_DATA, DOMAIN, UPDATE_SECONDS
|
||||
from .models import DormakabaDkeyData
|
||||
|
||||
PLATFORMS: list[Platform] = [Platform.LOCK, Platform.SENSOR]
|
||||
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.LOCK, Platform.SENSOR]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -132,7 +132,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
||||
try:
|
||||
association_data = await lock.associate(user_input["activation_code"])
|
||||
except BleakError:
|
||||
except BleakError as err:
|
||||
_LOGGER.warning("BleakError", exc_info=err)
|
||||
return self.async_abort(reason="cannot_connect")
|
||||
except dkey_errors.InvalidActivationCode:
|
||||
errors["base"] = "invalid_code"
|
||||
|
||||
@@ -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.2"]
|
||||
"requirements": ["py-dormakaba-dkey==1.0.3"]
|
||||
}
|
||||
|
||||
@@ -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 import entity_platform
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from . import EfergyEntity
|
||||
@@ -104,9 +104,7 @@ SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: entity_platform.AddEntitiesCallback,
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up Efergy sensors."""
|
||||
api: Efergy = hass.data[DOMAIN][entry.entry_id]
|
||||
|
||||
@@ -15,7 +15,10 @@ 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 import entity_platform as ep
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddEntitiesCallback,
|
||||
async_get_current_platform,
|
||||
)
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from . import EightSleepBaseEntity, EightSleepConfigEntryData
|
||||
@@ -68,7 +71,7 @@ SERVICE_EIGHT_SCHEMA = {
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: ep.AddEntitiesCallback
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up the eight sleep sensors."""
|
||||
config_entry_data: EightSleepConfigEntryData = hass.data[DOMAIN][entry.entry_id]
|
||||
@@ -95,7 +98,7 @@ async def async_setup_entry(
|
||||
|
||||
async_add_entities(all_sensors)
|
||||
|
||||
platform = ep.async_get_current_platform()
|
||||
platform = async_get_current_platform()
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_HEAT_SET,
|
||||
SERVICE_EIGHT_SCHEMA,
|
||||
|
||||
@@ -9,8 +9,7 @@ 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 entity_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
@@ -38,7 +37,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 = entity_registry.async_get(hass)
|
||||
ent_reg = er.async_get(hass)
|
||||
entity_id = ent_reg.async_get_entity_id(Platform.SWITCH, DOMAIN, old_unique_id)
|
||||
|
||||
if entity_id is not None:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from random import randint
|
||||
|
||||
from enturclient import EnturPublicTransportData
|
||||
import voluptuous as vol
|
||||
@@ -22,7 +23,7 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
from homeassistant.util import Throttle
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
API_CLIENT_NAME = "homeassistant-homeassistant"
|
||||
API_CLIENT_NAME = "homeassistant-{}"
|
||||
|
||||
CONF_STOP_IDS = "stop_ids"
|
||||
CONF_EXPAND_PLATFORMS = "expand_platforms"
|
||||
@@ -105,7 +106,7 @@ async def async_setup_platform(
|
||||
quays = [s for s in stop_ids if "Quay" in s]
|
||||
|
||||
data = EnturPublicTransportData(
|
||||
API_CLIENT_NAME,
|
||||
API_CLIENT_NAME.format(str(randint(100000, 999999))),
|
||||
stops=stops,
|
||||
quays=quays,
|
||||
line_whitelist=line_whitelist,
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/environment_canada",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["env_canada"],
|
||||
"requirements": ["env_canada==0.5.28"]
|
||||
"requirements": ["env_canada==0.5.29"]
|
||||
}
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["aioesphomeapi", "noiseprotocol"],
|
||||
"requirements": ["aioesphomeapi==13.4.0", "esphome-dashboard-api==1.2.3"],
|
||||
"requirements": ["aioesphomeapi==13.4.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,
|
||||
entity_platform,
|
||||
from homeassistant.helpers import config_validation as cv, discovery_flow
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddEntitiesCallback,
|
||||
async_get_current_platform,
|
||||
)
|
||||
|
||||
from .const import (
|
||||
@@ -53,9 +53,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: entity_platform.AddEntitiesCallback,
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
) -> None:
|
||||
"""Set up EZVIZ cameras based on a config entry."""
|
||||
|
||||
@@ -132,7 +130,7 @@ async def async_setup_entry(
|
||||
|
||||
async_add_entities(camera_entities)
|
||||
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
platform = async_get_current_platform()
|
||||
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_PTZ,
|
||||
|
||||
@@ -14,7 +14,11 @@ from homeassistant.const import (
|
||||
STATE_ON,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import condition, config_validation as cv, entity_registry
|
||||
from homeassistant.helpers import (
|
||||
condition,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
from homeassistant.helpers.config_validation import DEVICE_CONDITION_BASE_SCHEMA
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
|
||||
@@ -34,11 +38,11 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Fan devices."""
|
||||
registry = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
conditions = []
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -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
|
||||
from homeassistant.util.json import load_json_object
|
||||
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(config_path)
|
||||
config_file = load_json_object(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: ConfigType = cast(ConfigType, load_json(config_path))
|
||||
config_file = load_json_object(config_path)
|
||||
if config_file == DEFAULT_CONFIG:
|
||||
request_app_setup(
|
||||
hass, config, add_entities, config_path, discovery_info=None
|
||||
@@ -175,13 +175,10 @@ 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 is not None
|
||||
and refresh_token is not None
|
||||
and expires_at is not None
|
||||
(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
|
||||
):
|
||||
authd_client = Fitbit(
|
||||
config_file.get(CONF_CLIENT_ID),
|
||||
@@ -192,7 +189,7 @@ def setup_platform(
|
||||
refresh_cb=lambda x: None,
|
||||
)
|
||||
|
||||
if int(time.time()) - expires_at > 3600:
|
||||
if int(time.time()) - cast(int, expires_at) > 3600:
|
||||
authd_client.client.refresh_token()
|
||||
|
||||
user_profile = authd_client.user_profile_get()["user"]
|
||||
|
||||
@@ -87,14 +87,23 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
hass, STARTUP_SCAN_TIMEOUT
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_start_background_discovery(*_: Any) -> None:
|
||||
"""Run discovery in the background."""
|
||||
hass.async_create_background_task(_async_discovery(), "flux_led-discovery")
|
||||
|
||||
async def _async_discovery(*_: Any) -> None:
|
||||
async_trigger_discovery(
|
||||
hass, await async_discover_devices(hass, DISCOVER_SCAN_TIMEOUT)
|
||||
)
|
||||
|
||||
async_trigger_discovery(hass, domain_data[FLUX_LED_DISCOVERY])
|
||||
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, _async_discovery)
|
||||
async_track_time_interval(hass, _async_discovery, DISCOVERY_INTERVAL)
|
||||
hass.bus.async_listen_once(
|
||||
EVENT_HOMEASSISTANT_STARTED, _async_start_background_discovery
|
||||
)
|
||||
async_track_time_interval(
|
||||
hass, _async_start_background_discovery, DISCOVERY_INTERVAL
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -20,5 +20,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||
"integration_type": "system",
|
||||
"quality_scale": "internal",
|
||||
"requirements": ["home-assistant-frontend==20230222.0"]
|
||||
"requirements": ["home-assistant-frontend==20230227.0"]
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/garages_amsterdam",
|
||||
"iot_class": "cloud_polling",
|
||||
"requirements": ["odp-amsterdam==5.0.1"]
|
||||
"requirements": ["odp-amsterdam==5.1.0"]
|
||||
}
|
||||
|
||||
@@ -79,10 +79,10 @@ class GeniusClimateZone(GeniusHeatingZone, ClimateEntity):
|
||||
def hvac_action(self) -> str | None:
|
||||
"""Return the current running hvac operation if supported."""
|
||||
if "_state" in self._zone.data: # only for v3 API
|
||||
if self._zone.data["output"] == 1:
|
||||
return HVACAction.HEATING
|
||||
if not self._zone.data["_state"].get("bIsActive"):
|
||||
return HVACAction.OFF
|
||||
if self._zone.data["_state"].get("bOutRequestHeat"):
|
||||
return HVACAction.HEATING
|
||||
return HVACAction.IDLE
|
||||
return None
|
||||
|
||||
|
||||
@@ -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
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
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 = device_registry.async_get(hass)
|
||||
dev_reg = dr.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
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
ent_reg = er.async_get(hass)
|
||||
|
||||
if entity_id := ent_reg.async_get_entity_id(
|
||||
Platform.SENSOR, DOMAIN, old_unique_id
|
||||
|
||||
@@ -22,7 +22,12 @@ from homeassistant.const import (
|
||||
STATE_UNAVAILABLE,
|
||||
)
|
||||
from homeassistant.core import Context, HomeAssistant, State, callback
|
||||
from homeassistant.helpers import area_registry, device_registry, entity_registry, start
|
||||
from homeassistant.helpers import (
|
||||
area_registry as ar,
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
start,
|
||||
)
|
||||
from homeassistant.helpers.event import async_call_later
|
||||
from homeassistant.helpers.network import get_url
|
||||
from homeassistant.helpers.storage import Store
|
||||
@@ -52,15 +57,11 @@ LOCAL_SDK_MIN_VERSION = AwesomeVersion("2.1.5")
|
||||
@callback
|
||||
def _get_registry_entries(
|
||||
hass: HomeAssistant, entity_id: str
|
||||
) -> tuple[
|
||||
entity_registry.RegistryEntry | None,
|
||||
device_registry.DeviceEntry | None,
|
||||
area_registry.AreaEntry | None,
|
||||
]:
|
||||
) -> tuple[er.RegistryEntry | None, dr.DeviceEntry | None, ar.AreaEntry | None,]:
|
||||
"""Get registry entries."""
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
dev_reg = device_registry.async_get(hass)
|
||||
area_reg = area_registry.async_get(hass)
|
||||
ent_reg = er.async_get(hass)
|
||||
dev_reg = dr.async_get(hass)
|
||||
area_reg = ar.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)
|
||||
|
||||
@@ -832,7 +832,7 @@ class TemperatureControlTrait(_Trait):
|
||||
"temperatureUnitForUX": _google_temp_unit(
|
||||
self.hass.config.units.temperature_unit
|
||||
),
|
||||
"queryOnlyTemperatureSetting": True,
|
||||
"queryOnlyTemperatureControl": True,
|
||||
"temperatureRange": {
|
||||
"minThresholdCelsius": -100,
|
||||
"maxThresholdCelsius": 100,
|
||||
|
||||
@@ -8,7 +8,7 @@ from homeassistant.const import (
|
||||
ATTR_LONGITUDE,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import device_registry
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
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 = device_registry.async_get(hass)
|
||||
dev_reg = dr.async_get(hass)
|
||||
dev_ids = {
|
||||
identifier[1]
|
||||
for device in dev_reg.devices.values()
|
||||
|
||||
@@ -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
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
ent_reg = er.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
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
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: entity_registry.RegistryEntry):
|
||||
def _async_migrator(entity_entry: er.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 entity_registry.async_migrate_entries(hass, entry_id, _async_migrator)
|
||||
await er.async_migrate_entries(hass, entry_id, _async_migrator)
|
||||
|
||||
|
||||
@callback
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"domain": "hassio",
|
||||
"name": "Home Assistant Supervisor",
|
||||
"after_dependencies": ["panel_custom"],
|
||||
"codeowners": ["@home-assistant/supervisor"],
|
||||
"dependencies": ["http"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/hassio",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Config flow for HLK-SW16."""
|
||||
import asyncio
|
||||
|
||||
import async_timeout
|
||||
from hlk_sw16 import create_hlk_sw16_connection
|
||||
import voluptuous as vol
|
||||
|
||||
@@ -35,7 +36,8 @@ async def connect_client(hass, user_input):
|
||||
reconnect_interval=DEFAULT_RECONNECT_INTERVAL,
|
||||
keep_alive_interval=DEFAULT_KEEP_ALIVE_INTERVAL,
|
||||
)
|
||||
return await asyncio.wait_for(client_aw, timeout=CONNECTION_TIMEOUT)
|
||||
async with async_timeout.timeout(CONNECTION_TIMEOUT):
|
||||
return await client_aw
|
||||
|
||||
|
||||
async def validate_input(hass: HomeAssistant, user_input):
|
||||
|
||||
@@ -50,8 +50,12 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import CoreState, HomeAssistant, ServiceCall, State, callback
|
||||
from homeassistant.exceptions import HomeAssistantError, Unauthorized
|
||||
from homeassistant.helpers import device_registry, entity_registry, instance_id
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
instance_id,
|
||||
)
|
||||
from homeassistant.helpers.entityfilter import (
|
||||
BASE_FILTER_SCHEMA,
|
||||
FILTER_SCHEMA,
|
||||
@@ -431,20 +435,19 @@ 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 = device_registry.async_get(hass)
|
||||
dev_reg = dr.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 == device_registry.CONNECTION_NETWORK_MAC
|
||||
if ctype == dr.CONNECTION_NETWORK_MAC
|
||||
]
|
||||
matching_instances = [
|
||||
homekit
|
||||
for homekit in _async_all_homekit_instances(hass)
|
||||
if homekit.driver
|
||||
and device_registry.format_mac(homekit.driver.state.mac) in macs
|
||||
if homekit.driver and dr.format_mac(homekit.driver.state.mac) in macs
|
||||
]
|
||||
if not matching_instances:
|
||||
raise HomeAssistantError(
|
||||
@@ -698,7 +701,7 @@ class HomeKit:
|
||||
return False
|
||||
|
||||
def add_bridge_triggers_accessory(
|
||||
self, device: device_registry.DeviceEntry, device_triggers: list[dict[str, Any]]
|
||||
self, device: dr.DeviceEntry, device_triggers: list[dict[str, Any]]
|
||||
) -> None:
|
||||
"""Add device automation triggers to the bridge."""
|
||||
if self._would_exceed_max_devices(device.name):
|
||||
@@ -734,8 +737,8 @@ class HomeKit:
|
||||
|
||||
async def async_configure_accessories(self) -> list[State]:
|
||||
"""Configure accessories for the included states."""
|
||||
dev_reg = device_registry.async_get(self.hass)
|
||||
ent_reg = entity_registry.async_get(self.hass)
|
||||
dev_reg = dr.async_get(self.hass)
|
||||
ent_reg = er.async_get(self.hass)
|
||||
device_lookup = ent_reg.async_get_device_class_lookup(
|
||||
{
|
||||
(BINARY_SENSOR_DOMAIN, BinarySensorDeviceClass.BATTERY_CHARGING),
|
||||
@@ -830,8 +833,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 = device_registry.async_get(self.hass)
|
||||
formatted_mac = device_registry.format_mac(self.driver.state.mac)
|
||||
dev_reg = dr.async_get(self.hass)
|
||||
formatted_mac = dr.format_mac(self.driver.state.mac)
|
||||
# Connections and identifiers are both used here.
|
||||
#
|
||||
# connections exists so homekit_controller can know the
|
||||
@@ -844,7 +847,7 @@ class HomeKit:
|
||||
# because this was the way you had to fix homekit when pairing
|
||||
# failed.
|
||||
#
|
||||
connection = (device_registry.CONNECTION_NETWORK_MAC, formatted_mac)
|
||||
connection = (dr.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
|
||||
@@ -858,13 +861,13 @@ class HomeKit:
|
||||
manufacturer=MANUFACTURER,
|
||||
name=accessory_friendly_name(self._entry_title, self.driver.accessory),
|
||||
model=f"HomeKit {hk_mode_name}",
|
||||
entry_type=device_registry.DeviceEntryType.SERVICE,
|
||||
entry_type=dr.DeviceEntryType.SERVICE,
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_purge_old_bridges(
|
||||
self,
|
||||
dev_reg: device_registry.DeviceRegistry,
|
||||
dev_reg: dr.DeviceRegistry,
|
||||
identifier: tuple[str, str, str],
|
||||
connection: tuple[str, str],
|
||||
) -> None:
|
||||
@@ -920,7 +923,7 @@ class HomeKit:
|
||||
|
||||
async def _async_add_trigger_accessories(self) -> None:
|
||||
"""Add devices with triggers to the bridge."""
|
||||
dev_reg = device_registry.async_get(self.hass)
|
||||
dev_reg = dr.async_get(self.hass)
|
||||
valid_device_ids = []
|
||||
for device_id in self._devices:
|
||||
if not dev_reg.async_get(device_id):
|
||||
@@ -989,7 +992,7 @@ class HomeKit:
|
||||
@callback
|
||||
def _async_configure_linked_sensors(
|
||||
self,
|
||||
ent_reg_ent: entity_registry.RegistryEntry,
|
||||
ent_reg_ent: er.RegistryEntry,
|
||||
device_lookup: dict[str, dict[tuple[str, str | None], str]],
|
||||
state: State,
|
||||
) -> None:
|
||||
@@ -1051,8 +1054,8 @@ class HomeKit:
|
||||
|
||||
async def _async_set_device_info_attributes(
|
||||
self,
|
||||
ent_reg_ent: entity_registry.RegistryEntry,
|
||||
dev_reg: device_registry.DeviceRegistry,
|
||||
ent_reg_ent: er.RegistryEntry,
|
||||
dev_reg: dr.DeviceRegistry,
|
||||
entity_id: str,
|
||||
) -> None:
|
||||
"""Set attributes that will be used for homekit device info."""
|
||||
@@ -1070,7 +1073,7 @@ class HomeKit:
|
||||
ent_cfg[ATTR_INTEGRATION] = ent_reg_ent.platform
|
||||
|
||||
def _fill_config_from_device_registry_entry(
|
||||
self, device_entry: device_registry.DeviceEntry, config: dict[str, Any]
|
||||
self, device_entry: dr.DeviceEntry, config: dict[str, Any]
|
||||
) -> None:
|
||||
"""Populate a config dict from the registry."""
|
||||
if device_entry.manufacturer:
|
||||
|
||||
@@ -28,8 +28,11 @@ from homeassistant.const import (
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback, split_entity_id
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
from homeassistant.helpers import device_registry, entity_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
)
|
||||
from homeassistant.helpers.entityfilter import (
|
||||
CONF_EXCLUDE_DOMAINS,
|
||||
CONF_EXCLUDE_ENTITIES,
|
||||
@@ -630,7 +633,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 = device_registry.async_get(hass)
|
||||
dev_reg = dr.async_get(hass)
|
||||
unsorted: dict[str, str] = {}
|
||||
for device_id in results:
|
||||
entry = dev_reg.async_get(device_id)
|
||||
@@ -639,7 +642,7 @@ async def _async_get_supported_devices(hass: HomeAssistant) -> dict[str, str]:
|
||||
|
||||
|
||||
def _exclude_by_entity_registry(
|
||||
ent_reg: entity_registry.EntityRegistry,
|
||||
ent_reg: er.EntityRegistry,
|
||||
entity_id: str,
|
||||
include_entity_category: bool,
|
||||
include_hidden: bool,
|
||||
@@ -661,7 +664,7 @@ def _async_get_matching_entities(
|
||||
include_hidden: bool = False,
|
||||
) -> dict[str, str]:
|
||||
"""Fetch all entities or entities in the given domains."""
|
||||
ent_reg = entity_registry.async_get(hass)
|
||||
ent_reg = er.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
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
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 = entity_registry.async_get(self.hass)
|
||||
ent_reg = er.async_get(self.hass)
|
||||
for idx, trigger in enumerate(device_triggers):
|
||||
type_: str = trigger["type"]
|
||||
subtype: str | None = trigger.get("subtype")
|
||||
|
||||
@@ -14,6 +14,7 @@ PLATFORMS = [
|
||||
Platform.CLIMATE,
|
||||
Platform.COVER,
|
||||
Platform.LIGHT,
|
||||
Platform.LOCK,
|
||||
Platform.SENSOR,
|
||||
Platform.SWITCH,
|
||||
Platform.WEATHER,
|
||||
|
||||
39
homeassistant/components/homematicip_cloud/helpers.py
Normal file
39
homeassistant/components/homematicip_cloud/helpers.py
Normal file
@@ -0,0 +1,39 @@
|
||||
"""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
|
||||
95
homeassistant/components/homematicip_cloud/lock.py
Normal file
95
homeassistant/components/homematicip_cloud/lock.py
Normal file
@@ -0,0 +1,95 @@
|
||||
"""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
|
||||
}
|
||||
@@ -421,6 +421,7 @@ class HoneywellUSThermostat(ClimateEntity):
|
||||
"""Get the latest state from the service."""
|
||||
try:
|
||||
await self._device.refresh()
|
||||
self._attr_available = True
|
||||
except (
|
||||
aiosomecomfort.SomeComfortError,
|
||||
OSError,
|
||||
@@ -428,8 +429,10 @@ class HoneywellUSThermostat(ClimateEntity):
|
||||
try:
|
||||
await self._data.client.login()
|
||||
|
||||
except aiosomecomfort.SomeComfortError:
|
||||
except aiosomecomfort.AuthError:
|
||||
self._attr_available = False
|
||||
await self.hass.async_create_task(
|
||||
self.hass.config_entries.async_reload(self._data.entry_id)
|
||||
)
|
||||
except aiosomecomfort.SomeComfortError:
|
||||
self._attr_available = False
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/honeywell",
|
||||
"iot_class": "cloud_polling",
|
||||
"loggers": ["somecomfort"],
|
||||
"requirements": ["aiosomecomfort==0.0.8"]
|
||||
"requirements": ["aiosomecomfort==0.0.11"]
|
||||
}
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
"username": "[%key:common::config_flow::data::username%]",
|
||||
"password": "[%key:common::config_flow::data::password%]"
|
||||
}
|
||||
},
|
||||
"reauth_confirm": {
|
||||
"title": "[%key:common::config_flow::title::reauth%]",
|
||||
"description": "The Honeywell integration needs to re-authenticate your account",
|
||||
"data": {
|
||||
"password": "[%key:common::config_flow::data::password%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
|
||||
@@ -5,6 +5,7 @@ from collections.abc import Awaitable, Callable
|
||||
import logging
|
||||
import re
|
||||
from typing import Final
|
||||
from urllib.parse import unquote
|
||||
|
||||
from aiohttp.web import Application, HTTPBadRequest, Request, StreamResponse, middleware
|
||||
|
||||
@@ -39,18 +40,24 @@ FILTERS: Final = re.compile(
|
||||
def setup_security_filter(app: Application) -> None:
|
||||
"""Create security filter middleware for the app."""
|
||||
|
||||
def _recursive_unquote(value: str) -> str:
|
||||
"""Handle values that are encoded multiple times."""
|
||||
if (unquoted := unquote(value)) != value:
|
||||
unquoted = _recursive_unquote(unquoted)
|
||||
return unquoted
|
||||
|
||||
@middleware
|
||||
async def security_filter_middleware(
|
||||
request: Request, handler: Callable[[Request], Awaitable[StreamResponse]]
|
||||
) -> StreamResponse:
|
||||
"""Process request and tblock commonly known exploit attempts."""
|
||||
if FILTERS.search(request.path):
|
||||
"""Process request and block commonly known exploit attempts."""
|
||||
if FILTERS.search(_recursive_unquote(request.path)):
|
||||
_LOGGER.warning(
|
||||
"Filtered a potential harmful request to: %s", request.raw_path
|
||||
)
|
||||
raise HTTPBadRequest
|
||||
|
||||
if FILTERS.search(request.query_string):
|
||||
if FILTERS.search(_recursive_unquote(request.query_string)):
|
||||
_LOGGER.warning(
|
||||
"Filtered a request with a potential harmful query string: %s",
|
||||
request.raw_path,
|
||||
|
||||
@@ -44,7 +44,7 @@ from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
discovery,
|
||||
entity_registry,
|
||||
entity_registry as er,
|
||||
)
|
||||
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 = entity_registry.async_get(hass)
|
||||
for entity_entry in entity_registry.async_entries_for_config_entry(
|
||||
ent_reg = er.async_get(hass)
|
||||
for entity_entry in er.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
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
known_entities: list[Entity] = []
|
||||
track_wired_clients = router.config_entry.options.get(
|
||||
CONF_TRACK_WIRED_CLIENTS, DEFAULT_TRACK_WIRED_CLIENTS
|
||||
|
||||
@@ -18,8 +18,11 @@ 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, device_registry
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers import (
|
||||
aiohttp_client,
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
)
|
||||
from homeassistant.util.network import is_ipv6_address
|
||||
|
||||
from .const import (
|
||||
@@ -306,10 +309,8 @@ class HueV2OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
|
||||
# create a list of Hue device ID's that the user can select
|
||||
# to ignore availability status
|
||||
dev_reg = device_registry.async_get(self.hass)
|
||||
entries = device_registry.async_entries_for_config_entry(
|
||||
dev_reg, self.config_entry.entry_id
|
||||
)
|
||||
dev_reg = dr.async_get(self.hass)
|
||||
entries = dr.async_entries_for_config_entry(dev_reg, self.config_entry.entry_id)
|
||||
dev_ids = {
|
||||
identifier[1]: entry.name
|
||||
for entry in entries
|
||||
|
||||
@@ -35,6 +35,7 @@ TRIGGER_TYPE = {
|
||||
"remote_double_button_long_press": "both {subtype} released after long press",
|
||||
"remote_double_button_short_press": "both {subtype} released",
|
||||
"initial_press": "{subtype} pressed initially",
|
||||
"long_press": "{subtype} long press",
|
||||
"repeat": "{subtype} held down",
|
||||
"short_release": "{subtype} released after short press",
|
||||
"long_release": "{subtype} released after long press",
|
||||
|
||||
@@ -11,6 +11,6 @@
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["aiohue"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["aiohue==4.6.1"],
|
||||
"requirements": ["aiohue==4.6.2"],
|
||||
"zeroconf": ["_hue._tcp.local."]
|
||||
}
|
||||
|
||||
@@ -13,9 +13,12 @@ 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
|
||||
@@ -31,7 +34,7 @@ ATTR_BRIGHTNESS = "brightness"
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: entity_platform.AddEntitiesCallback,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up scene platform from Hue group scenes."""
|
||||
bridge: HueBridge = hass.data[DOMAIN][config_entry.entry_id]
|
||||
@@ -62,7 +65,7 @@ async def async_setup_entry(
|
||||
)
|
||||
|
||||
# add platform service to turn_on/activate scene with advanced options
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
platform = async_get_current_platform()
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_ACTIVATE_SCENE,
|
||||
{
|
||||
@@ -118,13 +121,14 @@ class HueSceneEntityBase(HueBaseEntity, SceneEntity):
|
||||
"""Return device (service) info."""
|
||||
# we create a virtual service/device for Hue scenes
|
||||
# so we have a parent for grouped lights and scenes
|
||||
group_type = self.group.type.value.title()
|
||||
return DeviceInfo(
|
||||
identifiers={(DOMAIN, self.group.id)},
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
name=self.group.metadata.name,
|
||||
manufacturer=self.bridge.api.config.bridge_device.product_data.manufacturer_name,
|
||||
model=self.group.type.value.title(),
|
||||
suggested_area=self.group.metadata.name,
|
||||
suggested_area=self.group.metadata.name if group_type == "Room" else None,
|
||||
via_device=(DOMAIN, self.bridge.api.config.bridge_device.id),
|
||||
)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ from homeassistant.const import (
|
||||
ATTR_VIA_DEVICE,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers import device_registry
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
|
||||
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 = device_registry.async_get(hass)
|
||||
dev_reg = dr.async_get(hass)
|
||||
dev_controller = api.devices
|
||||
|
||||
@callback
|
||||
def add_device(hue_device: Device) -> device_registry.DeviceEntry:
|
||||
def add_device(hue_device: Device) -> dr.DeviceEntry:
|
||||
"""Register a Hue device in device registry."""
|
||||
model = f"{hue_device.product_data.product_name} ({hue_device.product_data.model_id})"
|
||||
params = {
|
||||
@@ -51,9 +51,7 @@ 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] = {
|
||||
(device_registry.CONNECTION_NETWORK_MAC, zigbee.mac_address)
|
||||
}
|
||||
params[ATTR_CONNECTIONS] = {(dr.CONNECTION_NETWORK_MAC, zigbee.mac_address)}
|
||||
|
||||
return dev_reg.async_get_or_create(config_entry_id=entry.entry_id, **params)
|
||||
|
||||
@@ -77,9 +75,7 @@ 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 device_registry.async_entries_for_config_entry(
|
||||
dev_reg, entry.entry_id
|
||||
):
|
||||
for device in dr.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)
|
||||
|
||||
@@ -46,6 +46,7 @@ DEFAULT_BUTTON_EVENT_TYPES = (
|
||||
ButtonEvent.INITIAL_PRESS,
|
||||
ButtonEvent.REPEAT,
|
||||
ButtonEvent.SHORT_RELEASE,
|
||||
ButtonEvent.LONG_PRESS,
|
||||
ButtonEvent.LONG_RELEASE,
|
||||
)
|
||||
|
||||
|
||||
@@ -55,7 +55,13 @@ class HueBaseEntity(Entity):
|
||||
self._attr_unique_id = resource.id
|
||||
# device is precreated in main handler
|
||||
# this attaches the entity to the precreated device
|
||||
if self.device is not None:
|
||||
if self.device is None:
|
||||
# attach all device-less entities to the bridge itself
|
||||
# e.g. config based sensors like entertainment area
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, bridge.api.config.bridge.bridge_id)},
|
||||
)
|
||||
else:
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, self.device.id)},
|
||||
)
|
||||
@@ -137,17 +143,14 @@ class HueBaseEntity(Entity):
|
||||
def _handle_event(self, event_type: EventType, resource: HueResource) -> None:
|
||||
"""Handle status event for this resource (or it's parent)."""
|
||||
if event_type == EventType.RESOURCE_DELETED:
|
||||
# remove any services created for zones/rooms
|
||||
# handle removal of room and zone 'virtual' devices/services
|
||||
# regular devices are removed automatically by the logic in device.py.
|
||||
if resource.type in (ResourceTypes.ROOM, ResourceTypes.ZONE):
|
||||
dev_reg = async_get_device_registry(self.hass)
|
||||
if device := dev_reg.async_get_device({(DOMAIN, resource.id)}):
|
||||
dev_reg.async_remove_device(device.id)
|
||||
if resource.type in (
|
||||
ResourceTypes.GROUPED_LIGHT,
|
||||
ResourceTypes.SCENE,
|
||||
ResourceTypes.SMART_SCENE,
|
||||
):
|
||||
# cleanup entities that are not strictly device-bound and have the bridge as parent
|
||||
if self.device is None:
|
||||
ent_reg = async_get_entity_registry(self.hass)
|
||||
ent_reg.async_remove(self.entity_id)
|
||||
return
|
||||
|
||||
@@ -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
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
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 = device_registry.async_get(hass)
|
||||
dev_reg = dr.async_get(hass)
|
||||
|
||||
btn_controller = api.sensors.button
|
||||
rotary_controller = api.sensors.relative_rotary
|
||||
|
||||
@@ -8,14 +8,10 @@ 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,7 +21,13 @@ from homeassistant.components.sensor import (
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_ID, UnitOfEnergy, UnitOfPower, UnitOfVolume
|
||||
from homeassistant.const import (
|
||||
CONF_ID,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
UnitOfVolume,
|
||||
UnitOfVolumeFlowRate,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import (
|
||||
@@ -32,7 +38,6 @@ 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,
|
||||
@@ -179,7 +184,7 @@ SENSORS_INFO = [
|
||||
),
|
||||
HuisbaasjeSensorEntityDescription(
|
||||
name="Huisbaasje Current Gas",
|
||||
native_unit_of_measurement=FLOW_CUBIC_METERS_PER_HOUR,
|
||||
native_unit_of_measurement=UnitOfVolumeFlowRate.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
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
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 = entity_registry.async_get(hass)
|
||||
registry = er.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 entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -15,7 +15,11 @@ 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
|
||||
from homeassistant.helpers import (
|
||||
condition,
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
)
|
||||
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
|
||||
@@ -41,11 +45,11 @@ async def async_get_conditions(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device conditions for Humidifier devices."""
|
||||
registry = entity_registry.async_get(hass)
|
||||
registry = er.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 entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.async_entries_for_device(registry, device_id):
|
||||
if entry.domain != DOMAIN:
|
||||
continue
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ from homeassistant.const import (
|
||||
PERCENTAGE,
|
||||
)
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry
|
||||
from homeassistant.helpers import config_validation as cv, entity_registry as er
|
||||
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
@@ -56,11 +56,11 @@ async def async_get_triggers(
|
||||
hass: HomeAssistant, device_id: str
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device triggers for Humidifier devices."""
|
||||
registry = entity_registry.async_get(hass)
|
||||
registry = er.async_get(hass)
|
||||
triggers = await toggle_entity.async_get_triggers(hass, device_id, DOMAIN)
|
||||
|
||||
# Get all the integrations entities for this device
|
||||
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||
for entry in er.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