Update KNX component to xknx 0.11 (#24738)

* update component for xknx 0.11.0

- expose sensor state is not casted to float anymore
- climate mode operation list has no more None values
- light supports white_value (rgbw)
- sensor expects `group_address_state` now instead of `group_address`
- sensor forwards device_class if available

* update manifest to use xknx 0.11.0

* update requirements_all for xknx 0.11.0

* update for xknx 0.11.1

- require xknx 0.11.1
- use 'state_address' instead of 'address' in sensor and binary_sensor configuration
- optional 'sync_state' for sensors and binary_sensors

* remove questionable `del kwargs`
This commit is contained in:
Matthias Alphart 2019-07-11 22:01:37 +02:00 committed by Martin Hjelmare
parent 78a5dc71ac
commit e299d7b3d6
11 changed files with 108 additions and 66 deletions

View File

@ -36,12 +36,12 @@ ATTR_DISCOVER_DEVICES = 'devices'
TUNNELING_SCHEMA = vol.Schema({
vol.Required(CONF_HOST): cv.string,
vol.Required(CONF_KNX_LOCAL_IP): cv.string,
vol.Optional(CONF_KNX_LOCAL_IP): cv.string,
vol.Optional(CONF_PORT): cv.port,
})
ROUTING_SCHEMA = vol.Schema({
vol.Required(CONF_KNX_LOCAL_IP): cv.string,
vol.Optional(CONF_KNX_LOCAL_IP): cv.string,
})
EXPOSE_SCHEMA = vol.Schema({
@ -333,4 +333,13 @@ class KNXExposeSensor:
"""Handle entity change."""
if new_state is None:
return
await self.device.set(float(new_state.state))
if new_state.state == "unknown":
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)
else:
await self.device.set(new_state.state)

View File

@ -3,14 +3,16 @@ import voluptuous as vol
from homeassistant.components.binary_sensor import (
PLATFORM_SCHEMA, BinarySensorDevice)
from homeassistant.const import CONF_ADDRESS, CONF_DEVICE_CLASS, CONF_NAME
from homeassistant.const import CONF_DEVICE_CLASS, CONF_NAME
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from . import ATTR_DISCOVER_DEVICES, DATA_KNX, KNXAutomation
CONF_STATE_ADDRESS = 'state_address'
CONF_SIGNIFICANT_BIT = 'significant_bit'
CONF_DEFAULT_SIGNIFICANT_BIT = 1
CONF_SYNC_STATE = 'sync_state'
CONF_AUTOMATION = 'automation'
CONF_HOOK = 'hook'
CONF_DEFAULT_HOOK = 'on'
@ -31,11 +33,12 @@ AUTOMATION_SCHEMA = vol.Schema({
AUTOMATIONS_SCHEMA = vol.All(cv.ensure_list, [AUTOMATION_SCHEMA])
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_ADDRESS): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_DEVICE_CLASS): cv.string,
vol.Optional(CONF_SIGNIFICANT_BIT, default=CONF_DEFAULT_SIGNIFICANT_BIT):
cv.positive_int,
vol.Optional(CONF_SYNC_STATE, default=True): cv.boolean,
vol.Required(CONF_STATE_ADDRESS): cv.string,
vol.Optional(CONF_DEVICE_CLASS): cv.string,
vol.Optional(CONF_RESET_AFTER): cv.positive_int,
vol.Optional(CONF_AUTOMATION): AUTOMATIONS_SCHEMA,
})
@ -63,14 +66,15 @@ def async_add_entities_discovery(hass, discovery_info, async_add_entities):
@callback
def async_add_entities_config(hass, config, async_add_entities):
"""Set up binary senor for KNX platform configured within platform."""
name = config.get(CONF_NAME)
name = config[CONF_NAME]
import xknx
binary_sensor = xknx.devices.BinarySensor(
hass.data[DATA_KNX].xknx,
name=name,
group_address=config.get(CONF_ADDRESS),
group_address_state=config[CONF_STATE_ADDRESS],
sync_state=config[CONF_SYNC_STATE],
device_class=config.get(CONF_DEVICE_CLASS),
significant_bit=config.get(CONF_SIGNIFICANT_BIT),
significant_bit=config[CONF_SIGNIFICANT_BIT],
reset_after=config.get(CONF_RESET_AFTER))
hass.data[DATA_KNX].xknx.devices.add(binary_sensor)
@ -78,9 +82,9 @@ def async_add_entities_config(hass, config, async_add_entities):
automations = config.get(CONF_AUTOMATION)
if automations is not None:
for automation in automations:
counter = automation.get(CONF_COUNTER)
hook = automation.get(CONF_HOOK)
action = automation.get(CONF_ACTION)
counter = automation[CONF_COUNTER]
hook = automation[CONF_HOOK]
action = automation[CONF_ACTION]
entity.automations.append(KNXAutomation(
hass=hass, device=binary_sensor, hook=hook,
action=action, counter=counter))

