Remove deprecated Wink integration (#57634)
parent
b54fc0229d
commit
45f3eb6991
|
@ -1191,7 +1191,6 @@ omit =
|
|||
homeassistant/components/webostv/*
|
||||
homeassistant/components/whois/sensor.py
|
||||
homeassistant/components/wiffi/*
|
||||
homeassistant/components/wink/*
|
||||
homeassistant/components/wirelesstag/*
|
||||
homeassistant/components/wolflink/__init__.py
|
||||
homeassistant/components/wolflink/sensor.py
|
||||
|
|
|
@ -38,7 +38,6 @@ SERVICE_SAMSUNG_PRINTER = "samsung_printer"
|
|||
SERVICE_TELLDUSLIVE = "tellstick"
|
||||
SERVICE_YEELIGHT = "yeelight"
|
||||
SERVICE_WEMO = "belkin_wemo"
|
||||
SERVICE_WINK = "wink"
|
||||
SERVICE_XIAOMI_GW = "xiaomi_gw"
|
||||
|
||||
# These have custom protocols
|
||||
|
@ -94,7 +93,6 @@ MIGRATED_SERVICE_HANDLERS = [
|
|||
"sonos",
|
||||
"songpal",
|
||||
SERVICE_WEMO,
|
||||
SERVICE_WINK,
|
||||
SERVICE_XIAOMI_GW,
|
||||
"volumio",
|
||||
SERVICE_YEELIGHT,
|
||||
|
|
|
@ -1,971 +0,0 @@
|
|||
"""Support for Wink hubs."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
from aiohttp.web import Response
|
||||
from pubnubsubhandler import PubNubSubscriptionHandler
|
||||
import pywink
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.http import HomeAssistantView
|
||||
from homeassistant.const import (
|
||||
ATTR_BATTERY_LEVEL,
|
||||
ATTR_NAME,
|
||||
CONF_CLIENT_ID,
|
||||
CONF_CLIENT_SECRET,
|
||||
CONF_EMAIL,
|
||||
CONF_PASSWORD,
|
||||
EVENT_HOMEASSISTANT_START,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
__version__,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers import discovery
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.config_validation import make_entity_service_schema
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.helpers.event import track_time_interval
|
||||
from homeassistant.helpers.network import get_url
|
||||
from homeassistant.util.json import load_json, save_json
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DOMAIN = "wink"
|
||||
|
||||
SUBSCRIPTION_HANDLER = None
|
||||
|
||||
CONF_USER_AGENT = "user_agent"
|
||||
CONF_OAUTH = "oauth"
|
||||
CONF_LOCAL_CONTROL = "local_control"
|
||||
CONF_MISSING_OAUTH_MSG = "Missing oauth2 credentials."
|
||||
|
||||
ATTR_ACCESS_TOKEN = "access_token"
|
||||
ATTR_REFRESH_TOKEN = "refresh_token"
|
||||
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"
|
||||
WINK_CONFIG_FILE = ".wink.conf"
|
||||
USER_AGENT = f"Manufacturer/Home-Assistant{__version__} python/3 Wink/3"
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
CONF_CLIENT_ID: "CLIENT_ID_HERE",
|
||||
CONF_CLIENT_SECRET: "CLIENT_SECRET_HERE",
|
||||
}
|
||||
|
||||
SERVICE_ADD_NEW_DEVICES = "pull_newly_added_devices_from_wink"
|
||||
SERVICE_REFRESH_STATES = "refresh_state_from_wink"
|
||||
SERVICE_RENAME_DEVICE = "rename_wink_device"
|
||||
SERVICE_DELETE_DEVICE = "delete_wink_device"
|
||||
SERVICE_SET_PAIRING_MODE = "pair_new_device"
|
||||
SERVICE_SET_CHIME_VOLUME = "set_chime_volume"
|
||||
SERVICE_SET_SIREN_VOLUME = "set_siren_volume"
|
||||
SERVICE_ENABLE_CHIME = "enable_chime"
|
||||
SERVICE_SET_SIREN_TONE = "set_siren_tone"
|
||||
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",
|
||||
"william_tell",
|
||||
"rondo_alla_turca",
|
||||
"police_siren",
|
||||
"evacuation",
|
||||
"beep_beep",
|
||||
"beep",
|
||||
]
|
||||
CHIME_TONES = TONES + ["inactive"]
|
||||
AUTO_SHUTOFF_TIMES = [None, -1, 30, 60, 120]
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
vol.All(
|
||||
cv.deprecated(DOMAIN),
|
||||
{
|
||||
DOMAIN: vol.Schema(
|
||||
{
|
||||
vol.Inclusive(
|
||||
CONF_EMAIL, CONF_OAUTH, msg=CONF_MISSING_OAUTH_MSG
|
||||
): cv.string,
|
||||
vol.Inclusive(
|
||||
CONF_PASSWORD, CONF_OAUTH, msg=CONF_MISSING_OAUTH_MSG
|
||||
): cv.string,
|
||||
vol.Inclusive(
|
||||
CONF_CLIENT_ID, CONF_OAUTH, msg=CONF_MISSING_OAUTH_MSG
|
||||
): cv.string,
|
||||
vol.Inclusive(
|
||||
CONF_CLIENT_SECRET, CONF_OAUTH, msg=CONF_MISSING_OAUTH_MSG
|
||||
): cv.string,
|
||||
vol.Optional(CONF_LOCAL_CONTROL, default=False): cv.boolean,
|
||||
}
|
||||
),
|
||||
},
|
||||
),
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
RENAME_DEVICE_SCHEMA = make_entity_service_schema(
|
||||
{vol.Required(ATTR_NAME): cv.string}, extra=vol.ALLOW_EXTRA
|
||||
)
|
||||
|
||||
DELETE_DEVICE_SCHEMA = make_entity_service_schema({}, 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,
|
||||
)
|
||||
|
||||
SET_VOLUME_SCHEMA = make_entity_service_schema(
|
||||
{vol.Required(ATTR_VOLUME): vol.In(VOLUMES)}
|
||||
)
|
||||
|
||||
SET_SIREN_TONE_SCHEMA = make_entity_service_schema(
|
||||
{vol.Required(ATTR_TONE): vol.In(TONES)}
|
||||
)
|
||||
|
||||
SET_CHIME_MODE_SCHEMA = make_entity_service_schema(
|
||||
{vol.Required(ATTR_TONE): vol.In(CHIME_TONES)}
|
||||
)
|
||||
|
||||
SET_AUTO_SHUTOFF_SCHEMA = make_entity_service_schema(
|
||||
{vol.Required(ATTR_AUTO_SHUTOFF): vol.In(AUTO_SHUTOFF_TIMES)}
|
||||
)
|
||||
|
||||
SET_STROBE_ENABLED_SCHEMA = make_entity_service_schema(
|
||||
{vol.Required(ATTR_ENABLED): cv.boolean}
|
||||
)
|
||||
|
||||
ENABLED_SIREN_SCHEMA = make_entity_service_schema(
|
||||
{vol.Required(ATTR_ENABLED): cv.boolean}
|
||||
)
|
||||
|
||||
DIAL_CONFIG_SCHEMA = make_entity_service_schema(
|
||||
{
|
||||
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 = make_entity_service_schema(
|
||||
{
|
||||
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",
|
||||
"water_heater",
|
||||
]
|
||||
|
||||
WINK_HUBS: list[Any] = []
|
||||
|
||||
|
||||
def _request_app_setup(hass, config):
|
||||
"""Assist user with configuring the Wink dev application."""
|
||||
hass.data[DOMAIN]["configurator"] = True
|
||||
configurator = hass.components.configurator
|
||||
|
||||
def wink_configuration_callback(callback_data):
|
||||
"""Handle configuration updates."""
|
||||
_config_path = hass.config.path(WINK_CONFIG_FILE)
|
||||
if not os.path.isfile(_config_path):
|
||||
setup(hass, config)
|
||||
return
|
||||
|
||||
client_id = callback_data.get(CONF_CLIENT_ID).strip()
|
||||
client_secret = callback_data.get(CONF_CLIENT_SECRET).strip()
|
||||
if None not in (client_id, client_secret):
|
||||
save_json(
|
||||
_config_path,
|
||||
{CONF_CLIENT_ID: client_id, CONF_CLIENT_SECRET: client_secret},
|
||||
)
|
||||
setup(hass, config)
|
||||
return
|
||||
error_msg = "Your input was invalid. Please try again."
|
||||
_configurator = hass.data[DOMAIN]["configuring"][DOMAIN]
|
||||
configurator.notify_errors(_configurator, error_msg)
|
||||
|
||||
start_url = f"{get_url(hass)}{WINK_AUTH_CALLBACK_PATH}"
|
||||
|
||||
description = f"""Please create a Wink developer app at
|
||||
https://developer.wink.com.
|
||||
Add a Redirect URI of {start_url}.
|
||||
They will provide you a Client ID and secret
|
||||
after reviewing your request.
|
||||
(This can take several days).
|
||||
"""
|
||||
|
||||
hass.data[DOMAIN]["configuring"][DOMAIN] = configurator.request_config(
|
||||
DOMAIN,
|
||||
wink_configuration_callback,
|
||||
description=description,
|
||||
submit_caption="submit",
|
||||
description_image="/static/images/config_wink.png",
|
||||
fields=[
|
||||
{"id": CONF_CLIENT_ID, "name": "Client ID", "type": "string"},
|
||||
{"id": CONF_CLIENT_SECRET, "name": "Client secret", "type": "string"},
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def _request_oauth_completion(hass, config):
|
||||
"""Request user complete Wink OAuth2 flow."""
|
||||
hass.data[DOMAIN]["configurator"] = True
|
||||
configurator = hass.components.configurator
|
||||
if DOMAIN in hass.data[DOMAIN]["configuring"]:
|
||||
configurator.notify_errors(
|
||||
hass.data[DOMAIN]["configuring"][DOMAIN],
|
||||
"Failed to register, please try again.",
|
||||
)
|
||||
return
|
||||
|
||||
def wink_configuration_callback(callback_data):
|
||||
"""Call setup again."""
|
||||
setup(hass, config)
|
||||
|
||||
start_url = f"{get_url(hass)}{WINK_AUTH_START}"
|
||||
|
||||
description = f"Please authorize Wink by visiting {start_url}"
|
||||
|
||||
hass.data[DOMAIN]["configuring"][DOMAIN] = configurator.request_config(
|
||||
DOMAIN, wink_configuration_callback, description=description
|
||||
)
|
||||
|
||||
|
||||
def setup(hass, config): # noqa: C901
|
||||
"""Set up the Wink component."""
|
||||
_LOGGER.warning(
|
||||
"The Wink integration has been deprecated and is pending removal in "
|
||||
"Home Assistant Core 2021.11"
|
||||
)
|
||||
|
||||
if hass.data.get(DOMAIN) is None:
|
||||
hass.data[DOMAIN] = {
|
||||
"unique_ids": [],
|
||||
"entities": {},
|
||||
"oauth": {},
|
||||
"configuring": {},
|
||||
"pubnub": None,
|
||||
"configurator": False,
|
||||
}
|
||||
|
||||
if config.get(DOMAIN) is not None:
|
||||
client_id = config[DOMAIN].get(CONF_CLIENT_ID)
|
||||
client_secret = config[DOMAIN].get(CONF_CLIENT_SECRET)
|
||||
email = config[DOMAIN].get(CONF_EMAIL)
|
||||
password = config[DOMAIN].get(CONF_PASSWORD)
|
||||
local_control = config[DOMAIN].get(CONF_LOCAL_CONTROL)
|
||||
else:
|
||||
client_id = None
|
||||
client_secret = None
|
||||
email = None
|
||||
password = None
|
||||
local_control = None
|
||||
hass.data[DOMAIN]["configurator"] = True
|
||||
if None not in [client_id, client_secret]:
|
||||
_LOGGER.info("Using legacy OAuth authentication")
|
||||
if not local_control:
|
||||
pywink.disable_local_control()
|
||||
hass.data[DOMAIN]["oauth"][CONF_CLIENT_ID] = client_id
|
||||
hass.data[DOMAIN]["oauth"][CONF_CLIENT_SECRET] = client_secret
|
||||
hass.data[DOMAIN]["oauth"]["email"] = email
|
||||
hass.data[DOMAIN]["oauth"]["password"] = password
|
||||
pywink.legacy_set_wink_credentials(email, password, client_id, client_secret)
|
||||
else:
|
||||
_LOGGER.info("Using OAuth authentication")
|
||||
if not local_control:
|
||||
pywink.disable_local_control()
|
||||
config_path = hass.config.path(WINK_CONFIG_FILE)
|
||||
if os.path.isfile(config_path):
|
||||
config_file = load_json(config_path)
|
||||
if config_file == DEFAULT_CONFIG:
|
||||
_request_app_setup(hass, config)
|
||||
return True
|
||||
# else move on because the user modified the file
|
||||
else:
|
||||
save_json(config_path, DEFAULT_CONFIG)
|
||||
_request_app_setup(hass, config)
|
||||
return True
|
||||
|
||||
if DOMAIN in hass.data[DOMAIN]["configuring"]:
|
||||
_configurator = hass.data[DOMAIN]["configuring"]
|
||||
hass.components.configurator.request_done(_configurator.pop(DOMAIN))
|
||||
|
||||
# Using oauth
|
||||
access_token = config_file.get(ATTR_ACCESS_TOKEN)
|
||||
refresh_token = config_file.get(ATTR_REFRESH_TOKEN)
|
||||
|
||||
# This will be called after authorizing Home-Assistant
|
||||
if None not in (access_token, refresh_token):
|
||||
pywink.set_wink_credentials(
|
||||
config_file.get(CONF_CLIENT_ID),
|
||||
config_file.get(CONF_CLIENT_SECRET),
|
||||
access_token=access_token,
|
||||
refresh_token=refresh_token,
|
||||
)
|
||||
# This is called to create the redirect so the user can Authorize
|
||||
# Home .
|
||||
else:
|
||||
|
||||
redirect_uri = f"{get_url(hass)}{WINK_AUTH_CALLBACK_PATH}"
|
||||
|
||||
wink_auth_start_url = pywink.get_authorization_url(
|
||||
config_file.get(CONF_CLIENT_ID), redirect_uri
|
||||
)
|
||||
hass.http.register_redirect(WINK_AUTH_START, wink_auth_start_url)
|
||||
hass.http.register_view(
|
||||
WinkAuthCallbackView(config, config_file, pywink.request_token)
|
||||
)
|
||||
_request_oauth_completion(hass, config)
|
||||
return True
|
||||
|
||||
pywink.set_user_agent(USER_AGENT)
|
||||
sub_details = pywink.get_subscription_details()
|
||||
hass.data[DOMAIN]["pubnub"] = PubNubSubscriptionHandler(
|
||||
sub_details[0], origin=sub_details[1]
|
||||
)
|
||||
|
||||
def _subscribe():
|
||||
hass.data[DOMAIN]["pubnub"].subscribe()
|
||||
|
||||
# Call subscribe after the user sets up wink via the configurator
|
||||
# All other methods will complete setup before
|
||||
# EVENT_HOMEASSISTANT_START is called meaning they
|
||||
# will call subscribe via the method below. (start_subscription)
|
||||
if hass.data[DOMAIN]["configurator"]:
|
||||
_subscribe()
|
||||
|
||||
def keep_alive_call(event_time):
|
||||
"""Call the Wink API endpoints to keep PubNub working."""
|
||||
_LOGGER.info("Polling the Wink API to keep PubNub updates flowing")
|
||||
pywink.set_user_agent(str(int(time.time())))
|
||||
_temp_response = pywink.get_user()
|
||||
_LOGGER.debug(str(json.dumps(_temp_response)))
|
||||
time.sleep(1)
|
||||
pywink.set_user_agent(USER_AGENT)
|
||||
_temp_response = pywink.wink_api_fetch()
|
||||
_LOGGER.debug("%s", _temp_response)
|
||||
_temp_response = pywink.post_session()
|
||||
_LOGGER.debug("%s", _temp_response)
|
||||
|
||||
# Call the Wink API every hour to keep PubNub updates flowing
|
||||
track_time_interval(hass, keep_alive_call, timedelta(minutes=60))
|
||||
|
||||
def start_subscription(event):
|
||||
"""Start the PubNub subscription."""
|
||||
_subscribe()
|
||||
|
||||
hass.bus.listen(EVENT_HOMEASSISTANT_START, start_subscription)
|
||||
|
||||
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)
|
||||
|
||||
def save_credentials(event):
|
||||
"""Save currently set OAuth credentials."""
|
||||
if hass.data[DOMAIN]["oauth"].get("email") is None:
|
||||
config_path = hass.config.path(WINK_CONFIG_FILE)
|
||||
_config = pywink.get_current_oauth_credentials()
|
||||
save_json(config_path, _config)
|
||||
|
||||
hass.bus.listen(EVENT_HOMEASSISTANT_STOP, save_credentials)
|
||||
|
||||
# Save the users potentially updated oauth credentials at a regular
|
||||
# interval to prevent them from being expired after a HA reboot.
|
||||
track_time_interval(hass, save_credentials, timedelta(minutes=60))
|
||||
|
||||
def force_update(call):
|
||||
"""Force all devices to poll the Wink API."""
|
||||
_LOGGER.info("Refreshing Wink states from API")
|
||||
for entity_list in hass.data[DOMAIN]["entities"].values():
|
||||
# Throttle the calls to Wink API
|
||||
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):
|
||||
"""Pull new devices added to users Wink account since startup."""
|
||||
_LOGGER.info("Getting new devices from Wink API")
|
||||
for _component in WINK_COMPONENTS:
|
||||
discovery.load_platform(hass, _component, DOMAIN, {}, config)
|
||||
|
||||
hass.services.register(DOMAIN, SERVICE_ADD_NEW_DEVICES, pull_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, 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, 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,
|
||||
schema=SET_PAIRING_MODE_SCHEMA,
|
||||
)
|
||||
|
||||
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"]:
|
||||
if isinstance(switch, WinkSirenDevice):
|
||||
all_sirens.append(switch)
|
||||
sirens_to_set = []
|
||||
if entity_ids is None:
|
||||
sirens_to_set = all_sirens
|
||||
else:
|
||||
for siren in all_sirens:
|
||||
if siren.entity_id in entity_ids:
|
||||
sirens_to_set.append(siren)
|
||||
|
||||
for siren in sirens_to_set:
|
||||
_man = siren.wink.device_manufacturer()
|
||||
if (
|
||||
service.service != SERVICE_SET_AUTO_SHUTOFF
|
||||
and service.service != SERVICE_ENABLE_SIREN
|
||||
and _man not in ("dome", "wink")
|
||||
):
|
||||
_LOGGER.error("Service only valid for Dome or Wink sirens")
|
||||
return
|
||||
|
||||
if service.service == SERVICE_ENABLE_SIREN:
|
||||
siren.wink.set_state(service.data.get(ATTR_ENABLED))
|
||||
elif service.service == SERVICE_SET_AUTO_SHUTOFF:
|
||||
siren.wink.set_auto_shutoff(service.data.get(ATTR_AUTO_SHUTOFF))
|
||||
elif service.service == SERVICE_SET_CHIME_VOLUME:
|
||||
siren.wink.set_chime_volume(service.data.get(ATTR_VOLUME))
|
||||
elif service.service == SERVICE_SET_SIREN_VOLUME:
|
||||
siren.wink.set_siren_volume(service.data.get(ATTR_VOLUME))
|
||||
elif service.service == SERVICE_SET_SIREN_TONE:
|
||||
siren.wink.set_siren_sound(service.data.get(ATTR_TONE))
|
||||
elif service.service == SERVICE_ENABLE_CHIME:
|
||||
siren.wink.set_chime(service.data.get(ATTR_TONE))
|
||||
elif service.service == SERVICE_SIREN_STROBE_ENABLED:
|
||||
siren.wink.set_siren_strobe_enabled(service.data.get(ATTR_ENABLED))
|
||||
elif service.service == SERVICE_CHIME_STROBE_ENABLED:
|
||||
siren.wink.set_chime_strobe_enabled(service.data.get(ATTR_ENABLED))
|
||||
|
||||
# Load components for the devices in Wink that we support
|
||||
for wink_component in WINK_COMPONENTS:
|
||||
hass.data[DOMAIN]["entities"][wink_component] = []
|
||||
discovery.load_platform(hass, wink_component, DOMAIN, {}, config)
|
||||
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
sirens = []
|
||||
has_dome_or_wink_siren = False
|
||||
for siren in pywink.get_sirens():
|
||||
_man = siren.device_manufacturer()
|
||||
if _man in ("dome", "wink"):
|
||||
has_dome_or_wink_siren = True
|
||||
_id = siren.object_id() + siren.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
sirens.append(WinkSirenDevice(siren, hass))
|
||||
|
||||
if sirens:
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN,
|
||||
SERVICE_SET_AUTO_SHUTOFF,
|
||||
siren_service_handle,
|
||||
schema=SET_AUTO_SHUTOFF_SCHEMA,
|
||||
)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN,
|
||||
SERVICE_ENABLE_SIREN,
|
||||
siren_service_handle,
|
||||
schema=ENABLED_SIREN_SCHEMA,
|
||||
)
|
||||
|
||||
if has_dome_or_wink_siren:
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN,
|
||||
SERVICE_SET_SIREN_TONE,
|
||||
siren_service_handle,
|
||||
schema=SET_SIREN_TONE_SCHEMA,
|
||||
)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN,
|
||||
SERVICE_ENABLE_CHIME,
|
||||
siren_service_handle,
|
||||
schema=SET_CHIME_MODE_SCHEMA,
|
||||
)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN,
|
||||
SERVICE_SET_SIREN_VOLUME,
|
||||
siren_service_handle,
|
||||
schema=SET_VOLUME_SCHEMA,
|
||||
)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN,
|
||||
SERVICE_SET_CHIME_VOLUME,
|
||||
siren_service_handle,
|
||||
schema=SET_VOLUME_SCHEMA,
|
||||
)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN,
|
||||
SERVICE_SIREN_STROBE_ENABLED,
|
||||
siren_service_handle,
|
||||
schema=SET_STROBE_ENABLED_SCHEMA,
|
||||
)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN,
|
||||
SERVICE_CHIME_STROBE_ENABLED,
|
||||
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
|
||||
|
||||
|
||||
class WinkAuthCallbackView(HomeAssistantView):
|
||||
"""Handle OAuth finish callback requests."""
|
||||
|
||||
url = "/auth/wink/callback"
|
||||
name = "auth:wink:callback"
|
||||
requires_auth = False
|
||||
|
||||
def __init__(self, config, config_file, request_token):
|
||||
"""Initialize the OAuth callback view."""
|
||||
self.config = config
|
||||
self.config_file = config_file
|
||||
self.request_token = request_token
|
||||
|
||||
@callback
|
||||
def get(self, request):
|
||||
"""Finish OAuth callback request."""
|
||||
hass = request.app["hass"]
|
||||
data = request.query
|
||||
|
||||
response_message = """Wink has been successfully authorized!
|
||||
You can close this window now! For the best results you should reboot
|
||||
Home Assistant"""
|
||||
html_response = """<html><head><title>Wink Auth</title></head>
|
||||
<body><h1>{}</h1></body></html>"""
|
||||
|
||||
if data.get("code") is not None:
|
||||
response = self.request_token(
|
||||
data.get("code"), self.config_file[CONF_CLIENT_SECRET]
|
||||
)
|
||||
|
||||
config_contents = {
|
||||
ATTR_ACCESS_TOKEN: response["access_token"],
|
||||
ATTR_REFRESH_TOKEN: response["refresh_token"],
|
||||
CONF_CLIENT_ID: self.config_file[CONF_CLIENT_ID],
|
||||
CONF_CLIENT_SECRET: self.config_file[CONF_CLIENT_SECRET],
|
||||
}
|
||||
save_json(hass.config.path(WINK_CONFIG_FILE), config_contents)
|
||||
|
||||
hass.async_add_job(setup, hass, self.config)
|
||||
|
||||
return Response(
|
||||
text=html_response.format(response_message), content_type="text/html"
|
||||
)
|
||||
|
||||
error_msg = "No code returned from Wink API"
|
||||
_LOGGER.error(error_msg)
|
||||
return Response(text=html_response.format(error_msg), content_type="text/html")
|
||||
|
||||
|
||||
class WinkDevice(Entity):
|
||||
"""Representation a base Wink device."""
|
||||
|
||||
def __init__(self, wink, hass):
|
||||
"""Initialize the Wink device."""
|
||||
self.hass = hass
|
||||
self.wink = wink
|
||||
hass.data[DOMAIN]["pubnub"].add_subscription(
|
||||
self.wink.pubnub_channel, self._pubnub_update
|
||||
)
|
||||
hass.data[DOMAIN]["unique_ids"].append(self.wink.object_id() + self.wink.name())
|
||||
|
||||
def _pubnub_update(self, message):
|
||||
_LOGGER.debug(message)
|
||||
try:
|
||||
if message is None:
|
||||
_LOGGER.error(
|
||||
"Error on pubnub update for %s polling API for current state",
|
||||
self.name,
|
||||
)
|
||||
self.schedule_update_ha_state(True)
|
||||
else:
|
||||
self.wink.pubnub_update(message)
|
||||
self.schedule_update_ha_state()
|
||||
except (ValueError, KeyError, AttributeError):
|
||||
_LOGGER.error(
|
||||
"Error in pubnub JSON for %s polling API for current state", self.name
|
||||
)
|
||||
self.schedule_update_ha_state(True)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the device."""
|
||||
return self.wink.name()
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the unique id of the Wink device."""
|
||||
if hasattr(self.wink, "capability") and self.wink.capability() is not None:
|
||||
return f"{self.wink.object_id()}_{self.wink.capability()}"
|
||||
return self.wink.object_id()
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
"""Return true if connection == True."""
|
||||
return self.wink.available()
|
||||
|
||||
def update(self):
|
||||
"""Update state of the device."""
|
||||
self.wink.update_state()
|
||||
|
||||
@property
|
||||
def should_poll(self):
|
||||
"""Only poll if we are not subscribed to pubnub."""
|
||||
return self.wink.pubnub_channel is None
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
attributes = {}
|
||||
battery = self._battery_level
|
||||
if battery:
|
||||
attributes[ATTR_BATTERY_LEVEL] = battery
|
||||
man_dev_model = self._manufacturer_device_model
|
||||
if man_dev_model:
|
||||
attributes["manufacturer_device_model"] = man_dev_model
|
||||
man_dev_id = self._manufacturer_device_id
|
||||
if man_dev_id:
|
||||
attributes["manufacturer_device_id"] = man_dev_id
|
||||
dev_man = self._device_manufacturer
|
||||
if dev_man:
|
||||
attributes["device_manufacturer"] = dev_man
|
||||
model_name = self._model_name
|
||||
if model_name:
|
||||
attributes["model_name"] = model_name
|
||||
tamper = self._tamper
|
||||
if tamper is not None:
|
||||
attributes["tamper_detected"] = tamper
|
||||
return attributes
|
||||
|
||||
@property
|
||||
def _battery_level(self):
|
||||
"""Return the battery level."""
|
||||
if self.wink.battery_level() is not None:
|
||||
return self.wink.battery_level() * 100
|
||||
|
||||
@property
|
||||
def _manufacturer_device_model(self):
|
||||
"""Return the manufacturer device model."""
|
||||
return self.wink.manufacturer_device_model()
|
||||
|
||||
@property
|
||||
def _manufacturer_device_id(self):
|
||||
"""Return the manufacturer device id."""
|
||||
return self.wink.manufacturer_device_id()
|
||||
|
||||
@property
|
||||
def _device_manufacturer(self):
|
||||
"""Return the device manufacturer."""
|
||||
return self.wink.device_manufacturer()
|
||||
|
||||
@property
|
||||
def _model_name(self):
|
||||
"""Return the model name."""
|
||||
return self.wink.model_name()
|
||||
|
||||
@property
|
||||
def _tamper(self):
|
||||
"""Return the devices tamper status."""
|
||||
if hasattr(self.wink, "tamper_detected"):
|
||||
return self.wink.tamper_detected()
|
||||
return None
|
||||
|
||||
|
||||
class WinkSirenDevice(WinkDevice):
|
||||
"""Representation of a Wink siren device."""
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self.hass.data[DOMAIN]["entities"]["switch"].append(self)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return sirens state."""
|
||||
if self.wink.state():
|
||||
return STATE_ON
|
||||
return STATE_OFF
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
"""Return the icon to use in the frontend, if any."""
|
||||
return "mdi:bell-ring"
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the device state attributes."""
|
||||
attributes = super().extra_state_attributes
|
||||
|
||||
auto_shutoff = self.wink.auto_shutoff()
|
||||
if auto_shutoff is not None:
|
||||
attributes["auto_shutoff"] = auto_shutoff
|
||||
|
||||
siren_volume = self.wink.siren_volume()
|
||||
if siren_volume is not None:
|
||||
attributes["siren_volume"] = siren_volume
|
||||
|
||||
chime_volume = self.wink.chime_volume()
|
||||
if chime_volume is not None:
|
||||
attributes["chime_volume"] = chime_volume
|
||||
|
||||
strobe_enabled = self.wink.strobe_enabled()
|
||||
if strobe_enabled is not None:
|
||||
attributes["siren_strobe_enabled"] = strobe_enabled
|
||||
|
||||
chime_strobe_enabled = self.wink.chime_strobe_enabled()
|
||||
if chime_strobe_enabled is not None:
|
||||
attributes["chime_strobe_enabled"] = chime_strobe_enabled
|
||||
|
||||
siren_sound = self.wink.siren_sound()
|
||||
if siren_sound is not None:
|
||||
attributes["siren_sound"] = siren_sound
|
||||
|
||||
chime_mode = self.wink.chime_mode()
|
||||
if chime_mode is not None:
|
||||
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
|
||||
|
||||
async 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 f"{self.parent.name()} dial {self.wink.index() + 1}"
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the device state attributes."""
|
||||
attributes = super().extra_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,
|
||||
)
|
|
@ -1,75 +0,0 @@
|
|||
"""Support Wink alarm control panels."""
|
||||
import pywink
|
||||
|
||||
import homeassistant.components.alarm_control_panel as alarm
|
||||
from homeassistant.components.alarm_control_panel.const import (
|
||||
SUPPORT_ALARM_ARM_AWAY,
|
||||
SUPPORT_ALARM_ARM_HOME,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
STATE_ALARM_ARMED_AWAY,
|
||||
STATE_ALARM_ARMED_HOME,
|
||||
STATE_ALARM_DISARMED,
|
||||
)
|
||||
|
||||
from . import DOMAIN, WinkDevice
|
||||
|
||||
STATE_ALARM_PRIVACY = "Private"
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Wink platform."""
|
||||
|
||||
for camera in pywink.get_cameras():
|
||||
# get_cameras returns multiple device types.
|
||||
# Only add those that aren't sensors.
|
||||
try:
|
||||
camera.capability()
|
||||
except AttributeError:
|
||||
_id = camera.object_id() + camera.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkCameraDevice(camera, hass)])
|
||||
|
||||
|
||||
class WinkCameraDevice(WinkDevice, alarm.AlarmControlPanelEntity):
|
||||
"""Representation a Wink camera alarm."""
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call 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."""
|
||||
wink_state = self.wink.state()
|
||||
if wink_state == "away":
|
||||
state = STATE_ALARM_ARMED_AWAY
|
||||
elif wink_state == "home":
|
||||
state = STATE_ALARM_DISARMED
|
||||
elif wink_state == "night":
|
||||
state = STATE_ALARM_ARMED_HOME
|
||||
else:
|
||||
state = None
|
||||
return state
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int:
|
||||
"""Return the list of supported features."""
|
||||
return SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY
|
||||
|
||||
def alarm_disarm(self, code=None):
|
||||
"""Send disarm command."""
|
||||
self.wink.set_mode("home")
|
||||
|
||||
def alarm_arm_home(self, code=None):
|
||||
"""Send arm home command."""
|
||||
self.wink.set_mode("night")
|
||||
|
||||
def alarm_arm_away(self, code=None):
|
||||
"""Send arm away command."""
|
||||
self.wink.set_mode("away")
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
return {"private": self.wink.private()}
|
|
@ -1,197 +0,0 @@
|
|||
"""Support for Wink binary sensors."""
|
||||
import logging
|
||||
|
||||
import pywink
|
||||
|
||||
from homeassistant.components.binary_sensor import (
|
||||
DEVICE_CLASS_MOISTURE,
|
||||
DEVICE_CLASS_MOTION,
|
||||
DEVICE_CLASS_OCCUPANCY,
|
||||
DEVICE_CLASS_OPENING,
|
||||
DEVICE_CLASS_SMOKE,
|
||||
DEVICE_CLASS_SOUND,
|
||||
DEVICE_CLASS_VIBRATION,
|
||||
BinarySensorEntity,
|
||||
)
|
||||
|
||||
from . import DOMAIN, WinkDevice
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# These are the available sensors mapped to binary_sensor class
|
||||
SENSOR_TYPES = {
|
||||
"brightness": "light",
|
||||
"capturing_audio": DEVICE_CLASS_SOUND,
|
||||
"capturing_video": None,
|
||||
"co_detected": "gas",
|
||||
"liquid_detected": DEVICE_CLASS_MOISTURE,
|
||||
"loudness": DEVICE_CLASS_SOUND,
|
||||
"motion": DEVICE_CLASS_MOTION,
|
||||
"noise": DEVICE_CLASS_SOUND,
|
||||
"opened": DEVICE_CLASS_OPENING,
|
||||
"presence": DEVICE_CLASS_OCCUPANCY,
|
||||
"smoke_detected": DEVICE_CLASS_SMOKE,
|
||||
"vibration": DEVICE_CLASS_VIBRATION,
|
||||
}
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Wink binary sensor platform."""
|
||||
|
||||
for sensor in pywink.get_sensors():
|
||||
_id = sensor.object_id() + sensor.name()
|
||||
if (
|
||||
_id not in hass.data[DOMAIN]["unique_ids"]
|
||||
and sensor.capability() in SENSOR_TYPES
|
||||
):
|
||||
add_entities([WinkBinarySensorEntity(sensor, hass)])
|
||||
|
||||
for key in pywink.get_keys():
|
||||
_id = key.object_id() + key.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkBinarySensorEntity(key, hass)])
|
||||
|
||||
for sensor in pywink.get_smoke_and_co_detectors():
|
||||
_id = sensor.object_id() + sensor.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkSmokeDetector(sensor, hass)])
|
||||
|
||||
for hub in pywink.get_hubs():
|
||||
_id = hub.object_id() + hub.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkHub(hub, hass)])
|
||||
|
||||
for remote in pywink.get_remotes():
|
||||
_id = remote.object_id() + remote.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkRemote(remote, hass)])
|
||||
|
||||
for button in pywink.get_buttons():
|
||||
_id = button.object_id() + button.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkButton(button, hass)])
|
||||
|
||||
for gang in pywink.get_gangs():
|
||||
_id = gang.object_id() + gang.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkGang(gang, hass)])
|
||||
|
||||
for door_bell_sensor in pywink.get_door_bells():
|
||||
_id = door_bell_sensor.object_id() + door_bell_sensor.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkBinarySensorEntity(door_bell_sensor, hass)])
|
||||
|
||||
for camera_sensor in pywink.get_cameras():
|
||||
_id = camera_sensor.object_id() + camera_sensor.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
try:
|
||||
if camera_sensor.capability() in SENSOR_TYPES:
|
||||
add_entities([WinkBinarySensorEntity(camera_sensor, hass)])
|
||||
except AttributeError:
|
||||
_LOGGER.info("Device isn't a sensor, skipping")
|
||||
|
||||
|
||||
class WinkBinarySensorEntity(WinkDevice, BinarySensorEntity):
|
||||
"""Representation of a Wink binary sensor."""
|
||||
|
||||
def __init__(self, wink, hass):
|
||||
"""Initialize the Wink binary sensor."""
|
||||
super().__init__(wink, hass)
|
||||
if hasattr(self.wink, "unit"):
|
||||
self._unit_of_measurement = self.wink.unit()
|
||||
else:
|
||||
self._unit_of_measurement = None
|
||||
if hasattr(self.wink, "capability"):
|
||||
self.capability = self.wink.capability()
|
||||
else:
|
||||
self.capability = None
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call 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."""
|
||||
return self.wink.state()
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Return the class of this sensor, from DEVICE_CLASSES."""
|
||||
return SENSOR_TYPES.get(self.capability)
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the device state attributes."""
|
||||
return super().extra_state_attributes
|
||||
|
||||
|
||||
class WinkSmokeDetector(WinkBinarySensorEntity):
|
||||
"""Representation of a Wink Smoke detector."""
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the device state attributes."""
|
||||
_attributes = super().extra_state_attributes
|
||||
_attributes["test_activated"] = self.wink.test_activated()
|
||||
return _attributes
|
||||
|
||||
|
||||
class WinkHub(WinkBinarySensorEntity):
|
||||
"""Representation of a Wink Hub."""
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the device state attributes."""
|
||||
_attributes = super().extra_state_attributes
|
||||
_attributes["update_needed"] = self.wink.update_needed()
|
||||
_attributes["firmware_version"] = self.wink.firmware_version()
|
||||
_attributes["pairing_mode"] = self.wink.pairing_mode()
|
||||
_kidde_code = self.wink.kidde_radio_code()
|
||||
if _kidde_code is not None:
|
||||
# The service call to set the Kidde code
|
||||
# takes a string of 1s and 0s so it makes
|
||||
# sense to display it to the user that way
|
||||
_formatted_kidde_code = f"{_kidde_code:b}".zfill(8)
|
||||
_attributes["kidde_radio_code"] = _formatted_kidde_code
|
||||
return _attributes
|
||||
|
||||
|
||||
class WinkRemote(WinkBinarySensorEntity):
|
||||
"""Representation of a Wink Lutron Connected bulb remote."""
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
_attributes = super().extra_state_attributes
|
||||
_attributes["button_on_pressed"] = self.wink.button_on_pressed()
|
||||
_attributes["button_off_pressed"] = self.wink.button_off_pressed()
|
||||
_attributes["button_up_pressed"] = self.wink.button_up_pressed()
|
||||
_attributes["button_down_pressed"] = self.wink.button_down_pressed()
|
||||
return _attributes
|
||||
|
||||
@property
|
||||
def device_class(self):
|
||||
"""Return the class of this sensor, from DEVICE_CLASSES."""
|
||||
return None
|
||||
|
||||
|
||||
class WinkButton(WinkBinarySensorEntity):
|
||||
"""Representation of a Wink Relay button."""
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the device state attributes."""
|
||||
_attributes = super().extra_state_attributes
|
||||
_attributes["pressed"] = self.wink.pressed()
|
||||
_attributes["long_pressed"] = self.wink.long_pressed()
|
||||
return _attributes
|
||||
|
||||
|
||||
class WinkGang(WinkBinarySensorEntity):
|
||||
"""Representation of a Wink Relay gang."""
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if the gang is connected."""
|
||||
return self.wink.state()
|
|
@ -1,520 +0,0 @@
|
|||
"""Support for Wink thermostats and Air Conditioners."""
|
||||
import logging
|
||||
|
||||
import pywink
|
||||
|
||||
from homeassistant.components.climate import ClimateEntity
|
||||
from homeassistant.components.climate.const import (
|
||||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
CURRENT_HVAC_COOL,
|
||||
CURRENT_HVAC_HEAT,
|
||||
CURRENT_HVAC_IDLE,
|
||||
CURRENT_HVAC_OFF,
|
||||
FAN_AUTO,
|
||||
FAN_HIGH,
|
||||
FAN_LOW,
|
||||
FAN_MEDIUM,
|
||||
FAN_ON,
|
||||
HVAC_MODE_AUTO,
|
||||
HVAC_MODE_COOL,
|
||||
HVAC_MODE_FAN_ONLY,
|
||||
HVAC_MODE_HEAT,
|
||||
HVAC_MODE_OFF,
|
||||
PRESET_AWAY,
|
||||
PRESET_ECO,
|
||||
PRESET_NONE,
|
||||
SUPPORT_AUX_HEAT,
|
||||
SUPPORT_FAN_MODE,
|
||||
SUPPORT_PRESET_MODE,
|
||||
SUPPORT_TARGET_TEMPERATURE,
|
||||
SUPPORT_TARGET_TEMPERATURE_RANGE,
|
||||
)
|
||||
from homeassistant.const import ATTR_TEMPERATURE, PRECISION_TENTHS, TEMP_CELSIUS
|
||||
from homeassistant.helpers.temperature import display_temp as show_temp
|
||||
|
||||
from . import DOMAIN, WinkDevice
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTR_ECO_TARGET = "eco_target"
|
||||
ATTR_EXTERNAL_TEMPERATURE = "external_temperature"
|
||||
ATTR_OCCUPIED = "occupied"
|
||||
ATTR_SCHEDULE_ENABLED = "schedule_enabled"
|
||||
ATTR_SMART_TEMPERATURE = "smart_temperature"
|
||||
ATTR_TOTAL_CONSUMPTION = "total_consumption"
|
||||
|
||||
HA_HVAC_TO_WINK = {
|
||||
HVAC_MODE_AUTO: "auto",
|
||||
HVAC_MODE_COOL: "cool_only",
|
||||
HVAC_MODE_FAN_ONLY: "fan_only",
|
||||
HVAC_MODE_HEAT: "heat_only",
|
||||
HVAC_MODE_OFF: "off",
|
||||
}
|
||||
|
||||
WINK_HVAC_TO_HA = {value: key for key, value in HA_HVAC_TO_WINK.items()}
|
||||
|
||||
SUPPORT_FLAGS_THERMOSTAT = (
|
||||
SUPPORT_TARGET_TEMPERATURE
|
||||
| SUPPORT_TARGET_TEMPERATURE_RANGE
|
||||
| SUPPORT_FAN_MODE
|
||||
| SUPPORT_AUX_HEAT
|
||||
)
|
||||
SUPPORT_FAN_THERMOSTAT = [FAN_AUTO, FAN_ON]
|
||||
SUPPORT_PRESET_THERMOSTAT = [PRESET_AWAY, PRESET_ECO]
|
||||
|
||||
SUPPORT_FLAGS_AC = SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE | SUPPORT_PRESET_MODE
|
||||
SUPPORT_FAN_AC = [FAN_HIGH, FAN_LOW, FAN_MEDIUM]
|
||||
SUPPORT_PRESET_AC = [PRESET_NONE, PRESET_ECO]
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Wink climate devices."""
|
||||
for climate in pywink.get_thermostats():
|
||||
_id = climate.object_id() + climate.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([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_entities([WinkAC(climate, hass)])
|
||||
|
||||
|
||||
class WinkThermostat(WinkDevice, ClimateEntity):
|
||||
"""Representation of a Wink thermostat."""
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Return the list of supported features."""
|
||||
return SUPPORT_FLAGS_THERMOSTAT
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self.hass.data[DOMAIN]["entities"]["climate"].append(self)
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
"""Return the unit of measurement."""
|
||||
# The Wink API always returns temp in Celsius
|
||||
return TEMP_CELSIUS
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the optional device state attributes."""
|
||||
data = {}
|
||||
if self.external_temperature is not None:
|
||||
data[ATTR_EXTERNAL_TEMPERATURE] = show_temp(
|
||||
self.hass,
|
||||
self.external_temperature,
|
||||
self.temperature_unit,
|
||||
PRECISION_TENTHS,
|
||||
)
|
||||
|
||||
if self.smart_temperature:
|
||||
data[ATTR_SMART_TEMPERATURE] = self.smart_temperature
|
||||
|
||||
if self.occupied is not None:
|
||||
data[ATTR_OCCUPIED] = self.occupied
|
||||
|
||||
if self.eco_target is not None:
|
||||
data[ATTR_ECO_TARGET] = self.eco_target
|
||||
|
||||
return data
|
||||
|
||||
@property
|
||||
def current_temperature(self):
|
||||
"""Return the current temperature."""
|
||||
return self.wink.current_temperature()
|
||||
|
||||
@property
|
||||
def current_humidity(self):
|
||||
"""Return the current humidity."""
|
||||
if self.wink.current_humidity() is not None:
|
||||
# The API states humidity will be a float 0-1
|
||||
# the only example API response with humidity listed show an int
|
||||
# This will address both possibilities
|
||||
if self.wink.current_humidity() < 1:
|
||||
return self.wink.current_humidity() * 100
|
||||
return self.wink.current_humidity()
|
||||
return None
|
||||
|
||||
@property
|
||||
def external_temperature(self):
|
||||
"""Return the current external temperature."""
|
||||
return self.wink.current_external_temperature()
|
||||
|
||||
@property
|
||||
def smart_temperature(self):
|
||||
"""Return the current average temp of all remote sensor."""
|
||||
return self.wink.current_smart_temperature()
|
||||
|
||||
@property
|
||||
def eco_target(self):
|
||||
"""Return status of eco target (Is the thermostat in eco mode)."""
|
||||
return self.wink.eco_target()
|
||||
|
||||
@property
|
||||
def occupied(self):
|
||||
"""Return status of if the thermostat has detected occupancy."""
|
||||
return self.wink.occupied()
|
||||
|
||||
@property
|
||||
def preset_mode(self):
|
||||
"""Return the current preset mode, e.g., home, away, temp."""
|
||||
mode = self.wink.current_hvac_mode()
|
||||
if mode == "eco":
|
||||
return PRESET_ECO
|
||||
if self.wink.away():
|
||||
return PRESET_AWAY
|
||||
return None
|
||||
|
||||
@property
|
||||
def preset_modes(self):
|
||||
"""Return a list of available preset modes."""
|
||||
return SUPPORT_PRESET_THERMOSTAT
|
||||
|
||||
@property
|
||||
def target_humidity(self):
|
||||
"""Return the humidity we try to reach."""
|
||||
target_hum = None
|
||||
if self.wink.current_humidifier_mode() == "on":
|
||||
if self.wink.current_humidifier_set_point() is not None:
|
||||
target_hum = self.wink.current_humidifier_set_point() * 100
|
||||
elif self.wink.current_dehumidifier_mode() == "on":
|
||||
if self.wink.current_dehumidifier_set_point() is not None:
|
||||
target_hum = self.wink.current_dehumidifier_set_point() * 100
|
||||
else:
|
||||
target_hum = None
|
||||
return target_hum
|
||||
|
||||
@property
|
||||
def target_temperature(self):
|
||||
"""Return the temperature we try to reach."""
|
||||
if self.hvac_mode != HVAC_MODE_AUTO and not self.wink.away():
|
||||
if self.hvac_mode == HVAC_MODE_COOL:
|
||||
return self.wink.current_max_set_point()
|
||||
if self.hvac_mode == HVAC_MODE_HEAT:
|
||||
return self.wink.current_min_set_point()
|
||||
return None
|
||||
|
||||
@property
|
||||
def target_temperature_low(self):
|
||||
"""Return the lower bound temperature we try to reach."""
|
||||
if self.hvac_mode == HVAC_MODE_AUTO:
|
||||
return self.wink.current_min_set_point()
|
||||
return None
|
||||
|
||||
@property
|
||||
def target_temperature_high(self):
|
||||
"""Return the higher bound temperature we try to reach."""
|
||||
if self.hvac_mode == HVAC_MODE_AUTO:
|
||||
return self.wink.current_max_set_point()
|
||||
return None
|
||||
|
||||
@property
|
||||
def is_aux_heat(self):
|
||||
"""Return true if aux heater."""
|
||||
if "aux" not in self.wink.hvac_modes():
|
||||
return None
|
||||
if self.wink.current_hvac_mode() == "aux":
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> str:
|
||||
"""Return hvac operation ie. heat, cool mode.
|
||||
|
||||
Need to be one of HVAC_MODE_*.
|
||||
"""
|
||||
if not self.wink.is_on():
|
||||
return HVAC_MODE_OFF
|
||||
|
||||
wink_mode = self.wink.current_hvac_mode()
|
||||
if wink_mode == "aux":
|
||||
return HVAC_MODE_HEAT
|
||||
if wink_mode == "eco":
|
||||
return HVAC_MODE_AUTO
|
||||
return WINK_HVAC_TO_HA.get(wink_mode, "")
|
||||
|
||||
@property
|
||||
def hvac_modes(self):
|
||||
"""Return the list of available hvac operation modes.
|
||||
|
||||
Need to be a subset of HVAC_MODES.
|
||||
"""
|
||||
hvac_list = [HVAC_MODE_OFF]
|
||||
|
||||
modes = self.wink.hvac_modes()
|
||||
for mode in modes:
|
||||
if mode in ("eco", "aux"):
|
||||
continue
|
||||
try:
|
||||
ha_mode = WINK_HVAC_TO_HA[mode]
|
||||
hvac_list.append(ha_mode)
|
||||
except KeyError:
|
||||
_LOGGER.error(
|
||||
"Invalid operation mode mapping. %s doesn't map. "
|
||||
"Please report this",
|
||||
mode,
|
||||
)
|
||||
return hvac_list
|
||||
|
||||
@property
|
||||
def hvac_action(self):
|
||||
"""Return the current running hvac operation if supported.
|
||||
|
||||
Need to be one of CURRENT_HVAC_*.
|
||||
"""
|
||||
if not self.wink.is_on():
|
||||
return CURRENT_HVAC_OFF
|
||||
if self.wink.cool_on():
|
||||
return CURRENT_HVAC_COOL
|
||||
if self.wink.heat_on():
|
||||
return CURRENT_HVAC_HEAT
|
||||
return CURRENT_HVAC_IDLE
|
||||
|
||||
def set_temperature(self, **kwargs):
|
||||
"""Set new target temperature."""
|
||||
target_temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
target_temp_low = kwargs.get(ATTR_TARGET_TEMP_LOW)
|
||||
target_temp_high = kwargs.get(ATTR_TARGET_TEMP_HIGH)
|
||||
if target_temp is not None:
|
||||
if self.hvac_mode == HVAC_MODE_COOL:
|
||||
target_temp_high = target_temp
|
||||
if self.hvac_mode == HVAC_MODE_HEAT:
|
||||
target_temp_low = target_temp
|
||||
self.wink.set_temperature(target_temp_low, target_temp_high)
|
||||
|
||||
def set_hvac_mode(self, hvac_mode):
|
||||
"""Set new target hvac mode."""
|
||||
hvac_mode_to_set = HA_HVAC_TO_WINK.get(hvac_mode)
|
||||
self.wink.set_operation_mode(hvac_mode_to_set)
|
||||
|
||||
def set_preset_mode(self, preset_mode):
|
||||
"""Set new preset mode."""
|
||||
# Away
|
||||
if preset_mode != PRESET_AWAY and self.wink.away():
|
||||
self.wink.set_away_mode(False)
|
||||
elif preset_mode == PRESET_AWAY:
|
||||
self.wink.set_away_mode()
|
||||
|
||||
if preset_mode == PRESET_ECO:
|
||||
self.wink.set_operation_mode("eco")
|
||||
|
||||
@property
|
||||
def fan_mode(self):
|
||||
"""Return whether the fan is on."""
|
||||
if self.wink.current_fan_mode() == "on":
|
||||
return FAN_ON
|
||||
if self.wink.current_fan_mode() == "auto":
|
||||
return FAN_AUTO
|
||||
# No Fan available so disable slider
|
||||
return None
|
||||
|
||||
@property
|
||||
def fan_modes(self):
|
||||
"""List of available fan modes."""
|
||||
if self.wink.has_fan():
|
||||
return SUPPORT_FAN_THERMOSTAT
|
||||
return None
|
||||
|
||||
def set_fan_mode(self, fan_mode):
|
||||
"""Turn fan on/off."""
|
||||
self.wink.set_fan_mode(fan_mode.lower())
|
||||
|
||||
def turn_aux_heat_on(self):
|
||||
"""Turn auxiliary heater on."""
|
||||
self.wink.set_operation_mode("aux")
|
||||
|
||||
def turn_aux_heat_off(self):
|
||||
"""Turn auxiliary heater off."""
|
||||
self.wink.set_operation_mode("heat_only")
|
||||
|
||||
@property
|
||||
def min_temp(self):
|
||||
"""Return the minimum temperature."""
|
||||
minimum = 7 # Default minimum
|
||||
min_min = self.wink.min_min_set_point()
|
||||
min_max = self.wink.min_max_set_point()
|
||||
if self.hvac_mode == HVAC_MODE_HEAT:
|
||||
if min_min:
|
||||
return_value = min_min
|
||||
else:
|
||||
return_value = minimum
|
||||
elif self.hvac_mode == HVAC_MODE_COOL:
|
||||
if min_max:
|
||||
return_value = min_max
|
||||
else:
|
||||
return_value = minimum
|
||||
elif self.hvac_mode == HVAC_MODE_AUTO:
|
||||
if min_min and min_max:
|
||||
return_value = min(min_min, min_max)
|
||||
else:
|
||||
return_value = minimum
|
||||
else:
|
||||
return_value = minimum
|
||||
return return_value
|
||||
|
||||
@property
|
||||
def max_temp(self):
|
||||
"""Return the maximum temperature."""
|
||||
maximum = 35 # Default maximum
|
||||
max_min = self.wink.max_min_set_point()
|
||||
max_max = self.wink.max_max_set_point()
|
||||
if self.hvac_mode == HVAC_MODE_HEAT:
|
||||
if max_min:
|
||||
return_value = max_min
|
||||
else:
|
||||
return_value = maximum
|
||||
elif self.hvac_mode == HVAC_MODE_COOL:
|
||||
if max_max:
|
||||
return_value = max_max
|
||||
else:
|
||||
return_value = maximum
|
||||
elif self.hvac_mode == HVAC_MODE_AUTO:
|
||||
if max_min and max_max:
|
||||
return_value = min(max_min, max_max)
|
||||
else:
|
||||
return_value = maximum
|
||||
else:
|
||||
return_value = maximum
|
||||
return return_value
|
||||
|
||||
|
||||
class WinkAC(WinkDevice, ClimateEntity):
|
||||
"""Representation of a Wink air conditioner."""
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Return the list of supported features."""
|
||||
return SUPPORT_FLAGS_AC
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
"""Return the unit of measurement."""
|
||||
# The Wink API always returns temp in Celsius
|
||||
return TEMP_CELSIUS
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the optional device state attributes."""
|
||||
data = {}
|
||||
data[ATTR_TOTAL_CONSUMPTION] = self.wink.total_consumption()
|
||||
data[ATTR_SCHEDULE_ENABLED] = self.wink.schedule_enabled()
|
||||
|
||||
return data
|
||||
|
||||
@property
|
||||
def current_temperature(self):
|
||||
"""Return the current temperature."""
|
||||
return self.wink.current_temperature()
|
||||
|
||||
@property
|
||||
def preset_mode(self):
|
||||
"""Return the current preset mode, e.g., home, away, temp."""
|
||||
if not self.wink.is_on():
|
||||
return PRESET_NONE
|
||||
|
||||
mode = self.wink.current_mode()
|
||||
if mode == "auto_eco":
|
||||
return PRESET_ECO
|
||||
return PRESET_NONE
|
||||
|
||||
@property
|
||||
def preset_modes(self):
|
||||
"""Return a list of available preset modes."""
|
||||
return SUPPORT_PRESET_AC
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> str:
|
||||
"""Return hvac operation ie. heat, cool mode.
|
||||
|
||||
Need to be one of HVAC_MODE_*.
|
||||
"""
|
||||
if not self.wink.is_on():
|
||||
return HVAC_MODE_OFF
|
||||
|
||||
wink_mode = self.wink.current_mode()
|
||||
if wink_mode == "auto_eco":
|
||||
return HVAC_MODE_COOL
|
||||
return WINK_HVAC_TO_HA.get(wink_mode, "")
|
||||
|
||||
@property
|
||||
def hvac_modes(self):
|
||||
"""Return the list of available hvac operation modes.
|
||||
|
||||
Need to be a subset of HVAC_MODES.
|
||||
"""
|
||||
hvac_list = [HVAC_MODE_OFF]
|
||||
|
||||
modes = self.wink.modes()
|
||||
for mode in modes:
|
||||
if mode == "auto_eco":
|
||||
continue
|
||||
try:
|
||||
ha_mode = WINK_HVAC_TO_HA[mode]
|
||||
hvac_list.append(ha_mode)
|
||||
except KeyError:
|
||||
_LOGGER.error(
|
||||
"Invalid operation mode mapping. %s doesn't map. "
|
||||
"Please report this",
|
||||
mode,
|
||||
)
|
||||
return hvac_list
|
||||
|
||||
def set_temperature(self, **kwargs):
|
||||
"""Set new target temperature."""
|
||||
target_temp = kwargs.get(ATTR_TEMPERATURE)
|
||||
self.wink.set_temperature(target_temp)
|
||||
|
||||
def set_hvac_mode(self, hvac_mode):
|
||||
"""Set new target hvac mode."""
|
||||
hvac_mode_to_set = HA_HVAC_TO_WINK.get(hvac_mode)
|
||||
self.wink.set_operation_mode(hvac_mode_to_set)
|
||||
|
||||
def set_preset_mode(self, preset_mode):
|
||||
"""Set new preset mode."""
|
||||
if preset_mode == PRESET_ECO:
|
||||
self.wink.set_operation_mode("auto_eco")
|
||||
elif self.hvac_mode == HVAC_MODE_COOL and preset_mode == PRESET_NONE:
|
||||
self.set_hvac_mode(HVAC_MODE_COOL)
|
||||
|
||||
@property
|
||||
def target_temperature(self):
|
||||
"""Return the temperature we try to reach."""
|
||||
return self.wink.current_max_set_point()
|
||||
|
||||
@property
|
||||
def fan_mode(self):
|
||||
"""
|
||||
Return the current fan mode.
|
||||
|
||||
The official Wink app only supports 3 modes [low, medium, high]
|
||||
which are equal to [0.33, 0.66, 1.0] respectively.
|
||||
"""
|
||||
speed = self.wink.current_fan_speed()
|
||||
if speed <= 0.33:
|
||||
return FAN_LOW
|
||||
if speed <= 0.66:
|
||||
return FAN_MEDIUM
|
||||
return FAN_HIGH
|
||||
|
||||
@property
|
||||
def fan_modes(self):
|
||||
"""Return a list of available fan modes."""
|
||||
return SUPPORT_FAN_AC
|
||||
|
||||
def set_fan_mode(self, fan_mode):
|
||||
"""
|
||||
Set fan speed.
|
||||
|
||||
The official Wink app only supports 3 modes [low, medium, high]
|
||||
which are equal to [0.33, 0.66, 1.0] respectively.
|
||||
"""
|
||||
if fan_mode == FAN_LOW:
|
||||
speed = 0.33
|
||||
elif fan_mode == FAN_MEDIUM:
|
||||
speed = 0.66
|
||||
elif fan_mode == FAN_HIGH:
|
||||
speed = 1.0
|
||||
self.wink.set_ac_fan_speed(speed)
|
|
@ -1,57 +0,0 @@
|
|||
"""Support for Wink covers."""
|
||||
import pywink
|
||||
|
||||
from homeassistant.components.cover import ATTR_POSITION, CoverEntity
|
||||
|
||||
from . import DOMAIN, WinkDevice
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Wink cover platform."""
|
||||
|
||||
for shade in pywink.get_shades():
|
||||
_id = shade.object_id() + shade.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkCoverEntity(shade, hass)])
|
||||
for shade in pywink.get_shade_groups():
|
||||
_id = shade.object_id() + shade.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkCoverEntity(shade, hass)])
|
||||
for door in pywink.get_garage_doors():
|
||||
_id = door.object_id() + door.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkCoverEntity(door, hass)])
|
||||
|
||||
|
||||
class WinkCoverEntity(WinkDevice, CoverEntity):
|
||||
"""Representation of a Wink cover device."""
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self.hass.data[DOMAIN]["entities"]["cover"].append(self)
|
||||
|
||||
def close_cover(self, **kwargs):
|
||||
"""Close the cover."""
|
||||
self.wink.set_state(0)
|
||||
|
||||
def open_cover(self, **kwargs):
|
||||
"""Open the cover."""
|
||||
self.wink.set_state(1)
|
||||
|
||||
def set_cover_position(self, **kwargs):
|
||||
"""Move the cover shutter to a specific position."""
|
||||
position = kwargs.get(ATTR_POSITION)
|
||||
self.wink.set_state(position / 100)
|
||||
|
||||
@property
|
||||
def current_cover_position(self):
|
||||
"""Return the current position of cover shutter."""
|
||||
if self.wink.state() is not None:
|
||||
return int(self.wink.state() * 100)
|
||||
return None
|
||||
|
||||
@property
|
||||
def is_closed(self):
|
||||
"""Return if the cover is closed."""
|
||||
state = self.wink.state()
|
||||
return bool(state == 0)
|
|
@ -1,112 +0,0 @@
|
|||
"""Support for Wink fans."""
|
||||
from __future__ import annotations
|
||||
|
||||
import pywink
|
||||
|
||||
from homeassistant.components.fan import (
|
||||
SPEED_HIGH,
|
||||
SPEED_LOW,
|
||||
SPEED_MEDIUM,
|
||||
SUPPORT_DIRECTION,
|
||||
SUPPORT_SET_SPEED,
|
||||
FanEntity,
|
||||
)
|
||||
|
||||
from . import DOMAIN, WinkDevice
|
||||
|
||||
SPEED_AUTO = "auto"
|
||||
SPEED_LOWEST = "lowest"
|
||||
SUPPORTED_FEATURES = SUPPORT_DIRECTION + SUPPORT_SET_SPEED
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Wink platform."""
|
||||
|
||||
for fan in pywink.get_fans():
|
||||
if fan.object_id() + fan.name() not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkFanDevice(fan, hass)])
|
||||
|
||||
|
||||
class WinkFanDevice(WinkDevice, FanEntity):
|
||||
"""Representation of a Wink fan."""
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self.hass.data[DOMAIN]["entities"]["fan"].append(self)
|
||||
|
||||
def set_direction(self, direction: str) -> None:
|
||||
"""Set the direction of the fan."""
|
||||
self.wink.set_fan_direction(direction)
|
||||
|
||||
def set_speed(self, speed: str) -> None:
|
||||
"""Set the speed of the fan."""
|
||||
self.wink.set_state(True, speed)
|
||||
|
||||
#
|
||||
# The fan entity model has changed to use percentages and preset_modes
|
||||
# instead of speeds.
|
||||
#
|
||||
# Please review
|
||||
# https://developers.home-assistant.io/docs/core/entity/fan/
|
||||
#
|
||||
def turn_on(
|
||||
self,
|
||||
speed: str = None,
|
||||
percentage: int = None,
|
||||
preset_mode: str = None,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""Turn on the fan."""
|
||||
self.wink.set_state(True, speed)
|
||||
|
||||
def turn_off(self, **kwargs) -> None:
|
||||
"""Turn off the fan."""
|
||||
self.wink.set_state(False)
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if the entity is on."""
|
||||
return self.wink.state()
|
||||
|
||||
@property
|
||||
def speed(self) -> str | None:
|
||||
"""Return the current speed."""
|
||||
current_wink_speed = self.wink.current_fan_speed()
|
||||
if SPEED_AUTO == current_wink_speed:
|
||||
return SPEED_AUTO
|
||||
if SPEED_LOWEST == current_wink_speed:
|
||||
return SPEED_LOWEST
|
||||
if SPEED_LOW == current_wink_speed:
|
||||
return SPEED_LOW
|
||||
if SPEED_MEDIUM == current_wink_speed:
|
||||
return SPEED_MEDIUM
|
||||
if SPEED_HIGH == current_wink_speed:
|
||||
return SPEED_HIGH
|
||||
return None
|
||||
|
||||
@property
|
||||
def current_direction(self):
|
||||
"""Return direction of the fan [forward, reverse]."""
|
||||
return self.wink.current_fan_direction()
|
||||
|
||||
@property
|
||||
def speed_list(self) -> list:
|
||||
"""Get the list of available speeds."""
|
||||
wink_supported_speeds = self.wink.fan_speeds()
|
||||
supported_speeds = []
|
||||
if SPEED_AUTO in wink_supported_speeds:
|
||||
supported_speeds.append(SPEED_AUTO)
|
||||
if SPEED_LOWEST in wink_supported_speeds:
|
||||
supported_speeds.append(SPEED_LOWEST)
|
||||
if SPEED_LOW in wink_supported_speeds:
|
||||
supported_speeds.append(SPEED_LOW)
|
||||
if SPEED_MEDIUM in wink_supported_speeds:
|
||||
supported_speeds.append(SPEED_MEDIUM)
|
||||
if SPEED_HIGH in wink_supported_speeds:
|
||||
supported_speeds.append(SPEED_HIGH)
|
||||
return supported_speeds
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int:
|
||||
"""Flag supported features."""
|
||||
return SUPPORTED_FEATURES
|
|
@ -1,114 +0,0 @@
|
|||
"""Support for Wink lights."""
|
||||
import pywink
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_TEMP,
|
||||
ATTR_HS_COLOR,
|
||||
SUPPORT_BRIGHTNESS,
|
||||
SUPPORT_COLOR,
|
||||
SUPPORT_COLOR_TEMP,
|
||||
LightEntity,
|
||||
)
|
||||
from homeassistant.util import color as color_util
|
||||
from homeassistant.util.color import (
|
||||
color_temperature_mired_to_kelvin as mired_to_kelvin,
|
||||
)
|
||||
|
||||
from . import DOMAIN, WinkDevice
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Wink lights."""
|
||||
|
||||
for light in pywink.get_light_bulbs():
|
||||
_id = light.object_id() + light.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkLight(light, hass)])
|
||||
for light in pywink.get_light_groups():
|
||||
_id = light.object_id() + light.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkLight(light, hass)])
|
||||
|
||||
|
||||
class WinkLight(WinkDevice, LightEntity):
|
||||
"""Representation of a Wink light."""
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call 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."""
|
||||
return self.wink.state()
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""Return the brightness of the light."""
|
||||
if self.wink.brightness() is not None:
|
||||
return int(self.wink.brightness() * 255)
|
||||
return None
|
||||
|
||||
@property
|
||||
def hs_color(self):
|
||||
"""Define current bulb color."""
|
||||
if self.wink.supports_xy_color():
|
||||
return color_util.color_xy_to_hs(*self.wink.color_xy())
|
||||
|
||||
if self.wink.supports_hue_saturation():
|
||||
hue = self.wink.color_hue()
|
||||
saturation = self.wink.color_saturation()
|
||||
if hue is not None and saturation is not None:
|
||||
return hue * 360, saturation * 100
|
||||
|
||||
return None
|
||||
|
||||
@property
|
||||
def color_temp(self):
|
||||
"""Define current bulb color in degrees Kelvin."""
|
||||
if not self.wink.supports_temperature():
|
||||
return None
|
||||
return color_util.color_temperature_kelvin_to_mired(
|
||||
self.wink.color_temperature_kelvin()
|
||||
)
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Flag supported features."""
|
||||
supports = SUPPORT_BRIGHTNESS
|
||||
if self.wink.supports_temperature():
|
||||
supports = supports | SUPPORT_COLOR_TEMP
|
||||
if self.wink.supports_xy_color():
|
||||
supports = supports | SUPPORT_COLOR
|
||||
elif self.wink.supports_hue_saturation():
|
||||
supports = supports | SUPPORT_COLOR
|
||||
return supports
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
"""Turn the switch on."""
|
||||
brightness = kwargs.get(ATTR_BRIGHTNESS)
|
||||
hs_color = kwargs.get(ATTR_HS_COLOR)
|
||||
color_temp_mired = kwargs.get(ATTR_COLOR_TEMP)
|
||||
|
||||
state_kwargs = {}
|
||||
|
||||
if hs_color:
|
||||
if self.wink.supports_xy_color():
|
||||
xy_color = color_util.color_hs_to_xy(*hs_color)
|
||||
state_kwargs["color_xy"] = xy_color
|
||||
if self.wink.supports_hue_saturation():
|
||||
hs_scaled = hs_color[0] / 360, hs_color[1] / 100
|
||||
state_kwargs["color_hue_saturation"] = hs_scaled
|
||||
|
||||
if color_temp_mired:
|
||||
state_kwargs["color_kelvin"] = mired_to_kelvin(color_temp_mired)
|
||||
|
||||
if brightness:
|
||||
state_kwargs["brightness"] = brightness / 255.0
|
||||
|
||||
self.wink.set_state(True, **state_kwargs)
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn the switch off."""
|
||||
self.wink.set_state(False)
|
|
@ -1,211 +0,0 @@
|
|||
"""Support for Wink locks."""
|
||||
import pywink
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.lock import LockEntity
|
||||
from homeassistant.const import (
|
||||
ATTR_CODE,
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_MODE,
|
||||
ATTR_NAME,
|
||||
STATE_UNKNOWN,
|
||||
)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from . import DOMAIN, WinkDevice
|
||||
|
||||
SERVICE_SET_VACATION_MODE = "set_lock_vacation_mode"
|
||||
SERVICE_SET_ALARM_MODE = "set_lock_alarm_mode"
|
||||
SERVICE_SET_ALARM_SENSITIVITY = "set_lock_alarm_sensitivity"
|
||||
SERVICE_SET_ALARM_STATE = "set_lock_alarm_state"
|
||||
SERVICE_SET_BEEPER_STATE = "set_lock_beeper_state"
|
||||
SERVICE_ADD_KEY = "add_new_lock_key_code"
|
||||
|
||||
ATTR_ENABLED = "enabled"
|
||||
ATTR_SENSITIVITY = "sensitivity"
|
||||
|
||||
ALARM_SENSITIVITY_MAP = {
|
||||
"low": 0.2,
|
||||
"medium_low": 0.4,
|
||||
"medium": 0.6,
|
||||
"medium_high": 0.8,
|
||||
"high": 1.0,
|
||||
}
|
||||
|
||||
ALARM_MODES_MAP = {
|
||||
"activity": "alert",
|
||||
"forced_entry": "forced_entry",
|
||||
"tamper": "tamper",
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
)
|
||||
|
||||
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_entities, discovery_info=None):
|
||||
"""Set up the Wink platform."""
|
||||
|
||||
for lock in pywink.get_locks():
|
||||
_id = lock.object_id() + lock.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkLockDevice(lock, hass)])
|
||||
|
||||
def service_handle(service):
|
||||
"""Handle 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))
|
||||
elif service.service == SERVICE_ADD_KEY:
|
||||
name = service.data.get(ATTR_NAME)
|
||||
code = service.data.get(ATTR_CODE)
|
||||
lock.add_new_key(code, name)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN, SERVICE_SET_VACATION_MODE, service_handle, schema=SET_ENABLED_SCHEMA
|
||||
)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN, SERVICE_SET_ALARM_STATE, service_handle, schema=SET_ENABLED_SCHEMA
|
||||
)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN, SERVICE_SET_BEEPER_STATE, service_handle, schema=SET_ENABLED_SCHEMA
|
||||
)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN, SERVICE_SET_ALARM_MODE, service_handle, schema=SET_ALARM_MODES_SCHEMA
|
||||
)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN,
|
||||
SERVICE_SET_ALARM_SENSITIVITY,
|
||||
service_handle,
|
||||
schema=SET_SENSITIVITY_SCHEMA,
|
||||
)
|
||||
|
||||
hass.services.register(
|
||||
DOMAIN, SERVICE_ADD_KEY, service_handle, schema=ADD_KEY_SCHEMA
|
||||
)
|
||||
|
||||
|
||||
class WinkLockDevice(WinkDevice, LockEntity):
|
||||
"""Representation of a Wink lock."""
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call 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."""
|
||||
return self.wink.state()
|
||||
|
||||
def lock(self, **kwargs):
|
||||
"""Lock the device."""
|
||||
self.wink.set_state(True)
|
||||
|
||||
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 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.
|
||||
|
||||
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 extra_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
super_attrs = super().extra_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
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"domain": "wink",
|
||||
"name": "Wink",
|
||||
"documentation": "https://www.home-assistant.io/integrations/wink",
|
||||
"requirements": ["pubnubsub-handler==1.0.9", "python-wink==1.10.5"],
|
||||
"dependencies": ["configurator", "http"],
|
||||
"codeowners": [],
|
||||
"iot_class": "cloud_polling"
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
"""Support for Wink scenes."""
|
||||
from typing import Any
|
||||
|
||||
import pywink
|
||||
|
||||
from homeassistant.components.scene import Scene
|
||||
|
||||
from . import DOMAIN, WinkDevice
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Wink platform."""
|
||||
|
||||
for scene in pywink.get_scenes():
|
||||
_id = scene.object_id() + scene.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkScene(scene, hass)])
|
||||
|
||||
|
||||
class WinkScene(WinkDevice, Scene):
|
||||
"""Representation of a Wink shortcut/scene."""
|
||||
|
||||
def __init__(self, wink, hass):
|
||||
"""Initialize the Wink device."""
|
||||
super().__init__(wink, hass)
|
||||
hass.data[DOMAIN]["entities"]["scene"].append(self)
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self.hass.data[DOMAIN]["entities"]["scene"].append(self)
|
||||
|
||||
def activate(self, **kwargs: Any) -> None:
|
||||
"""Activate the scene."""
|
||||
self.wink.activate()
|
|
@ -1,98 +0,0 @@
|
|||
"""Support for Wink sensors."""
|
||||
from contextlib import suppress
|
||||
import logging
|
||||
|
||||
import pywink
|
||||
|
||||
from homeassistant.components.sensor import SensorEntity
|
||||
from homeassistant.const import DEGREE, TEMP_CELSIUS
|
||||
|
||||
from . import DOMAIN, WinkDevice
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SENSOR_TYPES = ["temperature", "humidity", "balance", "proximity"]
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Wink platform."""
|
||||
|
||||
for sensor in pywink.get_sensors():
|
||||
_id = sensor.object_id() + sensor.name()
|
||||
if (
|
||||
_id not in hass.data[DOMAIN]["unique_ids"]
|
||||
and sensor.capability() in SENSOR_TYPES
|
||||
):
|
||||
add_entities([WinkSensorEntity(sensor, hass)])
|
||||
|
||||
for eggtray in pywink.get_eggtrays():
|
||||
_id = eggtray.object_id() + eggtray.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkSensorEntity(eggtray, hass)])
|
||||
|
||||
for tank in pywink.get_propane_tanks():
|
||||
_id = tank.object_id() + tank.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkSensorEntity(tank, hass)])
|
||||
|
||||
for piggy_bank in pywink.get_piggy_banks():
|
||||
_id = piggy_bank.object_id() + piggy_bank.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
try:
|
||||
if piggy_bank.capability() in SENSOR_TYPES:
|
||||
add_entities([WinkSensorEntity(piggy_bank, hass)])
|
||||
except AttributeError:
|
||||
_LOGGER.info("Device is not a sensor")
|
||||
|
||||
|
||||
class WinkSensorEntity(WinkDevice, SensorEntity):
|
||||
"""Representation of a Wink sensor."""
|
||||
|
||||
def __init__(self, wink, hass):
|
||||
"""Initialize the Wink device."""
|
||||
super().__init__(wink, hass)
|
||||
self.capability = self.wink.capability()
|
||||
if self.wink.unit() == DEGREE:
|
||||
self._unit_of_measurement = TEMP_CELSIUS
|
||||
else:
|
||||
self._unit_of_measurement = self.wink.unit()
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call when entity is added to hass."""
|
||||
self.hass.data[DOMAIN]["entities"]["sensor"].append(self)
|
||||
|
||||
@property
|
||||
def native_value(self):
|
||||
"""Return the state."""
|
||||
state = None
|
||||
if self.capability == "humidity":
|
||||
if self.wink.state() is not None:
|
||||
state = round(self.wink.state())
|
||||
elif self.capability == "temperature":
|
||||
if self.wink.state() is not None:
|
||||
state = round(self.wink.state(), 1)
|
||||
elif self.capability == "balance":
|
||||
if self.wink.state() is not None:
|
||||
state = round(self.wink.state() / 100, 2)
|
||||
elif self.capability == "proximity":
|
||||
if self.wink.state() is not None:
|
||||
state = self.wink.state()
|
||||
else:
|
||||
state = self.wink.state()
|
||||
return state
|
||||
|
||||
@property
|
||||
def native_unit_of_measurement(self):
|
||||
"""Return the unit of measurement of this entity, if any."""
|
||||
return self._unit_of_measurement
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
super_attrs = super().extra_state_attributes
|
||||
|
||||
# Ignore error, this sensor isn't an eggminder
|
||||
with suppress(AttributeError):
|
||||
super_attrs["egg_times"] = self.wink.eggs()
|
||||
|
||||
return super_attrs
|
|
@ -1,431 +0,0 @@
|
|||
# Describes the format for available Wink services
|
||||
pair_new_device:
|
||||
name: Pair new device
|
||||
description: Pair a new device to a Wink Hub.
|
||||
fields:
|
||||
hub_name:
|
||||
name: Hub name
|
||||
description: The name of the hub to pair a new device to.
|
||||
required: true
|
||||
example: "My hub"
|
||||
selector:
|
||||
text:
|
||||
pairing_mode:
|
||||
name: Pairing mode
|
||||
description: Mode.
|
||||
required: true
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- 'bluetooth'
|
||||
- 'kidde'
|
||||
- 'lutron'
|
||||
- 'zigbee'
|
||||
- 'zwave'
|
||||
- 'zwave_exclusion'
|
||||
- 'zwave_network_rediscovery'
|
||||
kidde_radio_code:
|
||||
name: Kidde radio code
|
||||
description: "A string of 8 1s and 0s one for each dip switch on the kidde device left --> right = 1 --> 8. Down = 1 and Up = 0"
|
||||
example: "10101010"
|
||||
selector:
|
||||
text:
|
||||
|
||||
rename_wink_device:
|
||||
name: Rename wink device
|
||||
description: Rename the provided device.
|
||||
target:
|
||||
entity:
|
||||
integration: wink
|
||||
fields:
|
||||
name:
|
||||
name: Name
|
||||
description: The name to change it to.
|
||||
required: true
|
||||
example: back_door
|
||||
selector:
|
||||
text:
|
||||
|
||||
delete_wink_device:
|
||||
name: Delete wink device
|
||||
description: Remove/unpair device from Wink.
|
||||
target:
|
||||
entity:
|
||||
integration: wink
|
||||
|
||||
pull_newly_added_devices_from_wink:
|
||||
name: Pull newly added devices from wink
|
||||
description: Pull newly paired devices from Wink.
|
||||
|
||||
refresh_state_from_wink:
|
||||
name: Refresh state from wink
|
||||
description: Pull the latest states for every device.
|
||||
|
||||
set_siren_volume:
|
||||
name: Set siren volume
|
||||
description: Set the volume of the siren for a Dome siren/chime.
|
||||
target:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: switch
|
||||
fields:
|
||||
volume:
|
||||
name: Volume
|
||||
description: Volume level.
|
||||
required: true
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- 'low'
|
||||
- 'medium'
|
||||
- 'high'
|
||||
|
||||
enable_chime:
|
||||
name: Enable chime
|
||||
description: Enable the chime of a Dome siren with the provided sound.
|
||||
target:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: switch
|
||||
fields:
|
||||
tone:
|
||||
name: Tone
|
||||
description: >-
|
||||
The tone to use for the chime.
|
||||
required: true
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- 'alert'
|
||||
- 'beep'
|
||||
- 'beep_beep'
|
||||
- 'doorbell'
|
||||
- 'doorbell_extended'
|
||||
- 'evacuation'
|
||||
- 'fur_elise'
|
||||
- 'inactive'
|
||||
- 'police_siren'
|
||||
- 'rondo_alla_turca'
|
||||
- 'william_tell'
|
||||
|
||||
set_siren_tone:
|
||||
name: Set siren tone
|
||||
description: Set the sound to use when the siren is enabled. (This doesn't enable the siren)
|
||||
target:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: switch
|
||||
fields:
|
||||
tone:
|
||||
name: Tone
|
||||
description: >-
|
||||
The tone to use for the chime.
|
||||
required: true
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- 'alert'
|
||||
- 'beep'
|
||||
- 'beep_beep'
|
||||
- 'doorbell'
|
||||
- 'doorbell_extended'
|
||||
- 'evacuation'
|
||||
- 'fur_elise'
|
||||
- 'inactive'
|
||||
- 'police_siren'
|
||||
- 'rondo_alla_turca'
|
||||
- 'william_tell'
|
||||
|
||||
siren_set_auto_shutoff:
|
||||
name: Siren set auto shutoff
|
||||
description: How long to sound the siren before turning off.
|
||||
target:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: switch
|
||||
fields:
|
||||
auto_shutoff:
|
||||
name: Auto shutoff
|
||||
description: >-
|
||||
The time in seconds to sound the siren. (None and -1 are forever. Use None for gocontrol, and -1 for Dome)
|
||||
required: true
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- 'None'
|
||||
- '-1'
|
||||
- '30'
|
||||
- '60'
|
||||
- '120'
|
||||
|
||||
set_siren_strobe_enabled:
|
||||
name: Set siren strobe enabled
|
||||
description: Enable or disable the strobe light when the siren is sounding.
|
||||
target:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: switch
|
||||
fields:
|
||||
enabled:
|
||||
name: Enabled
|
||||
description: "True or False"
|
||||
required: true
|
||||
selector:
|
||||
boolean:
|
||||
|
||||
set_chime_strobe_enabled:
|
||||
name: Set chime strobe enabled
|
||||
description: Enable or disable the strobe light when the chime is sounding.
|
||||
target:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: switch
|
||||
fields:
|
||||
enabled:
|
||||
name: Enabled
|
||||
description: "True or False"
|
||||
required: true
|
||||
selector:
|
||||
boolean:
|
||||
|
||||
enable_siren:
|
||||
name: Enable siren
|
||||
description: Enable/disable the siren.
|
||||
target:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: switch
|
||||
fields:
|
||||
enabled:
|
||||
name: Enabled
|
||||
description: "true or false"
|
||||
required: true
|
||||
selector:
|
||||
boolean:
|
||||
|
||||
set_chime_volume:
|
||||
name: Set chime volume
|
||||
description: Set the volume of the chime for a Dome siren/chime.
|
||||
target:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: switch
|
||||
fields:
|
||||
volume:
|
||||
name: Volume
|
||||
description: Volume level.
|
||||
required: true
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- 'low'
|
||||
- 'medium'
|
||||
- 'high'
|
||||
|
||||
set_nimbus_dial_configuration:
|
||||
name: Set nimbus dial configuration
|
||||
description: Set the configuration of an individual nimbus dial
|
||||
target:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: switch
|
||||
fields:
|
||||
rotation:
|
||||
name: Rotation
|
||||
description: Direction dial hand should spin.
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- 'cw'
|
||||
- 'ccw'
|
||||
ticks:
|
||||
name: Ticks
|
||||
description: Number of times the hand should move
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 3600
|
||||
scale:
|
||||
name: Scale
|
||||
description: How the dial should move in response to higher values.
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- 'linear'
|
||||
- 'log'
|
||||
min_value:
|
||||
name: minimum value
|
||||
description: The minimum value allowed to be set
|
||||
example: 0
|
||||
selector:
|
||||
text:
|
||||
max_value:
|
||||
name: Maximum value
|
||||
description: The maximum value allowed to be set
|
||||
example: 500
|
||||
selector:
|
||||
text:
|
||||
min_position:
|
||||
name: Minimum position
|
||||
description: The minimum position the dial hand can rotate to generally.
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 360
|
||||
max_position:
|
||||
name: Maximum position
|
||||
description: The maximum position the dial hand can rotate to generally.
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 360
|
||||
|
||||
set_nimbus_dial_state:
|
||||
name: Set nimbus dial state
|
||||
description: Set the value and labels of an individual nimbus dial
|
||||
target:
|
||||
entity:
|
||||
integration: wink
|
||||
fields:
|
||||
value:
|
||||
name: Value
|
||||
description: The value that should be set (Should be between min_value and max_value)
|
||||
required: true
|
||||
example: 250
|
||||
selector:
|
||||
text:
|
||||
labels:
|
||||
name: 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"]
|
||||
selector:
|
||||
object:
|
||||
|
||||
set_lock_vacation_mode:
|
||||
name: Set lock vacation mode
|
||||
description: Set vacation mode for all or specified locks. Disables all user codes.
|
||||
fields:
|
||||
entity_id:
|
||||
name: Entity
|
||||
description: Name of lock to unlock.
|
||||
selector:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: lock
|
||||
enabled:
|
||||
name: Enabled
|
||||
description: enable or disable. true or false.
|
||||
required: true
|
||||
selector:
|
||||
boolean:
|
||||
|
||||
set_lock_alarm_mode:
|
||||
name: Set lock alarm mode
|
||||
description: Set alarm mode for all or specified locks.
|
||||
fields:
|
||||
entity_id:
|
||||
name: Entity
|
||||
description: Name of lock to unlock.
|
||||
selector:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: lock
|
||||
mode:
|
||||
name: Mode
|
||||
description: Select mode.
|
||||
required: true
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- 'activity'
|
||||
- 'forced_entry'
|
||||
- 'tamper'
|
||||
|
||||
set_lock_alarm_sensitivity:
|
||||
name: Set lock alarm sensitivity
|
||||
description: Set alarm sensitivity for all or specified locks.
|
||||
fields:
|
||||
entity_id:
|
||||
name: Entity
|
||||
description: Name of lock to unlock.
|
||||
selector:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: lock
|
||||
sensitivity:
|
||||
name: Sensitivity
|
||||
description: Choose the sensitivity.
|
||||
required: true
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- 'low'
|
||||
- 'medium_low'
|
||||
- 'medium'
|
||||
- 'medium_high'
|
||||
- 'high'
|
||||
|
||||
set_lock_alarm_state:
|
||||
name: Set lok alarm state
|
||||
description: Set alarm state.
|
||||
fields:
|
||||
entity_id:
|
||||
name: Entity
|
||||
description: Name of lock to unlock.
|
||||
selector:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: lock
|
||||
enabled:
|
||||
name: Enabled
|
||||
description: enable or disable.
|
||||
required: true
|
||||
selector:
|
||||
boolean:
|
||||
|
||||
set_lock_beeper_state:
|
||||
name: Set lock beeper state
|
||||
description: Set beeper state.
|
||||
fields:
|
||||
entity_id:
|
||||
name: Entity
|
||||
description: Name of lock to unlock.
|
||||
selector:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: lock
|
||||
enabled:
|
||||
name: Enabled
|
||||
description: enable or disable.
|
||||
required: true
|
||||
selector:
|
||||
boolean:
|
||||
|
||||
add_new_lock_key_code:
|
||||
name: Add new lock key code
|
||||
description: Add a new user key code.
|
||||
fields:
|
||||
entity_id:
|
||||
name: Entity
|
||||
description: Name of lock to unlock.
|
||||
selector:
|
||||
entity:
|
||||
integration: wink
|
||||
domain: lock
|
||||
name:
|
||||
name: Name
|
||||
description: name of the new key code.
|
||||
required: true
|
||||
example: Bob
|
||||
selector:
|
||||
text:
|
||||
code:
|
||||
name: Code
|
||||
description: new key code, length must match length of other codes. Default length is 4.
|
||||
required: true
|
||||
example: 1234
|
||||
selector:
|
||||
text:
|
|
@ -1,60 +0,0 @@
|
|||
"""Support for Wink switches."""
|
||||
import pywink
|
||||
|
||||
from homeassistant.helpers.entity import ToggleEntity
|
||||
|
||||
from . import DOMAIN, WinkDevice
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Wink platform."""
|
||||
|
||||
for switch in pywink.get_switches():
|
||||
_id = switch.object_id() + switch.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkToggleDevice(switch, hass)])
|
||||
for switch in pywink.get_powerstrips():
|
||||
_id = switch.object_id() + switch.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkToggleDevice(switch, hass)])
|
||||
for sprinkler in pywink.get_sprinklers():
|
||||
_id = sprinkler.object_id() + sprinkler.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkToggleDevice(sprinkler, hass)])
|
||||
for switch in pywink.get_binary_switch_groups():
|
||||
_id = switch.object_id() + switch.name()
|
||||
if _id not in hass.data[DOMAIN]["unique_ids"]:
|
||||
add_entities([WinkToggleDevice(switch, hass)])
|
||||
|
||||
|
||||
class WinkToggleDevice(WinkDevice, ToggleEntity):
|
||||
"""Representation of a Wink toggle device."""
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Call 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."""
|
||||
return self.wink.state()
|
||||
|
||||
def turn_on(self, **kwargs):
|
||||
"""Turn the device on."""
|
||||
self.wink.set_state(True)
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn the device off."""
|
||||
self.wink.set_state(False)
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the state attributes."""
|
||||
attributes = super().extra_state_attributes
|
||||
try:
|
||||
event = self.wink.last_event()
|
||||
if event is not None:
|
||||
attributes["last_event"] = event
|
||||
except AttributeError:
|
||||
pass
|
||||
return attributes
|
|
@ -1,143 +0,0 @@
|
|||
"""Support for Wink water heaters."""
|
||||
import logging
|
||||
|
||||
import pywink
|
||||
|
||||
from homeassistant.components.water_heater import (
|
||||
ATTR_TEMPERATURE,
|
||||
STATE_ECO,
|
||||
STATE_ELECTRIC,
|
||||
STATE_GAS,
|
||||
STATE_HEAT_PUMP,
|
||||
STATE_HIGH_DEMAND,
|
||||
STATE_PERFORMANCE,
|
||||
SUPPORT_AWAY_MODE,
|
||||
SUPPORT_OPERATION_MODE,
|
||||
SUPPORT_TARGET_TEMPERATURE,
|
||||
WaterHeaterEntity,
|
||||
)
|
||||
from homeassistant.const import STATE_OFF, STATE_UNKNOWN, TEMP_CELSIUS
|
||||
|
||||
from . import DOMAIN, WinkDevice
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SUPPORT_FLAGS_HEATER = (
|
||||
SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE | SUPPORT_AWAY_MODE
|
||||
)
|
||||
|
||||
ATTR_RHEEM_TYPE = "rheem_type"
|
||||
ATTR_VACATION_MODE = "vacation_mode"
|
||||
|
||||
HA_STATE_TO_WINK = {
|
||||
STATE_ECO: "eco",
|
||||
STATE_ELECTRIC: "electric_only",
|
||||
STATE_GAS: "gas",
|
||||
STATE_HEAT_PUMP: "heat_pump",
|
||||
STATE_HIGH_DEMAND: "high_demand",
|
||||
STATE_OFF: "off",
|
||||
STATE_PERFORMANCE: "performance",
|
||||
}
|
||||
|
||||
WINK_STATE_TO_HA = {value: key for key, value in HA_STATE_TO_WINK.items()}
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||
"""Set up the Wink water heater devices."""
|
||||
|
||||
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_entities([WinkWaterHeater(water_heater, hass)])
|
||||
|
||||
|
||||
class WinkWaterHeater(WinkDevice, WaterHeaterEntity):
|
||||
"""Representation of a Wink water heater."""
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Return the list of supported features."""
|
||||
return SUPPORT_FLAGS_HEATER
|
||||
|
||||
@property
|
||||
def temperature_unit(self):
|
||||
"""Return the unit of measurement."""
|
||||
# The Wink API always returns temp in Celsius
|
||||
return TEMP_CELSIUS
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self):
|
||||
"""Return the optional device state attributes."""
|
||||
data = {}
|
||||
data[ATTR_VACATION_MODE] = self.wink.vacation_mode_enabled()
|
||||
data[ATTR_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 = (
|
||||
"Invalid operation mode mapping. "
|
||||
f"{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()
|
|
@ -1259,9 +1259,6 @@ proxmoxer==1.1.1
|
|||
# homeassistant.components.systemmonitor
|
||||
psutil==5.8.0
|
||||
|
||||
# homeassistant.components.wink
|
||||
pubnubsub-handler==1.0.9
|
||||
|
||||
# homeassistant.components.pulseaudio_loopback
|
||||
pulsectl==20.2.4
|
||||
|
||||
|
@ -1948,9 +1945,6 @@ python-vlc==1.1.2
|
|||
# homeassistant.components.whois
|
||||
python-whois==0.7.3
|
||||
|
||||
# homeassistant.components.wink
|
||||
python-wink==1.10.5
|
||||
|
||||
# homeassistant.components.awair
|
||||
python_awair==0.2.1
|
||||
|
||||
|
|
|
@ -62,7 +62,6 @@ ALLOWED_IGNORE_VIOLATIONS = {
|
|||
("velux", "scene.py"),
|
||||
("wemo", "config_flow.py"),
|
||||
("wiffi", "config_flow.py"),
|
||||
("wink", "scene.py"),
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue