update knx module to xknx 0.11.3 (#35154)
- add expose attribute function and default value - default climate havc_mode to "heat" if modes are not supported - support `update_entity` service callpull/37072/head
parent
c41fb2a21f
commit
7147c5306d
homeassistant/components/knx
|
@ -4,15 +4,20 @@ import logging
|
|||
import voluptuous as vol
|
||||
from xknx import XKNX
|
||||
from xknx.devices import ActionCallback, DateTime, DateTimeBroadcastType, ExposeSensor
|
||||
from xknx.dpt import DPTArray, DPTBinary
|
||||
from xknx.exceptions import XKNXException
|
||||
from xknx.io import DEFAULT_MCAST_PORT, ConnectionConfig, ConnectionType
|
||||
from xknx.knx import AddressFilter, DPTArray, DPTBinary, GroupAddress, Telegram
|
||||
from xknx.telegram import AddressFilter, GroupAddress, Telegram
|
||||
|
||||
from homeassistant.const import (
|
||||
CONF_ENTITY_ID,
|
||||
CONF_HOST,
|
||||
CONF_PORT,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers import discovery
|
||||
|
@ -35,6 +40,8 @@ CONF_KNX_STATE_UPDATER = "state_updater"
|
|||
CONF_KNX_RATE_LIMIT = "rate_limit"
|
||||
CONF_KNX_EXPOSE = "expose"
|
||||
CONF_KNX_EXPOSE_TYPE = "type"
|
||||
CONF_KNX_EXPOSE_ATTRIBUTE = "attribute"
|
||||
CONF_KNX_EXPOSE_DEFAULT = "default"
|
||||
CONF_KNX_EXPOSE_ADDRESS = "address"
|
||||
|
||||
SERVICE_KNX_SEND = "send"
|
||||
|
@ -57,6 +64,8 @@ EXPOSE_SCHEMA = vol.Schema(
|
|||
{
|
||||
vol.Required(CONF_KNX_EXPOSE_TYPE): cv.string,
|
||||
vol.Optional(CONF_ENTITY_ID): cv.entity_id,
|
||||
vol.Optional(CONF_KNX_EXPOSE_ATTRIBUTE): cv.string,
|
||||
vol.Optional(CONF_KNX_EXPOSE_DEFAULT): cv.match_all,
|
||||
vol.Required(CONF_KNX_EXPOSE_ADDRESS): cv.string,
|
||||
}
|
||||
)
|
||||
|
@ -244,6 +253,8 @@ class KNXModule:
|
|||
for to_expose in self.config[DOMAIN][CONF_KNX_EXPOSE]:
|
||||
expose_type = to_expose.get(CONF_KNX_EXPOSE_TYPE)
|
||||
entity_id = to_expose.get(CONF_ENTITY_ID)
|
||||
attribute = to_expose.get(CONF_KNX_EXPOSE_ATTRIBUTE)
|
||||
default = to_expose.get(CONF_KNX_EXPOSE_DEFAULT)
|
||||
address = to_expose.get(CONF_KNX_EXPOSE_ADDRESS)
|
||||
if expose_type in ["time", "date", "datetime"]:
|
||||
exposure = KNXExposeTime(self.xknx, expose_type, address)
|
||||
|
@ -251,7 +262,13 @@ class KNXModule:
|
|||
self.exposures.append(exposure)
|
||||
else:
|
||||
exposure = KNXExposeSensor(
|
||||
self.hass, self.xknx, expose_type, entity_id, address
|
||||
self.hass,
|
||||
self.xknx,
|
||||
expose_type,
|
||||
entity_id,
|
||||
attribute,
|
||||
default,
|
||||
address,
|
||||
)
|
||||
exposure.async_register()
|
||||
self.exposures.append(exposure)
|
||||
|
@ -325,23 +342,26 @@ class KNXExposeTime:
|
|||
class KNXExposeSensor:
|
||||
"""Object to Expose Home Assistant entity to KNX bus."""
|
||||
|
||||
def __init__(self, hass, xknx, expose_type, entity_id, address):
|
||||
def __init__(self, hass, xknx, expose_type, entity_id, attribute, default, address):
|
||||
"""Initialize of Expose class."""
|
||||
self.hass = hass
|
||||
self.xknx = xknx
|
||||
self.type = expose_type
|
||||
self.entity_id = entity_id
|
||||
self.expose_attribute = attribute
|
||||
self.expose_default = default
|
||||
self.address = address
|
||||
self.device = None
|
||||
|
||||
@callback
|
||||
def async_register(self):
|
||||
"""Register listener."""
|
||||
if self.expose_attribute is not None:
|
||||
_name = self.entity_id + "__" + self.expose_attribute
|
||||
else:
|
||||
_name = self.entity_id
|
||||
self.device = ExposeSensor(
|
||||
self.xknx,
|
||||
name=self.entity_id,
|
||||
group_address=self.address,
|
||||
value_type=self.type,
|
||||
self.xknx, name=_name, group_address=self.address, value_type=self.type,
|
||||
)
|
||||
self.xknx.devices.add(self.device)
|
||||
async_track_state_change(self.hass, self.entity_id, self._async_entity_changed)
|
||||
|
@ -350,13 +370,31 @@ class KNXExposeSensor:
|
|||
"""Handle entity change."""
|
||||
if new_state is None:
|
||||
return
|
||||
if new_state.state == "unknown":
|
||||
if new_state.state in (STATE_UNKNOWN, STATE_UNAVAILABLE):
|
||||
return
|
||||
|
||||
if self.type == "binary":
|
||||
if new_state.state == "on":
|
||||
await self.device.set(True)
|
||||
elif new_state.state == "off":
|
||||
await self.device.set(False)
|
||||
if self.expose_attribute is not None:
|
||||
new_attribute = new_state.attributes.get(self.expose_attribute)
|
||||
if old_state is not None:
|
||||
old_attribute = old_state.attributes.get(self.expose_attribute)
|
||||
if old_attribute == new_attribute:
|
||||
# don't send same value sequentially
|
||||
return
|
||||
await self._async_set_knx_value(new_attribute)
|
||||
else:
|
||||
await self.device.set(new_state.state)
|
||||
await self._async_set_knx_value(new_state.state)
|
||||
|
||||
async def _async_set_knx_value(self, value):
|
||||
"""Set new value on xknx ExposeSensor."""
|
||||
if value is None:
|
||||
if self.expose_default is None:
|
||||
return
|
||||
value = self.expose_default
|
||||
|
||||
if self.type == "binary":
|
||||
if value == STATE_ON:
|
||||
value = True
|
||||
elif value == STATE_OFF:
|
||||
value = False
|
||||
|
||||
await self.device.set(value)
|
||||
|
|
|
@ -124,6 +124,10 @@ class KNXBinarySensor(BinarySensorEntity):
|
|||
"""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."""
|
||||
|
|
|
@ -3,7 +3,7 @@ from typing import List, Optional
|
|||
|
||||
import voluptuous as vol
|
||||
from xknx.devices import Climate as XknxClimate, ClimateMode as XknxClimateMode
|
||||
from xknx.knx import HVACOperationMode
|
||||
from xknx.dpt import HVACOperationMode
|
||||
|
||||
from homeassistant.components.climate import PLATFORM_SCHEMA, ClimateEntity
|
||||
from homeassistant.components.climate.const import (
|
||||
|
@ -215,6 +215,11 @@ class KNXClimate(ClimateEntity):
|
|||
self.device.register_device_updated_cb(after_update_callback)
|
||||
self.device.mode.register_device_updated_cb(after_update_callback)
|
||||
|
||||
async def async_update(self):
|
||||
"""Request a state update from KNX bus."""
|
||||
await self.device.sync()
|
||||
await self.device.mode.sync()
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
"""Return the name of the KNX device."""
|
||||
|
@ -279,7 +284,8 @@ class KNXClimate(ClimateEntity):
|
|||
return OPERATION_MODES.get(
|
||||
self.device.mode.operation_mode.value, HVAC_MODE_HEAT
|
||||
)
|
||||
return None
|
||||
# default to "heat"
|
||||
return HVAC_MODE_HEAT
|
||||
|
||||
@property
|
||||
def hvac_modes(self) -> Optional[List[str]]:
|
||||
|
@ -293,7 +299,9 @@ class KNXClimate(ClimateEntity):
|
|||
_operations.append(HVAC_MODE_HEAT)
|
||||
_operations.append(HVAC_MODE_OFF)
|
||||
|
||||
return [op for op in _operations if op is not None]
|
||||
_modes = list(filter(None, _operations))
|
||||
# default to ["heat"]
|
||||
return _modes if _modes else [HVAC_MODE_HEAT]
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: str) -> None:
|
||||
"""Set operation mode."""
|
||||
|
|
|
@ -116,6 +116,10 @@ class KNXCover(CoverEntity):
|
|||
"""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."""
|
||||
|
|
|
@ -162,6 +162,10 @@ class KNXLight(LightEntity):
|
|||
"""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."""
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
"domain": "knx",
|
||||
"name": "KNX",
|
||||
"documentation": "https://www.home-assistant.io/integrations/knx",
|
||||
"requirements": ["xknx==0.11.2"],
|
||||
"requirements": ["xknx==0.11.3"],
|
||||
"codeowners": ["@Julius2342"]
|
||||
}
|
||||
|
|
|
@ -77,6 +77,10 @@ class KNXSensor(Entity):
|
|||
"""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."""
|
||||
|
|
|
@ -73,6 +73,10 @@ class KNXSwitch(SwitchEntity):
|
|||
"""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."""
|
||||
|
|
|
@ -2207,7 +2207,7 @@ xboxapi==0.1.1
|
|||
xfinity-gateway==0.0.4
|
||||
|
||||
# homeassistant.components.knx
|
||||
xknx==0.11.2
|
||||
xknx==0.11.3
|
||||
|
||||
# homeassistant.components.bluesound
|
||||
# homeassistant.components.rest
|
||||
|
|
Loading…
Reference in New Issue