View File

@ -69,11 +69,6 @@ PRESET_MODES_INV = dict((
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Required(CONF_TEMPERATURE_ADDRESS): cv.string,
vol.Required(CONF_TARGET_TEMPERATURE_STATE_ADDRESS): cv.string,
vol.Optional(CONF_TARGET_TEMPERATURE_ADDRESS): cv.string,
vol.Optional(CONF_SETPOINT_SHIFT_ADDRESS): cv.string,
vol.Optional(CONF_SETPOINT_SHIFT_STATE_ADDRESS): cv.string,
vol.Optional(CONF_SETPOINT_SHIFT_STEP,
default=DEFAULT_SETPOINT_SHIFT_STEP): vol.All(
float, vol.Range(min=0, max=2)),
@ -81,6 +76,11 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.All(int, vol.Range(min=0, max=32)),
vol.Optional(CONF_SETPOINT_SHIFT_MIN, default=DEFAULT_SETPOINT_SHIFT_MIN):
vol.All(int, vol.Range(min=-32, max=0)),
vol.Required(CONF_TEMPERATURE_ADDRESS): cv.string,
vol.Required(CONF_TARGET_TEMPERATURE_STATE_ADDRESS): cv.string,
vol.Optional(CONF_TARGET_TEMPERATURE_ADDRESS): cv.string,
vol.Optional(CONF_SETPOINT_SHIFT_ADDRESS): cv.string,
vol.Optional(CONF_SETPOINT_SHIFT_STATE_ADDRESS): cv.string,
vol.Optional(CONF_OPERATION_MODE_ADDRESS): cv.string,
vol.Optional(CONF_OPERATION_MODE_STATE_ADDRESS): cv.string,
vol.Optional(CONF_CONTROLLER_STATUS_ADDRESS): cv.string,
@ -125,7 +125,7 @@ def async_add_entities_config(hass, config, async_add_entities):
climate_mode = xknx.devices.ClimateMode(
hass.data[DATA_KNX].xknx,
name=config.get(CONF_NAME) + " Mode",
name=config[CONF_NAME] + " Mode",
group_address_operation_mode=config.get(CONF_OPERATION_MODE_ADDRESS),
group_address_operation_mode_state=config.get(
CONF_OPERATION_MODE_STATE_ADDRESS),
@ -149,7 +149,7 @@ def async_add_entities_config(hass, config, async_add_entities):
climate = xknx.devices.Climate(
hass.data[DATA_KNX].xknx,
name=config.get(CONF_NAME),
name=config[CONF_NAME],
group_address_temperature=config[CONF_TEMPERATURE_ADDRESS],
group_address_target_temperature=config.get(
CONF_TARGET_TEMPERATURE_ADDRESS),
@ -158,9 +158,9 @@ def async_add_entities_config(hass, config, async_add_entities):
group_address_setpoint_shift=config.get(CONF_SETPOINT_SHIFT_ADDRESS),
group_address_setpoint_shift_state=config.get(
CONF_SETPOINT_SHIFT_STATE_ADDRESS),
setpoint_shift_step=config.get(CONF_SETPOINT_SHIFT_STEP),
setpoint_shift_max=config.get(CONF_SETPOINT_SHIFT_MAX),
setpoint_shift_min=config.get(CONF_SETPOINT_SHIFT_MIN),
setpoint_shift_step=config[CONF_SETPOINT_SHIFT_STEP],
setpoint_shift_max=config[CONF_SETPOINT_SHIFT_MAX],
setpoint_shift_min=config[CONF_SETPOINT_SHIFT_MIN],
group_address_on_off=config.get(CONF_ON_OFF_ADDRESS),
group_address_on_off_state=config.get(CONF_ON_OFF_STATE_ADDRESS),
min_temp=config.get(CONF_MIN_TEMP),

View File

@ -67,7 +67,7 @@ def async_add_entities_config(hass, config, async_add_entities):
import xknx
cover = xknx.devices.Cover(
hass.data[DATA_KNX].xknx,
name=config.get(CONF_NAME),
name=config[CONF_NAME],
group_address_long=config.get(CONF_MOVE_LONG_ADDRESS),
group_address_short=config.get(CONF_MOVE_SHORT_ADDRESS),
group_address_position_state=config.get(
@ -75,10 +75,10 @@ def async_add_entities_config(hass, config, async_add_entities):
group_address_angle=config.get(CONF_ANGLE_ADDRESS),
group_address_angle_state=config.get(CONF_ANGLE_STATE_ADDRESS),
group_address_position=config.get(CONF_POSITION_ADDRESS),
travel_time_down=config.get(CONF_TRAVELLING_TIME_DOWN),
travel_time_up=config.get(CONF_TRAVELLING_TIME_UP),
invert_position=config.get(CONF_INVERT_POSITION),
invert_angle=config.get(CONF_INVERT_ANGLE))
travel_time_down=config[CONF_TRAVELLING_TIME_DOWN],
travel_time_up=config[CONF_TRAVELLING_TIME_UP],
invert_position=config[CONF_INVERT_POSITION],
invert_angle=config[CONF_INVERT_ANGLE])
hass.data[DATA_KNX].xknx.devices.add(cover)
async_add_entities([KNXCover(cover)])

View File

@ -4,8 +4,9 @@ from enum import Enum
import voluptuous as vol
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_HS_COLOR, PLATFORM_SCHEMA,
SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP, Light)
ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_HS_COLOR, ATTR_WHITE_VALUE,
PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP,
SUPPORT_WHITE_VALUE, Light)
from homeassistant.const import CONF_ADDRESS, CONF_NAME
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
@ -21,13 +22,16 @@ CONF_COLOR_STATE_ADDRESS = 'color_state_address'
CONF_COLOR_TEMP_ADDRESS = 'color_temperature_address'
CONF_COLOR_TEMP_STATE_ADDRESS = 'color_temperature_state_address'
CONF_COLOR_TEMP_MODE = 'color_temperature_mode'
CONF_RGBW_ADDRESS = 'rgbw_address'
CONF_RGBW_STATE_ADDRESS = 'rgbw_state_address'
CONF_MIN_KELVIN = 'min_kelvin'
CONF_MAX_KELVIN = 'max_kelvin'
DEFAULT_NAME = 'KNX Light'
DEFAULT_COLOR = [255, 255, 255]
DEFAULT_COLOR = (0., 0.)
DEFAULT_BRIGHTNESS = 255
DEFAULT_COLOR_TEMP_MODE = 'absolute'
DEFAULT_WHITE_VALUE = 255
DEFAULT_MIN_KELVIN = 2700 # 370 mireds
DEFAULT_MAX_KELVIN = 6000 # 166 mireds
@ -51,6 +55,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_COLOR_TEMP_STATE_ADDRESS): cv.string,
vol.Optional(CONF_COLOR_TEMP_MODE, default=DEFAULT_COLOR_TEMP_MODE):
cv.enum(ColorTempModes),
vol.Optional(CONF_RGBW_ADDRESS): cv.string,
vol.Optional(CONF_RGBW_STATE_ADDRESS): cv.string,
vol.Optional(CONF_MIN_KELVIN, default=DEFAULT_MIN_KELVIN):
vol.All(vol.Coerce(int), vol.Range(min=1)),
vol.Optional(CONF_MAX_KELVIN, default=DEFAULT_MAX_KELVIN):
@ -105,6 +111,8 @@ def async_add_entities_config(hass, config, async_add_entities):
CONF_BRIGHTNESS_STATE_ADDRESS),
group_address_color=config.get(CONF_COLOR_ADDRESS),
group_address_color_state=config.get(CONF_COLOR_STATE_ADDRESS),
group_address_rgbw=config.get(CONF_RGBW_ADDRESS),
group_address_rgbw_state=config.get(CONF_RGBW_STATE_ADDRESS),
group_address_tunable_white=group_address_tunable_white,
group_address_tunable_white_state=group_address_tunable_white_state,
group_address_color_temperature=group_address_color_temp,
@ -159,23 +167,28 @@ class KNXLight(Light):
@property
def brightness(self):
"""Return the brightness of this light between 0..255."""
if self.device.supports_color:
if self.device.current_color is None:
return None
return max(self.device.current_color)
if self.device.supports_brightness:
return self.device.current_brightness
if (self.device.supports_color or self.device.supports_rgbw) and \
self.device.current_color:
return max(self.device.current_color)
return None
@property
def hs_color(self):
"""Return the HS color value."""
if self.device.supports_color:
rgb = self.device.current_color
if rgb is None:
return None
return color_util.color_RGB_to_hs(*rgb)
return None
rgb = None
if self.device.supports_rgbw or self.device.supports_color:
rgb, _ = self.device.current_color
return color_util.color_RGB_to_hs(*rgb) if rgb else None
@property
def white_value(self):
"""Return the white value."""
white = None
if self.device.supports_rgbw:
_, white = self.device.current_color
return white
@property
def color_temp(self):
@ -190,9 +203,8 @@ class KNXLight(Light):
# as KNX devices typically use Kelvin we use it as base for
# calculating ct from percent
return color_util.color_temperature_kelvin_to_mired(
self._min_kelvin + (
(relative_ct / 255) *
(self._max_kelvin - self._min_kelvin)))
self._min_kelvin + ((relative_ct / 255) * (
self._max_kelvin - self._min_kelvin)))
return None
@property
@ -228,6 +240,8 @@ class KNXLight(Light):
flags |= SUPPORT_BRIGHTNESS
if self.device.supports_color:
flags |= SUPPORT_COLOR | SUPPORT_BRIGHTNESS
if self.device.supports_rgbw:
flags |= SUPPORT_COLOR | SUPPORT_WHITE_VALUE
if self.device.supports_color_temperature or \
self.device.supports_tunable_white:
flags |= SUPPORT_COLOR_TEMP
@ -237,10 +251,12 @@ class KNXLight(Light):
"""Turn the light on."""
brightness = kwargs.get(ATTR_BRIGHTNESS, self.brightness)
hs_color = kwargs.get(ATTR_HS_COLOR, self.hs_color)
white_value = kwargs.get(ATTR_WHITE_VALUE, self.white_value)
mireds = kwargs.get(ATTR_COLOR_TEMP, self.color_temp)
update_brightness = ATTR_BRIGHTNESS in kwargs
update_color = ATTR_HS_COLOR in kwargs
update_white_value = ATTR_WHITE_VALUE in kwargs
update_color_temp = ATTR_COLOR_TEMP in kwargs
# always only go one path for turning on (avoid conflicting changes
@ -251,17 +267,20 @@ class KNXLight(Light):
# directly if supported; don't do it if color also has to be
# changed, as RGB color implicitly sets the brightness as well
await self.device.set_brightness(brightness)
elif self.device.supports_color and \
(update_brightness or update_color):
# change RGB color (includes brightness)
elif (self.device.supports_rgbw or self.device.supports_color) and \
(update_brightness or update_color or update_white_value):
# change RGB color, white value )if supported), and brightness
# if brightness or hs_color was not yet set use the default value
# to calculate RGB from as a fallback
if brightness is None:
brightness = DEFAULT_BRIGHTNESS
if hs_color is None:
hs_color = DEFAULT_COLOR
await self.device.set_color(
color_util.color_hsv_to_RGB(*hs_color, brightness * 100 / 255))
if white_value is None and self.device.supports_rgbw:
white_value = DEFAULT_WHITE_VALUE
rgb = color_util.color_hsv_to_RGB(*hs_color,
brightness * 100 / 255)
await self.device.set_color(rgb, white_value)
elif self.device.supports_color_temperature and \
update_color_temp:
# change color temperature without ON telegram
@ -275,8 +294,8 @@ class KNXLight(Light):
update_color_temp:
# calculate relative_ct from Kelvin to fit typical KNX devices
kelvin = int(color_util.color_temperature_mired_to_kelvin(mireds))
relative_ct = int(255 * (kelvin - self._min_kelvin) /
(self._max_kelvin - self._min_kelvin))
relative_ct = int(255 * (kelvin - self._min_kelvin) / (
self._max_kelvin - self._min_kelvin))
await self.device.set_tunable_white(relative_ct)
else:
# no color/brightness change requested, so just turn it on

View File

@ -3,10 +3,10 @@
"name": "Knx",
"documentation": "https://www.home-assistant.io/components/knx",
"requirements": [
"xknx==0.10.0"
"xknx==0.11.1"
],
"dependencies": [],
"codeowners": [
"@Julius2342"
]
}
}

View File

@ -43,8 +43,8 @@ def async_get_service_config(hass, config):
import xknx
notification = xknx.devices.Notification(
hass.data[DATA_KNX].xknx,
name=config.get(CONF_NAME),
group_address=config.get(CONF_ADDRESS))
name=config[CONF_NAME],
group_address=config[CONF_ADDRESS])
hass.data[DATA_KNX].xknx.devices.add(notification)
return KNXNotificationService([notification, ])

View File

@ -44,9 +44,9 @@ def async_add_entities_config(hass, config, async_add_entities):
import xknx
scene = xknx.devices.Scene(
hass.data[DATA_KNX].xknx,
name=config.get(CONF_NAME),
group_address=config.get(CONF_ADDRESS),
scene_number=config.get(CONF_SCENE_NUMBER))
name=config[CONF_NAME],
group_address=config[CONF_ADDRESS],
scene_number=config[CONF_SCENE_NUMBER])
hass.data[DATA_KNX].xknx.devices.add(scene)
async_add_entities([KNXScene(scene)])

