mirror of
https://github.com/home-assistant/core.git
synced 2026-03-22 02:35:12 +01:00
Compare commits
9 Commits
knx-defaul
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5dcbc1d5d9 | ||
|
|
3068653cc7 | ||
|
|
61b1a45889 | ||
|
|
573d4eba02 | ||
|
|
09895aa601 | ||
|
|
aa6a4c7eab | ||
|
|
662c44b125 | ||
|
|
5a80087cf4 | ||
|
|
c28dc32168 |
@@ -13,6 +13,7 @@ from fritzconnection.core.exceptions import (
|
||||
FritzSecurityError,
|
||||
FritzServiceError,
|
||||
)
|
||||
from requests.exceptions import ConnectionError
|
||||
|
||||
from homeassistant.const import Platform
|
||||
|
||||
@@ -68,6 +69,7 @@ BUTTON_TYPE_WOL = "WakeOnLan"
|
||||
UPTIME_DEVIATION = 5
|
||||
|
||||
FRITZ_EXCEPTIONS = (
|
||||
ConnectionError,
|
||||
FritzActionError,
|
||||
FritzActionFailedError,
|
||||
FritzConnectionException,
|
||||
|
||||
@@ -7,9 +7,10 @@ from typing import Any
|
||||
from xknx.devices import BinarySensor as XknxBinarySensor
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.binary_sensor import ENTITY_ID_FORMAT, BinarySensorEntity
|
||||
from homeassistant.components.binary_sensor import BinarySensorEntity
|
||||
from homeassistant.const import (
|
||||
CONF_DEVICE_CLASS,
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_NAME,
|
||||
STATE_ON,
|
||||
STATE_UNAVAILABLE,
|
||||
@@ -80,7 +81,6 @@ class _KnxBinarySensor(BinarySensorEntity, RestoreEntity):
|
||||
"""Representation of a KNX binary sensor."""
|
||||
|
||||
_device: XknxBinarySensor
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Restore last state."""
|
||||
@@ -128,7 +128,8 @@ class KnxYamlBinarySensor(_KnxBinarySensor, KnxYamlEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=str(self._device.remote_value.group_address_state),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
|
||||
self._attr_device_class = config.get(CONF_DEVICE_CLASS)
|
||||
|
||||
@@ -5,8 +5,8 @@ from __future__ import annotations
|
||||
from xknx.devices import RawValue as XknxRawValue
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.button import ENTITY_ID_FORMAT, ButtonEntity
|
||||
from homeassistant.const import CONF_NAME, CONF_PAYLOAD, Platform
|
||||
from homeassistant.components.button import ButtonEntity
|
||||
from homeassistant.const import CONF_ENTITY_CATEGORY, CONF_NAME, CONF_PAYLOAD, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
@@ -32,7 +32,6 @@ class KNXButton(KnxYamlEntity, ButtonEntity):
|
||||
"""Representation of a KNX button."""
|
||||
|
||||
_device: XknxRawValue
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
def __init__(self, knx_module: KNXModule, config: ConfigType) -> None:
|
||||
"""Initialize a KNX button."""
|
||||
@@ -46,7 +45,8 @@ class KNXButton(KnxYamlEntity, ButtonEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=f"{self._device.remote_value.group_address}_{self._payload}",
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
|
||||
async def async_press(self) -> None:
|
||||
|
||||
@@ -16,7 +16,6 @@ from xknx.remote_value.remote_value_setpoint_shift import SetpointShiftMode
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.climate import (
|
||||
ENTITY_ID_FORMAT,
|
||||
FAN_HIGH,
|
||||
FAN_LOW,
|
||||
FAN_MEDIUM,
|
||||
@@ -28,7 +27,13 @@ from homeassistant.components.climate import (
|
||||
HVACAction,
|
||||
HVACMode,
|
||||
)
|
||||
from homeassistant.const import ATTR_TEMPERATURE, CONF_NAME, Platform, UnitOfTemperature
|
||||
from homeassistant.const import (
|
||||
ATTR_TEMPERATURE,
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_NAME,
|
||||
Platform,
|
||||
UnitOfTemperature,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddConfigEntryEntitiesCallback,
|
||||
@@ -318,7 +323,6 @@ class _KnxClimate(ClimateEntity, _KnxEntityBase):
|
||||
_device: XknxClimate
|
||||
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
_attr_translation_key = "knx_climate"
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
default_hvac_mode: HVACMode
|
||||
_last_hvac_mode: HVACMode
|
||||
@@ -651,7 +655,8 @@ class KnxYamlClimate(_KnxClimate, KnxYamlEntity):
|
||||
f"{self._device.target_temperature.group_address}_"
|
||||
f"{self._device._setpoint_shift.group_address}" # noqa: SLF001
|
||||
),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
default_hvac_mode: HVACMode = config[ClimateConf.DEFAULT_CONTROLLER_MODE]
|
||||
fan_max_step = config[ClimateConf.FAN_MAX_STEP]
|
||||
|
||||
@@ -67,7 +67,6 @@ CONF_KNX_SECURE_USER_PASSWORD: Final = "user_password"
|
||||
CONF_KNX_SECURE_DEVICE_AUTHENTICATION: Final = "device_authentication"
|
||||
|
||||
|
||||
CONF_DEFAULT_ENTITY_ID: Final = "default_entity_id"
|
||||
CONF_CONTEXT_TIMEOUT: Final = "context_timeout"
|
||||
CONF_IGNORE_INTERNAL_STATE: Final = "ignore_internal_state"
|
||||
CONF_PAYLOAD_LENGTH: Final = "payload_length"
|
||||
|
||||
@@ -11,12 +11,16 @@ from homeassistant import config_entries
|
||||
from homeassistant.components.cover import (
|
||||
ATTR_POSITION,
|
||||
ATTR_TILT_POSITION,
|
||||
ENTITY_ID_FORMAT,
|
||||
CoverDeviceClass,
|
||||
CoverEntity,
|
||||
CoverEntityFeature,
|
||||
)
|
||||
from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME, Platform
|
||||
from homeassistant.const import (
|
||||
CONF_DEVICE_CLASS,
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_NAME,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddConfigEntryEntitiesCallback,
|
||||
@@ -76,7 +80,6 @@ class _KnxCover(CoverEntity):
|
||||
"""Representation of a KNX cover."""
|
||||
|
||||
_device: XknxCover
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
def init_base(self) -> None:
|
||||
"""Initialize common attributes - may be based on xknx device instance."""
|
||||
@@ -212,7 +215,8 @@ class KnxYamlCover(_KnxCover, KnxYamlEntity):
|
||||
f"{self._device.updown.group_address}_"
|
||||
f"{self._device.position_target.group_address}"
|
||||
),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
self.init_base()
|
||||
if custom_device_class := config.get(CONF_DEVICE_CLASS):
|
||||
|
||||
@@ -9,8 +9,14 @@ from xknx.devices import DateDevice as XknxDateDevice
|
||||
from xknx.dpt.dpt_11 import KNXDate as XKNXDate
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.date import ENTITY_ID_FORMAT, DateEntity
|
||||
from homeassistant.const import CONF_NAME, STATE_UNAVAILABLE, STATE_UNKNOWN, Platform
|
||||
from homeassistant.components.date import DateEntity
|
||||
from homeassistant.const import (
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_NAME,
|
||||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddConfigEntryEntitiesCallback,
|
||||
@@ -69,7 +75,6 @@ class _KNXDate(DateEntity, RestoreEntity):
|
||||
"""Representation of a KNX date."""
|
||||
|
||||
_device: XknxDateDevice
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Restore last state."""
|
||||
@@ -112,7 +117,8 @@ class KnxYamlDate(_KNXDate, KnxYamlEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=str(self._device.remote_value.group_address),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -9,8 +9,14 @@ from xknx.devices import DateTimeDevice as XknxDateTimeDevice
|
||||
from xknx.dpt.dpt_19 import KNXDateTime as XKNXDateTime
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.datetime import ENTITY_ID_FORMAT, DateTimeEntity
|
||||
from homeassistant.const import CONF_NAME, STATE_UNAVAILABLE, STATE_UNKNOWN, Platform
|
||||
from homeassistant.components.datetime import DateTimeEntity
|
||||
from homeassistant.const import (
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_NAME,
|
||||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddConfigEntryEntitiesCallback,
|
||||
@@ -70,7 +76,6 @@ class _KNXDateTime(DateTimeEntity, RestoreEntity):
|
||||
"""Representation of a KNX datetime."""
|
||||
|
||||
_device: XknxDateTimeDevice
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Restore last state."""
|
||||
@@ -117,7 +122,8 @@ class KnxYamlDateTime(_KNXDateTime, KnxYamlEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=str(self._device.remote_value.group_address),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ from xknx.devices import Device as XknxDevice
|
||||
|
||||
from homeassistant.const import CONF_ENTITY_CATEGORY, CONF_NAME, EntityCategory
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity import Entity, async_generate_entity_id
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.entity_platform import EntityPlatform
|
||||
from homeassistant.helpers.entity_registry import RegistryEntry
|
||||
|
||||
from .const import CONF_DEFAULT_ENTITY_ID, DOMAIN
|
||||
from .const import DOMAIN
|
||||
from .storage.config_store import PlatformControllerBase
|
||||
from .storage.const import CONF_DEVICE_INFO
|
||||
|
||||
@@ -54,7 +54,6 @@ class _KnxEntityBase(Entity):
|
||||
_attr_should_poll = False
|
||||
|
||||
_attr_unique_id: str
|
||||
_entity_id_format: str
|
||||
_knx_module: KNXModule
|
||||
_device: XknxDevice
|
||||
|
||||
@@ -102,20 +101,14 @@ class KnxYamlEntity(_KnxEntityBase):
|
||||
self,
|
||||
knx_module: KNXModule,
|
||||
unique_id: str,
|
||||
entity_config: dict[str, Any],
|
||||
name: str,
|
||||
entity_category: EntityCategory | None,
|
||||
) -> None:
|
||||
"""Initialize the YAML entity."""
|
||||
self._knx_module = knx_module
|
||||
self._attr_name = entity_config[CONF_NAME] or None
|
||||
self._attr_name = name or None
|
||||
self._attr_unique_id = unique_id
|
||||
self._attr_entity_category = entity_config.get(CONF_ENTITY_CATEGORY)
|
||||
|
||||
default_entity_id: str | None
|
||||
if (default_entity_id := entity_config.get(CONF_DEFAULT_ENTITY_ID)) is not None:
|
||||
_, _, object_id = default_entity_id.partition(".")
|
||||
self.entity_id = async_generate_entity_id(
|
||||
self._entity_id_format, object_id, hass=knx_module.hass
|
||||
)
|
||||
self._attr_entity_category = entity_category
|
||||
|
||||
|
||||
class KnxUiEntity(_KnxEntityBase):
|
||||
|
||||
@@ -11,8 +11,8 @@ from xknx.devices import Fan as XknxFan
|
||||
from xknx.telegram.address import parse_device_group_address
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.fan import ENTITY_ID_FORMAT, FanEntity, FanEntityFeature
|
||||
from homeassistant.const import CONF_NAME, Platform
|
||||
from homeassistant.components.fan import FanEntity, FanEntityFeature
|
||||
from homeassistant.const import CONF_ENTITY_CATEGORY, CONF_NAME, Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
@@ -130,7 +130,6 @@ class _KnxFan(FanEntity):
|
||||
"""Representation of a KNX fan."""
|
||||
|
||||
_device: XknxFan
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
_step_range: tuple[int, int] | None
|
||||
|
||||
def _get_knx_speed(self, percentage: int) -> int:
|
||||
@@ -230,7 +229,8 @@ class KnxYamlFan(_KnxFan, KnxYamlEntity):
|
||||
if self._device.speed.group_address
|
||||
else str(self._device.switch.group_address)
|
||||
),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
# FanSpeedMode.STEP if max_step is set
|
||||
self._step_range: tuple[int, int] | None = (1, max_step) if max_step else None
|
||||
|
||||
@@ -16,11 +16,10 @@ from homeassistant.components.light import (
|
||||
ATTR_RGB_COLOR,
|
||||
ATTR_RGBW_COLOR,
|
||||
ATTR_XY_COLOR,
|
||||
ENTITY_ID_FORMAT,
|
||||
ColorMode,
|
||||
LightEntity,
|
||||
)
|
||||
from homeassistant.const import CONF_NAME, Platform
|
||||
from homeassistant.const import CONF_ENTITY_CATEGORY, CONF_NAME, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddConfigEntryEntitiesCallback,
|
||||
@@ -325,7 +324,6 @@ class _KnxLight(LightEntity):
|
||||
_attr_max_color_temp_kelvin: int
|
||||
_attr_min_color_temp_kelvin: int
|
||||
_device: XknxLight
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
@@ -564,7 +562,8 @@ class KnxYamlLight(_KnxLight, KnxYamlEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=self._device_unique_id(),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
self._attr_color_mode = next(iter(self.supported_color_modes))
|
||||
self._attr_max_color_temp_kelvin: int = config[LightSchema.CONF_MAX_KELVIN]
|
||||
|
||||
@@ -6,8 +6,8 @@ from xknx import XKNX
|
||||
from xknx.devices import Notification as XknxNotification
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.notify import ENTITY_ID_FORMAT, NotifyEntity
|
||||
from homeassistant.const import CONF_NAME, CONF_TYPE, Platform
|
||||
from homeassistant.components.notify import NotifyEntity
|
||||
from homeassistant.const import CONF_ENTITY_CATEGORY, CONF_NAME, CONF_TYPE, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
@@ -43,7 +43,6 @@ class KNXNotify(KnxYamlEntity, NotifyEntity):
|
||||
"""Representation of a KNX notification entity."""
|
||||
|
||||
_device: XknxNotification
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
def __init__(self, knx_module: KNXModule, config: ConfigType) -> None:
|
||||
"""Initialize a KNX notification."""
|
||||
@@ -51,7 +50,8 @@ class KNXNotify(KnxYamlEntity, NotifyEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=str(self._device.remote_value.group_address),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
|
||||
async def async_send_message(self, message: str, title: str | None = None) -> None:
|
||||
|
||||
@@ -7,14 +7,10 @@ from typing import cast
|
||||
from xknx.devices import NumericValue
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.number import (
|
||||
ENTITY_ID_FORMAT,
|
||||
NumberDeviceClass,
|
||||
NumberMode,
|
||||
RestoreNumber,
|
||||
)
|
||||
from homeassistant.components.number import NumberDeviceClass, NumberMode, RestoreNumber
|
||||
from homeassistant.const import (
|
||||
CONF_DEVICE_CLASS,
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_MODE,
|
||||
CONF_NAME,
|
||||
CONF_TYPE,
|
||||
@@ -83,7 +79,6 @@ class _KnxNumber(RestoreNumber):
|
||||
"""Representation of a KNX number."""
|
||||
|
||||
_device: NumericValue
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Restore last state."""
|
||||
@@ -125,7 +120,8 @@ class KnxYamlNumber(_KnxNumber, KnxYamlEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=str(self._device.sensor_value.group_address),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
dpt_string = self._device.sensor_value.dpt_class.dpt_number_str()
|
||||
dpt_info = get_supported_dpts()[dpt_string]
|
||||
|
||||
@@ -8,7 +8,7 @@ from xknx.devices import Device as XknxDevice, Scene as XknxScene
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.scene import BaseScene
|
||||
from homeassistant.const import CONF_NAME, Platform
|
||||
from homeassistant.const import CONF_ENTITY_CATEGORY, CONF_NAME, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddConfigEntryEntitiesCallback,
|
||||
@@ -65,7 +65,6 @@ class _KnxScene(BaseScene, _KnxEntityBase):
|
||||
"""Representation of a KNX scene."""
|
||||
|
||||
_device: XknxScene
|
||||
_entity_id_format = "scene.{}"
|
||||
|
||||
async def _async_activate(self, **kwargs: Any) -> None:
|
||||
"""Activate the scene."""
|
||||
@@ -95,7 +94,8 @@ class KnxYamlScene(_KnxScene, KnxYamlEntity):
|
||||
unique_id=(
|
||||
f"{self._device.scene_value.group_address}_{self._device.scene_number}"
|
||||
),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ from homeassistant.helpers.entity import ENTITY_CATEGORIES_SCHEMA
|
||||
|
||||
from .const import (
|
||||
CONF_CONTEXT_TIMEOUT,
|
||||
CONF_DEFAULT_ENTITY_ID,
|
||||
CONF_IGNORE_INTERNAL_STATE,
|
||||
CONF_INVERT,
|
||||
CONF_KNX_EXPOSE,
|
||||
@@ -200,17 +199,12 @@ class KNXPlatformSchema(ABC):
|
||||
}
|
||||
|
||||
|
||||
def _entity_base_schema(platform: Platform) -> vol.Schema:
|
||||
"""Return a base schema for KNX entities."""
|
||||
return vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_NAME, default=""): cv.string,
|
||||
vol.Optional(CONF_DEFAULT_ENTITY_ID): vol.All(
|
||||
cv.entity_id, cv.entity_domain(platform)
|
||||
),
|
||||
vol.Optional(CONF_ENTITY_CATEGORY): ENTITY_CATEGORIES_SCHEMA,
|
||||
}
|
||||
)
|
||||
COMMON_ENTITY_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_NAME, default=""): cv.string,
|
||||
vol.Optional(CONF_ENTITY_CATEGORY): ENTITY_CATEGORIES_SCHEMA,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class BinarySensorSchema(KNXPlatformSchema):
|
||||
@@ -219,7 +213,7 @@ class BinarySensorSchema(KNXPlatformSchema):
|
||||
PLATFORM = Platform.BINARY_SENSOR
|
||||
|
||||
ENTITY_SCHEMA = vol.All(
|
||||
_entity_base_schema(PLATFORM).extend(
|
||||
COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_SYNC_STATE, default=True): sync_state_validator,
|
||||
vol.Optional(CONF_IGNORE_INTERNAL_STATE, default=False): cv.boolean,
|
||||
@@ -248,7 +242,7 @@ class ButtonSchema(KNXPlatformSchema):
|
||||
)
|
||||
|
||||
ENTITY_SCHEMA = vol.All(
|
||||
_entity_base_schema(PLATFORM).extend(
|
||||
COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(KNX_ADDRESS): ga_validator,
|
||||
vol.Exclusive(
|
||||
@@ -338,7 +332,7 @@ class ClimateSchema(KNXPlatformSchema):
|
||||
DEFAULT_FAN_SPEED_MODE = "percent"
|
||||
|
||||
ENTITY_SCHEMA = vol.All(
|
||||
_entity_base_schema(PLATFORM).extend(
|
||||
COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(
|
||||
ClimateConf.SETPOINT_SHIFT_MAX, default=DEFAULT_SETPOINT_SHIFT_MAX
|
||||
@@ -440,7 +434,7 @@ class CoverSchema(KNXPlatformSchema):
|
||||
DEFAULT_TRAVEL_TIME = 25
|
||||
|
||||
ENTITY_SCHEMA = vol.All(
|
||||
_entity_base_schema(PLATFORM).extend(
|
||||
COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_MOVE_LONG_ADDRESS): ga_list_validator,
|
||||
vol.Optional(CONF_MOVE_SHORT_ADDRESS): ga_list_validator,
|
||||
@@ -483,7 +477,7 @@ class DateSchema(KNXPlatformSchema):
|
||||
|
||||
PLATFORM = Platform.DATE
|
||||
|
||||
ENTITY_SCHEMA = _entity_base_schema(PLATFORM).extend(
|
||||
ENTITY_SCHEMA = COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_RESPOND_TO_READ, default=False): cv.boolean,
|
||||
vol.Optional(CONF_SYNC_STATE, default=True): sync_state_validator,
|
||||
@@ -498,7 +492,7 @@ class DateTimeSchema(KNXPlatformSchema):
|
||||
|
||||
PLATFORM = Platform.DATETIME
|
||||
|
||||
ENTITY_SCHEMA = _entity_base_schema(PLATFORM).extend(
|
||||
ENTITY_SCHEMA = COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_RESPOND_TO_READ, default=False): cv.boolean,
|
||||
vol.Optional(CONF_SYNC_STATE, default=True): sync_state_validator,
|
||||
@@ -566,7 +560,7 @@ class FanSchema(KNXPlatformSchema):
|
||||
CONF_SWITCH_STATE_ADDRESS = "switch_state_address"
|
||||
|
||||
ENTITY_SCHEMA = vol.All(
|
||||
_entity_base_schema(PLATFORM).extend(
|
||||
COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(KNX_ADDRESS): ga_list_validator,
|
||||
vol.Optional(CONF_STATE_ADDRESS): ga_list_validator,
|
||||
@@ -650,7 +644,7 @@ class LightSchema(KNXPlatformSchema):
|
||||
)
|
||||
|
||||
ENTITY_SCHEMA = vol.All(
|
||||
_entity_base_schema(PLATFORM).extend(
|
||||
COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(KNX_ADDRESS): ga_list_validator,
|
||||
vol.Optional(CONF_STATE_ADDRESS): ga_list_validator,
|
||||
@@ -746,7 +740,7 @@ class NotifySchema(KNXPlatformSchema):
|
||||
|
||||
PLATFORM = Platform.NOTIFY
|
||||
|
||||
ENTITY_SCHEMA = _entity_base_schema(PLATFORM).extend(
|
||||
ENTITY_SCHEMA = COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_TYPE, default="latin_1"): string_type_validator,
|
||||
vol.Required(KNX_ADDRESS): ga_validator,
|
||||
@@ -760,7 +754,7 @@ class NumberSchema(KNXPlatformSchema):
|
||||
PLATFORM = Platform.NUMBER
|
||||
|
||||
ENTITY_SCHEMA = vol.All(
|
||||
_entity_base_schema(PLATFORM).extend(
|
||||
COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_RESPOND_TO_READ, default=False): cv.boolean,
|
||||
vol.Optional(CONF_MODE, default=NumberMode.AUTO): vol.Coerce(
|
||||
@@ -787,7 +781,7 @@ class SceneSchema(KNXPlatformSchema):
|
||||
|
||||
CONF_SCENE_NUMBER = "scene_number"
|
||||
|
||||
ENTITY_SCHEMA = _entity_base_schema(PLATFORM).extend(
|
||||
ENTITY_SCHEMA = COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(KNX_ADDRESS): ga_list_validator,
|
||||
vol.Required(SceneConf.SCENE_NUMBER): vol.All(
|
||||
@@ -806,7 +800,7 @@ class SelectSchema(KNXPlatformSchema):
|
||||
CONF_OPTIONS = "options"
|
||||
|
||||
ENTITY_SCHEMA = vol.All(
|
||||
_entity_base_schema(PLATFORM).extend(
|
||||
COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_SYNC_STATE, default=True): sync_state_validator,
|
||||
vol.Optional(CONF_RESPOND_TO_READ, default=False): cv.boolean,
|
||||
@@ -837,7 +831,7 @@ class SensorSchema(KNXPlatformSchema):
|
||||
CONF_SYNC_STATE = CONF_SYNC_STATE
|
||||
|
||||
ENTITY_SCHEMA = vol.All(
|
||||
_entity_base_schema(PLATFORM).extend(
|
||||
COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_SYNC_STATE, default=True): sync_state_validator,
|
||||
vol.Optional(CONF_ALWAYS_CALLBACK, default=False): cv.boolean,
|
||||
@@ -860,7 +854,7 @@ class SwitchSchema(KNXPlatformSchema):
|
||||
CONF_INVERT = CONF_INVERT
|
||||
CONF_STATE_ADDRESS = CONF_STATE_ADDRESS
|
||||
|
||||
ENTITY_SCHEMA = _entity_base_schema(PLATFORM).extend(
|
||||
ENTITY_SCHEMA = COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_INVERT, default=False): cv.boolean,
|
||||
vol.Optional(CONF_RESPOND_TO_READ, default=False): cv.boolean,
|
||||
@@ -876,7 +870,7 @@ class TextSchema(KNXPlatformSchema):
|
||||
|
||||
PLATFORM = Platform.TEXT
|
||||
|
||||
ENTITY_SCHEMA = _entity_base_schema(PLATFORM).extend(
|
||||
ENTITY_SCHEMA = COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_RESPOND_TO_READ, default=False): cv.boolean,
|
||||
vol.Optional(CONF_TYPE, default="latin_1"): string_type_validator,
|
||||
@@ -892,7 +886,7 @@ class TimeSchema(KNXPlatformSchema):
|
||||
|
||||
PLATFORM = Platform.TIME
|
||||
|
||||
ENTITY_SCHEMA = _entity_base_schema(PLATFORM).extend(
|
||||
ENTITY_SCHEMA = COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_RESPOND_TO_READ, default=False): cv.boolean,
|
||||
vol.Optional(CONF_SYNC_STATE, default=True): sync_state_validator,
|
||||
@@ -922,7 +916,7 @@ class WeatherSchema(KNXPlatformSchema):
|
||||
CONF_KNX_AIR_PRESSURE_ADDRESS = "address_air_pressure"
|
||||
CONF_KNX_HUMIDITY_ADDRESS = "address_humidity"
|
||||
|
||||
ENTITY_SCHEMA = _entity_base_schema(PLATFORM).extend(
|
||||
ENTITY_SCHEMA = COMMON_ENTITY_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_SYNC_STATE, default=True): sync_state_validator,
|
||||
vol.Required(CONF_KNX_TEMPERATURE_ADDRESS): ga_list_validator,
|
||||
|
||||
@@ -6,8 +6,9 @@ from xknx import XKNX
|
||||
from xknx.devices import Device as XknxDevice, RawValue
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.select import ENTITY_ID_FORMAT, SelectEntity
|
||||
from homeassistant.components.select import SelectEntity
|
||||
from homeassistant.const import (
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_NAME,
|
||||
CONF_PAYLOAD,
|
||||
STATE_UNAVAILABLE,
|
||||
@@ -61,7 +62,6 @@ class KNXSelect(KnxYamlEntity, SelectEntity, RestoreEntity):
|
||||
"""Representation of a KNX select."""
|
||||
|
||||
_device: RawValue
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
def __init__(self, knx_module: KNXModule, config: ConfigType) -> None:
|
||||
"""Initialize a KNX select."""
|
||||
@@ -69,7 +69,8 @@ class KNXSelect(KnxYamlEntity, SelectEntity, RestoreEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=str(self._device.remote_value.group_address),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
self._option_payloads: dict[str, int] = {
|
||||
option[SelectSchema.CONF_OPTION]: option[CONF_PAYLOAD]
|
||||
|
||||
@@ -14,7 +14,6 @@ from xknx.devices import Device as XknxDevice, Sensor as XknxSensor
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.sensor import (
|
||||
CONF_STATE_CLASS,
|
||||
ENTITY_ID_FORMAT,
|
||||
RestoreSensor,
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
@@ -23,6 +22,7 @@ from homeassistant.components.sensor import (
|
||||
)
|
||||
from homeassistant.const import (
|
||||
CONF_DEVICE_CLASS,
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_NAME,
|
||||
CONF_TYPE,
|
||||
CONF_UNIT_OF_MEASUREMENT,
|
||||
@@ -170,7 +170,6 @@ class _KnxSensor(RestoreSensor, _KnxEntityBase):
|
||||
"""Representation of a KNX sensor."""
|
||||
|
||||
_device: XknxSensor
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Restore last state."""
|
||||
@@ -214,7 +213,8 @@ class KnxYamlSensor(_KnxSensor, KnxYamlEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=str(self._device.sensor_value.group_address_state),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
dpt_string = self._device.sensor_value.dpt_class.dpt_number_str()
|
||||
dpt_info = get_supported_dpts()[dpt_string]
|
||||
|
||||
@@ -7,9 +7,10 @@ from typing import Any
|
||||
from xknx.devices import Switch as XknxSwitch
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.switch import ENTITY_ID_FORMAT, SwitchEntity
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.const import (
|
||||
CONF_DEVICE_CLASS,
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_NAME,
|
||||
STATE_ON,
|
||||
STATE_UNAVAILABLE,
|
||||
@@ -75,7 +76,6 @@ class _KnxSwitch(SwitchEntity, RestoreEntity):
|
||||
"""Base class for a KNX switch."""
|
||||
|
||||
_device: XknxSwitch
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Restore last state."""
|
||||
@@ -118,7 +118,8 @@ class KnxYamlSwitch(_KnxSwitch, KnxYamlEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=str(self._device.switch.group_address),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
self._attr_device_class = config.get(CONF_DEVICE_CLASS)
|
||||
|
||||
|
||||
@@ -7,8 +7,9 @@ from xknx.devices import Notification as XknxNotification
|
||||
from xknx.dpt import DPTLatin1
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.text import ENTITY_ID_FORMAT, TextEntity, TextMode
|
||||
from homeassistant.components.text import TextEntity, TextMode
|
||||
from homeassistant.const import (
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_MODE,
|
||||
CONF_NAME,
|
||||
CONF_TYPE,
|
||||
@@ -74,7 +75,6 @@ class _KnxText(TextEntity, RestoreEntity):
|
||||
"""Representation of a KNX text."""
|
||||
|
||||
_device: XknxNotification
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
_attr_native_max = 14
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
@@ -123,7 +123,8 @@ class KnxYamlText(_KnxText, KnxYamlEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=str(self._device.remote_value.group_address),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
self._attr_mode = config[CONF_MODE]
|
||||
|
||||
|
||||
@@ -9,8 +9,14 @@ from xknx.devices import TimeDevice as XknxTimeDevice
|
||||
from xknx.dpt.dpt_10 import KNXTime as XknxTime
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.time import ENTITY_ID_FORMAT, TimeEntity
|
||||
from homeassistant.const import CONF_NAME, STATE_UNAVAILABLE, STATE_UNKNOWN, Platform
|
||||
from homeassistant.components.time import TimeEntity
|
||||
from homeassistant.const import (
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_NAME,
|
||||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddConfigEntryEntitiesCallback,
|
||||
@@ -69,7 +75,6 @@ class _KNXTime(TimeEntity, RestoreEntity):
|
||||
"""Representation of a KNX time."""
|
||||
|
||||
_device: XknxTimeDevice
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Restore last state."""
|
||||
@@ -112,7 +117,8 @@ class KnxYamlTime(_KNXTime, KnxYamlEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=str(self._device.remote_value.group_address),
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@ from xknx import XKNX
|
||||
from xknx.devices import Weather as XknxWeather
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.weather import ENTITY_ID_FORMAT, WeatherEntity
|
||||
from homeassistant.components.weather import WeatherEntity
|
||||
from homeassistant.const import (
|
||||
CONF_ENTITY_CATEGORY,
|
||||
CONF_NAME,
|
||||
Platform,
|
||||
UnitOfPressure,
|
||||
@@ -78,7 +79,6 @@ class KNXWeather(KnxYamlEntity, WeatherEntity):
|
||||
"""Representation of a KNX weather device."""
|
||||
|
||||
_device: XknxWeather
|
||||
_entity_id_format = ENTITY_ID_FORMAT
|
||||
_attr_native_pressure_unit = UnitOfPressure.PA
|
||||
_attr_native_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
_attr_native_wind_speed_unit = UnitOfSpeed.METERS_PER_SECOND
|
||||
@@ -89,7 +89,8 @@ class KNXWeather(KnxYamlEntity, WeatherEntity):
|
||||
super().__init__(
|
||||
knx_module=knx_module,
|
||||
unique_id=str(self._device._temperature.group_address_state), # noqa: SLF001
|
||||
entity_config=config,
|
||||
name=config[CONF_NAME],
|
||||
entity_category=config.get(CONF_ENTITY_CATEGORY),
|
||||
)
|
||||
|
||||
@property
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/opendisplay",
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["opendisplay"],
|
||||
"quality_scale": "silver",
|
||||
"requirements": ["py-opendisplay==5.5.0"]
|
||||
}
|
||||
|
||||
@@ -20,12 +20,18 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import (
|
||||
RoborockB01Q10UpdateCoordinator,
|
||||
RoborockConfigEntry,
|
||||
RoborockDataUpdateCoordinator,
|
||||
RoborockDataUpdateCoordinatorA01,
|
||||
RoborockWashingMachineUpdateCoordinator,
|
||||
)
|
||||
from .entity import RoborockCoordinatedEntityA01, RoborockEntity, RoborockEntityV1
|
||||
from .entity import (
|
||||
RoborockCoordinatedEntityA01,
|
||||
RoborockCoordinatedEntityB01Q10,
|
||||
RoborockEntity,
|
||||
RoborockEntityV1,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -97,6 +103,14 @@ ZEO_BUTTON_DESCRIPTIONS = [
|
||||
]
|
||||
|
||||
|
||||
Q10_BUTTON_DESCRIPTIONS = [
|
||||
ButtonEntityDescription(
|
||||
key="empty_dustbin",
|
||||
translation_key="empty_dustbin",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: RoborockConfigEntry,
|
||||
@@ -139,6 +153,15 @@ async def async_setup_entry(
|
||||
if isinstance(coordinator, RoborockWashingMachineUpdateCoordinator)
|
||||
for description in ZEO_BUTTON_DESCRIPTIONS
|
||||
),
|
||||
(
|
||||
RoborockQ10EmptyDustbinButtonEntity(
|
||||
coordinator,
|
||||
description,
|
||||
)
|
||||
for coordinator in config_entry.runtime_data.b01_q10
|
||||
if isinstance(coordinator, RoborockB01Q10UpdateCoordinator)
|
||||
for description in Q10_BUTTON_DESCRIPTIONS
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -233,3 +256,37 @@ class RoborockButtonEntityA01(RoborockCoordinatedEntityA01, ButtonEntity):
|
||||
) from err
|
||||
finally:
|
||||
await self.coordinator.async_request_refresh()
|
||||
|
||||
|
||||
class RoborockQ10EmptyDustbinButtonEntity(
|
||||
RoborockCoordinatedEntityB01Q10, ButtonEntity
|
||||
):
|
||||
"""A class to define Q10 empty dustbin button entity."""
|
||||
|
||||
entity_description: ButtonEntityDescription
|
||||
coordinator: RoborockB01Q10UpdateCoordinator
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: RoborockB01Q10UpdateCoordinator,
|
||||
entity_description: ButtonEntityDescription,
|
||||
) -> None:
|
||||
"""Create a Q10 empty dustbin button entity."""
|
||||
self.entity_description = entity_description
|
||||
super().__init__(
|
||||
f"{entity_description.key}_{coordinator.duid_slug}",
|
||||
coordinator,
|
||||
)
|
||||
|
||||
async def async_press(self, **kwargs: Any) -> None:
|
||||
"""Press the button to empty dustbin."""
|
||||
try:
|
||||
await self.coordinator.api.vacuum.empty_dustbin()
|
||||
except RoborockException as err:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="command_failed",
|
||||
translation_placeholders={
|
||||
"command": "empty_dustbin",
|
||||
},
|
||||
) from err
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"loggers": ["roborock"],
|
||||
"quality_scale": "silver",
|
||||
"requirements": [
|
||||
"python-roborock==4.25.0",
|
||||
"python-roborock==4.26.2",
|
||||
"vacuum-map-parser-roborock==0.1.4"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -84,6 +84,9 @@
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
"empty_dustbin": {
|
||||
"name": "Empty dustbin"
|
||||
},
|
||||
"pause": {
|
||||
"name": "Pause"
|
||||
},
|
||||
|
||||
@@ -208,6 +208,16 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
supported_states_attributes=Attribute.SUPPORTED_COOKTOP_OPERATING_STATE,
|
||||
)
|
||||
},
|
||||
Capability.SAMSUNG_CE_CLEAN_STATION_STICK_STATUS: {
|
||||
Attribute.STATUS: SmartThingsBinarySensorEntityDescription(
|
||||
key=Attribute.STATUS,
|
||||
component_translation_key={
|
||||
"station": "stick_cleaner_status",
|
||||
},
|
||||
exists_fn=lambda component, _: component == "station",
|
||||
is_on_key="attached",
|
||||
)
|
||||
},
|
||||
Capability.SAMSUNG_CE_MICROFIBER_FILTER_STATUS: {
|
||||
Attribute.STATUS: SmartThingsBinarySensorEntityDescription(
|
||||
key=Attribute.STATUS,
|
||||
|
||||
@@ -85,6 +85,9 @@
|
||||
"robot_cleaner_dust_bag": {
|
||||
"name": "Dust bag full"
|
||||
},
|
||||
"stick_cleaner_status": {
|
||||
"name": "Stick cleaner in station"
|
||||
},
|
||||
"sub_remote_control": {
|
||||
"name": "Upper washer remote control"
|
||||
},
|
||||
|
||||
@@ -105,6 +105,7 @@ SENSORS: list[SmSensorEntityDescription] = [
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
EXTRA_SENSOR = SmSensorEntityDescription(
|
||||
key="zigbee_temperature_2",
|
||||
translation_key="zigbee_temperature",
|
||||
@@ -115,6 +116,15 @@ EXTRA_SENSOR = SmSensorEntityDescription(
|
||||
value_fn=lambda x: x.zb_temp2,
|
||||
)
|
||||
|
||||
PSRAM_SENSOR = SmSensorEntityDescription(
|
||||
key="psram_usage",
|
||||
translation_key="psram_usage",
|
||||
device_class=SensorDeviceClass.DATA_SIZE,
|
||||
native_unit_of_measurement=UnitOfInformation.KILOBYTES,
|
||||
entity_registry_enabled_default=False,
|
||||
value_fn=lambda x: x.psram_usage,
|
||||
)
|
||||
|
||||
UPTIME: list[SmSensorEntityDescription] = [
|
||||
SmSensorEntityDescription(
|
||||
key="core_uptime",
|
||||
@@ -156,6 +166,9 @@ async def async_setup_entry(
|
||||
if coordinator.data.sensors.zb_temp2 is not None:
|
||||
entities.append(SmSensorEntity(coordinator, EXTRA_SENSOR))
|
||||
|
||||
if coordinator.data.info.u_device:
|
||||
entities.append(SmSensorEntity(coordinator, PSRAM_SENSOR))
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
|
||||
@@ -104,6 +104,9 @@
|
||||
"fs_usage": {
|
||||
"name": "Filesystem usage"
|
||||
},
|
||||
"psram_usage": {
|
||||
"name": "PSRAM usage"
|
||||
},
|
||||
"ram_usage": {
|
||||
"name": "RAM usage"
|
||||
},
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
"iot_class": "local_push",
|
||||
"loggers": ["aiotedee"],
|
||||
"quality_scale": "platinum",
|
||||
"requirements": ["aiotedee==0.2.25"]
|
||||
"requirements": ["aiotedee==0.2.27"]
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/xiaomi_ble",
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_push",
|
||||
"requirements": ["xiaomi-ble==1.6.0"]
|
||||
"requirements": ["xiaomi-ble==1.10.0"]
|
||||
}
|
||||
|
||||
6
requirements_all.txt
generated
6
requirements_all.txt
generated
@@ -422,7 +422,7 @@ aiosyncthing==0.7.1
|
||||
aiotankerkoenig==0.5.1
|
||||
|
||||
# homeassistant.components.tedee
|
||||
aiotedee==0.2.25
|
||||
aiotedee==0.2.27
|
||||
|
||||
# homeassistant.components.tractive
|
||||
aiotractive==1.0.0
|
||||
@@ -2660,7 +2660,7 @@ python-rabbitair==0.0.8
|
||||
python-ripple-api==0.0.3
|
||||
|
||||
# homeassistant.components.roborock
|
||||
python-roborock==4.25.0
|
||||
python-roborock==4.26.2
|
||||
|
||||
# homeassistant.components.smarttub
|
||||
python-smarttub==0.0.47
|
||||
@@ -3319,7 +3319,7 @@ wsdot==0.0.1
|
||||
wyoming==1.7.2
|
||||
|
||||
# homeassistant.components.xiaomi_ble
|
||||
xiaomi-ble==1.6.0
|
||||
xiaomi-ble==1.10.0
|
||||
|
||||
# homeassistant.components.knx
|
||||
xknx==3.15.0
|
||||
|
||||
6
requirements_test_all.txt
generated
6
requirements_test_all.txt
generated
@@ -407,7 +407,7 @@ aiosyncthing==0.7.1
|
||||
aiotankerkoenig==0.5.1
|
||||
|
||||
# homeassistant.components.tedee
|
||||
aiotedee==0.2.25
|
||||
aiotedee==0.2.27
|
||||
|
||||
# homeassistant.components.tractive
|
||||
aiotractive==1.0.0
|
||||
@@ -2256,7 +2256,7 @@ python-pooldose==0.8.6
|
||||
python-rabbitair==0.0.8
|
||||
|
||||
# homeassistant.components.roborock
|
||||
python-roborock==4.25.0
|
||||
python-roborock==4.26.2
|
||||
|
||||
# homeassistant.components.smarttub
|
||||
python-smarttub==0.0.47
|
||||
@@ -2801,7 +2801,7 @@ wsdot==0.0.1
|
||||
wyoming==1.7.2
|
||||
|
||||
# homeassistant.components.xiaomi_ble
|
||||
xiaomi-ble==1.6.0
|
||||
xiaomi-ble==1.10.0
|
||||
|
||||
# homeassistant.components.knx
|
||||
xknx==3.15.0
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
"""KNX base entity tests."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.knx.const import KNX_ADDRESS
|
||||
from homeassistant.const import STATE_OFF, EntityCategory, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from .conftest import KNXTestKit
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("config", "expected_entity_id", "expected_friendly_name"),
|
||||
[
|
||||
(
|
||||
{
|
||||
"name": "test",
|
||||
KNX_ADDRESS: "1/2/3",
|
||||
},
|
||||
"switch.test",
|
||||
"test",
|
||||
),
|
||||
(
|
||||
{
|
||||
KNX_ADDRESS: "1/2/3",
|
||||
},
|
||||
"switch.knx_1_2_3", # generated from unique_id
|
||||
None,
|
||||
),
|
||||
(
|
||||
{
|
||||
"name": "",
|
||||
KNX_ADDRESS: "1/2/3",
|
||||
},
|
||||
"switch.knx_1_2_3", # generated from unique_id
|
||||
None,
|
||||
),
|
||||
(
|
||||
{
|
||||
"default_entity_id": "switch.test_default_entity_id",
|
||||
KNX_ADDRESS: "1/2/3",
|
||||
},
|
||||
"switch.test_default_entity_id",
|
||||
None,
|
||||
),
|
||||
(
|
||||
{
|
||||
"name": "my_test_name",
|
||||
"default_entity_id": "switch.test_default_entity_id",
|
||||
KNX_ADDRESS: "1/2/3",
|
||||
},
|
||||
"switch.test_default_entity_id",
|
||||
"my_test_name",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_yaml_entity_naming(
|
||||
hass: HomeAssistant,
|
||||
knx: KNXTestKit,
|
||||
config: dict[str, Any],
|
||||
expected_entity_id: str,
|
||||
expected_friendly_name: str | None,
|
||||
) -> None:
|
||||
"""Test KNX entity id and name setting from YAML configuration."""
|
||||
await knx.setup_integration({Platform.SWITCH: config})
|
||||
knx.assert_state(
|
||||
expected_entity_id,
|
||||
STATE_OFF,
|
||||
friendly_name=expected_friendly_name,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("config", "expected_entity_category"),
|
||||
[
|
||||
(
|
||||
{},
|
||||
None,
|
||||
),
|
||||
(
|
||||
{
|
||||
"entity_category": "diagnostic",
|
||||
},
|
||||
EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
(
|
||||
{
|
||||
"entity_category": "config",
|
||||
},
|
||||
EntityCategory.CONFIG,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_yaml_entity_category(
|
||||
hass: HomeAssistant,
|
||||
knx: KNXTestKit,
|
||||
entity_registry: er.EntityRegistry,
|
||||
config: dict[str, Any],
|
||||
expected_entity_category: EntityCategory | None,
|
||||
) -> None:
|
||||
"""Test KNX entity category setting from YAML configuration."""
|
||||
await knx.setup_integration(
|
||||
{
|
||||
Platform.SWITCH: [
|
||||
{
|
||||
"default_entity_id": "switch.test",
|
||||
KNX_ADDRESS: "1/1/1",
|
||||
**config,
|
||||
},
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
entity = entity_registry.async_get("switch.test")
|
||||
assert entity.entity_category is expected_entity_category
|
||||
@@ -1,4 +1,54 @@
|
||||
# serializer version: 1
|
||||
# name: test_buttons[button.roborock_q10_s5_empty_dustbin-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.roborock_q10_s5_empty_dustbin',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Empty dustbin',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Empty dustbin',
|
||||
'platform': 'roborock',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'empty_dustbin',
|
||||
'unique_id': 'empty_dustbin_q10_duid',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_buttons[button.roborock_q10_s5_empty_dustbin-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Roborock Q10 S5+ Empty dustbin',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.roborock_q10_s5_empty_dustbin',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_buttons[button.roborock_s7_2_reset_air_filter_consumable-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
|
||||
@@ -272,3 +272,55 @@ async def test_press_a01_button_failure(
|
||||
|
||||
washing_machine.zeo.set_value.assert_called_once()
|
||||
assert hass.states.get(entity_id).state == "2023-10-30T08:50:00+00:00"
|
||||
|
||||
|
||||
@pytest.mark.freeze_time("2023-10-30 08:50:00")
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_press_q10_empty_dustbin_button_success(
|
||||
hass: HomeAssistant,
|
||||
bypass_api_client_fixture: None,
|
||||
setup_entry: MockConfigEntry,
|
||||
fake_q10_vacuum: FakeDevice,
|
||||
) -> None:
|
||||
"""Test pressing Q10 empty dustbin button entity."""
|
||||
entity_id = "button.roborock_q10_s5_empty_dustbin"
|
||||
|
||||
assert hass.states.get(entity_id) is not None
|
||||
await hass.services.async_call(
|
||||
"button",
|
||||
SERVICE_PRESS,
|
||||
blocking=True,
|
||||
target={"entity_id": entity_id},
|
||||
)
|
||||
|
||||
assert fake_q10_vacuum.b01_q10_properties is not None
|
||||
fake_q10_vacuum.b01_q10_properties.vacuum.empty_dustbin.assert_called_once()
|
||||
assert hass.states.get(entity_id).state == "2023-10-30T08:50:00+00:00"
|
||||
|
||||
|
||||
@pytest.mark.freeze_time("2023-10-30 08:50:00")
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_press_q10_empty_dustbin_button_failure(
|
||||
hass: HomeAssistant,
|
||||
bypass_api_client_fixture: None,
|
||||
setup_entry: MockConfigEntry,
|
||||
fake_q10_vacuum: FakeDevice,
|
||||
) -> None:
|
||||
"""Test failure while pressing Q10 empty dustbin button entity."""
|
||||
entity_id = "button.roborock_q10_s5_empty_dustbin"
|
||||
assert fake_q10_vacuum.b01_q10_properties is not None
|
||||
fake_q10_vacuum.b01_q10_properties.vacuum.empty_dustbin.side_effect = (
|
||||
RoborockException
|
||||
)
|
||||
|
||||
assert hass.states.get(entity_id) is not None
|
||||
with pytest.raises(HomeAssistantError, match="Error while calling empty_dustbin"):
|
||||
await hass.services.async_call(
|
||||
"button",
|
||||
SERVICE_PRESS,
|
||||
blocking=True,
|
||||
target={"entity_id": entity_id},
|
||||
)
|
||||
|
||||
fake_q10_vacuum.b01_q10_properties.vacuum.empty_dustbin.assert_called_once()
|
||||
assert hass.states.get(entity_id).state == "2023-10-30T08:50:00+00:00"
|
||||
|
||||
@@ -2023,6 +2023,56 @@
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_vc_stick_01001][binary_sensor.stick_vacuum_stick_cleaner_in_station-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'binary_sensor.stick_vacuum_stick_cleaner_in_station',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Stick cleaner in station',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Stick cleaner in station',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'stick_cleaner_status',
|
||||
'unique_id': 'e1f93c0c-6fe0-c65a-a314-c8f7b163c86b_station_samsungce.cleanStationStickStatus_status_status',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_vc_stick_01001][binary_sensor.stick_vacuum_stick_cleaner_in_station-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Stick vacuum Stick cleaner in station',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.stick_vacuum_stick_cleaner_in_station',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_dw_000001][binary_sensor.dishwasher_child_lock-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
|
||||
@@ -6,6 +6,7 @@ from pysmlight import Info, Sensors
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.components.smlight.const import DOMAIN
|
||||
from homeassistant.const import STATE_UNKNOWN, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -113,3 +114,55 @@ async def test_zigbee_type_sensors(
|
||||
state = hass.states.get("sensor.mock_title_zigbee_type_2")
|
||||
assert state
|
||||
assert state.state == "router"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_psram_usage_sensor(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_smlight_client: MagicMock,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test PSRAM usage sensor creation for u-devices."""
|
||||
mock_smlight_client.get_info.side_effect = None
|
||||
mock_smlight_client.get_info.return_value = Info(
|
||||
MAC="AA:BB:CC:DD:EE:FF",
|
||||
model="SLZB-MR3U",
|
||||
u_device=True,
|
||||
)
|
||||
mock_smlight_client.get_sensors.return_value = Sensors(psram_usage=156)
|
||||
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
entity_id = entity_registry.async_get_entity_id(
|
||||
SENSOR_DOMAIN, DOMAIN, "aa:bb:cc:dd:ee:ff_psram_usage"
|
||||
)
|
||||
assert entity_id is not None
|
||||
|
||||
state = hass.states.get(entity_id)
|
||||
assert state is not None
|
||||
assert state.state == "156"
|
||||
assert state.attributes["unit_of_measurement"] == "kB"
|
||||
|
||||
|
||||
async def test_psram_usage_sensor_not_created(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_smlight_client: MagicMock,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test PSRAM usage sensor is not created for non-u devices."""
|
||||
mock_smlight_client.get_info.side_effect = None
|
||||
mock_smlight_client.get_info.return_value = Info(
|
||||
MAC="AA:BB:CC:DD:EE:FF",
|
||||
model="SLZB-MR3",
|
||||
u_device=False,
|
||||
)
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
assert hass.states.get("sensor.mock_title_psram_usage") is None
|
||||
|
||||
entity_id = entity_registry.async_get_entity_id(
|
||||
SENSOR_DOMAIN, DOMAIN, "aa:bb:cc:dd:ee:ff_psram_usage"
|
||||
)
|
||||
assert entity_id is None
|
||||
|
||||
Reference in New Issue
Block a user