From e299d7b3d6fbfc4e1f643ec4806b90df2c56c198 Mon Sep 17 00:00:00 2001 From: Matthias Alphart Date: Thu, 11 Jul 2019 22:01:37 +0200 Subject: [PATCH] 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` --- homeassistant/components/knx/__init__.py | 15 ++++- homeassistant/components/knx/binary_sensor.py | 22 ++++--- homeassistant/components/knx/climate.py | 20 +++--- homeassistant/components/knx/cover.py | 10 +-- homeassistant/components/knx/light.py | 65 ++++++++++++------- homeassistant/components/knx/manifest.json | 4 +- homeassistant/components/knx/notify.py | 4 +- homeassistant/components/knx/scene.py | 6 +- homeassistant/components/knx/sensor.py | 22 +++++-- homeassistant/components/knx/switch.py | 4 +- requirements_all.txt | 2 +- 11 files changed, 108 insertions(+), 66 deletions(-) diff --git a/homeassistant/components/knx/__init__.py b/homeassistant/components/knx/__init__.py index 04b51730be1..6ffe3115a0d 100644 --- a/homeassistant/components/knx/__init__.py +++ b/homeassistant/components/knx/__init__.py @@ -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) diff --git a/homeassistant/components/knx/binary_sensor.py b/homeassistant/components/knx/binary_sensor.py index 65d10722500..51dace9ff16 100644 --- a/homeassistant/components/knx/binary_sensor.py +++ b/homeassistant/components/knx/binary_sensor.py @@ -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)) diff --git a/homeassistant/components/knx/climate.py b/homeassistant/components/knx/climate.py index 4b5998016e1..649be4cbc5b 100644 --- a/homeassistant/components/knx/climate.py +++ b/homeassistant/components/knx/climate.py @@ -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), diff --git a/homeassistant/components/knx/cover.py b/homeassistant/components/knx/cover.py index bbee54e00cd..b1419fd1886 100644 --- a/homeassistant/components/knx/cover.py +++ b/homeassistant/components/knx/cover.py @@ -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)]) diff --git a/homeassistant/components/knx/light.py b/homeassistant/components/knx/light.py index b94d91514af..fd39e518f65 100644 --- a/homeassistant/components/knx/light.py +++ b/homeassistant/components/knx/light.py @@ -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 diff --git a/homeassistant/components/knx/manifest.json b/homeassistant/components/knx/manifest.json index 1b1f16ccb03..3b2d1414034 100644 --- a/homeassistant/components/knx/manifest.json +++ b/homeassistant/components/knx/manifest.json @@ -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" ] -} +} \ No newline at end of file diff --git a/homeassistant/components/knx/notify.py b/homeassistant/components/knx/notify.py index 486908c3cff..6287132cbdc 100644 --- a/homeassistant/components/knx/notify.py +++ b/homeassistant/components/knx/notify.py @@ -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, ]) diff --git a/homeassistant/components/knx/scene.py b/homeassistant/components/knx/scene.py index 4f0c7b2d4fc..42b9a2189c6 100644 --- a/homeassistant/components/knx/scene.py +++ b/homeassistant/components/knx/scene.py @@ -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)]) diff --git a/homeassistant/components/knx/sensor.py b/homeassistant/components/knx/sensor.py index bb3128eaee7..ea66a785e3e 100644 --- a/homeassistant/components/knx/sensor.py +++ b/homeassistant/components/knx/sensor.py @@ -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.""" diff --git a/homeassistant/components/knx/switch.py b/homeassistant/components/knx/switch.py index 461b27e94c0..3e5b73a727d 100644 --- a/homeassistant/components/knx/switch.py +++ b/homeassistant/components/knx/switch.py @@ -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)]) diff --git a/requirements_all.txt b/requirements_all.txt index c9a4e829ec6..9449322798e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -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