View File

@ -2,18 +2,22 @@
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import CONF_ADDRESS, CONF_NAME, CONF_TYPE
from homeassistant.const import CONF_NAME, CONF_TYPE
from homeassistant.core import callback
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from . import ATTR_DISCOVER_DEVICES, DATA_KNX
CONF_STATE_ADDRESS = 'state_address'
CONF_SYNC_STATE = 'sync_state'
DEFAULT_NAME = 'KNX Sensor'
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_ADDRESS): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_TYPE): cv.string,
vol.Optional(CONF_SYNC_STATE, default=True): cv.boolean,
vol.Required(CONF_STATE_ADDRESS): cv.string,
vol.Required(CONF_TYPE): cv.string,
})
@ -42,9 +46,10 @@ def async_add_entities_config(hass, config, async_add_entities):
import xknx
sensor = xknx.devices.Sensor(
hass.data[DATA_KNX].xknx,
name=config.get(CONF_NAME),
group_address=config.get(CONF_ADDRESS),
value_type=config.get(CONF_TYPE))
name=config[CONF_NAME],
group_address_state=config[CONF_STATE_ADDRESS],
sync_state=config[CONF_SYNC_STATE],
value_type=config[CONF_TYPE])
hass.data[DATA_KNX].xknx.devices.add(sensor)
async_add_entities([KNXSensor(sensor)])
@ -93,6 +98,11 @@ class KNXSensor(Entity):
"""Return the unit this state is expressed in."""
return self.device.unit_of_measurement()
@property
def device_class(self):
"""Return the device class of the sensor."""
return self.device.ha_device_class()
@property
def device_state_attributes(self):
"""Return the state attributes."""

View File

@ -43,8 +43,8 @@ def async_add_entities_config(hass, config, async_add_entities):
import xknx
switch = xknx.devices.Switch(
hass.data[DATA_KNX].xknx,
name=config.get(CONF_NAME),
group_address=config.get(CONF_ADDRESS),
name=config[CONF_NAME],
group_address=config[CONF_ADDRESS],
group_address_state=config.get(CONF_STATE_ADDRESS))
hass.data[DATA_KNX].xknx.devices.add(switch)
async_add_entities([KNXSwitch(switch)])

View File

@ -1905,7 +1905,7 @@ xboxapi==0.1.1
xfinity-gateway==0.0.4
# homeassistant.components.knx
xknx==0.10.0
xknx==0.11.1
# homeassistant.components.bluesound
# homeassistant.components.startca