Use centralized KnxEntity for all KNX platforms (#40381)
This commit is contained in:
parent
c13fbf795d
commit
3d6434be75
12 changed files with 206 additions and 338 deletions
|
@ -29,7 +29,7 @@ from homeassistant.helpers import discovery
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.event import async_track_state_change_event
|
from homeassistant.helpers.event import async_track_state_change_event
|
||||||
|
|
||||||
from .const import DATA_KNX, DOMAIN, SupportedPlatforms
|
from .const import DOMAIN, SupportedPlatforms
|
||||||
from .factory import create_knx_device
|
from .factory import create_knx_device
|
||||||
from .schema import (
|
from .schema import (
|
||||||
BinarySensorSchema,
|
BinarySensorSchema,
|
||||||
|
@ -139,9 +139,9 @@ SERVICE_KNX_SEND_SCHEMA = vol.Schema(
|
||||||
async def async_setup(hass, config):
|
async def async_setup(hass, config):
|
||||||
"""Set up the KNX component."""
|
"""Set up the KNX component."""
|
||||||
try:
|
try:
|
||||||
hass.data[DATA_KNX] = KNXModule(hass, config)
|
hass.data[DOMAIN] = KNXModule(hass, config)
|
||||||
hass.data[DATA_KNX].async_create_exposures()
|
hass.data[DOMAIN].async_create_exposures()
|
||||||
await hass.data[DATA_KNX].start()
|
await hass.data[DOMAIN].start()
|
||||||
except XKNXException as ex:
|
except XKNXException as ex:
|
||||||
_LOGGER.warning("Could not connect to KNX interface: %s", ex)
|
_LOGGER.warning("Could not connect to KNX interface: %s", ex)
|
||||||
hass.components.persistent_notification.async_create(
|
hass.components.persistent_notification.async_create(
|
||||||
|
@ -151,7 +151,7 @@ async def async_setup(hass, config):
|
||||||
for platform in SupportedPlatforms:
|
for platform in SupportedPlatforms:
|
||||||
if platform.value in config[DOMAIN]:
|
if platform.value in config[DOMAIN]:
|
||||||
for device_config in config[DOMAIN][platform.value]:
|
for device_config in config[DOMAIN][platform.value]:
|
||||||
create_knx_device(platform, hass.data[DATA_KNX].xknx, device_config)
|
create_knx_device(platform, hass.data[DOMAIN].xknx, device_config)
|
||||||
|
|
||||||
# We need to wait until all entities are loaded into the device list since they could also be created from other platforms
|
# We need to wait until all entities are loaded into the device list since they could also be created from other platforms
|
||||||
for platform in SupportedPlatforms:
|
for platform in SupportedPlatforms:
|
||||||
|
@ -159,7 +159,7 @@ async def async_setup(hass, config):
|
||||||
discovery.async_load_platform(hass, platform.value, DOMAIN, {}, config)
|
discovery.async_load_platform(hass, platform.value, DOMAIN, {}, config)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not hass.data[DATA_KNX].xknx.devices:
|
if not hass.data[DOMAIN].xknx.devices:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"No KNX devices are configured. Please read "
|
"No KNX devices are configured. Please read "
|
||||||
"https://www.home-assistant.io/blog/2020/09/17/release-115/#breaking-changes"
|
"https://www.home-assistant.io/blog/2020/09/17/release-115/#breaking-changes"
|
||||||
|
@ -168,7 +168,7 @@ async def async_setup(hass, config):
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_KNX_SEND,
|
SERVICE_KNX_SEND,
|
||||||
hass.data[DATA_KNX].service_send_to_knx_bus,
|
hass.data[DOMAIN].service_send_to_knx_bus,
|
||||||
schema=SERVICE_KNX_SEND_SCHEMA,
|
schema=SERVICE_KNX_SEND_SCHEMA,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -3,72 +3,41 @@ from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from xknx.devices import BinarySensor as XknxBinarySensor
|
from xknx.devices import BinarySensor as XknxBinarySensor
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import BinarySensorEntity
|
from homeassistant.components.binary_sensor import DEVICE_CLASSES, BinarySensorEntity
|
||||||
from homeassistant.core import callback
|
|
||||||
|
|
||||||
from .const import ATTR_COUNTER, DATA_KNX
|
from .const import ATTR_COUNTER, DOMAIN
|
||||||
|
from .knx_entity import KnxEntity
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
"""Set up binary sensor(s) for KNX platform."""
|
"""Set up binary sensor(s) for KNX platform."""
|
||||||
entities = []
|
entities = []
|
||||||
for device in hass.data[DATA_KNX].xknx.devices:
|
for device in hass.data[DOMAIN].xknx.devices:
|
||||||
if isinstance(device, XknxBinarySensor):
|
if isinstance(device, XknxBinarySensor):
|
||||||
entities.append(KNXBinarySensor(device))
|
entities.append(KNXBinarySensor(device))
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class KNXBinarySensor(BinarySensorEntity):
|
class KNXBinarySensor(KnxEntity, BinarySensorEntity):
|
||||||
"""Representation of a KNX binary sensor."""
|
"""Representation of a KNX binary sensor."""
|
||||||
|
|
||||||
def __init__(self, device: XknxBinarySensor):
|
def __init__(self, device: XknxBinarySensor):
|
||||||
"""Initialize of KNX binary sensor."""
|
"""Initialize of KNX binary sensor."""
|
||||||
self.device = device
|
super().__init__(device)
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_register_callbacks(self):
|
|
||||||
"""Register callbacks to update hass after device was changed."""
|
|
||||||
|
|
||||||
async def after_update_callback(device: XknxBinarySensor):
|
|
||||||
"""Call after device was updated."""
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
self.device.register_device_updated_cb(after_update_callback)
|
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
|
||||||
"""Store register state change callback."""
|
|
||||||
self.async_register_callbacks()
|
|
||||||
|
|
||||||
async def async_update(self):
|
|
||||||
"""Request a state update from KNX bus."""
|
|
||||||
await self.device.sync()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the KNX device."""
|
|
||||||
return self.device.name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def available(self):
|
|
||||||
"""Return True if entity is available."""
|
|
||||||
return self.hass.data[DATA_KNX].connected
|
|
||||||
|
|
||||||
@property
|
|
||||||
def should_poll(self):
|
|
||||||
"""No polling needed within KNX."""
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_class(self):
|
def device_class(self):
|
||||||
"""Return the class of this sensor."""
|
"""Return the class of this sensor."""
|
||||||
return self.device.device_class
|
if self._device.device_class in DEVICE_CLASSES:
|
||||||
|
return self._device.device_class
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Return true if the binary sensor is on."""
|
"""Return true if the binary sensor is on."""
|
||||||
return self.device.is_on()
|
return self._device.is_on()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self) -> Optional[Dict[str, Any]]:
|
def device_state_attributes(self) -> Optional[Dict[str, Any]]:
|
||||||
"""Return device specific state attributes."""
|
"""Return device specific state attributes."""
|
||||||
return {ATTR_COUNTER: self.device.counter}
|
return {ATTR_COUNTER: self._device.counter}
|
||||||
|
|
|
@ -14,8 +14,8 @@ from homeassistant.components.climate.const import (
|
||||||
)
|
)
|
||||||
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
|
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
|
||||||
|
|
||||||
from . import DATA_KNX
|
from .const import DOMAIN, OPERATION_MODES, PRESET_MODES
|
||||||
from .const import OPERATION_MODES, PRESET_MODES
|
from .knx_entity import KnxEntity
|
||||||
|
|
||||||
OPERATION_MODES_INV = dict(reversed(item) for item in OPERATION_MODES.items())
|
OPERATION_MODES_INV = dict(reversed(item) for item in OPERATION_MODES.items())
|
||||||
PRESET_MODES_INV = dict(reversed(item) for item in PRESET_MODES.items())
|
PRESET_MODES_INV = dict(reversed(item) for item in PRESET_MODES.items())
|
||||||
|
@ -24,18 +24,19 @@ PRESET_MODES_INV = dict(reversed(item) for item in PRESET_MODES.items())
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
"""Set up climate(s) for KNX platform."""
|
"""Set up climate(s) for KNX platform."""
|
||||||
entities = []
|
entities = []
|
||||||
for device in hass.data[DATA_KNX].xknx.devices:
|
for device in hass.data[DOMAIN].xknx.devices:
|
||||||
if isinstance(device, XknxClimate):
|
if isinstance(device, XknxClimate):
|
||||||
entities.append(KNXClimate(device))
|
entities.append(KNXClimate(device))
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class KNXClimate(ClimateEntity):
|
class KNXClimate(KnxEntity, ClimateEntity):
|
||||||
"""Representation of a KNX climate device."""
|
"""Representation of a KNX climate device."""
|
||||||
|
|
||||||
def __init__(self, device: XknxClimate):
|
def __init__(self, device: XknxClimate):
|
||||||
"""Initialize of a KNX climate device."""
|
"""Initialize of a KNX climate device."""
|
||||||
self.device = device
|
super().__init__(device)
|
||||||
|
|
||||||
self._unit_of_measurement = TEMP_CELSIUS
|
self._unit_of_measurement = TEMP_CELSIUS
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -43,35 +44,10 @@ class KNXClimate(ClimateEntity):
|
||||||
"""Return the list of supported features."""
|
"""Return the list of supported features."""
|
||||||
return SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE
|
return SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
|
||||||
"""Register callbacks to update hass after device was changed."""
|
|
||||||
|
|
||||||
async def after_update_callback(device):
|
|
||||||
"""Call after device was updated."""
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
self.device.register_device_updated_cb(after_update_callback)
|
|
||||||
self.device.mode.register_device_updated_cb(after_update_callback)
|
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Request a state update from KNX bus."""
|
"""Request a state update from KNX bus."""
|
||||||
await self.device.sync()
|
await self._device.sync()
|
||||||
await self.device.mode.sync()
|
await self._device.mode.sync()
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self) -> str:
|
|
||||||
"""Return the name of the KNX device."""
|
|
||||||
return self.device.name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def available(self) -> bool:
|
|
||||||
"""Return True if entity is available."""
|
|
||||||
return self.hass.data[DATA_KNX].connected
|
|
||||||
|
|
||||||
@property
|
|
||||||
def should_poll(self) -> bool:
|
|
||||||
"""No polling needed within KNX."""
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def temperature_unit(self):
|
def temperature_unit(self):
|
||||||
|
@ -81,44 +57,44 @@ class KNXClimate(ClimateEntity):
|
||||||
@property
|
@property
|
||||||
def current_temperature(self):
|
def current_temperature(self):
|
||||||
"""Return the current temperature."""
|
"""Return the current temperature."""
|
||||||
return self.device.temperature.value
|
return self._device.temperature.value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_temperature_step(self):
|
def target_temperature_step(self):
|
||||||
"""Return the supported step of target temperature."""
|
"""Return the supported step of target temperature."""
|
||||||
return self.device.temperature_step
|
return self._device.temperature_step
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_temperature(self):
|
def target_temperature(self):
|
||||||
"""Return the temperature we try to reach."""
|
"""Return the temperature we try to reach."""
|
||||||
return self.device.target_temperature.value
|
return self._device.target_temperature.value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_temp(self):
|
def min_temp(self):
|
||||||
"""Return the minimum temperature."""
|
"""Return the minimum temperature."""
|
||||||
return self.device.target_temperature_min
|
return self._device.target_temperature_min
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_temp(self):
|
def max_temp(self):
|
||||||
"""Return the maximum temperature."""
|
"""Return the maximum temperature."""
|
||||||
return self.device.target_temperature_max
|
return self._device.target_temperature_max
|
||||||
|
|
||||||
async def async_set_temperature(self, **kwargs) -> None:
|
async def async_set_temperature(self, **kwargs) -> None:
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
temperature = kwargs.get(ATTR_TEMPERATURE)
|
temperature = kwargs.get(ATTR_TEMPERATURE)
|
||||||
if temperature is None:
|
if temperature is None:
|
||||||
return
|
return
|
||||||
await self.device.set_target_temperature(temperature)
|
await self._device.set_target_temperature(temperature)
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hvac_mode(self) -> Optional[str]:
|
def hvac_mode(self) -> Optional[str]:
|
||||||
"""Return current operation ie. heat, cool, idle."""
|
"""Return current operation ie. heat, cool, idle."""
|
||||||
if self.device.supports_on_off and not self.device.is_on:
|
if self._device.supports_on_off and not self._device.is_on:
|
||||||
return HVAC_MODE_OFF
|
return HVAC_MODE_OFF
|
||||||
if self.device.mode.supports_operation_mode:
|
if self._device.mode.supports_operation_mode:
|
||||||
return OPERATION_MODES.get(
|
return OPERATION_MODES.get(
|
||||||
self.device.mode.operation_mode.value, HVAC_MODE_HEAT
|
self._device.mode.operation_mode.value, HVAC_MODE_HEAT
|
||||||
)
|
)
|
||||||
# default to "heat"
|
# default to "heat"
|
||||||
return HVAC_MODE_HEAT
|
return HVAC_MODE_HEAT
|
||||||
|
@ -128,10 +104,10 @@ class KNXClimate(ClimateEntity):
|
||||||
"""Return the list of available operation modes."""
|
"""Return the list of available operation modes."""
|
||||||
_operations = [
|
_operations = [
|
||||||
OPERATION_MODES.get(operation_mode.value)
|
OPERATION_MODES.get(operation_mode.value)
|
||||||
for operation_mode in self.device.mode.operation_modes
|
for operation_mode in self._device.mode.operation_modes
|
||||||
]
|
]
|
||||||
|
|
||||||
if self.device.supports_on_off:
|
if self._device.supports_on_off:
|
||||||
if not _operations:
|
if not _operations:
|
||||||
_operations.append(HVAC_MODE_HEAT)
|
_operations.append(HVAC_MODE_HEAT)
|
||||||
_operations.append(HVAC_MODE_OFF)
|
_operations.append(HVAC_MODE_OFF)
|
||||||
|
@ -142,16 +118,16 @@ class KNXClimate(ClimateEntity):
|
||||||
|
|
||||||
async def async_set_hvac_mode(self, hvac_mode: str) -> None:
|
async def async_set_hvac_mode(self, hvac_mode: str) -> None:
|
||||||
"""Set operation mode."""
|
"""Set operation mode."""
|
||||||
if self.device.supports_on_off and hvac_mode == HVAC_MODE_OFF:
|
if self._device.supports_on_off and hvac_mode == HVAC_MODE_OFF:
|
||||||
await self.device.turn_off()
|
await self._device.turn_off()
|
||||||
else:
|
else:
|
||||||
if self.device.supports_on_off and not self.device.is_on:
|
if self._device.supports_on_off and not self._device.is_on:
|
||||||
await self.device.turn_on()
|
await self._device.turn_on()
|
||||||
if self.device.mode.supports_operation_mode:
|
if self._device.mode.supports_operation_mode:
|
||||||
knx_operation_mode = HVACOperationMode(
|
knx_operation_mode = HVACOperationMode(
|
||||||
OPERATION_MODES_INV.get(hvac_mode)
|
OPERATION_MODES_INV.get(hvac_mode)
|
||||||
)
|
)
|
||||||
await self.device.mode.set_operation_mode(knx_operation_mode)
|
await self._device.mode.set_operation_mode(knx_operation_mode)
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -160,8 +136,8 @@ class KNXClimate(ClimateEntity):
|
||||||
|
|
||||||
Requires SUPPORT_PRESET_MODE.
|
Requires SUPPORT_PRESET_MODE.
|
||||||
"""
|
"""
|
||||||
if self.device.mode.supports_operation_mode:
|
if self._device.mode.supports_operation_mode:
|
||||||
return PRESET_MODES.get(self.device.mode.operation_mode.value, PRESET_AWAY)
|
return PRESET_MODES.get(self._device.mode.operation_mode.value, PRESET_AWAY)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -172,14 +148,14 @@ class KNXClimate(ClimateEntity):
|
||||||
"""
|
"""
|
||||||
_presets = [
|
_presets = [
|
||||||
PRESET_MODES.get(operation_mode.value)
|
PRESET_MODES.get(operation_mode.value)
|
||||||
for operation_mode in self.device.mode.operation_modes
|
for operation_mode in self._device.mode.operation_modes
|
||||||
]
|
]
|
||||||
|
|
||||||
return list(filter(None, _presets))
|
return list(filter(None, _presets))
|
||||||
|
|
||||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||||
"""Set new preset mode."""
|
"""Set new preset mode."""
|
||||||
if self.device.mode.supports_operation_mode:
|
if self._device.mode.supports_operation_mode:
|
||||||
knx_operation_mode = HVACOperationMode(PRESET_MODES_INV.get(preset_mode))
|
knx_operation_mode = HVACOperationMode(PRESET_MODES_INV.get(preset_mode))
|
||||||
await self.device.mode.set_operation_mode(knx_operation_mode)
|
await self._device.mode.set_operation_mode(knx_operation_mode)
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
|
@ -15,7 +15,6 @@ from homeassistant.components.climate.const import (
|
||||||
)
|
)
|
||||||
|
|
||||||
DOMAIN = "knx"
|
DOMAIN = "knx"
|
||||||
DATA_KNX = "data_knx"
|
|
||||||
|
|
||||||
CONF_STATE_ADDRESS = "state_address"
|
CONF_STATE_ADDRESS = "state_address"
|
||||||
CONF_SYNC_STATE = "sync_state"
|
CONF_SYNC_STATE = "sync_state"
|
||||||
|
|
|
@ -15,65 +15,39 @@ from homeassistant.components.cover import (
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.event import async_track_utc_time_change
|
from homeassistant.helpers.event import async_track_utc_time_change
|
||||||
|
|
||||||
from . import DATA_KNX
|
from .const import DOMAIN
|
||||||
|
from .knx_entity import KnxEntity
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
"""Set up cover(s) for KNX platform."""
|
"""Set up cover(s) for KNX platform."""
|
||||||
entities = []
|
entities = []
|
||||||
for device in hass.data[DATA_KNX].xknx.devices:
|
for device in hass.data[DOMAIN].xknx.devices:
|
||||||
if isinstance(device, XknxCover):
|
if isinstance(device, XknxCover):
|
||||||
entities.append(KNXCover(device))
|
entities.append(KNXCover(device))
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class KNXCover(CoverEntity):
|
class KNXCover(KnxEntity, CoverEntity):
|
||||||
"""Representation of a KNX cover."""
|
"""Representation of a KNX cover."""
|
||||||
|
|
||||||
def __init__(self, device: XknxCover):
|
def __init__(self, device: XknxCover):
|
||||||
"""Initialize the cover."""
|
"""Initialize the cover."""
|
||||||
self.device = device
|
super().__init__(device)
|
||||||
|
|
||||||
self._unsubscribe_auto_updater = None
|
self._unsubscribe_auto_updater = None
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_register_callbacks(self):
|
async def after_update_callback(self, device):
|
||||||
"""Register callbacks to update hass after device was changed."""
|
"""Call after device was updated."""
|
||||||
|
self.async_write_ha_state()
|
||||||
async def after_update_callback(device):
|
if self._device.is_traveling():
|
||||||
"""Call after device was updated."""
|
self.start_auto_updater()
|
||||||
self.async_write_ha_state()
|
|
||||||
if self.device.is_traveling():
|
|
||||||
self.start_auto_updater()
|
|
||||||
|
|
||||||
self.device.register_device_updated_cb(after_update_callback)
|
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
|
||||||
"""Store register state change callback."""
|
|
||||||
self.async_register_callbacks()
|
|
||||||
|
|
||||||
async def async_update(self):
|
|
||||||
"""Request a state update from KNX bus."""
|
|
||||||
await self.device.sync()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the KNX device."""
|
|
||||||
return self.device.name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def available(self):
|
|
||||||
"""Return True if entity is available."""
|
|
||||||
return self.hass.data[DATA_KNX].connected
|
|
||||||
|
|
||||||
@property
|
|
||||||
def should_poll(self):
|
|
||||||
"""No polling needed within KNX."""
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_class(self):
|
def device_class(self):
|
||||||
"""Return the class of this device, from component DEVICE_CLASSES."""
|
"""Return the class of this device, from component DEVICE_CLASSES."""
|
||||||
if self.device.supports_angle:
|
if self._device.supports_angle:
|
||||||
return DEVICE_CLASS_BLIND
|
return DEVICE_CLASS_BLIND
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -81,9 +55,9 @@ class KNXCover(CoverEntity):
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Flag supported features."""
|
"""Flag supported features."""
|
||||||
supported_features = SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_SET_POSITION
|
supported_features = SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_SET_POSITION
|
||||||
if self.device.supports_stop:
|
if self._device.supports_stop:
|
||||||
supported_features |= SUPPORT_STOP
|
supported_features |= SUPPORT_STOP
|
||||||
if self.device.supports_angle:
|
if self._device.supports_angle:
|
||||||
supported_features |= SUPPORT_SET_TILT_POSITION
|
supported_features |= SUPPORT_SET_TILT_POSITION
|
||||||
return supported_features
|
return supported_features
|
||||||
|
|
||||||
|
@ -95,57 +69,57 @@ class KNXCover(CoverEntity):
|
||||||
"""
|
"""
|
||||||
# In KNX 0 is open, 100 is closed.
|
# In KNX 0 is open, 100 is closed.
|
||||||
try:
|
try:
|
||||||
return 100 - self.device.current_position()
|
return 100 - self._device.current_position()
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_closed(self):
|
def is_closed(self):
|
||||||
"""Return if the cover is closed."""
|
"""Return if the cover is closed."""
|
||||||
return self.device.is_closed()
|
return self._device.is_closed()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_opening(self):
|
def is_opening(self):
|
||||||
"""Return if the cover is opening or not."""
|
"""Return if the cover is opening or not."""
|
||||||
return self.device.is_opening()
|
return self._device.is_opening()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_closing(self):
|
def is_closing(self):
|
||||||
"""Return if the cover is closing or not."""
|
"""Return if the cover is closing or not."""
|
||||||
return self.device.is_closing()
|
return self._device.is_closing()
|
||||||
|
|
||||||
async def async_close_cover(self, **kwargs):
|
async def async_close_cover(self, **kwargs):
|
||||||
"""Close the cover."""
|
"""Close the cover."""
|
||||||
await self.device.set_down()
|
await self._device.set_down()
|
||||||
|
|
||||||
async def async_open_cover(self, **kwargs):
|
async def async_open_cover(self, **kwargs):
|
||||||
"""Open the cover."""
|
"""Open the cover."""
|
||||||
await self.device.set_up()
|
await self._device.set_up()
|
||||||
|
|
||||||
async def async_set_cover_position(self, **kwargs):
|
async def async_set_cover_position(self, **kwargs):
|
||||||
"""Move the cover to a specific position."""
|
"""Move the cover to a specific position."""
|
||||||
knx_position = 100 - kwargs[ATTR_POSITION]
|
knx_position = 100 - kwargs[ATTR_POSITION]
|
||||||
await self.device.set_position(knx_position)
|
await self._device.set_position(knx_position)
|
||||||
|
|
||||||
async def async_stop_cover(self, **kwargs):
|
async def async_stop_cover(self, **kwargs):
|
||||||
"""Stop the cover."""
|
"""Stop the cover."""
|
||||||
await self.device.stop()
|
await self._device.stop()
|
||||||
self.stop_auto_updater()
|
self.stop_auto_updater()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_cover_tilt_position(self):
|
def current_cover_tilt_position(self):
|
||||||
"""Return current tilt position of cover."""
|
"""Return current tilt position of cover."""
|
||||||
if not self.device.supports_angle:
|
if not self._device.supports_angle:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
return 100 - self.device.current_angle()
|
return 100 - self._device.current_angle()
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def async_set_cover_tilt_position(self, **kwargs):
|
async def async_set_cover_tilt_position(self, **kwargs):
|
||||||
"""Move the cover tilt to a specific position."""
|
"""Move the cover tilt to a specific position."""
|
||||||
knx_tilt_position = 100 - kwargs[ATTR_TILT_POSITION]
|
knx_tilt_position = 100 - kwargs[ATTR_TILT_POSITION]
|
||||||
await self.device.set_angle(knx_tilt_position)
|
await self._device.set_angle(knx_tilt_position)
|
||||||
|
|
||||||
def start_auto_updater(self):
|
def start_auto_updater(self):
|
||||||
"""Start the autoupdater to update Home Assistant while cover is moving."""
|
"""Start the autoupdater to update Home Assistant while cover is moving."""
|
||||||
|
@ -164,7 +138,7 @@ class KNXCover(CoverEntity):
|
||||||
def auto_updater_hook(self, now):
|
def auto_updater_hook(self, now):
|
||||||
"""Call for the autoupdater."""
|
"""Call for the autoupdater."""
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
if self.device.position_reached():
|
if self._device.position_reached():
|
||||||
self.stop_auto_updater()
|
self.stop_auto_updater()
|
||||||
|
|
||||||
self.hass.add_job(self.device.auto_stop_if_necessary())
|
self.hass.add_job(self._device.auto_stop_if_necessary())
|
||||||
|
|
51
homeassistant/components/knx/knx_entity.py
Normal file
51
homeassistant/components/knx/knx_entity.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
"""Base class for KNX devices."""
|
||||||
|
from xknx.devices import Climate as XknxClimate, Device as XknxDevice
|
||||||
|
|
||||||
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
|
||||||
|
class KnxEntity(Entity):
|
||||||
|
"""Representation of a KNX entity."""
|
||||||
|
|
||||||
|
def __init__(self, device: XknxDevice):
|
||||||
|
"""Set up device."""
|
||||||
|
self._device = device
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the KNX device."""
|
||||||
|
return self._device.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self):
|
||||||
|
"""Return True if entity is available."""
|
||||||
|
return self.hass.data[DOMAIN].connected
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""No polling needed within KNX."""
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def async_update(self):
|
||||||
|
"""Request a state update from KNX bus."""
|
||||||
|
await self._device.sync()
|
||||||
|
|
||||||
|
async def after_update_callback(self, device: XknxDevice):
|
||||||
|
"""Call after device was updated."""
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
async def async_added_to_hass(self) -> None:
|
||||||
|
"""Store register state change callback."""
|
||||||
|
self._device.register_device_updated_cb(self.after_update_callback)
|
||||||
|
|
||||||
|
if isinstance(self._device, XknxClimate):
|
||||||
|
self._device.mode.register_device_updated_cb(self.after_update_callback)
|
||||||
|
|
||||||
|
async def async_will_remove_from_hass(self) -> None:
|
||||||
|
"""Disconnect device object when removed."""
|
||||||
|
self._device.unregister_device_updated_cb(self.after_update_callback)
|
||||||
|
|
||||||
|
if isinstance(self._device, XknxClimate):
|
||||||
|
self._device.mode.unregister_device_updated_cb(self.after_update_callback)
|
|
@ -12,10 +12,10 @@ from homeassistant.components.light import (
|
||||||
SUPPORT_WHITE_VALUE,
|
SUPPORT_WHITE_VALUE,
|
||||||
LightEntity,
|
LightEntity,
|
||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
|
||||||
import homeassistant.util.color as color_util
|
import homeassistant.util.color as color_util
|
||||||
|
|
||||||
from . import DATA_KNX
|
from .const import DOMAIN
|
||||||
|
from .knx_entity import KnxEntity
|
||||||
|
|
||||||
DEFAULT_COLOR = (0.0, 0.0)
|
DEFAULT_COLOR = (0.0, 0.0)
|
||||||
DEFAULT_BRIGHTNESS = 255
|
DEFAULT_BRIGHTNESS = 255
|
||||||
|
@ -25,18 +25,18 @@ DEFAULT_WHITE_VALUE = 255
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
"""Set up lights for KNX platform."""
|
"""Set up lights for KNX platform."""
|
||||||
entities = []
|
entities = []
|
||||||
for device in hass.data[DATA_KNX].xknx.devices:
|
for device in hass.data[DOMAIN].xknx.devices:
|
||||||
if isinstance(device, XknxLight):
|
if isinstance(device, XknxLight):
|
||||||
entities.append(KNXLight(device))
|
entities.append(KNXLight(device))
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class KNXLight(LightEntity):
|
class KNXLight(KnxEntity, LightEntity):
|
||||||
"""Representation of a KNX light."""
|
"""Representation of a KNX light."""
|
||||||
|
|
||||||
def __init__(self, device: XknxLight):
|
def __init__(self, device: XknxLight):
|
||||||
"""Initialize of KNX light."""
|
"""Initialize of KNX light."""
|
||||||
self.device = device
|
super().__init__(device)
|
||||||
|
|
||||||
self._min_kelvin = device.min_kelvin
|
self._min_kelvin = device.min_kelvin
|
||||||
self._max_kelvin = device.max_kelvin
|
self._max_kelvin = device.max_kelvin
|
||||||
|
@ -47,46 +47,13 @@ class KNXLight(LightEntity):
|
||||||
self._min_kelvin
|
self._min_kelvin
|
||||||
)
|
)
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_register_callbacks(self):
|
|
||||||
"""Register callbacks to update hass after device was changed."""
|
|
||||||
|
|
||||||
async def after_update_callback(device):
|
|
||||||
"""Call after device was updated."""
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
self.device.register_device_updated_cb(after_update_callback)
|
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
|
||||||
"""Store register state change callback."""
|
|
||||||
self.async_register_callbacks()
|
|
||||||
|
|
||||||
async def async_update(self):
|
|
||||||
"""Request a state update from KNX bus."""
|
|
||||||
await self.device.sync()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the KNX device."""
|
|
||||||
return self.device.name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def available(self):
|
|
||||||
"""Return True if entity is available."""
|
|
||||||
return self.hass.data[DATA_KNX].connected
|
|
||||||
|
|
||||||
@property
|
|
||||||
def should_poll(self):
|
|
||||||
"""No polling needed within KNX."""
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def brightness(self):
|
def brightness(self):
|
||||||
"""Return the brightness of this light between 0..255."""
|
"""Return the brightness of this light between 0..255."""
|
||||||
if self.device.supports_brightness:
|
if self._device.supports_brightness:
|
||||||
return self.device.current_brightness
|
return self._device.current_brightness
|
||||||
hsv_color = self._hsv_color
|
hsv_color = self._hsv_color
|
||||||
if self.device.supports_color and hsv_color:
|
if self._device.supports_color and hsv_color:
|
||||||
return round(hsv_color[-1] / 100 * 255)
|
return round(hsv_color[-1] / 100 * 255)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -94,35 +61,35 @@ class KNXLight(LightEntity):
|
||||||
def hs_color(self):
|
def hs_color(self):
|
||||||
"""Return the HS color value."""
|
"""Return the HS color value."""
|
||||||
rgb = None
|
rgb = None
|
||||||
if self.device.supports_rgbw or self.device.supports_color:
|
if self._device.supports_rgbw or self._device.supports_color:
|
||||||
rgb, _ = self.device.current_color
|
rgb, _ = self._device.current_color
|
||||||
return color_util.color_RGB_to_hs(*rgb) if rgb else None
|
return color_util.color_RGB_to_hs(*rgb) if rgb else None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _hsv_color(self):
|
def _hsv_color(self):
|
||||||
"""Return the HSV color value."""
|
"""Return the HSV color value."""
|
||||||
rgb = None
|
rgb = None
|
||||||
if self.device.supports_rgbw or self.device.supports_color:
|
if self._device.supports_rgbw or self._device.supports_color:
|
||||||
rgb, _ = self.device.current_color
|
rgb, _ = self._device.current_color
|
||||||
return color_util.color_RGB_to_hsv(*rgb) if rgb else None
|
return color_util.color_RGB_to_hsv(*rgb) if rgb else None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def white_value(self):
|
def white_value(self):
|
||||||
"""Return the white value."""
|
"""Return the white value."""
|
||||||
white = None
|
white = None
|
||||||
if self.device.supports_rgbw:
|
if self._device.supports_rgbw:
|
||||||
_, white = self.device.current_color
|
_, white = self._device.current_color
|
||||||
return white
|
return white
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def color_temp(self):
|
def color_temp(self):
|
||||||
"""Return the color temperature in mireds."""
|
"""Return the color temperature in mireds."""
|
||||||
if self.device.supports_color_temperature:
|
if self._device.supports_color_temperature:
|
||||||
kelvin = self.device.current_color_temperature
|
kelvin = self._device.current_color_temperature
|
||||||
if kelvin is not None:
|
if kelvin is not None:
|
||||||
return color_util.color_temperature_kelvin_to_mired(kelvin)
|
return color_util.color_temperature_kelvin_to_mired(kelvin)
|
||||||
if self.device.supports_tunable_white:
|
if self._device.supports_tunable_white:
|
||||||
relative_ct = self.device.current_tunable_white
|
relative_ct = self._device.current_tunable_white
|
||||||
if relative_ct is not None:
|
if relative_ct is not None:
|
||||||
# as KNX devices typically use Kelvin we use it as base for
|
# as KNX devices typically use Kelvin we use it as base for
|
||||||
# calculating ct from percent
|
# calculating ct from percent
|
||||||
|
@ -155,19 +122,22 @@ class KNXLight(LightEntity):
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Return true if light is on."""
|
"""Return true if light is on."""
|
||||||
return self.device.state
|
return self._device.state
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Flag supported features."""
|
"""Flag supported features."""
|
||||||
flags = 0
|
flags = 0
|
||||||
if self.device.supports_brightness:
|
if self._device.supports_brightness:
|
||||||
flags |= SUPPORT_BRIGHTNESS
|
flags |= SUPPORT_BRIGHTNESS
|
||||||
if self.device.supports_color:
|
if self._device.supports_color:
|
||||||
flags |= SUPPORT_COLOR | SUPPORT_BRIGHTNESS
|
flags |= SUPPORT_COLOR | SUPPORT_BRIGHTNESS
|
||||||
if self.device.supports_rgbw:
|
if self._device.supports_rgbw:
|
||||||
flags |= SUPPORT_COLOR | SUPPORT_WHITE_VALUE
|
flags |= SUPPORT_COLOR | SUPPORT_WHITE_VALUE
|
||||||
if self.device.supports_color_temperature or self.device.supports_tunable_white:
|
if (
|
||||||
|
self._device.supports_color_temperature
|
||||||
|
or self._device.supports_tunable_white
|
||||||
|
):
|
||||||
flags |= SUPPORT_COLOR_TEMP
|
flags |= SUPPORT_COLOR_TEMP
|
||||||
return flags
|
return flags
|
||||||
|
|
||||||
|
@ -191,14 +161,16 @@ class KNXLight(LightEntity):
|
||||||
or update_white_value
|
or update_white_value
|
||||||
or update_color_temp
|
or update_color_temp
|
||||||
):
|
):
|
||||||
await self.device.set_on()
|
await self._device.set_on()
|
||||||
|
|
||||||
if self.device.supports_brightness and (update_brightness and not update_color):
|
if self._device.supports_brightness and (
|
||||||
|
update_brightness and not update_color
|
||||||
|
):
|
||||||
# if we don't need to update the color, try updating brightness
|
# if we don't need to update the color, try updating brightness
|
||||||
# directly if supported; don't do it if color also has to be
|
# directly if supported; don't do it if color also has to be
|
||||||
# changed, as RGB color implicitly sets the brightness as well
|
# changed, as RGB color implicitly sets the brightness as well
|
||||||
await self.device.set_brightness(brightness)
|
await self._device.set_brightness(brightness)
|
||||||
elif (self.device.supports_rgbw or self.device.supports_color) and (
|
elif (self._device.supports_rgbw or self._device.supports_color) and (
|
||||||
update_brightness or update_color or update_white_value
|
update_brightness or update_color or update_white_value
|
||||||
):
|
):
|
||||||
# change RGB color, white value (if supported), and brightness
|
# change RGB color, white value (if supported), and brightness
|
||||||
|
@ -208,25 +180,25 @@ class KNXLight(LightEntity):
|
||||||
brightness = DEFAULT_BRIGHTNESS
|
brightness = DEFAULT_BRIGHTNESS
|
||||||
if hs_color is None:
|
if hs_color is None:
|
||||||
hs_color = DEFAULT_COLOR
|
hs_color = DEFAULT_COLOR
|
||||||
if white_value is None and self.device.supports_rgbw:
|
if white_value is None and self._device.supports_rgbw:
|
||||||
white_value = DEFAULT_WHITE_VALUE
|
white_value = DEFAULT_WHITE_VALUE
|
||||||
rgb = color_util.color_hsv_to_RGB(*hs_color, brightness * 100 / 255)
|
rgb = color_util.color_hsv_to_RGB(*hs_color, brightness * 100 / 255)
|
||||||
await self.device.set_color(rgb, white_value)
|
await self._device.set_color(rgb, white_value)
|
||||||
|
|
||||||
if update_color_temp:
|
if update_color_temp:
|
||||||
kelvin = int(color_util.color_temperature_mired_to_kelvin(mireds))
|
kelvin = int(color_util.color_temperature_mired_to_kelvin(mireds))
|
||||||
kelvin = min(self._max_kelvin, max(self._min_kelvin, kelvin))
|
kelvin = min(self._max_kelvin, max(self._min_kelvin, kelvin))
|
||||||
|
|
||||||
if self.device.supports_color_temperature:
|
if self._device.supports_color_temperature:
|
||||||
await self.device.set_color_temperature(kelvin)
|
await self._device.set_color_temperature(kelvin)
|
||||||
elif self.device.supports_tunable_white:
|
elif self._device.supports_tunable_white:
|
||||||
relative_ct = int(
|
relative_ct = int(
|
||||||
255
|
255
|
||||||
* (kelvin - self._min_kelvin)
|
* (kelvin - self._min_kelvin)
|
||||||
/ (self._max_kelvin - self._min_kelvin)
|
/ (self._max_kelvin - self._min_kelvin)
|
||||||
)
|
)
|
||||||
await self.device.set_tunable_white(relative_ct)
|
await self._device.set_tunable_white(relative_ct)
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs):
|
async def async_turn_off(self, **kwargs):
|
||||||
"""Turn the light off."""
|
"""Turn the light off."""
|
||||||
await self.device.set_off()
|
await self._device.set_off()
|
||||||
|
|
|
@ -5,13 +5,13 @@ from xknx.devices import Notification as XknxNotification
|
||||||
|
|
||||||
from homeassistant.components.notify import BaseNotificationService
|
from homeassistant.components.notify import BaseNotificationService
|
||||||
|
|
||||||
from . import DATA_KNX
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
|
||||||
async def async_get_service(hass, config, discovery_info=None):
|
async def async_get_service(hass, config, discovery_info=None):
|
||||||
"""Get the KNX notification service."""
|
"""Get the KNX notification service."""
|
||||||
notification_devices = []
|
notification_devices = []
|
||||||
for device in hass.data[DATA_KNX].xknx.devices:
|
for device in hass.data[DOMAIN].xknx.devices:
|
||||||
if isinstance(device, XknxNotification):
|
if isinstance(device, XknxNotification):
|
||||||
notification_devices.append(device)
|
notification_devices.append(device)
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -5,30 +5,26 @@ from xknx.devices import Scene as XknxScene
|
||||||
|
|
||||||
from homeassistant.components.scene import Scene
|
from homeassistant.components.scene import Scene
|
||||||
|
|
||||||
from . import DATA_KNX
|
from .const import DOMAIN
|
||||||
|
from .knx_entity import KnxEntity
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
"""Set up the scenes for KNX platform."""
|
"""Set up the scenes for KNX platform."""
|
||||||
entities = []
|
entities = []
|
||||||
for device in hass.data[DATA_KNX].xknx.devices:
|
for device in hass.data[DOMAIN].xknx.devices:
|
||||||
if isinstance(device, XknxScene):
|
if isinstance(device, XknxScene):
|
||||||
entities.append(KNXScene(device))
|
entities.append(KNXScene(device))
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class KNXScene(Scene):
|
class KNXScene(KnxEntity, Scene):
|
||||||
"""Representation of a KNX scene."""
|
"""Representation of a KNX scene."""
|
||||||
|
|
||||||
def __init__(self, scene: XknxScene):
|
def __init__(self, device: XknxScene):
|
||||||
"""Init KNX scene."""
|
"""Init KNX scene."""
|
||||||
self.scene = scene
|
super().__init__(device)
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the scene."""
|
|
||||||
return self.scene.name
|
|
||||||
|
|
||||||
async def async_activate(self, **kwargs: Any) -> None:
|
async def async_activate(self, **kwargs: Any) -> None:
|
||||||
"""Activate the scene."""
|
"""Activate the scene."""
|
||||||
await self.scene.run()
|
await self._device.run()
|
||||||
|
|
|
@ -1,77 +1,43 @@
|
||||||
"""Support for KNX/IP sensors."""
|
"""Support for KNX/IP sensors."""
|
||||||
from xknx.devices import Sensor as XknxSensor
|
from xknx.devices import Sensor as XknxSensor
|
||||||
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.components.sensor import DEVICE_CLASSES
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
from . import DATA_KNX
|
from .const import DOMAIN
|
||||||
|
from .knx_entity import KnxEntity
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
"""Set up sensor(s) for KNX platform."""
|
"""Set up sensor(s) for KNX platform."""
|
||||||
entities = []
|
entities = []
|
||||||
for device in hass.data[DATA_KNX].xknx.devices:
|
for device in hass.data[DOMAIN].xknx.devices:
|
||||||
if isinstance(device, XknxSensor):
|
if isinstance(device, XknxSensor):
|
||||||
entities.append(KNXSensor(device))
|
entities.append(KNXSensor(device))
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class KNXSensor(Entity):
|
class KNXSensor(KnxEntity, Entity):
|
||||||
"""Representation of a KNX sensor."""
|
"""Representation of a KNX sensor."""
|
||||||
|
|
||||||
def __init__(self, device: XknxSensor):
|
def __init__(self, device: XknxSensor):
|
||||||
"""Initialize of a KNX sensor."""
|
"""Initialize of a KNX sensor."""
|
||||||
self.device = device
|
super().__init__(device)
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_register_callbacks(self):
|
|
||||||
"""Register callbacks to update hass after device was changed."""
|
|
||||||
|
|
||||||
async def after_update_callback(device):
|
|
||||||
"""Call after device was updated."""
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
self.device.register_device_updated_cb(after_update_callback)
|
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
|
||||||
"""Store register state change callback."""
|
|
||||||
self.async_register_callbacks()
|
|
||||||
|
|
||||||
async def async_update(self):
|
|
||||||
"""Update the state from KNX."""
|
|
||||||
await self.device.sync()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the KNX device."""
|
|
||||||
return self.device.name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def available(self):
|
|
||||||
"""Return True if entity is available."""
|
|
||||||
return self.hass.data[DATA_KNX].connected
|
|
||||||
|
|
||||||
@property
|
|
||||||
def should_poll(self):
|
|
||||||
"""No polling needed within KNX."""
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the state of the sensor."""
|
"""Return the state of the sensor."""
|
||||||
return self.device.resolve_state()
|
return self._device.resolve_state()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unit_of_measurement(self):
|
def unit_of_measurement(self):
|
||||||
"""Return the unit this state is expressed in."""
|
"""Return the unit this state is expressed in."""
|
||||||
return self.device.unit_of_measurement()
|
return self._device.unit_of_measurement()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_class(self):
|
def device_class(self):
|
||||||
"""Return the device class of the sensor."""
|
"""Return the device class of the sensor."""
|
||||||
return self.device.ha_device_class()
|
device_class = self._device.ha_device_class()
|
||||||
|
if device_class in DEVICE_CLASSES:
|
||||||
@property
|
return device_class
|
||||||
def device_state_attributes(self):
|
|
||||||
"""Return the state attributes."""
|
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -2,69 +2,36 @@
|
||||||
from xknx.devices import Switch as XknxSwitch
|
from xknx.devices import Switch as XknxSwitch
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchEntity
|
from homeassistant.components.switch import SwitchEntity
|
||||||
from homeassistant.core import callback
|
|
||||||
|
|
||||||
from . import DATA_KNX
|
from . import DOMAIN
|
||||||
|
from .knx_entity import KnxEntity
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
"""Set up switch(es) for KNX platform."""
|
"""Set up switch(es) for KNX platform."""
|
||||||
entities = []
|
entities = []
|
||||||
for device in hass.data[DATA_KNX].xknx.devices:
|
for device in hass.data[DOMAIN].xknx.devices:
|
||||||
if isinstance(device, XknxSwitch):
|
if isinstance(device, XknxSwitch):
|
||||||
entities.append(KNXSwitch(device))
|
entities.append(KNXSwitch(device))
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class KNXSwitch(SwitchEntity):
|
class KNXSwitch(KnxEntity, SwitchEntity):
|
||||||
"""Representation of a KNX switch."""
|
"""Representation of a KNX switch."""
|
||||||
|
|
||||||
def __init__(self, device: XknxSwitch):
|
def __init__(self, device: XknxSwitch):
|
||||||
"""Initialize of KNX switch."""
|
"""Initialize of KNX switch."""
|
||||||
self.device = device
|
super().__init__(device)
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_register_callbacks(self):
|
|
||||||
"""Register callbacks to update hass after device was changed."""
|
|
||||||
|
|
||||||
async def after_update_callback(device):
|
|
||||||
"""Call after device was updated."""
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
self.device.register_device_updated_cb(after_update_callback)
|
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
|
||||||
"""Store register state change callback."""
|
|
||||||
self.async_register_callbacks()
|
|
||||||
|
|
||||||
async def async_update(self):
|
|
||||||
"""Request a state update from KNX bus."""
|
|
||||||
await self.device.sync()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the KNX device."""
|
|
||||||
return self.device.name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def available(self):
|
|
||||||
"""Return true if entity is available."""
|
|
||||||
return self.hass.data[DATA_KNX].connected
|
|
||||||
|
|
||||||
@property
|
|
||||||
def should_poll(self):
|
|
||||||
"""Return the polling state. Not needed within KNX."""
|
|
||||||
return False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Return true if device is on."""
|
"""Return true if device is on."""
|
||||||
return self.device.state
|
return self._device.state
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs):
|
async def async_turn_on(self, **kwargs):
|
||||||
"""Turn the device on."""
|
"""Turn the device on."""
|
||||||
await self.device.set_on()
|
await self._device.set_on()
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs):
|
async def async_turn_off(self, **kwargs):
|
||||||
"""Turn the device off."""
|
"""Turn the device off."""
|
||||||
await self.device.set_off()
|
await self._device.set_off()
|
||||||
|
|
|
@ -5,34 +5,30 @@ from xknx.devices import Weather as XknxWeather
|
||||||
from homeassistant.components.weather import WeatherEntity
|
from homeassistant.components.weather import WeatherEntity
|
||||||
from homeassistant.const import TEMP_CELSIUS
|
from homeassistant.const import TEMP_CELSIUS
|
||||||
|
|
||||||
from .const import DATA_KNX
|
from .const import DOMAIN
|
||||||
|
from .knx_entity import KnxEntity
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
||||||
"""Set up the scenes for KNX platform."""
|
"""Set up the scenes for KNX platform."""
|
||||||
entities = []
|
entities = []
|
||||||
for device in hass.data[DATA_KNX].xknx.devices:
|
for device in hass.data[DOMAIN].xknx.devices:
|
||||||
if isinstance(device, XknxWeather):
|
if isinstance(device, XknxWeather):
|
||||||
entities.append(KNXWeather(device))
|
entities.append(KNXWeather(device))
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
class KNXWeather(WeatherEntity):
|
class KNXWeather(KnxEntity, WeatherEntity):
|
||||||
"""Representation of a KNX weather device."""
|
"""Representation of a KNX weather device."""
|
||||||
|
|
||||||
def __init__(self, device: XknxWeather):
|
def __init__(self, device: XknxWeather):
|
||||||
"""Initialize of a KNX sensor."""
|
"""Initialize of a KNX sensor."""
|
||||||
self.device = device
|
super().__init__(device)
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the weather device."""
|
|
||||||
return self.device.name
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def temperature(self):
|
def temperature(self):
|
||||||
"""Return current temperature."""
|
"""Return current temperature."""
|
||||||
return self.device.temperature
|
return self._device.temperature
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def temperature_unit(self):
|
def temperature_unit(self):
|
||||||
|
@ -44,25 +40,27 @@ class KNXWeather(WeatherEntity):
|
||||||
"""Return current air pressure."""
|
"""Return current air pressure."""
|
||||||
# KNX returns pA - HA requires hPa
|
# KNX returns pA - HA requires hPa
|
||||||
return (
|
return (
|
||||||
self.device.air_pressure / 100
|
self._device.air_pressure / 100
|
||||||
if self.device.air_pressure is not None
|
if self._device.air_pressure is not None
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def condition(self):
|
def condition(self):
|
||||||
"""Return current weather condition."""
|
"""Return current weather condition."""
|
||||||
return self.device.ha_current_state().value
|
return self._device.ha_current_state().value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def humidity(self):
|
def humidity(self):
|
||||||
"""Return current humidity."""
|
"""Return current humidity."""
|
||||||
return self.device.humidity if self.device.humidity is not None else None
|
return self._device.humidity if self._device.humidity is not None else None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def wind_speed(self):
|
def wind_speed(self):
|
||||||
"""Return current wind speed in km/h."""
|
"""Return current wind speed in km/h."""
|
||||||
# KNX only supports wind speed in m/s
|
# KNX only supports wind speed in m/s
|
||||||
return (
|
return (
|
||||||
self.device.wind_speed * 3.6 if self.device.wind_speed is not None else None
|
self._device.wind_speed * 3.6
|
||||||
|
if self._device.wind_speed is not None
|
||||||
|
else None
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue