Additional Wink lock features (#7445)

* Additional Wink lock features
This commit is contained in:
William Scanlon 2017-05-13 14:09:00 -04:00 committed by GitHub
parent cfea4b17e3
commit cfbbade6d1
12 changed files with 279 additions and 4 deletions

View file

@ -4,6 +4,7 @@ Interfaces with Wink Cameras.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/alarm_control_panel.wink/
"""
import asyncio
import logging
import homeassistant.components.alarm_control_panel as alarm
@ -42,6 +43,11 @@ class WinkCameraDevice(WinkDevice, alarm.AlarmControlPanel):
"""Initialize the Wink alarm."""
super().__init__(wink, hass)
@asyncio.coroutine
def async_added_to_hass(self):
"""Callback when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['alarm_control_panel'].append(self)
@property
def state(self):
"""Return the state of the device."""

View file

@ -4,6 +4,7 @@ Support for Wink binary sensors.
For more details about this platform, please refer to the documentation at
at https://home-assistant.io/components/binary_sensor.wink/
"""
import asyncio
import logging
from homeassistant.components.binary_sensor import BinarySensorDevice
@ -101,6 +102,11 @@ class WinkBinarySensorDevice(WinkDevice, BinarySensorDevice, Entity):
else:
self.capability = None
@asyncio.coroutine
def async_added_to_hass(self):
"""Callback when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['binary_sensor'].append(self)
@property
def is_on(self):
"""Return true if the binary sensor is on."""

View file

@ -4,6 +4,8 @@ Support for Wink thermostats.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/climate.wink/
"""
import asyncio
from homeassistant.components.wink import WinkDevice, DOMAIN
from homeassistant.components.climate import (
STATE_AUTO, STATE_COOL, STATE_HEAT, ClimateDevice,
@ -52,6 +54,11 @@ class WinkThermostat(WinkDevice, ClimateDevice):
super().__init__(wink, hass)
self._config_temp_unit = temp_unit
@asyncio.coroutine
def async_added_to_hass(self):
"""Callback when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['climate'].append(self)
@property
def temperature_unit(self):
"""Return the unit of measurement."""

View file

@ -4,6 +4,8 @@ Support for Wink Covers.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/cover.wink/
"""
import asyncio
from homeassistant.components.cover import CoverDevice
from homeassistant.components.wink import WinkDevice, DOMAIN
@ -31,6 +33,11 @@ class WinkCoverDevice(WinkDevice, CoverDevice):
"""Initialize the cover."""
super().__init__(wink, hass)
@asyncio.coroutine
def async_added_to_hass(self):
"""Callback when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['cover'].append(self)
def close_cover(self):
"""Close the shade."""
self.wink.set_state(0)

View file

@ -4,6 +4,7 @@ Support for Wink fans.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/fan.wink/
"""
import asyncio
import logging
from homeassistant.components.fan import (FanEntity, SPEED_HIGH,
@ -12,6 +13,8 @@ from homeassistant.components.fan import (FanEntity, SPEED_HIGH,
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.components.wink import WinkDevice, DOMAIN
DEPENDENCIES = ['wink']
_LOGGER = logging.getLogger(__name__)
SPEED_LOWEST = 'lowest'
@ -34,6 +37,11 @@ class WinkFanDevice(WinkDevice, FanEntity):
"""Initialize the fan."""
super().__init__(wink, hass)
@asyncio.coroutine
def async_added_to_hass(self):
"""Callback when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['fan'].append(self)
def set_direction(self: ToggleEntity, direction: str) -> None:
"""Set the direction of the fan."""
self.wink.set_fan_direction(direction)

View file

@ -4,6 +4,7 @@ Support for Wink lights.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/light.wink/
"""
import asyncio
import colorsys
from homeassistant.components.light import (
@ -38,6 +39,11 @@ class WinkLight(WinkDevice, Light):
"""Initialize the Wink device."""
super().__init__(wink, hass)
@asyncio.coroutine
def async_added_to_hass(self):
"""Callback when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['light'].append(self)
@property
def is_on(self):
"""Return true if light is on."""

View file

@ -55,3 +55,59 @@ unlock:
code:
description: An optional code to unlock the lock with
example: 1234
wink_set_lock_vacation_mode:
description: Set vacation mode for all or specified locks. Disables all user codes.
fields:
entity_id:
description: Name of lock to unlock
example: 'lock.front_door'
enabled:
description: enable or disable. true or false.
example: true
wink_set_lock_alarm_mode:
description: Set alarm mode for all or specified locks.
fields:
entity_id:
description: Name of lock to unlock
example: 'lock.front_door'
mode:
description: One of tamper, activity, or forced_entry
example: tamper
wink_set_lock_alarm_sensitivity:
description: Set alarm sensitivity for all or specified locks.
fields:
entity_id:
description: Name of lock to unlock
example: 'lock.front_door'
sensitivity:
description: One of low, medium_low, medium, medium_high, high
example: medium
wink_set_lock_alarm_state:
description: Set alarm state.
fields:
entity_id:
description: Name of lock to unlock
example: 'lock.front_door'
enabled:
description: enable or disable. true or false.
example: true
wink_set_lock_beeper_state:
description: Set beeper state.
fields:
entity_id:
description: Name of lock to unlock
example: 'lock.front_door'
enabled:
description: enable or disable. true or false.
example: true

View file

@ -4,11 +4,55 @@ Support for Wink locks.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/lock.wink/
"""
import asyncio
import logging
from os import path
import voluptuous as vol
from homeassistant.components.lock import LockDevice
from homeassistant.components.wink import WinkDevice, DOMAIN
import homeassistant.helpers.config_validation as cv
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN
from homeassistant.config import load_yaml_config_file
DEPENDENCIES = ['wink']
_LOGGER = logging.getLogger(__name__)
SERVICE_SET_VACATION_MODE = 'wink_set_lock_vacation_mode'
SERVICE_SET_ALARM_MODE = 'wink_set_lock_alarm_mode'
SERVICE_SET_ALARM_SENSITIVITY = 'wink_set_lock_alarm_sensitivity'
SERVICE_SET_ALARM_STATE = 'wink_set_lock_alarm_state'
SERVICE_SET_BEEPER_STATE = 'wink_set_lock_beeper_state'
ATTR_ENABLED = 'enabled'
ATTR_SENSITIVITY = 'sensitivity'
ATTR_MODE = 'mode'
ALARM_SENSITIVITY_MAP = {"low": 0.2, "medium_low": 0.4,
"medium": 0.6, "medium_high": 0.8,
"high": 1.0}
ALARM_MODES_MAP = {"tamper": "tamper",
"activity": "alert",
"forced_entry": "forced_entry"}
SET_ENABLED_SCHEMA = vol.Schema({
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
vol.Required(ATTR_ENABLED): cv.string,
})
SET_SENSITIVITY_SCHEMA = vol.Schema({
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
vol.Required(ATTR_SENSITIVITY): vol.In(ALARM_SENSITIVITY_MAP)
})
SET_ALARM_MODES_SCHEMA = vol.Schema({
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
vol.Required(ATTR_MODE): vol.In(ALARM_MODES_MAP)
})
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the Wink platform."""
@ -19,6 +63,58 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
if _id not in hass.data[DOMAIN]['unique_ids']:
add_devices([WinkLockDevice(lock, hass)])
def service_handle(service):
"""Handler for services."""
entity_ids = service.data.get('entity_id')
all_locks = hass.data[DOMAIN]['entities']['lock']
locks_to_set = []
if entity_ids is None:
locks_to_set = all_locks
else:
for lock in all_locks:
if lock.entity_id in entity_ids:
locks_to_set.append(lock)
for lock in locks_to_set:
if service.service == SERVICE_SET_VACATION_MODE:
lock.set_vacation_mode(service.data.get(ATTR_ENABLED))
elif service.service == SERVICE_SET_ALARM_STATE:
lock.set_alarm_state(service.data.get(ATTR_ENABLED))
elif service.service == SERVICE_SET_BEEPER_STATE:
lock.set_beeper_state(service.data.get(ATTR_ENABLED))
elif service.service == SERVICE_SET_ALARM_MODE:
lock.set_alarm_mode(service.data.get(ATTR_MODE))
elif service.service == SERVICE_SET_ALARM_SENSITIVITY:
lock.set_alarm_sensitivity(service.data.get(ATTR_SENSITIVITY))
descriptions = load_yaml_config_file(
path.join(path.dirname(__file__), 'services.yaml'))
hass.services.register(DOMAIN, SERVICE_SET_VACATION_MODE,
service_handle,
descriptions.get(SERVICE_SET_VACATION_MODE),
schema=SET_ENABLED_SCHEMA)
hass.services.register(DOMAIN, SERVICE_SET_ALARM_STATE,
service_handle,
descriptions.get(SERVICE_SET_ALARM_STATE),
schema=SET_ENABLED_SCHEMA)
hass.services.register(DOMAIN, SERVICE_SET_BEEPER_STATE,
service_handle,
descriptions.get(SERVICE_SET_BEEPER_STATE),
schema=SET_ENABLED_SCHEMA)
hass.services.register(DOMAIN, SERVICE_SET_ALARM_MODE,
service_handle,
descriptions.get(SERVICE_SET_ALARM_MODE),
schema=SET_ALARM_MODES_SCHEMA)
hass.services.register(DOMAIN, SERVICE_SET_ALARM_SENSITIVITY,
service_handle,
descriptions.get(SERVICE_SET_ALARM_SENSITIVITY),
schema=SET_SENSITIVITY_SCHEMA)
class WinkLockDevice(WinkDevice, LockDevice):
"""Representation of a Wink lock."""
@ -27,6 +123,11 @@ class WinkLockDevice(WinkDevice, LockDevice):
"""Initialize the lock."""
super().__init__(wink, hass)
@asyncio.coroutine
def async_added_to_hass(self):
"""Callback when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['lock'].append(self)
@property
def is_locked(self):
"""Return true if device is locked."""
@ -39,3 +140,60 @@ class WinkLockDevice(WinkDevice, LockDevice):
def unlock(self, **kwargs):
"""Unlock the device."""
self.wink.set_state(False)
def set_alarm_state(self, enabled):
"""Set lock's alarm state."""
self.wink.set_alarm_state(enabled)
def set_vacation_mode(self, enabled):
"""Set lock's vacation mode."""
self.wink.set_vacation_mode(enabled)
def set_beeper_state(self, enabled):
"""Set lock's beeper mode."""
self.wink.set_beeper_mode(enabled)
def set_alarm_sensitivity(self, sensitivity):
"""
Set lock's alarm sensitivity.
Valid sensitivities:
0.2, 0.4, 0.6, 0.8, 1.0
"""
self.wink.set_alarm_sensitivity(sensitivity)
def set_alarm_mode(self, mode):
"""
Set lock's alarm mode.
Valid modes:
alert - Beep when lock is locked or unlocked
tamper - 15 sec alarm when lock is disturbed when locked
forced_entry - 3 min alarm when significant force applied
to door when locked.
"""
self.wink.set_alarm_mode(mode)
@property
def device_state_attributes(self):
"""Return the state attributes."""
super_attrs = super().device_state_attributes
sensitivity = dict_value_to_key(ALARM_SENSITIVITY_MAP,
self.wink.alarm_sensitivity())
super_attrs['alarm sensitivity'] = sensitivity
super_attrs['vacation mode'] = self.wink.vacation_mode_enabled()
super_attrs['beeper mode'] = self.wink.beeper_enabled()
super_attrs['auto lock'] = self.wink.auto_lock_enabled()
alarm_mode = dict_value_to_key(ALARM_MODES_MAP,
self.wink.alarm_mode())
super_attrs['alarm mode'] = alarm_mode
super_attrs['alarm enabled'] = self.wink.alarm_enabled()
return super_attrs
def dict_value_to_key(dict_map, comp_value):
"""Return the key that has the provided value."""
for key, value in dict_map.items():
if value == comp_value:
return key
return STATE_UNKNOWN

View file

@ -4,6 +4,7 @@ Support for Wink scenes.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/scene.wink/
"""
import asyncio
import logging
from homeassistant.components.scene import Scene
@ -29,6 +30,12 @@ class WinkScene(WinkDevice, Scene):
def __init__(self, wink, hass):
"""Initialize the Wink device."""
super().__init__(wink, hass)
hass.data[DOMAIN]['entities']['scene'].append(self)
@asyncio.coroutine
def async_added_to_hass(self):
"""Callback when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['scene'].append(self)
@property
def is_on(self):

View file

@ -4,6 +4,7 @@ Support for Wink sensors.
For more details about this platform, please refer to the documentation at
at https://home-assistant.io/components/sensor.wink/
"""
import asyncio
import logging
from homeassistant.const import TEMP_CELSIUS
@ -58,6 +59,11 @@ class WinkSensorDevice(WinkDevice, Entity):
else:
self._unit_of_measurement = self.wink.unit()
@asyncio.coroutine
def async_added_to_hass(self):
"""Callback when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['sensor'].append(self)
@property
def state(self):
"""Return the state."""

View file

@ -4,6 +4,7 @@ Support for Wink switches.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/switch.wink/
"""
import asyncio
from homeassistant.components.wink import WinkDevice, DOMAIN
from homeassistant.helpers.entity import ToggleEntity
@ -40,6 +41,11 @@ class WinkToggleDevice(WinkDevice, ToggleEntity):
"""Initialize the Wink device."""
super().__init__(wink, hass)
@asyncio.coroutine
def async_added_to_hass(self):
"""Callback when entity is added to hass."""
self.hass.data[DOMAIN]['entities']['switch'].append(self)
@property
def is_on(self):
"""Return true if device is on."""

View file

@ -75,6 +75,7 @@ def setup(hass, config):
hass.data[DOMAIN] = {}
hass.data[DOMAIN]['entities'] = []
hass.data[DOMAIN]['unique_ids'] = []
hass.data[DOMAIN]['entities'] = {}
user_agent = config[DOMAIN].get(CONF_USER_AGENT)
@ -154,10 +155,11 @@ def setup(hass, config):
def force_update(call):
"""Force all devices to poll the Wink API."""
_LOGGER.info("Refreshing Wink states from API")
for entity in hass.data[DOMAIN]['entities']:
for entity_list in hass.data[DOMAIN]['entities'].values():
# Throttle the calls to Wink API
time.sleep(1)
entity.schedule_update_ha_state(True)
for entity in entity_list:
time.sleep(1)
entity.schedule_update_ha_state(True)
hass.services.register(DOMAIN, SERVICE_REFRESH_STATES, force_update)
def pull_new_devices(call):
@ -169,6 +171,7 @@ def setup(hass, config):
# Load components for the devices in Wink that we support
for component in WINK_COMPONENTS:
hass.data[DOMAIN]['entities'][component] = []
discovery.load_platform(hass, component, DOMAIN, {}, config)
return True
@ -183,7 +186,6 @@ class WinkDevice(Entity):
self.wink = wink
hass.data[DOMAIN]['pubnub'].add_subscription(
self.wink.pubnub_channel, self._pubnub_update)
hass.data[DOMAIN]['entities'].append(self)
hass.data[DOMAIN]['unique_ids'].append(self.wink.object_id() +
self.wink.name())