diff --git a/homeassistant/components/climate/knx.py b/homeassistant/components/climate/knx.py index b52bd4b418defe1a70214c2290dbd817e116107e..77d995af2a19f8d1233ba59618ab60d53295ae8f 100644 --- a/homeassistant/components/climate/knx.py +++ b/homeassistant/components/climate/knx.py @@ -6,14 +6,17 @@ https://home-assistant.io/components/climate.knx/ """ import voluptuous as vol - +import homeassistant.helpers.config_validation as cv from homeassistant.components.climate import ( - PLATFORM_SCHEMA, SUPPORT_OPERATION_MODE, SUPPORT_TARGET_TEMPERATURE, - ClimateDevice) -from homeassistant.components.knx import ATTR_DISCOVER_DEVICES, DATA_KNX -from homeassistant.const import ATTR_TEMPERATURE, CONF_NAME, TEMP_CELSIUS + PLATFORM_SCHEMA, SUPPORT_ON_OFF, SUPPORT_OPERATION_MODE, + SUPPORT_TARGET_TEMPERATURE, STATE_HEAT, + STATE_IDLE, STATE_MANUAL, STATE_DRY, + STATE_FAN_ONLY, STATE_ECO, ClimateDevice) +from homeassistant.const import ( + ATTR_TEMPERATURE, CONF_NAME, TEMP_CELSIUS) from homeassistant.core import callback -import homeassistant.helpers.config_validation as cv + +from homeassistant.components.knx import DATA_KNX, ATTR_DISCOVER_DEVICES CONF_SETPOINT_SHIFT_ADDRESS = 'setpoint_shift_address' CONF_SETPOINT_SHIFT_STATE_ADDRESS = 'setpoint_shift_state_address' @@ -26,10 +29,17 @@ CONF_OPERATION_MODE_ADDRESS = 'operation_mode_address' CONF_OPERATION_MODE_STATE_ADDRESS = 'operation_mode_state_address' CONF_CONTROLLER_STATUS_ADDRESS = 'controller_status_address' CONF_CONTROLLER_STATUS_STATE_ADDRESS = 'controller_status_state_address' +CONF_CONTROLLER_MODE_ADDRESS = 'controller_mode_address' +CONF_CONTROLLER_MODE_STATE_ADDRESS = 'controller_mode_state_address' CONF_OPERATION_MODE_FROST_PROTECTION_ADDRESS = \ 'operation_mode_frost_protection_address' CONF_OPERATION_MODE_NIGHT_ADDRESS = 'operation_mode_night_address' CONF_OPERATION_MODE_COMFORT_ADDRESS = 'operation_mode_comfort_address' +CONF_OPERATION_MODES = 'operation_modes' +CONF_ON_OFF_ADDRESS = 'on_off_address' +CONF_ON_OFF_STATE_ADDRESS = 'on_off_state_address' +CONF_MIN_TEMP = 'min_temp' +CONF_MAX_TEMP = 'max_temp' DEFAULT_NAME = 'KNX Climate' DEFAULT_SETPOINT_SHIFT_STEP = 0.5 @@ -37,6 +47,21 @@ DEFAULT_SETPOINT_SHIFT_MAX = 6 DEFAULT_SETPOINT_SHIFT_MIN = -6 DEPENDENCIES = ['knx'] +# Map KNX operation modes to HA modes. This list might not be full. +OPERATION_MODES = { + # Map DPT 201.100 HVAC operating modes + "Frost Protection": STATE_MANUAL, + "Night": STATE_IDLE, + "Standby": STATE_ECO, + "Comfort": STATE_HEAT, + # Map DPT 201.104 HVAC control modes + "Fan only": STATE_FAN_ONLY, + "Dehumidification": STATE_DRY +} + +OPERATION_MODES_INV = dict(( + reversed(item) for item in OPERATION_MODES.items())) + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, vol.Required(CONF_TEMPERATURE_ADDRESS): cv.string, @@ -54,9 +79,17 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Optional(CONF_OPERATION_MODE_STATE_ADDRESS): cv.string, vol.Optional(CONF_CONTROLLER_STATUS_ADDRESS): cv.string, vol.Optional(CONF_CONTROLLER_STATUS_STATE_ADDRESS): cv.string, + vol.Optional(CONF_CONTROLLER_MODE_ADDRESS): cv.string, + vol.Optional(CONF_CONTROLLER_MODE_STATE_ADDRESS): cv.string, vol.Optional(CONF_OPERATION_MODE_FROST_PROTECTION_ADDRESS): cv.string, vol.Optional(CONF_OPERATION_MODE_NIGHT_ADDRESS): cv.string, vol.Optional(CONF_OPERATION_MODE_COMFORT_ADDRESS): cv.string, + vol.Optional(CONF_ON_OFF_ADDRESS): cv.string, + vol.Optional(CONF_ON_OFF_STATE_ADDRESS): cv.string, + vol.Optional(CONF_OPERATION_MODES): vol.All(cv.ensure_list, + [vol.In(OPERATION_MODES)]), + vol.Optional(CONF_MIN_TEMP): vol.Coerce(float), + vol.Optional(CONF_MAX_TEMP): vol.Coerce(float), }) @@ -84,18 +117,9 @@ def async_add_entities_config(hass, config, async_add_entities): """Set up climate for KNX platform configured within platform.""" import xknx - climate = xknx.devices.Climate( + climate_mode = xknx.devices.ClimateMode( hass.data[DATA_KNX].xknx, - name=config.get(CONF_NAME), - group_address_temperature=config.get(CONF_TEMPERATURE_ADDRESS), - group_address_target_temperature=config.get( - CONF_TARGET_TEMPERATURE_ADDRESS), - 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), + name=config.get(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), @@ -103,13 +127,41 @@ def async_add_entities_config(hass, config, async_add_entities): CONF_CONTROLLER_STATUS_ADDRESS), group_address_controller_status_state=config.get( CONF_CONTROLLER_STATUS_STATE_ADDRESS), + group_address_controller_mode=config.get( + CONF_CONTROLLER_MODE_ADDRESS), + group_address_controller_mode_state=config.get( + CONF_CONTROLLER_MODE_STATE_ADDRESS), group_address_operation_mode_protection=config.get( CONF_OPERATION_MODE_FROST_PROTECTION_ADDRESS), group_address_operation_mode_night=config.get( CONF_OPERATION_MODE_NIGHT_ADDRESS), group_address_operation_mode_comfort=config.get( - CONF_OPERATION_MODE_COMFORT_ADDRESS)) + CONF_OPERATION_MODE_COMFORT_ADDRESS), + operation_modes=config.get( + CONF_OPERATION_MODES)) + hass.data[DATA_KNX].xknx.devices.add(climate_mode) + + climate = xknx.devices.Climate( + hass.data[DATA_KNX].xknx, + name=config.get(CONF_NAME), + group_address_temperature=config.get(CONF_TEMPERATURE_ADDRESS), + group_address_target_temperature=config.get( + CONF_TARGET_TEMPERATURE_ADDRESS), + 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), + 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), + max_temp=config.get(CONF_MAX_TEMP), + mode=climate_mode) hass.data[DATA_KNX].xknx.devices.add(climate) + async_add_entities([KNXClimate(climate)]) @@ -119,26 +171,25 @@ class KNXClimate(ClimateDevice): def __init__(self, device): """Initialize of a KNX climate device.""" self.device = device + self._unit_of_measurement = TEMP_CELSIUS @property def supported_features(self): """Return the list of supported features.""" support = SUPPORT_TARGET_TEMPERATURE - if self.device.supports_operation_mode: + if self.device.mode.supports_operation_mode: support |= SUPPORT_OPERATION_MODE + if self.device.supports_on_off: + support |= SUPPORT_ON_OFF return support - def async_register_callbacks(self): + async def async_added_to_hass(self): """Register callbacks to update hass after device was changed.""" async def after_update_callback(device): """Call after device was updated.""" await self.async_update_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() - @property def name(self): """Return the name of the KNX device.""" @@ -157,7 +208,7 @@ class KNXClimate(ClimateDevice): @property def temperature_unit(self): """Return the unit of measurement.""" - return TEMP_CELSIUS + return self._unit_of_measurement @property def current_temperature(self): @@ -195,20 +246,37 @@ class KNXClimate(ClimateDevice): @property def current_operation(self): """Return current operation ie. heat, cool, idle.""" - if self.device.supports_operation_mode: - return self.device.operation_mode.value + if self.device.mode.supports_operation_mode: + return OPERATION_MODES.get(self.device.mode.operation_mode.value) return None @property def operation_list(self): """Return the list of available operation modes.""" - return [operation_mode.value for + return [OPERATION_MODES.get(operation_mode.value) for operation_mode in - self.device.get_supported_operation_modes()] + self.device.mode.operation_modes] async def async_set_operation_mode(self, operation_mode): """Set operation mode.""" - if self.device.supports_operation_mode: + if self.device.mode.supports_operation_mode: from xknx.knx import HVACOperationMode - knx_operation_mode = HVACOperationMode(operation_mode) - await self.device.set_operation_mode(knx_operation_mode) + knx_operation_mode = HVACOperationMode( + OPERATION_MODES_INV.get(operation_mode)) + await self.device.mode.set_operation_mode(knx_operation_mode) + await self.async_update_ha_state() + + @property + def is_on(self): + """Return true if the device is on.""" + if self.device.supports_on_off: + return self.device.is_on + return None + + async def async_turn_on(self): + """Turn on.""" + await self.device.turn_on() + + async def async_turn_off(self): + """Turn off.""" + await self.device.turn_off() diff --git a/homeassistant/components/knx.py b/homeassistant/components/knx.py index abedc9862c2a5dc16dfce92c5e34f19a0f8d902f..366ec4405cd76774b06fe2b3c7a786b62c5aeb84 100644 --- a/homeassistant/components/knx.py +++ b/homeassistant/components/knx.py @@ -17,7 +17,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.event import async_track_state_change from homeassistant.helpers.script import Script -REQUIREMENTS = ['xknx==0.9.1'] +REQUIREMENTS = ['xknx==0.9.3'] DOMAIN = "knx" DATA_KNX = "data_knx" diff --git a/requirements_all.txt b/requirements_all.txt index 807d48f2f21b603ab385212eff9f821b887bbe62..66fa6fd3c09d2ee027710407210035a551ec0cd6 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1689,7 +1689,7 @@ xbee-helper==0.0.7 xboxapi==0.1.1 # homeassistant.components.knx -xknx==0.9.1 +xknx==0.9.3 # homeassistant.components.media_player.bluesound # homeassistant.components.sensor.startca