From 6cc285aea5ca8e321815d12e4bf378c4091608b1 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 11 Jan 2018 00:04:35 +0200 Subject: [PATCH] Add sensibo_assume_state service to Sensibo climate (#11567) --- homeassistant/components/climate/sensibo.py | 74 ++++++++++++++++--- .../components/climate/services.yaml | 10 +++ requirements_all.txt | 2 +- 3 files changed, 76 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/climate/sensibo.py b/homeassistant/components/climate/sensibo.py index 32a5a998d87..c38f62bc60e 100644 --- a/homeassistant/components/climate/sensibo.py +++ b/homeassistant/components/climate/sensibo.py @@ -13,9 +13,10 @@ import async_timeout import voluptuous as vol from homeassistant.const import ( - ATTR_TEMPERATURE, CONF_API_KEY, CONF_ID, TEMP_CELSIUS, TEMP_FAHRENHEIT) + ATTR_ENTITY_ID, ATTR_STATE, ATTR_TEMPERATURE, CONF_API_KEY, CONF_ID, + STATE_ON, STATE_OFF, TEMP_CELSIUS, TEMP_FAHRENHEIT) from homeassistant.components.climate import ( - ATTR_CURRENT_HUMIDITY, ClimateDevice, PLATFORM_SCHEMA, + ATTR_CURRENT_HUMIDITY, ClimateDevice, DOMAIN, PLATFORM_SCHEMA, SUPPORT_TARGET_TEMPERATURE, SUPPORT_OPERATION_MODE, SUPPORT_FAN_MODE, SUPPORT_SWING_MODE, SUPPORT_AUX_HEAT, SUPPORT_ON_OFF) @@ -24,18 +25,25 @@ from homeassistant.helpers import config_validation as cv from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.util.temperature import convert as convert_temperature -REQUIREMENTS = ['pysensibo==1.0.1'] +REQUIREMENTS = ['pysensibo==1.0.2'] _LOGGER = logging.getLogger(__name__) ALL = 'all' TIMEOUT = 10 +SERVICE_ASSUME_STATE = 'sensibo_assume_state' + PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_API_KEY): cv.string, vol.Optional(CONF_ID, default=ALL): vol.All(cv.ensure_list, [cv.string]), }) +ASSUME_STATE_SCHEMA = vol.Schema({ + vol.Optional(ATTR_ENTITY_ID): cv.entity_ids, + vol.Required(ATTR_STATE): cv.string, +}) + _FETCH_FIELDS = ','.join([ 'room{name}', 'measurements', 'remoteCapabilities', 'acState', 'connectionStatus{isAlive}', 'temperatureUnit']) @@ -72,6 +80,28 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None): if devices: async_add_devices(devices) + @asyncio.coroutine + def async_assume_state(service): + """Set state according to external service call..""" + entity_ids = service.data.get(ATTR_ENTITY_ID) + if entity_ids: + target_climate = [device for device in devices + if device.entity_id in entity_ids] + else: + target_climate = devices + + update_tasks = [] + for climate in target_climate: + yield from climate.async_assume_state( + service.data.get(ATTR_STATE)) + update_tasks.append(climate.async_update_ha_state(True)) + + if update_tasks: + yield from asyncio.wait(update_tasks, loop=hass.loop) + hass.services.async_register( + DOMAIN, SERVICE_ASSUME_STATE, async_assume_state, + schema=ASSUME_STATE_SCHEMA) + class SensiboClimate(ClimateDevice): """Representation of a Sensibo device.""" @@ -84,6 +114,7 @@ class SensiboClimate(ClimateDevice): """ self._client = client self._id = data['id'] + self._external_state = None self._do_update(data) @property @@ -115,6 +146,11 @@ class SensiboClimate(ClimateDevice): if key in FIELD_TO_FLAG: self._supported_features |= FIELD_TO_FLAG[key] + @property + def state(self): + """Return the current state.""" + return self._external_state or super().state + @property def device_state_attributes(self): """Return the state attributes.""" @@ -236,46 +272,66 @@ class SensiboClimate(ClimateDevice): with async_timeout.timeout(TIMEOUT): yield from self._client.async_set_ac_state_property( - self._id, 'targetTemperature', temperature) + self._id, 'targetTemperature', temperature, self._ac_states) @asyncio.coroutine def async_set_fan_mode(self, fan): """Set new target fan mode.""" with async_timeout.timeout(TIMEOUT): yield from self._client.async_set_ac_state_property( - self._id, 'fanLevel', fan) + self._id, 'fanLevel', fan, self._ac_states) @asyncio.coroutine def async_set_operation_mode(self, operation_mode): """Set new target operation mode.""" with async_timeout.timeout(TIMEOUT): yield from self._client.async_set_ac_state_property( - self._id, 'mode', operation_mode) + self._id, 'mode', operation_mode, self._ac_states) @asyncio.coroutine def async_set_swing_mode(self, swing_mode): """Set new target swing operation.""" with async_timeout.timeout(TIMEOUT): yield from self._client.async_set_ac_state_property( - self._id, 'swing', swing_mode) + self._id, 'swing', swing_mode, self._ac_states) @asyncio.coroutine def async_turn_aux_heat_on(self): """Turn Sensibo unit on.""" with async_timeout.timeout(TIMEOUT): yield from self._client.async_set_ac_state_property( - self._id, 'on', True) + self._id, 'on', True, self._ac_states) @asyncio.coroutine def async_turn_aux_heat_off(self): """Turn Sensibo unit on.""" with async_timeout.timeout(TIMEOUT): yield from self._client.async_set_ac_state_property( - self._id, 'on', False) + self._id, 'on', False, self._ac_states) async_on = async_turn_aux_heat_on async_off = async_turn_aux_heat_off + @asyncio.coroutine + def async_assume_state(self, state): + """Set external state.""" + change_needed = (state != STATE_OFF and not self.is_on) \ + or (state == STATE_OFF and self.is_on) + if change_needed: + with async_timeout.timeout(TIMEOUT): + yield from self._client.async_set_ac_state_property( + self._id, + 'on', + state != STATE_OFF, # value + self._ac_states, + True # assumed_state + ) + + if state in [STATE_ON, STATE_OFF]: + self._external_state = None + else: + self._external_state = state + @asyncio.coroutine def async_update(self): """Retrieve latest state.""" diff --git a/homeassistant/components/climate/services.yaml b/homeassistant/components/climate/services.yaml index cb3db926b85..fbb21962c6e 100644 --- a/homeassistant/components/climate/services.yaml +++ b/homeassistant/components/climate/services.yaml @@ -142,3 +142,13 @@ econet_delete_vacation: entity_id: description: Name(s) of entities to change. example: 'climate.water_heater' + +sensibo_assume_state: + description: Set Sensibo device to external state. + fields: + entity_id: + description: Name(s) of entities to change. + example: 'climate.kitchen' + state: + description: State to set. + example: 'idle' diff --git a/requirements_all.txt b/requirements_all.txt index bc90f75b02b..9884c56454e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -825,7 +825,7 @@ pyqwikswitch==0.4 pyrainbird==0.1.3 # homeassistant.components.climate.sensibo -pysensibo==1.0.1 +pysensibo==1.0.2 # homeassistant.components.sensor.serial pyserial-asyncio==0.4