diff --git a/homeassistant/components/climate/wink.py b/homeassistant/components/climate/wink.py index d8e6843bec84e39ca3cd87177799dece3b7064f4..3013a155380a8d5943db1e98bddb242cf348a6e4 100644 --- a/homeassistant/components/climate/wink.py +++ b/homeassistant/components/climate/wink.py @@ -118,7 +118,7 @@ class WinkThermostat(WinkDevice, ClimateDevice): self.hass, self.target_temperature_low, self.temperature_unit, PRECISION_TENTHS) - if self.external_temperature: + if self.external_temperature is not None: data[ATTR_EXTERNAL_TEMPERATURE] = show_temp( self.hass, self.external_temperature, self.temperature_unit, PRECISION_TENTHS) @@ -126,16 +126,16 @@ class WinkThermostat(WinkDevice, ClimateDevice): if self.smart_temperature: data[ATTR_SMART_TEMPERATURE] = self.smart_temperature - if self.occupied: + if self.occupied is not None: data[ATTR_OCCUPIED] = self.occupied - if self.eco_target: + if self.eco_target is not None: data[ATTR_ECO_TARGET] = self.eco_target - if self.heat_on: + if self.heat_on is not None: data[ATTR_HEAT_ON] = self.heat_on - if self.cool_on: + if self.cool_on is not None: data[ATTR_COOL_ON] = self.cool_on current_humidity = self.current_humidity diff --git a/homeassistant/components/wink/__init__.py b/homeassistant/components/wink/__init__.py index c996572bf510e586fccbaa4b8228b28a0d2cafbe..0399b25b278ea340bbac42b16c98c8f628c3dc9d 100644 --- a/homeassistant/components/wink/__init__.py +++ b/homeassistant/components/wink/__init__.py @@ -26,7 +26,7 @@ from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.event import track_time_interval from homeassistant.util.json import load_json, save_json -REQUIREMENTS = ['python-wink==1.9.1', 'pubnubsub-handler==1.0.2'] +REQUIREMENTS = ['python-wink==1.10.1', 'pubnubsub-handler==1.0.2'] _LOGGER = logging.getLogger(__name__) @@ -73,11 +73,25 @@ SERVICE_SET_AUTO_SHUTOFF = "siren_set_auto_shutoff" SERVICE_SIREN_STROBE_ENABLED = "set_siren_strobe_enabled" SERVICE_CHIME_STROBE_ENABLED = "set_chime_strobe_enabled" SERVICE_ENABLE_SIREN = "enable_siren" +SERVICE_SET_DIAL_CONFIG = "set_nimbus_dial_configuration" +SERVICE_SET_DIAL_STATE = "set_nimbus_dial_state" ATTR_VOLUME = "volume" ATTR_TONE = "tone" ATTR_ENABLED = "enabled" ATTR_AUTO_SHUTOFF = "auto_shutoff" +ATTR_MIN_VALUE = "min_value" +ATTR_MAX_VALUE = "max_value" +ATTR_ROTATION = "rotation" +ATTR_SCALE = "scale" +ATTR_TICKS = "ticks" +ATTR_MIN_POSITION = "min_position" +ATTR_MAX_POSITION = "max_position" +ATTR_VALUE = "value" +ATTR_LABELS = "labels" + +SCALES = ["linear", "log"] +ROTATIONS = ["cw", "ccw"] VOLUMES = ["low", "medium", "high"] TONES = ["doorbell", "fur_elise", "doorbell_extended", "alert", @@ -145,6 +159,23 @@ ENABLED_SIREN_SCHEMA = vol.Schema({ vol.Required(ATTR_ENABLED): cv.boolean }) +DIAL_CONFIG_SCHEMA = vol.Schema({ + vol.Required(ATTR_ENTITY_ID): cv.entity_ids, + vol.Optional(ATTR_MIN_VALUE): vol.Coerce(int), + vol.Optional(ATTR_MAX_VALUE): vol.Coerce(int), + vol.Optional(ATTR_MIN_POSITION): cv.positive_int, + vol.Optional(ATTR_MAX_POSITION): cv.positive_int, + vol.Optional(ATTR_ROTATION): vol.In(ROTATIONS), + vol.Optional(ATTR_SCALE): vol.In(SCALES), + vol.Optional(ATTR_TICKS): cv.positive_int +}) + +DIAL_STATE_SCHEMA = vol.Schema({ + vol.Required(ATTR_ENTITY_ID): cv.entity_ids, + vol.Required(ATTR_VALUE): vol.Coerce(int), + vol.Optional(ATTR_LABELS): cv.ensure_list(cv.string) +}) + WINK_COMPONENTS = [ 'binary_sensor', 'sensor', 'light', 'switch', 'lock', 'cover', 'climate', 'fan', 'alarm_control_panel', 'scene' @@ -432,8 +463,23 @@ def setup(hass, config): DOMAIN, SERVICE_SET_PAIRING_MODE, set_pairing_mode, schema=SET_PAIRING_MODE_SCHEMA) - def service_handle(service): - """Handle services.""" + def nimbus_service_handle(service): + """Handle nimbus services.""" + entity_id = service.data.get('entity_id')[0] + _all_dials = [] + for sensor in hass.data[DOMAIN]['entities']['sensor']: + if isinstance(sensor, WinkNimbusDialDevice): + _all_dials.append(sensor) + for _dial in _all_dials: + if _dial.entity_id == entity_id: + if service.service == SERVICE_SET_DIAL_CONFIG: + _dial.set_configuration(**service.data) + if service.service == SERVICE_SET_DIAL_STATE: + _dial.wink.set_state(service.data.get("value"), + service.data.get("labels")) + + def siren_service_handle(service): + """Handle siren services.""" entity_ids = service.data.get('entity_id') all_sirens = [] for switch in hass.data[DOMAIN]['entities']['switch']: @@ -495,41 +541,68 @@ def setup(hass, config): if sirens: hass.services.register(DOMAIN, SERVICE_SET_AUTO_SHUTOFF, - service_handle, + siren_service_handle, schema=SET_AUTO_SHUTOFF_SCHEMA) hass.services.register(DOMAIN, SERVICE_ENABLE_SIREN, - service_handle, + siren_service_handle, schema=ENABLED_SIREN_SCHEMA) if has_dome_or_wink_siren: hass.services.register(DOMAIN, SERVICE_SET_SIREN_TONE, - service_handle, + siren_service_handle, schema=SET_SIREN_TONE_SCHEMA) hass.services.register(DOMAIN, SERVICE_ENABLE_CHIME, - service_handle, + siren_service_handle, schema=SET_CHIME_MODE_SCHEMA) hass.services.register(DOMAIN, SERVICE_SET_SIREN_VOLUME, - service_handle, + siren_service_handle, schema=SET_VOLUME_SCHEMA) hass.services.register(DOMAIN, SERVICE_SET_CHIME_VOLUME, - service_handle, + siren_service_handle, schema=SET_VOLUME_SCHEMA) hass.services.register(DOMAIN, SERVICE_SIREN_STROBE_ENABLED, - service_handle, + siren_service_handle, schema=SET_STROBE_ENABLED_SCHEMA) hass.services.register(DOMAIN, SERVICE_CHIME_STROBE_ENABLED, - service_handle, + siren_service_handle, schema=SET_STROBE_ENABLED_SCHEMA) component.add_entities(sirens) + nimbi = [] + dials = {} + all_nimbi = pywink.get_cloud_clocks() + all_dials = [] + for nimbus in all_nimbi: + if nimbus.object_type() == "cloud_clock": + nimbi.append(nimbus) + dials[nimbus.object_id()] = [] + for nimbus in all_nimbi: + if nimbus.object_type() == "dial": + dials[nimbus.parent_id()].append(nimbus) + + for nimbus in nimbi: + for dial in dials[nimbus.object_id()]: + all_dials.append(WinkNimbusDialDevice(nimbus, dial, hass)) + + if nimbi: + hass.services.register(DOMAIN, SERVICE_SET_DIAL_CONFIG, + nimbus_service_handle, + schema=DIAL_CONFIG_SCHEMA) + + hass.services.register(DOMAIN, SERVICE_SET_DIAL_STATE, + nimbus_service_handle, + schema=DIAL_STATE_SCHEMA) + + component.add_entities(all_dials) + return True @@ -596,6 +669,7 @@ class WinkDevice(Entity): self.wink.name()) def _pubnub_update(self, message): + _LOGGER.debug(message) try: if message is None: _LOGGER.error("Error on pubnub update for %s " @@ -740,3 +814,70 @@ class WinkSirenDevice(WinkDevice): attributes["chime_mode"] = chime_mode return attributes + + +class WinkNimbusDialDevice(WinkDevice): + """Representation of the Quirky Nimbus device.""" + + def __init__(self, nimbus, dial, hass): + """Initialize the Nimbus dial.""" + super().__init__(dial, hass) + self.parent = nimbus + + @asyncio.coroutine + def async_added_to_hass(self): + """Call when entity is added to hass.""" + self.hass.data[DOMAIN]['entities']['sensor'].append(self) + + @property + def state(self): + """Return dials current value.""" + return self.wink.state() + + @property + def name(self): + """Return the name of the device.""" + return self.parent.name() + " dial " + str(self.wink.index() + 1) + + @property + def device_state_attributes(self): + """Return the device state attributes.""" + attributes = super(WinkNimbusDialDevice, self).device_state_attributes + dial_attributes = self.dial_attributes() + + return {**attributes, **dial_attributes} + + def dial_attributes(self): + """Return the dial only attributes.""" + return { + "labels": self.wink.labels(), + "position": self.wink.position(), + "rotation": self.wink.rotation(), + "max_value": self.wink.max_value(), + "min_value": self.wink.min_value(), + "num_ticks": self.wink.ticks(), + "scale_type": self.wink.scale(), + "max_position": self.wink.max_position(), + "min_position": self.wink.min_position() + } + + def set_configuration(self, **kwargs): + """ + Set the dial config. + + Anything not sent will default to current setting. + """ + attributes = {**self.dial_attributes(), **kwargs} + + min_value = attributes["min_value"] + max_value = attributes["max_value"] + rotation = attributes["rotation"] + ticks = attributes["num_ticks"] + scale = attributes["scale_type"] + min_position = attributes["min_position"] + max_position = attributes["max_position"] + + self.wink.set_configuration(min_value, max_value, rotation, + scale=scale, ticks=ticks, + min_position=min_position, + max_position=max_position) diff --git a/homeassistant/components/wink/services.yaml b/homeassistant/components/wink/services.yaml index 1dc4ecf959bf1186679e1dfffcf3fd30242f5603..a3b489f9cf54badef0305fcdbdcbba977a3ab47b 100644 --- a/homeassistant/components/wink/services.yaml +++ b/homeassistant/components/wink/services.yaml @@ -111,3 +111,44 @@ set_chime_volume: volume: description: Volume level. One of ["low", "medium", "high"] example: "low" + +set_nimbus_dial_configuration: + description: Set the configuration of an individual nimbus dial + fields: + entity_id: + description: Name of the entity to set. + example: 'wink.nimbus_dial_3' + rotation: + description: Direction dial hand should spin ["cw" or "ccw"] + example: 'cw' + ticks: + description: Number of times the hand should move + example: 12 + scale: + description: How the dial should move in response to higher values ["log" or "linear"] + example: "linear" + min_value: + description: The minimum value allowed to be set + example: 0 + max_value: + description: The maximum value allowd to be set + example: 500 + min_position: + description: The minimum position the dial hand can rotate to generally [0-360] + example: 0 + max_position: + description: The maximum position the dial hand can rotate to generally [0-360] + example: 360 + +set_nimbus_dial_state: + description: Set the value and lables of an individual nimbus dial + fields: + entity_id: + description: Name fo the entity to set. + example: 'wink.nimbus_dial_3' + value: + description: The value that should be set (Should be between min_value and max_value) + example: 250 + labels: + description: The values shown on the dial labels ["Dial 1", "test"] the first value is what is shown by default the second value is shown when the nimbus is pressed + example: ["example", "test"] \ No newline at end of file diff --git a/requirements_all.txt b/requirements_all.txt index 933245e02e820cb4b360f4af410e319bb8fd7acd..a5936d14169e5196e4ff0ea72b7eddc253cee027 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1160,7 +1160,7 @@ python-velbus==2.0.19 python-vlc==1.1.2 # homeassistant.components.wink -python-wink==1.9.1 +python-wink==1.10.1 # homeassistant.components.sensor.swiss_public_transport python_opendata_transport==0.1.3