New Wink services. pair new device, rename, and delete, add new lock key code. Add water heater support (#9303)
* Pair new device, rename, delete, and lock key code services. Also add water heater support. * Fixed tox
This commit is contained in:
parent
9d839f1f53
commit
312de6b3a3
9 changed files with 363 additions and 124 deletions
|
@ -136,8 +136,9 @@ class WinkHub(WinkBinarySensorDevice):
|
|||
def device_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
return {
|
||||
'update needed': self.wink.update_needed(),
|
||||
'firmware version': self.wink.firmware_version()
|
||||
'update_needed': self.wink.update_needed(),
|
||||
'firmware_version': self.wink.firmware_version(),
|
||||
'pairing_mode': self.wink.pairing_mode()
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -44,6 +44,12 @@ STATE_IDLE = 'idle'
|
|||
STATE_AUTO = 'auto'
|
||||
STATE_DRY = 'dry'
|
||||
STATE_FAN_ONLY = 'fan_only'
|
||||
STATE_ECO = 'eco'
|
||||
STATE_ELECTRIC = 'electric'
|
||||
STATE_PERFORMANCE = 'performance'
|
||||
STATE_HIGH_DEMAND = 'high_demand'
|
||||
STATE_HEAT_PUMP = 'heat_pump'
|
||||
STATE_GAS = 'gas'
|
||||
|
||||
ATTR_CURRENT_TEMPERATURE = 'current_temperature'
|
||||
ATTR_MAX_TEMP = 'max_temp'
|
||||
|
|
|
@ -114,7 +114,7 @@ class DemoClimate(ClimateDevice):
|
|||
|
||||
@property
|
||||
def is_aux_heat_on(self):
|
||||
"""Return true if away mode is on."""
|
||||
"""Return true if aux heat is on."""
|
||||
return self._aux
|
||||
|
||||
@property
|
||||
|
@ -183,7 +183,7 @@ class DemoClimate(ClimateDevice):
|
|||
self.schedule_update_ha_state()
|
||||
|
||||
def turn_aux_heat_on(self):
|
||||
"""Turn away auxiliary heater on."""
|
||||
"""Turn auxillary heater on."""
|
||||
self._aux = True
|
||||
self.schedule_update_ha_state()
|
||||
|
||||
|
|
|
@ -1,30 +1,45 @@
|
|||
"""
|
||||
Support for Wink thermostats.
|
||||
Support for Wink thermostats, Air Conditioners, and Water Heaters.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/climate.wink/
|
||||
"""
|
||||
import logging
|
||||
import asyncio
|
||||
|
||||
from homeassistant.components.wink import WinkDevice, DOMAIN
|
||||
from homeassistant.components.climate import (
|
||||
STATE_AUTO, STATE_COOL, STATE_HEAT, ClimateDevice,
|
||||
ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW,
|
||||
ATTR_TEMPERATURE,
|
||||
ATTR_CURRENT_HUMIDITY)
|
||||
ATTR_TEMPERATURE, STATE_FAN_ONLY,
|
||||
ATTR_CURRENT_HUMIDITY, STATE_ECO, STATE_ELECTRIC,
|
||||
STATE_PERFORMANCE, STATE_HIGH_DEMAND,
|
||||
STATE_HEAT_PUMP, STATE_GAS)
|
||||
from homeassistant.const import (
|
||||
TEMP_CELSIUS, STATE_ON,
|
||||
STATE_OFF, STATE_UNKNOWN)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEPENDENCIES = ['wink']
|
||||
|
||||
STATE_AUX = 'aux'
|
||||
STATE_ECO = 'eco'
|
||||
STATE_FAN = 'fan'
|
||||
SPEED_LOW = 'low'
|
||||
SPEED_MEDIUM = 'medium'
|
||||
SPEED_HIGH = 'high'
|
||||
|
||||
HA_STATE_TO_WINK = {STATE_AUTO: 'auto',
|
||||
STATE_ECO: 'eco',
|
||||
STATE_FAN_ONLY: 'fan_only',
|
||||
STATE_HEAT: 'heat_only',
|
||||
STATE_COOL: 'cool_only',
|
||||
STATE_PERFORMANCE: 'performance',
|
||||
STATE_HIGH_DEMAND: 'high_demand',
|
||||
STATE_HEAT_PUMP: 'heat_pump',
|
||||
STATE_ELECTRIC: 'electric_only',
|
||||
STATE_GAS: 'gas',
|
||||
STATE_OFF: 'off'}
|
||||
WINK_STATE_TO_HA = {value: key for key, value in HA_STATE_TO_WINK.items()}
|
||||
|
||||
ATTR_EXTERNAL_TEMPERATURE = "external_temperature"
|
||||
ATTR_SMART_TEMPERATURE = "smart_temperature"
|
||||
ATTR_ECO_TARGET = "eco_target"
|
||||
|
@ -32,28 +47,26 @@ ATTR_OCCUPIED = "occupied"
|
|||
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Set up the Wink thermostat."""
|
||||
"""Set up the Wink climate devices."""
|
||||
import pywink
|
||||
temp_unit = hass.config.units.temperature_unit
|
||||
for climate in pywink.get_thermostats():
|
||||
_id = climate.object_id() + climate.name()
|
||||
if _id not in hass.data[DOMAIN]['unique_ids']:
|
||||
add_devices([WinkThermostat(climate, hass, temp_unit)])
|
||||
add_devices([WinkThermostat(climate, hass)])
|
||||
for climate in pywink.get_air_conditioners():
|
||||
_id = climate.object_id() + climate.name()
|
||||
if _id not in hass.data[DOMAIN]['unique_ids']:
|
||||
add_devices([WinkAC(climate, hass, temp_unit)])
|
||||
add_devices([WinkAC(climate, hass)])
|
||||
for water_heater in pywink.get_water_heaters():
|
||||
_id = water_heater.object_id() + water_heater.name()
|
||||
if _id not in hass.data[DOMAIN]['unique_ids']:
|
||||
add_devices([WinkWaterHeater(water_heater, hass)])
|
||||
|
||||
|
||||
# pylint: disable=abstract-method
|
||||
class WinkThermostat(WinkDevice, ClimateDevice):
|
||||
"""Representation of a Wink thermostat."""
|
||||
|
||||
def __init__(self, wink, hass, temp_unit):
|
||||
"""Initialize the Wink device."""
|
||||
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."""
|
||||
|
@ -139,17 +152,11 @@ class WinkThermostat(WinkDevice, ClimateDevice):
|
|||
"""Return current operation ie. heat, cool, idle."""
|
||||
if not self.wink.is_on():
|
||||
current_op = STATE_OFF
|
||||
elif self.wink.current_hvac_mode() == 'cool_only':
|
||||
current_op = STATE_COOL
|
||||
elif self.wink.current_hvac_mode() == 'heat_only':
|
||||
current_op = STATE_HEAT
|
||||
elif self.wink.current_hvac_mode() == 'aux':
|
||||
current_op = STATE_HEAT
|
||||
elif self.wink.current_hvac_mode() == 'auto':
|
||||
current_op = STATE_AUTO
|
||||
elif self.wink.current_hvac_mode() == 'eco':
|
||||
current_op = STATE_ECO
|
||||
else:
|
||||
current_op = WINK_STATE_TO_HA.get(self.wink.current_hvac_mode())
|
||||
if current_op == 'aux':
|
||||
return STATE_HEAT
|
||||
if current_op is None:
|
||||
current_op = STATE_UNKNOWN
|
||||
return current_op
|
||||
|
||||
|
@ -199,12 +206,13 @@ class WinkThermostat(WinkDevice, ClimateDevice):
|
|||
@property
|
||||
def is_aux_heat_on(self):
|
||||
"""Return true if aux heater."""
|
||||
if self.wink.current_hvac_mode() == 'aux' and self.wink.is_on():
|
||||
return True
|
||||
elif self.wink.current_hvac_mode() == 'aux' and not self.wink.is_on():
|
||||
return False
|
||||
if 'aux' not in self.wink.hvac_modes():
|
||||
return None
|
||||
|
||||
if self.wink.current_hvac_mode() == 'aux':
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_temperature(self, **kwargs):
|
||||
"""Set new target temperature."""
|
||||
target_temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
|
@ -223,32 +231,27 @@ class WinkThermostat(WinkDevice, ClimateDevice):
|
|||
|
||||
def set_operation_mode(self, operation_mode):
|
||||
"""Set operation mode."""
|
||||
if operation_mode == STATE_HEAT:
|
||||
self.wink.set_operation_mode('heat_only')
|
||||
elif operation_mode == STATE_COOL:
|
||||
self.wink.set_operation_mode('cool_only')
|
||||
elif operation_mode == STATE_AUTO:
|
||||
self.wink.set_operation_mode('auto')
|
||||
elif operation_mode == STATE_OFF:
|
||||
self.wink.set_operation_mode('off')
|
||||
elif operation_mode == STATE_AUX:
|
||||
self.wink.set_operation_mode('aux')
|
||||
elif operation_mode == STATE_ECO:
|
||||
self.wink.set_operation_mode('eco')
|
||||
op_mode_to_set = HA_STATE_TO_WINK.get(operation_mode)
|
||||
# The only way to disable aux heat is with the toggle
|
||||
if self.is_aux_heat_on and op_mode_to_set == STATE_HEAT:
|
||||
return
|
||||
self.wink.set_operation_mode(op_mode_to_set)
|
||||
|
||||
@property
|
||||
def operation_list(self):
|
||||
"""List of available operation modes."""
|
||||
op_list = ['off']
|
||||
modes = self.wink.hvac_modes()
|
||||
if 'cool_only' in modes:
|
||||
op_list.append(STATE_COOL)
|
||||
if 'heat_only' in modes or 'aux' in modes:
|
||||
op_list.append(STATE_HEAT)
|
||||
if 'auto' in modes:
|
||||
op_list.append(STATE_AUTO)
|
||||
if 'eco' in modes:
|
||||
op_list.append(STATE_ECO)
|
||||
for mode in modes:
|
||||
if mode == 'aux':
|
||||
continue
|
||||
ha_mode = WINK_STATE_TO_HA.get(mode)
|
||||
if ha_mode is not None:
|
||||
op_list.append(ha_mode)
|
||||
else:
|
||||
error = "Invaid operation mode mapping. " + mode + \
|
||||
" doesn't map. Please report this."
|
||||
_LOGGER.error(error)
|
||||
return op_list
|
||||
|
||||
def turn_away_mode_on(self):
|
||||
|
@ -282,11 +285,11 @@ class WinkThermostat(WinkDevice, ClimateDevice):
|
|||
|
||||
def turn_aux_heat_on(self):
|
||||
"""Turn auxiliary heater on."""
|
||||
self.set_operation_mode(STATE_AUX)
|
||||
self.wink.set_operation_mode('aux')
|
||||
|
||||
def turn_aux_heat_off(self):
|
||||
"""Turn auxiliary heater off."""
|
||||
self.set_operation_mode(STATE_AUTO)
|
||||
self.set_operation_mode(STATE_HEAT)
|
||||
|
||||
@property
|
||||
def min_temp(self):
|
||||
|
@ -344,11 +347,6 @@ class WinkThermostat(WinkDevice, ClimateDevice):
|
|||
class WinkAC(WinkDevice, ClimateDevice):
|
||||
"""Representation of a Wink air conditioner."""
|
||||
|
||||
def __init__(self, wink, hass, temp_unit):
|
||||
"""Initialize the Wink device."""
|
||||
super().__init__(wink, hass)
|
||||
self._config_temp_unit = temp_unit
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
"""Return the unit of measurement."""
|
||||
|
@ -382,13 +380,9 @@ class WinkAC(WinkDevice, ClimateDevice):
|
|||
"""Return current operation ie. heat, cool, idle."""
|
||||
if not self.wink.is_on():
|
||||
current_op = STATE_OFF
|
||||
elif self.wink.current_mode() == 'cool_only':
|
||||
current_op = STATE_COOL
|
||||
elif self.wink.current_mode() == 'auto_eco':
|
||||
current_op = STATE_ECO
|
||||
elif self.wink.current_mode() == 'fan_only':
|
||||
current_op = STATE_FAN
|
||||
else:
|
||||
current_op = WINK_STATE_TO_HA.get(self.wink.current_hvac_mode())
|
||||
if current_op is None:
|
||||
current_op = STATE_UNKNOWN
|
||||
return current_op
|
||||
|
||||
|
@ -397,12 +391,14 @@ class WinkAC(WinkDevice, ClimateDevice):
|
|||
"""List of available operation modes."""
|
||||
op_list = ['off']
|
||||
modes = self.wink.modes()
|
||||
if 'cool_only' in modes:
|
||||
op_list.append(STATE_COOL)
|
||||
if 'auto_eco' in modes:
|
||||
op_list.append(STATE_ECO)
|
||||
if 'fan_only' in modes:
|
||||
op_list.append(STATE_FAN)
|
||||
for mode in modes:
|
||||
ha_mode = WINK_STATE_TO_HA.get(mode)
|
||||
if ha_mode is not None:
|
||||
op_list.append(ha_mode)
|
||||
else:
|
||||
error = "Invaid operation mode mapping. " + mode + \
|
||||
" doesn't map. Please report this."
|
||||
_LOGGER.error(error)
|
||||
return op_list
|
||||
|
||||
def set_temperature(self, **kwargs):
|
||||
|
@ -412,30 +408,16 @@ class WinkAC(WinkDevice, ClimateDevice):
|
|||
|
||||
def set_operation_mode(self, operation_mode):
|
||||
"""Set operation mode."""
|
||||
if operation_mode == STATE_COOL:
|
||||
self.wink.set_operation_mode('cool_only')
|
||||
elif operation_mode == STATE_ECO:
|
||||
self.wink.set_operation_mode('auto_eco')
|
||||
elif operation_mode == STATE_OFF:
|
||||
self.wink.set_operation_mode('off')
|
||||
elif operation_mode == STATE_FAN:
|
||||
self.wink.set_operation_mode('fan_only')
|
||||
op_mode_to_set = HA_STATE_TO_WINK.get(operation_mode)
|
||||
if op_mode_to_set == 'eco':
|
||||
op_mode_to_set = 'auto_eco'
|
||||
self.wink.set_operation_mode(op_mode_to_set)
|
||||
|
||||
@property
|
||||
def target_temperature(self):
|
||||
"""Return the temperature we try to reach."""
|
||||
return self.wink.current_max_set_point()
|
||||
|
||||
@property
|
||||
def target_temperature_low(self):
|
||||
"""Only supports cool."""
|
||||
return None
|
||||
|
||||
@property
|
||||
def target_temperature_high(self):
|
||||
"""Only supports cool."""
|
||||
return None
|
||||
|
||||
@property
|
||||
def current_fan_mode(self):
|
||||
"""Return the current fan mode."""
|
||||
|
@ -453,12 +435,97 @@ class WinkAC(WinkDevice, ClimateDevice):
|
|||
"""Return a list of available fan modes."""
|
||||
return [SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH]
|
||||
|
||||
def set_fan_mode(self, mode):
|
||||
def set_fan_mode(self, fan):
|
||||
"""Set fan speed."""
|
||||
if mode == SPEED_LOW:
|
||||
if fan == SPEED_LOW:
|
||||
speed = 0.4
|
||||
elif mode == SPEED_MEDIUM:
|
||||
elif fan == SPEED_MEDIUM:
|
||||
speed = 0.8
|
||||
elif mode == SPEED_HIGH:
|
||||
elif fan == SPEED_HIGH:
|
||||
speed = 1.0
|
||||
self.wink.set_ac_fan_speed(speed)
|
||||
|
||||
|
||||
class WinkWaterHeater(WinkDevice, ClimateDevice):
|
||||
"""Representation of a Wink water heater."""
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
"""Return the unit of measurement."""
|
||||
# The Wink API always returns temp in Celsius
|
||||
return TEMP_CELSIUS
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return the optional state attributes."""
|
||||
data = {}
|
||||
data["vacation_mode"] = self.wink.vacation_mode_enabled()
|
||||
data["rheem_type"] = self.wink.rheem_type()
|
||||
|
||||
return data
|
||||
|
||||
@property
|
||||
def current_operation(self):
|
||||
"""
|
||||
Return current operation one of the following.
|
||||
|
||||
["eco", "performance", "heat_pump",
|
||||
"high_demand", "electric_only", "gas]
|
||||
"""
|
||||
if not self.wink.is_on():
|
||||
current_op = STATE_OFF
|
||||
else:
|
||||
current_op = WINK_STATE_TO_HA.get(self.wink.current_mode())
|
||||
if current_op is None:
|
||||
current_op = STATE_UNKNOWN
|
||||
return current_op
|
||||
|
||||
@property
|
||||
def operation_list(self):
|
||||
"""List of available operation modes."""
|
||||
op_list = ['off']
|
||||
modes = self.wink.modes()
|
||||
for mode in modes:
|
||||
if mode == 'aux':
|
||||
continue
|
||||
ha_mode = WINK_STATE_TO_HA.get(mode)
|
||||
if ha_mode is not None:
|
||||
op_list.append(ha_mode)
|
||||
else:
|
||||
error = "Invaid operation mode mapping. " + mode + \
|
||||
" doesn't map. Please report this."
|
||||
_LOGGER.error(error)
|
||||
return op_list
|
||||
|
||||
def set_temperature(self, **kwargs):
|
||||
"""Set new target temperature."""
|
||||
target_temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
self.wink.set_temperature(target_temp)
|
||||
|
||||
def set_operation_mode(self, operation_mode):
|
||||
"""Set operation mode."""
|
||||
op_mode_to_set = HA_STATE_TO_WINK.get(operation_mode)
|
||||
self.wink.set_operation_mode(op_mode_to_set)
|
||||
|
||||
@property
|
||||
def target_temperature(self):
|
||||
"""Return the temperature we try to reach."""
|
||||
return self.wink.current_set_point()
|
||||
|
||||
def turn_away_mode_on(self):
|
||||
"""Turn away on."""
|
||||
self.wink.set_vacation_mode(True)
|
||||
|
||||
def turn_away_mode_off(self):
|
||||
"""Turn away off."""
|
||||
self.wink.set_vacation_mode(False)
|
||||
|
||||
@property
|
||||
def min_temp(self):
|
||||
"""Return the minimum temperature."""
|
||||
return self.wink.min_set_point()
|
||||
|
||||
@property
|
||||
def max_temp(self):
|
||||
"""Return the maximum temperature."""
|
||||
return self.wink.max_set_point()
|
||||
|
|
|
@ -130,3 +130,16 @@ wink_set_lock_beeper_state:
|
|||
description: enable or disable. true or false.
|
||||
example: true
|
||||
|
||||
wink_add_new_lock_key_code:
|
||||
description: Add a new user key code.
|
||||
|
||||
fields:
|
||||
entity_id:
|
||||
description: Name of lock to unlock
|
||||
example: 'lock.front_door'
|
||||
name:
|
||||
description: name of the new key code.
|
||||
example: Bob
|
||||
code:
|
||||
description: new key code, length must match length of other codes. Default length is 4.
|
||||
example: 1234
|
||||
|
|
|
@ -13,7 +13,7 @@ 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.const import ATTR_ENTITY_ID, STATE_UNKNOWN, ATTR_CODE
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
|
||||
DEPENDENCIES = ['wink']
|
||||
|
@ -25,10 +25,12 @@ 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'
|
||||
SERVICE_ADD_KEY = 'wink_add_new_lock_key_code'
|
||||
|
||||
ATTR_ENABLED = 'enabled'
|
||||
ATTR_SENSITIVITY = 'sensitivity'
|
||||
ATTR_MODE = 'mode'
|
||||
ATTR_NAME = 'name'
|
||||
|
||||
ALARM_SENSITIVITY_MAP = {"low": 0.2, "medium_low": 0.4,
|
||||
"medium": 0.6, "medium_high": 0.8,
|
||||
|
@ -53,6 +55,12 @@ SET_ALARM_MODES_SCHEMA = vol.Schema({
|
|||
vol.Required(ATTR_MODE): vol.In(ALARM_MODES_MAP)
|
||||
})
|
||||
|
||||
ADD_KEY_SCHEMA = vol.Schema({
|
||||
vol.Optional(ATTR_ENTITY_ID): cv.entity_ids,
|
||||
vol.Required(ATTR_NAME): cv.string,
|
||||
vol.Required(ATTR_CODE): cv.positive_int,
|
||||
})
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Set up the Wink platform."""
|
||||
|
@ -86,6 +94,10 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||
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))
|
||||
elif service.service == SERVICE_ADD_KEY:
|
||||
name = service.data.get(ATTR_NAME)
|
||||
code = service.data.get(ATTR_CODE)
|
||||
lock.add_new_key(code, name)
|
||||
|
||||
descriptions = load_yaml_config_file(
|
||||
path.join(path.dirname(__file__), 'services.yaml'))
|
||||
|
@ -115,6 +127,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
|
|||
descriptions.get(SERVICE_SET_ALARM_SENSITIVITY),
|
||||
schema=SET_SENSITIVITY_SCHEMA)
|
||||
|
||||
hass.services.register(DOMAIN, SERVICE_ADD_KEY,
|
||||
service_handle,
|
||||
descriptions.get(SERVICE_ADD_KEY),
|
||||
schema=ADD_KEY_SCHEMA)
|
||||
|
||||
|
||||
class WinkLockDevice(WinkDevice, LockDevice):
|
||||
"""Representation of a Wink lock."""
|
||||
|
@ -149,6 +166,10 @@ class WinkLockDevice(WinkDevice, LockDevice):
|
|||
"""Set lock's beeper mode."""
|
||||
self.wink.set_beeper_mode(enabled)
|
||||
|
||||
def add_new_key(self, code, name):
|
||||
"""Add a new user key code."""
|
||||
self.wink.add_new_key(code, name)
|
||||
|
||||
def set_alarm_sensitivity(self, sensitivity):
|
||||
"""
|
||||
Set lock's alarm sensitivity.
|
||||
|
@ -176,14 +197,14 @@ class WinkLockDevice(WinkDevice, LockDevice):
|
|||
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()
|
||||
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()
|
||||
super_attrs['alarm_mode'] = alarm_mode
|
||||
super_attrs['alarm_enabled'] = self.wink.alarm_enabled()
|
||||
return super_attrs
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
foursquare:
|
||||
checkin:
|
||||
description: Check a user into a Foursquare venue
|
||||
|
@ -625,3 +626,42 @@ input_boolean:
|
|||
entity_id:
|
||||
description: Entity id of the input boolean to turn on
|
||||
example: 'input_boolean.notify_alerts'
|
||||
|
||||
wink:
|
||||
pair_new_device:
|
||||
description: Pair a new device to a Wink Hub.
|
||||
|
||||
fields:
|
||||
hub_name:
|
||||
description: The name of the hub to pair a new device to.
|
||||
example: 'My hub'
|
||||
pairing_mode:
|
||||
description: One of ["zigbee", "zwave", "zwave_exclusion", "zwave_network_rediscovery", "lutron", "bluetooth", "kidde"]
|
||||
example: 'zigbee'
|
||||
kidde_radio_code:
|
||||
description: A string of 8 1s and 0s one for each dip switch on the kidde device left --> right = 1 --> 8
|
||||
example: '10101010'
|
||||
|
||||
rename_wink_device:
|
||||
description: Rename the provided device.
|
||||
|
||||
fields:
|
||||
entity_id:
|
||||
description: The entity_id of the device to rename.
|
||||
example: binary_sensor.front_door_opened
|
||||
name:
|
||||
description: The name to change it to.
|
||||
example: back_door
|
||||
|
||||
delete_wink_device:
|
||||
description: Remove/unpair device from Wink.
|
||||
|
||||
fields:
|
||||
entity_id:
|
||||
description: The entity_id of the device to delete.
|
||||
|
||||
pull_newly_added_devices_from_wink:
|
||||
description: Pull newly pair devices from Wink.
|
||||
|
||||
refresh_state_from_wink:
|
||||
description: Pull the latest states for every device.
|
||||
|
|
|
@ -20,11 +20,12 @@ from homeassistant.helpers.event import track_time_interval
|
|||
from homeassistant.const import (
|
||||
ATTR_BATTERY_LEVEL, CONF_EMAIL, CONF_PASSWORD,
|
||||
EVENT_HOMEASSISTANT_START,
|
||||
EVENT_HOMEASSISTANT_STOP, __version__)
|
||||
EVENT_HOMEASSISTANT_STOP, __version__, ATTR_ENTITY_ID)
|
||||
from homeassistant.helpers.entity import Entity
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.config import load_yaml_config_file
|
||||
|
||||
REQUIREMENTS = ['python-wink==1.5.1', 'pubnubsub-handler==1.0.2']
|
||||
REQUIREMENTS = ['python-wink==1.6.0', 'pubnubsub-handler==1.0.2']
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -45,6 +46,10 @@ ATTR_ACCESS_TOKEN = 'access_token'
|
|||
ATTR_REFRESH_TOKEN = 'refresh_token'
|
||||
ATTR_CLIENT_ID = 'client_id'
|
||||
ATTR_CLIENT_SECRET = 'client_secret'
|
||||
ATTR_NAME = 'name'
|
||||
ATTR_PAIRING_MODE = 'pairing_mode'
|
||||
ATTR_KIDDE_RADIO_CODE = 'kidde_radio_code'
|
||||
ATTR_HUB_NAME = 'hub_name'
|
||||
|
||||
WINK_AUTH_CALLBACK_PATH = '/auth/wink/callback'
|
||||
WINK_AUTH_START = '/auth/wink'
|
||||
|
@ -56,9 +61,12 @@ DEFAULT_CONFIG = {
|
|||
'client_secret': 'CLIENT_SECRET_HERE'
|
||||
}
|
||||
|
||||
SERVICE_ADD_NEW_DEVICES = 'add_new_devices'
|
||||
SERVICE_ADD_NEW_DEVICES = 'pull_newly_added_devices_from_wink'
|
||||
SERVICE_REFRESH_STATES = 'refresh_state_from_wink'
|
||||
SERVICE_KEEP_ALIVE = 'keep_pubnub_updates_flowing'
|
||||
SERVICE_RENAME_DEVICE = 'rename_wink_device'
|
||||
SERVICE_DELETE_DEVICE = 'delete_wink_device'
|
||||
SERVICE_SET_PAIRING_MODE = 'pair_new_device'
|
||||
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
|
@ -74,11 +82,29 @@ CONFIG_SCHEMA = vol.Schema({
|
|||
})
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
||||
RENAME_DEVICE_SCHEMA = vol.Schema({
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_ids,
|
||||
vol.Required(ATTR_NAME): cv.string
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
DELETE_DEVICE_SCHEMA = vol.Schema({
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_ids
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
SET_PAIRING_MODE_SCHEMA = vol.Schema({
|
||||
vol.Required(ATTR_HUB_NAME): cv.string,
|
||||
vol.Required(ATTR_PAIRING_MODE): cv.string,
|
||||
vol.Optional(ATTR_KIDDE_RADIO_CODE): cv.string
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
WINK_COMPONENTS = [
|
||||
'binary_sensor', 'sensor', 'light', 'switch', 'lock', 'cover', 'climate',
|
||||
'fan', 'alarm_control_panel', 'scene'
|
||||
]
|
||||
|
||||
WINK_HUBS = []
|
||||
|
||||
|
||||
def _write_config_file(file_path, config):
|
||||
try:
|
||||
|
@ -177,6 +203,9 @@ def setup(hass, config):
|
|||
import pywink
|
||||
from pubnubsubhandler import PubNubSubscriptionHandler
|
||||
|
||||
descriptions = load_yaml_config_file(
|
||||
os.path.join(os.path.dirname(__file__), 'services.yaml')).get(DOMAIN)
|
||||
|
||||
if hass.data.get(DOMAIN) is None:
|
||||
hass.data[DOMAIN] = {
|
||||
'unique_ids': [],
|
||||
|
@ -313,6 +342,7 @@ def setup(hass, config):
|
|||
def stop_subscription(event):
|
||||
"""Stop the pubnub subscription."""
|
||||
hass.data[DOMAIN]['pubnub'].unsubscribe()
|
||||
hass.data[DOMAIN]['pubnub'] = None
|
||||
|
||||
hass.bus.listen(EVENT_HOMEASSISTANT_STOP, stop_subscription)
|
||||
|
||||
|
@ -333,7 +363,9 @@ def setup(hass, config):
|
|||
for entity in entity_list:
|
||||
time.sleep(1)
|
||||
entity.schedule_update_ha_state(True)
|
||||
hass.services.register(DOMAIN, SERVICE_REFRESH_STATES, force_update)
|
||||
|
||||
hass.services.register(DOMAIN, SERVICE_REFRESH_STATES, force_update,
|
||||
descriptions.get(SERVICE_REFRESH_STATES))
|
||||
|
||||
def pull_new_devices(call):
|
||||
"""Pull new devices added to users Wink account since startup."""
|
||||
|
@ -341,12 +373,71 @@ def setup(hass, config):
|
|||
for _component in WINK_COMPONENTS:
|
||||
discovery.load_platform(hass, _component, DOMAIN, {}, config)
|
||||
|
||||
hass.services.register(DOMAIN, SERVICE_ADD_NEW_DEVICES, pull_new_devices)
|
||||
hass.services.register(DOMAIN, SERVICE_ADD_NEW_DEVICES, pull_new_devices,
|
||||
descriptions.get(SERVICE_ADD_NEW_DEVICES))
|
||||
|
||||
def set_pairing_mode(call):
|
||||
"""Put the hub in provided pairing mode."""
|
||||
hub_name = call.data.get('hub_name')
|
||||
pairing_mode = call.data.get('pairing_mode')
|
||||
kidde_code = call.data.get('kidde_radio_code')
|
||||
for hub in WINK_HUBS:
|
||||
if hub.name() == hub_name:
|
||||
hub.pair_new_device(pairing_mode,
|
||||
kidde_radio_code=kidde_code)
|
||||
|
||||
def rename_device(call):
|
||||
"""Set specified device's name."""
|
||||
# This should only be called on one device at a time.
|
||||
found_device = None
|
||||
entity_id = call.data.get('entity_id')[0]
|
||||
all_devices = []
|
||||
for list_of_devices in hass.data[DOMAIN]['entities'].values():
|
||||
all_devices += list_of_devices
|
||||
for device in all_devices:
|
||||
if device.entity_id == entity_id:
|
||||
found_device = device
|
||||
if found_device is not None:
|
||||
name = call.data.get('name')
|
||||
found_device.wink.set_name(name)
|
||||
|
||||
hass.services.register(DOMAIN, SERVICE_RENAME_DEVICE, rename_device,
|
||||
descriptions.get(SERVICE_RENAME_DEVICE),
|
||||
schema=RENAME_DEVICE_SCHEMA)
|
||||
|
||||
def delete_device(call):
|
||||
"""Delete specified device."""
|
||||
# This should only be called on one device at a time.
|
||||
found_device = None
|
||||
entity_id = call.data.get('entity_id')[0]
|
||||
all_devices = []
|
||||
for list_of_devices in hass.data[DOMAIN]['entities'].values():
|
||||
all_devices += list_of_devices
|
||||
for device in all_devices:
|
||||
if device.entity_id == entity_id:
|
||||
found_device = device
|
||||
if found_device is not None:
|
||||
found_device.wink.remove_device()
|
||||
|
||||
hass.services.register(DOMAIN, SERVICE_DELETE_DEVICE, delete_device,
|
||||
descriptions.get(SERVICE_DELETE_DEVICE),
|
||||
schema=DELETE_DEVICE_SCHEMA)
|
||||
|
||||
hubs = pywink.get_hubs()
|
||||
for hub in hubs:
|
||||
if hub.device_manufacturer() == 'wink':
|
||||
WINK_HUBS.append(hub)
|
||||
|
||||
if WINK_HUBS:
|
||||
hass.services.register(
|
||||
DOMAIN, SERVICE_SET_PAIRING_MODE, set_pairing_mode,
|
||||
descriptions.get(SERVICE_SET_PAIRING_MODE),
|
||||
schema=SET_PAIRING_MODE_SCHEMA)
|
||||
|
||||
# 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)
|
||||
for wink_component in WINK_COMPONENTS:
|
||||
hass.data[DOMAIN]['entities'][wink_component] = []
|
||||
discovery.load_platform(hass, wink_component, DOMAIN, {}, config)
|
||||
|
||||
return True
|
||||
|
||||
|
|
|
@ -807,7 +807,7 @@ python-velbus==2.0.11
|
|||
python-vlc==1.1.2
|
||||
|
||||
# homeassistant.components.wink
|
||||
python-wink==1.5.1
|
||||
python-wink==1.6.0
|
||||
|
||||
# homeassistant.components.sensor.swiss_public_transport
|
||||
python_opendata_transport==0.0.2
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue