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 call
This commit is contained in:
Matthias Alphart 2020-05-13 15:19:00 +02:00 committed by GitHub
parent c41fb2a21f
commit 7147c5306d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 85 additions and 19 deletions

View File

@ -4,15 +4,20 @@ import logging
import voluptuous as vol import voluptuous as vol
from xknx import XKNX from xknx import XKNX
from xknx.devices import ActionCallback, DateTime, DateTimeBroadcastType, ExposeSensor from xknx.devices import ActionCallback, DateTime, DateTimeBroadcastType, ExposeSensor
from xknx.dpt import DPTArray, DPTBinary
from xknx.exceptions import XKNXException from xknx.exceptions import XKNXException
from xknx.io import DEFAULT_MCAST_PORT, ConnectionConfig, ConnectionType 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 ( from homeassistant.const import (
CONF_ENTITY_ID, CONF_ENTITY_ID,
CONF_HOST, CONF_HOST,
CONF_PORT, CONF_PORT,
EVENT_HOMEASSISTANT_STOP, EVENT_HOMEASSISTANT_STOP,
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
) )
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
@ -35,6 +40,8 @@ CONF_KNX_STATE_UPDATER = "state_updater"
CONF_KNX_RATE_LIMIT = "rate_limit" CONF_KNX_RATE_LIMIT = "rate_limit"
CONF_KNX_EXPOSE = "expose" CONF_KNX_EXPOSE = "expose"
CONF_KNX_EXPOSE_TYPE = "type" CONF_KNX_EXPOSE_TYPE = "type"
CONF_KNX_EXPOSE_ATTRIBUTE = "attribute"
CONF_KNX_EXPOSE_DEFAULT = "default"
CONF_KNX_EXPOSE_ADDRESS = "address" CONF_KNX_EXPOSE_ADDRESS = "address"
SERVICE_KNX_SEND = "send" SERVICE_KNX_SEND = "send"
@ -57,6 +64,8 @@ EXPOSE_SCHEMA = vol.Schema(
{ {
vol.Required(CONF_KNX_EXPOSE_TYPE): cv.string, vol.Required(CONF_KNX_EXPOSE_TYPE): cv.string,
vol.Optional(CONF_ENTITY_ID): cv.entity_id, 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, vol.Required(CONF_KNX_EXPOSE_ADDRESS): cv.string,
} }
) )
@ -244,6 +253,8 @@ class KNXModule:
for to_expose in self.config[DOMAIN][CONF_KNX_EXPOSE]: for to_expose in self.config[DOMAIN][CONF_KNX_EXPOSE]:
expose_type = to_expose.get(CONF_KNX_EXPOSE_TYPE) expose_type = to_expose.get(CONF_KNX_EXPOSE_TYPE)
entity_id = to_expose.get(CONF_ENTITY_ID) 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) address = to_expose.get(CONF_KNX_EXPOSE_ADDRESS)
if expose_type in ["time", "date", "datetime"]: if expose_type in ["time", "date", "datetime"]:
exposure = KNXExposeTime(self.xknx, expose_type, address) exposure = KNXExposeTime(self.xknx, expose_type, address)
@ -251,7 +262,13 @@ class KNXModule:
self.exposures.append(exposure) self.exposures.append(exposure)
else: else:
exposure = KNXExposeSensor( 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() exposure.async_register()
self.exposures.append(exposure) self.exposures.append(exposure)
@ -325,23 +342,26 @@ class KNXExposeTime:
class KNXExposeSensor: class KNXExposeSensor:
"""Object to Expose Home Assistant entity to KNX bus.""" """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.""" """Initialize of Expose class."""
self.hass = hass self.hass = hass
self.xknx = xknx self.xknx = xknx
self.type = expose_type self.type = expose_type
self.entity_id = entity_id self.entity_id = entity_id
self.expose_attribute = attribute
self.expose_default = default
self.address = address self.address = address
self.device = None self.device = None
@callback @callback
def async_register(self): def async_register(self):
"""Register listener.""" """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.device = ExposeSensor(
self.xknx, self.xknx, name=_name, group_address=self.address, value_type=self.type,
name=self.entity_id,
group_address=self.address,
value_type=self.type,
) )
self.xknx.devices.add(self.device) self.xknx.devices.add(self.device)
async_track_state_change(self.hass, self.entity_id, self._async_entity_changed) async_track_state_change(self.hass, self.entity_id, self._async_entity_changed)
@ -350,13 +370,31 @@ class KNXExposeSensor:
"""Handle entity change.""" """Handle entity change."""
if new_state is None: if new_state is None:
return return
if new_state.state == "unknown": if new_state.state in (STATE_UNKNOWN, STATE_UNAVAILABLE):
return return
if self.type == "binary": if self.expose_attribute is not None:
if new_state.state == "on": new_attribute = new_state.attributes.get(self.expose_attribute)
await self.device.set(True) if old_state is not None:
elif new_state.state == "off": old_attribute = old_state.attributes.get(self.expose_attribute)
await self.device.set(False) if old_attribute == new_attribute:
# don't send same value sequentially
return
await self._async_set_knx_value(new_attribute)
else: 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)

View File

@ -124,6 +124,10 @@ class KNXBinarySensor(BinarySensorEntity):
"""Store register state change callback.""" """Store register state change callback."""
self.async_register_callbacks() self.async_register_callbacks()
async def async_update(self):
"""Request a state update from KNX bus."""
await self.device.sync()
@property @property
def name(self): def name(self):
"""Return the name of the KNX device.""" """Return the name of the KNX device."""

View File

@ -3,7 +3,7 @@ from typing import List, Optional
import voluptuous as vol import voluptuous as vol
from xknx.devices import Climate as XknxClimate, ClimateMode as XknxClimateMode 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 import PLATFORM_SCHEMA, ClimateEntity
from homeassistant.components.climate.const import ( from homeassistant.components.climate.const import (
@ -215,6 +215,11 @@ class KNXClimate(ClimateEntity):
self.device.register_device_updated_cb(after_update_callback) self.device.register_device_updated_cb(after_update_callback)
self.device.mode.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 @property
def name(self) -> str: def name(self) -> str:
"""Return the name of the KNX device.""" """Return the name of the KNX device."""
@ -279,7 +284,8 @@ class KNXClimate(ClimateEntity):
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
) )
return None # default to "heat"
return HVAC_MODE_HEAT
@property @property
def hvac_modes(self) -> Optional[List[str]]: def hvac_modes(self) -> Optional[List[str]]:
@ -293,7 +299,9 @@ class KNXClimate(ClimateEntity):
_operations.append(HVAC_MODE_HEAT) _operations.append(HVAC_MODE_HEAT)
_operations.append(HVAC_MODE_OFF) _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: async def async_set_hvac_mode(self, hvac_mode: str) -> None:
"""Set operation mode.""" """Set operation mode."""

View File

@ -116,6 +116,10 @@ class KNXCover(CoverEntity):
"""Store register state change callback.""" """Store register state change callback."""
self.async_register_callbacks() self.async_register_callbacks()
async def async_update(self):
"""Request a state update from KNX bus."""
await self.device.sync()
@property @property
def name(self): def name(self):
"""Return the name of the KNX device.""" """Return the name of the KNX device."""

View File

@ -162,6 +162,10 @@ class KNXLight(LightEntity):
"""Store register state change callback.""" """Store register state change callback."""
self.async_register_callbacks() self.async_register_callbacks()
async def async_update(self):
"""Request a state update from KNX bus."""
await self.device.sync()
@property @property
def name(self): def name(self):
"""Return the name of the KNX device.""" """Return the name of the KNX device."""

View File

@ -2,6 +2,6 @@
"domain": "knx", "domain": "knx",
"name": "KNX", "name": "KNX",
"documentation": "https://www.home-assistant.io/integrations/knx", "documentation": "https://www.home-assistant.io/integrations/knx",
"requirements": ["xknx==0.11.2"], "requirements": ["xknx==0.11.3"],
"codeowners": ["@Julius2342"] "codeowners": ["@Julius2342"]
} }

View File

@ -77,6 +77,10 @@ class KNXSensor(Entity):
"""Store register state change callback.""" """Store register state change callback."""
self.async_register_callbacks() self.async_register_callbacks()
async def async_update(self):
"""Update the state from KNX."""
await self.device.sync()
@property @property
def name(self): def name(self):
"""Return the name of the KNX device.""" """Return the name of the KNX device."""

View File

@ -73,6 +73,10 @@ class KNXSwitch(SwitchEntity):
"""Store register state change callback.""" """Store register state change callback."""
self.async_register_callbacks() self.async_register_callbacks()
async def async_update(self):
"""Request a state update from KNX bus."""
await self.device.sync()
@property @property
def name(self): def name(self):
"""Return the name of the KNX device.""" """Return the name of the KNX device."""

View File

@ -2207,7 +2207,7 @@ xboxapi==0.1.1
xfinity-gateway==0.0.4 xfinity-gateway==0.0.4
# homeassistant.components.knx # homeassistant.components.knx
xknx==0.11.2 xknx==0.11.3
# homeassistant.components.bluesound # homeassistant.components.bluesound
# homeassistant.components.rest # homeassistant.components.rest