Merge branch 'component-wink' into dev
* component-wink: Wink component bug fixes Bugfixes to make Wink component work Added wink component to auto-load other needed components Initial version wink component by @loghound changed bearer_token to access_token in conf file Wink Hub integration of it's switches & lights Conflicts: homeassistant/components/switch/__init__.py homeassistant/const.py
This commit is contained in:
commit
86e4fb9655
11 changed files with 520 additions and 52 deletions
|
@ -11,6 +11,10 @@ api_password=mypass
|
||||||
[light]
|
[light]
|
||||||
platform=hue
|
platform=hue
|
||||||
|
|
||||||
|
[wink]
|
||||||
|
# Get your token at https://winkbearertoken.appspot.com
|
||||||
|
token=YOUR_TOKEN
|
||||||
|
|
||||||
[device_tracker]
|
[device_tracker]
|
||||||
# The following types are available: netgear, tomato, luci, nmap_tracker
|
# The following types are available: netgear, tomato, luci, nmap_tracker
|
||||||
platform=netgear
|
platform=netgear
|
||||||
|
|
|
@ -15,15 +15,13 @@ from homeassistant.external.netdisco.netdisco import DiscoveryService
|
||||||
import homeassistant.external.netdisco.netdisco.const as services
|
import homeassistant.external.netdisco.netdisco.const as services
|
||||||
|
|
||||||
from homeassistant import bootstrap
|
from homeassistant import bootstrap
|
||||||
from homeassistant.const import EVENT_HOMEASSISTANT_START, ATTR_SERVICE
|
from homeassistant.const import (
|
||||||
|
EVENT_HOMEASSISTANT_START, EVENT_SERVICE_DISCOVERED,
|
||||||
|
ATTR_SERVICE, ATTR_DISCOVERED)
|
||||||
|
|
||||||
DOMAIN = "discovery"
|
DOMAIN = "discovery"
|
||||||
DEPENDENCIES = []
|
DEPENDENCIES = []
|
||||||
|
|
||||||
EVENT_SERVICE_DISCOVERED = "service_discovered"
|
|
||||||
|
|
||||||
ATTR_DISCOVERED = "discovered"
|
|
||||||
|
|
||||||
SCAN_INTERVAL = 300 # seconds
|
SCAN_INTERVAL = 300 # seconds
|
||||||
|
|
||||||
SERVICE_HANDLERS = {
|
SERVICE_HANDLERS = {
|
||||||
|
@ -39,8 +37,10 @@ def listen(hass, service, callback):
|
||||||
Service can be a string or a list/tuple.
|
Service can be a string or a list/tuple.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not isinstance(service, str):
|
if isinstance(service, str):
|
||||||
service = (service,)
|
service = (service,)
|
||||||
|
else:
|
||||||
|
service = tuple(service)
|
||||||
|
|
||||||
def discovery_event_listener(event):
|
def discovery_event_listener(event):
|
||||||
""" Listens for discovery events. """
|
""" Listens for discovery events. """
|
||||||
|
|
|
@ -52,12 +52,13 @@ import logging
|
||||||
import os
|
import os
|
||||||
import csv
|
import csv
|
||||||
|
|
||||||
|
from homeassistant.loader import get_component
|
||||||
import homeassistant.util as util
|
import homeassistant.util as util
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
|
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
|
||||||
from homeassistant.helpers import (
|
from homeassistant.helpers import (
|
||||||
extract_entity_ids, platform_devices_from_config)
|
extract_entity_ids, platform_devices_from_config)
|
||||||
from homeassistant.components import group
|
from homeassistant.components import group, discovery, wink
|
||||||
|
|
||||||
|
|
||||||
DOMAIN = "light"
|
DOMAIN = "light"
|
||||||
|
@ -87,9 +88,13 @@ ATTR_FLASH = "flash"
|
||||||
FLASH_SHORT = "short"
|
FLASH_SHORT = "short"
|
||||||
FLASH_LONG = "long"
|
FLASH_LONG = "long"
|
||||||
|
|
||||||
|
|
||||||
LIGHT_PROFILES_FILE = "light_profiles.csv"
|
LIGHT_PROFILES_FILE = "light_profiles.csv"
|
||||||
|
|
||||||
|
# Maps discovered services to their platforms
|
||||||
|
DISCOVERY_PLATFORMS = {
|
||||||
|
wink.DISCOVER_LIGHTS: 'wink',
|
||||||
|
}
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -166,19 +171,41 @@ def setup(hass, config):
|
||||||
lights = platform_devices_from_config(
|
lights = platform_devices_from_config(
|
||||||
config, DOMAIN, hass, ENTITY_ID_FORMAT, _LOGGER)
|
config, DOMAIN, hass, ENTITY_ID_FORMAT, _LOGGER)
|
||||||
|
|
||||||
if not lights:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def update_lights_state(now):
|
def update_lights_state(now):
|
||||||
""" Update the states of all the lights. """
|
""" Update the states of all the lights. """
|
||||||
for light in lights.values():
|
if lights:
|
||||||
light.update_ha_state(hass)
|
_LOGGER.info("Updating light states")
|
||||||
|
|
||||||
|
for light in lights.values():
|
||||||
|
light.update_ha_state(hass)
|
||||||
|
|
||||||
update_lights_state(None)
|
update_lights_state(None)
|
||||||
|
|
||||||
# Track all lights in a group
|
# Track all lights in a group
|
||||||
group.Group(hass, GROUP_NAME_ALL_LIGHTS, lights.keys(), False)
|
light_group = group.Group(
|
||||||
|
hass, GROUP_NAME_ALL_LIGHTS, lights.keys(), False)
|
||||||
|
|
||||||
|
def light_discovered(service, info):
|
||||||
|
""" Called when a light is discovered. """
|
||||||
|
platform = get_component(
|
||||||
|
"{}.{}".format(DOMAIN, DISCOVERY_PLATFORMS[service]))
|
||||||
|
|
||||||
|
discovered = platform.devices_discovered(hass, config, info)
|
||||||
|
|
||||||
|
for light in discovered:
|
||||||
|
if light is not None and light not in lights.values():
|
||||||
|
light.entity_id = util.ensure_unique_string(
|
||||||
|
ENTITY_ID_FORMAT.format(util.slugify(light.get_name())),
|
||||||
|
lights.keys())
|
||||||
|
|
||||||
|
lights[light.entity_id] = light
|
||||||
|
|
||||||
|
light.update_ha_state(hass)
|
||||||
|
|
||||||
|
light_group.update_tracked_entity_ids(lights.keys())
|
||||||
|
|
||||||
|
discovery.listen(hass, DISCOVERY_PLATFORMS.keys(), light_discovered)
|
||||||
|
|
||||||
def handle_light_service(service):
|
def handle_light_service(service):
|
||||||
""" Hande a turn light on or off service call. """
|
""" Hande a turn light on or off service call. """
|
||||||
|
|
63
homeassistant/components/light/wink.py
Normal file
63
homeassistant/components/light/wink.py
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
""" Support for Hue lights. """
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# pylint: disable=no-name-in-module, import-error
|
||||||
|
import homeassistant.external.wink.pywink as pywink
|
||||||
|
|
||||||
|
from homeassistant.helpers import ToggleDevice
|
||||||
|
from homeassistant.const import ATTR_FRIENDLY_NAME, CONF_ACCESS_TOKEN
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
def get_devices(hass, config):
|
||||||
|
""" Find and return Wink lights. """
|
||||||
|
token = config.get(CONF_ACCESS_TOKEN)
|
||||||
|
|
||||||
|
if token is None:
|
||||||
|
logging.getLogger(__name__).error(
|
||||||
|
"Missing wink access_token - "
|
||||||
|
"get one at https://winkbearertoken.appspot.com/")
|
||||||
|
return []
|
||||||
|
|
||||||
|
pywink.set_bearer_token(token)
|
||||||
|
|
||||||
|
return get_lights()
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
def devices_discovered(hass, config, info):
|
||||||
|
""" Called when a device is discovered. """
|
||||||
|
return get_lights()
|
||||||
|
|
||||||
|
|
||||||
|
def get_lights():
|
||||||
|
""" Returns the Wink switches. """
|
||||||
|
return [WinkLight(light) for light in pywink.get_bulbs()]
|
||||||
|
|
||||||
|
|
||||||
|
class WinkLight(ToggleDevice):
|
||||||
|
""" Represents a Wink light """
|
||||||
|
|
||||||
|
def __init__(self, wink):
|
||||||
|
self.wink = wink
|
||||||
|
self.state_attr = {ATTR_FRIENDLY_NAME: wink.name()}
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
""" Returns the name of the light if any. """
|
||||||
|
return self.wink.name()
|
||||||
|
|
||||||
|
def turn_on(self, **kwargs):
|
||||||
|
""" Turns the light on. """
|
||||||
|
self.wink.setState(True)
|
||||||
|
|
||||||
|
def turn_off(self):
|
||||||
|
""" Turns the light off. """
|
||||||
|
self.wink.setState(False)
|
||||||
|
|
||||||
|
def is_on(self):
|
||||||
|
""" True if light is on. """
|
||||||
|
return self.wink.state()
|
||||||
|
|
||||||
|
def get_state_attributes(self):
|
||||||
|
""" Returns optional state attributes. """
|
||||||
|
return self.state_attr
|
|
@ -12,7 +12,7 @@ from homeassistant.const import (
|
||||||
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
|
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, ATTR_ENTITY_ID)
|
||||||
from homeassistant.helpers import (
|
from homeassistant.helpers import (
|
||||||
extract_entity_ids, platform_devices_from_config)
|
extract_entity_ids, platform_devices_from_config)
|
||||||
from homeassistant.components import group, discovery
|
from homeassistant.components import group, discovery, wink
|
||||||
|
|
||||||
DOMAIN = 'switch'
|
DOMAIN = 'switch'
|
||||||
DEPENDENCIES = []
|
DEPENDENCIES = []
|
||||||
|
@ -29,8 +29,9 @@ ATTR_CURRENT_POWER_MWH = "current_power_mwh"
|
||||||
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
|
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
|
||||||
|
|
||||||
# Maps discovered services to their platforms
|
# Maps discovered services to their platforms
|
||||||
DISCOVERY = {
|
DISCOVERY_PLATFORMS = {
|
||||||
discovery.services.BELKIN_WEMO: 'wemo'
|
discovery.services.BELKIN_WEMO: 'wemo',
|
||||||
|
wink.DISCOVER_SWITCHES: 'wink',
|
||||||
}
|
}
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
@ -82,22 +83,24 @@ def setup(hass, config):
|
||||||
|
|
||||||
def switch_discovered(service, info):
|
def switch_discovered(service, info):
|
||||||
""" Called when a switch is discovered. """
|
""" Called when a switch is discovered. """
|
||||||
platform = get_component("{}.{}".format(DOMAIN, DISCOVERY[service]))
|
platform = get_component("{}.{}".format(
|
||||||
|
DOMAIN, DISCOVERY_PLATFORMS[service]))
|
||||||
|
|
||||||
switch = platform.device_discovered(hass, config, info)
|
discovered = platform.devices_discovered(hass, config, info)
|
||||||
|
|
||||||
if switch is not None and switch not in switches.values():
|
for switch in discovered:
|
||||||
switch.entity_id = util.ensure_unique_string(
|
if switch is not None and switch not in switches.values():
|
||||||
ENTITY_ID_FORMAT.format(util.slugify(switch.name)),
|
switch.entity_id = util.ensure_unique_string(
|
||||||
switches.keys())
|
ENTITY_ID_FORMAT.format(util.slugify(switch.name)),
|
||||||
|
switches.keys())
|
||||||
|
|
||||||
switches[switch.entity_id] = switch
|
switches[switch.entity_id] = switch
|
||||||
|
|
||||||
switch.update_ha_state(hass)
|
switch.update_ha_state(hass)
|
||||||
|
|
||||||
switch_group.update_tracked_entity_ids(switches.keys())
|
switch_group.update_tracked_entity_ids(switches.keys())
|
||||||
|
|
||||||
discovery.listen(hass, discovery.services.BELKIN_WEMO, switch_discovered)
|
discovery.listen(hass, DISCOVERY_PLATFORMS.keys(), switch_discovered)
|
||||||
|
|
||||||
def handle_switch_service(service):
|
def handle_switch_service(service):
|
||||||
""" Handles calls to the switch services. """
|
""" Handles calls to the switch services. """
|
||||||
|
|
|
@ -24,16 +24,16 @@ def get_devices(hass, config):
|
||||||
if isinstance(switch, pywemo.Switch)]
|
if isinstance(switch, pywemo.Switch)]
|
||||||
|
|
||||||
|
|
||||||
def device_discovered(hass, config, info):
|
def devices_discovered(hass, config, info):
|
||||||
""" Called when a device is discovered. """
|
""" Called when a device is discovered. """
|
||||||
_, discovery = get_pywemo()
|
_, discovery = get_pywemo()
|
||||||
|
|
||||||
if discovery is None:
|
if discovery is None:
|
||||||
return
|
return []
|
||||||
|
|
||||||
device = discovery.device_from_description(info)
|
device = discovery.device_from_description(info)
|
||||||
|
|
||||||
return None if device is None else WemoSwitch(device)
|
return [] if device is None else [WemoSwitch(device)]
|
||||||
|
|
||||||
|
|
||||||
def get_pywemo():
|
def get_pywemo():
|
||||||
|
|
63
homeassistant/components/switch/wink.py
Normal file
63
homeassistant/components/switch/wink.py
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
""" Support for WeMo switchces. """
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# pylint: disable=no-name-in-module, import-error
|
||||||
|
import homeassistant.external.wink.pywink as pywink
|
||||||
|
|
||||||
|
from homeassistant.helpers import ToggleDevice
|
||||||
|
from homeassistant.const import ATTR_FRIENDLY_NAME, CONF_ACCESS_TOKEN
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
def get_devices(hass, config):
|
||||||
|
""" Find and return Wink switches. """
|
||||||
|
token = config.get(CONF_ACCESS_TOKEN)
|
||||||
|
|
||||||
|
if token is None:
|
||||||
|
logging.getLogger(__name__).error(
|
||||||
|
"Missing wink access_token - "
|
||||||
|
"get one at https://winkbearertoken.appspot.com/")
|
||||||
|
return []
|
||||||
|
|
||||||
|
pywink.set_bearer_token(token)
|
||||||
|
|
||||||
|
return get_switches()
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
def devices_discovered(hass, config, info):
|
||||||
|
""" Called when a device is discovered. """
|
||||||
|
return get_switches()
|
||||||
|
|
||||||
|
|
||||||
|
def get_switches():
|
||||||
|
""" Returns the Wink switches. """
|
||||||
|
return [WinkSwitch(switch) for switch in pywink.get_switches()]
|
||||||
|
|
||||||
|
|
||||||
|
class WinkSwitch(ToggleDevice):
|
||||||
|
""" represents a WeMo switch within home assistant. """
|
||||||
|
|
||||||
|
def __init__(self, wink):
|
||||||
|
self.wink = wink
|
||||||
|
self.state_attr = {ATTR_FRIENDLY_NAME: wink.name()}
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
""" Returns the name of the switch if any. """
|
||||||
|
return self.wink.name()
|
||||||
|
|
||||||
|
def turn_on(self, **kwargs):
|
||||||
|
""" Turns the switch on. """
|
||||||
|
self.wink.setState(True)
|
||||||
|
|
||||||
|
def turn_off(self):
|
||||||
|
""" Turns the switch off. """
|
||||||
|
self.wink.setState(False)
|
||||||
|
|
||||||
|
def is_on(self):
|
||||||
|
""" True if switch is on. """
|
||||||
|
return self.wink.state()
|
||||||
|
|
||||||
|
def get_state_attributes(self):
|
||||||
|
""" Returns optional state attributes. """
|
||||||
|
return self.state_attr
|
51
homeassistant/components/wink.py
Normal file
51
homeassistant/components/wink.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
"""
|
||||||
|
Connects to a Wink hub and loads relevant components to control its devices.
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# pylint: disable=no-name-in-module, import-error
|
||||||
|
import homeassistant.external.wink.pywink as pywink
|
||||||
|
|
||||||
|
from homeassistant import bootstrap
|
||||||
|
from homeassistant.loader import get_component
|
||||||
|
from homeassistant.helpers import validate_config
|
||||||
|
from homeassistant.const import (
|
||||||
|
EVENT_SERVICE_DISCOVERED, ATTR_SERVICE, ATTR_DISCOVERED, CONF_ACCESS_TOKEN)
|
||||||
|
|
||||||
|
DOMAIN = "wink"
|
||||||
|
DEPENDENCIES = []
|
||||||
|
|
||||||
|
DISCOVER_LIGHTS = "wink.lights"
|
||||||
|
DISCOVER_SWITCHES = "wink.switches"
|
||||||
|
|
||||||
|
|
||||||
|
def setup(hass, config):
|
||||||
|
""" Sets up the Wink component. """
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
if not validate_config(config, {DOMAIN: [CONF_ACCESS_TOKEN]}, logger):
|
||||||
|
return False
|
||||||
|
|
||||||
|
pywink.set_bearer_token(config[DOMAIN][CONF_ACCESS_TOKEN])
|
||||||
|
|
||||||
|
# Load components for the devices in the Wink that we support
|
||||||
|
for component_name, func_exists, discovery_type in (
|
||||||
|
('light', pywink.get_bulbs, DISCOVER_LIGHTS),
|
||||||
|
('switch', pywink.get_switches, DISCOVER_SWITCHES)):
|
||||||
|
|
||||||
|
if func_exists():
|
||||||
|
component = get_component(component_name)
|
||||||
|
|
||||||
|
# Ensure component is loaded
|
||||||
|
if component.DOMAIN not in hass.components:
|
||||||
|
# Add a worker on succesfull setup
|
||||||
|
if bootstrap.setup_component(hass, component.DOMAIN, config):
|
||||||
|
hass.pool.add_worker()
|
||||||
|
|
||||||
|
# Fire discovery event
|
||||||
|
hass.bus.fire(EVENT_SERVICE_DISCOVERED, {
|
||||||
|
ATTR_SERVICE: discovery_type,
|
||||||
|
ATTR_DISCOVERED: {}
|
||||||
|
})
|
||||||
|
|
||||||
|
return True
|
|
@ -18,6 +18,7 @@ CONF_HOSTS = "hosts"
|
||||||
CONF_USERNAME = "username"
|
CONF_USERNAME = "username"
|
||||||
CONF_PASSWORD = "password"
|
CONF_PASSWORD = "password"
|
||||||
CONF_API_KEY = "api_key"
|
CONF_API_KEY = "api_key"
|
||||||
|
CONF_ACCESS_TOKEN = "access_token"
|
||||||
|
|
||||||
# #### EVENTS ####
|
# #### EVENTS ####
|
||||||
EVENT_HOMEASSISTANT_START = "homeassistant_start"
|
EVENT_HOMEASSISTANT_START = "homeassistant_start"
|
||||||
|
@ -26,6 +27,7 @@ EVENT_STATE_CHANGED = "state_changed"
|
||||||
EVENT_TIME_CHANGED = "time_changed"
|
EVENT_TIME_CHANGED = "time_changed"
|
||||||
EVENT_CALL_SERVICE = "call_service"
|
EVENT_CALL_SERVICE = "call_service"
|
||||||
EVENT_SERVICE_EXECUTED = "service_executed"
|
EVENT_SERVICE_EXECUTED = "service_executed"
|
||||||
|
EVENT_SERVICE_DISCOVERED = "service_discovered"
|
||||||
|
|
||||||
# #### STATES ####
|
# #### STATES ####
|
||||||
STATE_ON = 'on'
|
STATE_ON = 'on'
|
||||||
|
@ -64,6 +66,9 @@ ATTR_TEMPERATURE = "temperature"
|
||||||
TEMP_CELCIUS = "°C"
|
TEMP_CELCIUS = "°C"
|
||||||
TEMP_FAHRENHEIT = "°F"
|
TEMP_FAHRENHEIT = "°F"
|
||||||
|
|
||||||
|
# Contains the information that is discovered
|
||||||
|
ATTR_DISCOVERED = "discovered"
|
||||||
|
|
||||||
# #### SERVICES ####
|
# #### SERVICES ####
|
||||||
SERVICE_HOMEASSISTANT_STOP = "stop"
|
SERVICE_HOMEASSISTANT_STOP = "stop"
|
||||||
|
|
||||||
|
|
274
homeassistant/external/wink/pywink.py
vendored
Normal file
274
homeassistant/external/wink/pywink.py
vendored
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
__author__ = 'JOHNMCL'
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
baseUrl = "https://winkapi.quirky.com"
|
||||||
|
|
||||||
|
object_type = "light_bulb"
|
||||||
|
object_type_plural = "light_bulbs"
|
||||||
|
|
||||||
|
bearer_token=""
|
||||||
|
|
||||||
|
headers = {}
|
||||||
|
|
||||||
|
|
||||||
|
class wink_binary_switch():
|
||||||
|
""" represents a wink.py switch
|
||||||
|
json_obj holds the json stat at init (and if there is a refresh it's updated
|
||||||
|
it's the native format for this objects methods
|
||||||
|
and looks like so:
|
||||||
|
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"binary_switch_id": "4153",
|
||||||
|
"name": "Garage door indicator",
|
||||||
|
"locale": "en_us",
|
||||||
|
"units": {},
|
||||||
|
"created_at": 1411614982,
|
||||||
|
"hidden_at": null,
|
||||||
|
"capabilities": {},
|
||||||
|
"subscription": {},
|
||||||
|
"triggers": [],
|
||||||
|
"desired_state": {
|
||||||
|
"powered": false
|
||||||
|
},
|
||||||
|
"manufacturer_device_model": "leviton_dzs15",
|
||||||
|
"manufacturer_device_id": null,
|
||||||
|
"device_manufacturer": "leviton",
|
||||||
|
"model_name": "Switch",
|
||||||
|
"upc_id": "94",
|
||||||
|
"gang_id": null,
|
||||||
|
"hub_id": "11780",
|
||||||
|
"local_id": "9",
|
||||||
|
"radio_type": "zwave",
|
||||||
|
"last_reading": {
|
||||||
|
"powered": false,
|
||||||
|
"powered_updated_at": 1411614983.6153464,
|
||||||
|
"powering_mode": null,
|
||||||
|
"powering_mode_updated_at": null,
|
||||||
|
"consumption": null,
|
||||||
|
"consumption_updated_at": null,
|
||||||
|
"cost": null,
|
||||||
|
"cost_updated_at": null,
|
||||||
|
"budget_percentage": null,
|
||||||
|
"budget_percentage_updated_at": null,
|
||||||
|
"budget_velocity": null,
|
||||||
|
"budget_velocity_updated_at": null,
|
||||||
|
"summation_delivered": null,
|
||||||
|
"summation_delivered_updated_at": null,
|
||||||
|
"sum_delivered_multiplier": null,
|
||||||
|
"sum_delivered_multiplier_updated_at": null,
|
||||||
|
"sum_delivered_divisor": null,
|
||||||
|
"sum_delivered_divisor_updated_at": null,
|
||||||
|
"sum_delivered_formatting": null,
|
||||||
|
"sum_delivered_formatting_updated_at": null,
|
||||||
|
"sum_unit_of_measure": null,
|
||||||
|
"sum_unit_of_measure_updated_at": null,
|
||||||
|
"desired_powered": false,
|
||||||
|
"desired_powered_updated_at": 1417893563.7567682,
|
||||||
|
"desired_powering_mode": null,
|
||||||
|
"desired_powering_mode_updated_at": null
|
||||||
|
},
|
||||||
|
"current_budget": null,
|
||||||
|
"lat_lng": [
|
||||||
|
38.429996,
|
||||||
|
-122.653721
|
||||||
|
],
|
||||||
|
"location": "",
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
"errors": [],
|
||||||
|
"pagination": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
jsonState = {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, aJSonObj):
|
||||||
|
self.jsonState = aJSonObj
|
||||||
|
self.objectprefix = "binary_switches"
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "%s %s %s" % (self.name(), self.deviceId(), self.state())
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Wink switch %s %s %s>" % (self.name(), self.deviceId(), self.state())
|
||||||
|
|
||||||
|
def name(self):
|
||||||
|
name = self.jsonState.get('name')
|
||||||
|
return name or "Unknown Name"
|
||||||
|
|
||||||
|
def state(self):
|
||||||
|
state = self.jsonState.get('desired_state').get('powered')
|
||||||
|
return state
|
||||||
|
|
||||||
|
def setState(self, state):
|
||||||
|
"""
|
||||||
|
:param state: a boolean of true (on) or false ('off')
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
urlString = baseUrl + "/%s/%s" % (self.objectprefix, self.deviceId())
|
||||||
|
values = {"desired_state": {"powered": state}}
|
||||||
|
urlString = baseUrl + "/%s/%s" % (self.objectprefix, self.deviceId())
|
||||||
|
arequest = requests.put(urlString, data=json.dumps(values), headers=headers)
|
||||||
|
self._updateStateFromResponse(arequest.json())
|
||||||
|
|
||||||
|
|
||||||
|
def deviceId(self):
|
||||||
|
deviceId = self.jsonState.get('binary_switch_id')
|
||||||
|
return deviceId or "Unknown Device ID"
|
||||||
|
|
||||||
|
def updateState(self):
|
||||||
|
urlString = baseUrl + "/%s/%s" % (self.objectprefix, self.deviceId())
|
||||||
|
arequest = requests.get(urlString, headers=headers)
|
||||||
|
self._updateStateFromResponse(arequest.json())
|
||||||
|
|
||||||
|
def _updateStateFromResponse(self, response_json):
|
||||||
|
"""
|
||||||
|
:param response_json: the json obj returned from query
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.jsonState = response_json.get('data')
|
||||||
|
|
||||||
|
class wink_bulb(wink_binary_switch):
|
||||||
|
""" represents a wink.py bulb
|
||||||
|
json_obj holds the json stat at init (and if there is a refresh it's updated
|
||||||
|
it's the native format for this objects methods
|
||||||
|
and looks like so:
|
||||||
|
|
||||||
|
"light_bulb_id": "33990",
|
||||||
|
"name": "downstaurs lamp",
|
||||||
|
"locale": "en_us",
|
||||||
|
"units":{},
|
||||||
|
"created_at": 1410925804,
|
||||||
|
"hidden_at": null,
|
||||||
|
"capabilities":{},
|
||||||
|
"subscription":{},
|
||||||
|
"triggers":[],
|
||||||
|
"desired_state":{"powered": true, "brightness": 1},
|
||||||
|
"manufacturer_device_model": "lutron_p_pkg1_w_wh_d",
|
||||||
|
"manufacturer_device_id": null,
|
||||||
|
"device_manufacturer": "lutron",
|
||||||
|
"model_name": "Caseta Wireless Dimmer & Pico",
|
||||||
|
"upc_id": "3",
|
||||||
|
"hub_id": "11780",
|
||||||
|
"local_id": "8",
|
||||||
|
"radio_type": "lutron",
|
||||||
|
"linked_service_id": null,
|
||||||
|
"last_reading":{
|
||||||
|
"brightness": 1,
|
||||||
|
"brightness_updated_at": 1417823487.490747,
|
||||||
|
"connection": true,
|
||||||
|
"connection_updated_at": 1417823487.4907365,
|
||||||
|
"powered": true,
|
||||||
|
"powered_updated_at": 1417823487.4907532,
|
||||||
|
"desired_powered": true,
|
||||||
|
"desired_powered_updated_at": 1417823485.054675,
|
||||||
|
"desired_brightness": 1,
|
||||||
|
"desired_brightness_updated_at": 1417409293.2591703
|
||||||
|
},
|
||||||
|
"lat_lng":[38.429962, -122.653715],
|
||||||
|
"location": "",
|
||||||
|
"order": 0
|
||||||
|
|
||||||
|
"""
|
||||||
|
jsonState = {}
|
||||||
|
|
||||||
|
def __init__(self, ajsonobj):
|
||||||
|
self.jsonState = ajsonobj
|
||||||
|
self.objectprefix = "light_bulbs"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "%s %s %s" % (self.name(), self.deviceId(), self.state())
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Wink Bulb %s %s %s>" % (self.name(), self.deviceId(), self.state())
|
||||||
|
|
||||||
|
def name(self):
|
||||||
|
name = self.jsonState.get('name')
|
||||||
|
return name or "Unknown Name"
|
||||||
|
|
||||||
|
def state(self):
|
||||||
|
state = self.jsonState.get('desired_state').get('powered')
|
||||||
|
return state
|
||||||
|
|
||||||
|
def setState(self, state):
|
||||||
|
"""
|
||||||
|
:param state: a boolean of true (on) or false ('off')
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
urlString = baseUrl + "/light_bulbs/%s" % self.deviceId()
|
||||||
|
values = {"desired_state": {"desired_powered": state, "powered": state}}
|
||||||
|
urlString = baseUrl + "/light_bulbs/%s" % self.deviceId()
|
||||||
|
arequest = requests.put(urlString, data=json.dumps(values), headers=headers)
|
||||||
|
|
||||||
|
self.updateState()
|
||||||
|
|
||||||
|
|
||||||
|
def deviceId(self):
|
||||||
|
deviceId = self.jsonState.get('light_bulb_id')
|
||||||
|
return deviceId or "Unknown Device ID"
|
||||||
|
|
||||||
|
|
||||||
|
def get_bulbs_and_switches():
|
||||||
|
arequestUrl = baseUrl + "/users/me/wink_devices"
|
||||||
|
j = requests.get(arequestUrl, headers=headers).json()
|
||||||
|
|
||||||
|
items = j.get('data')
|
||||||
|
|
||||||
|
switches = []
|
||||||
|
for item in items:
|
||||||
|
id = item.get('light_bulb_id')
|
||||||
|
if id != None:
|
||||||
|
switches.append(wink_bulb(item))
|
||||||
|
id = item.get('binary_switch_id')
|
||||||
|
if id != None:
|
||||||
|
switches.append(wink_binary_switch(item))
|
||||||
|
|
||||||
|
return switches
|
||||||
|
|
||||||
|
|
||||||
|
def get_bulbs():
|
||||||
|
arequestUrl = baseUrl + "/users/me/wink_devices"
|
||||||
|
j = requests.get(arequestUrl, headers=headers).json()
|
||||||
|
|
||||||
|
items = j.get('data')
|
||||||
|
|
||||||
|
switches = []
|
||||||
|
for item in items:
|
||||||
|
id = item.get('light_bulb_id')
|
||||||
|
if id != None:
|
||||||
|
switches.append(wink_bulb(item))
|
||||||
|
|
||||||
|
return switches
|
||||||
|
|
||||||
|
|
||||||
|
def get_switches():
|
||||||
|
arequestUrl = baseUrl + "/users/me/wink_devices"
|
||||||
|
j = requests.get(arequestUrl, headers=headers).json()
|
||||||
|
|
||||||
|
items = j.get('data')
|
||||||
|
|
||||||
|
switches = []
|
||||||
|
for item in items:
|
||||||
|
id = item.get('binary_switch_id')
|
||||||
|
if id != None:
|
||||||
|
switches.append(wink_binary_switch(item))
|
||||||
|
|
||||||
|
return switches
|
||||||
|
|
||||||
|
def set_bearer_token(token):
|
||||||
|
global headers
|
||||||
|
bearer_token=token
|
||||||
|
headers={"Content-Type": "application/json", "Authorization": "Bearer {}".format(token)}
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sw = get_bulbs()
|
||||||
|
lamp = sw[3]
|
||||||
|
lamp.setState(False)
|
|
@ -214,28 +214,6 @@ class TestLight(unittest.TestCase):
|
||||||
light.ATTR_XY_COLOR: [prof_x, prof_y]},
|
light.ATTR_XY_COLOR: [prof_x, prof_y]},
|
||||||
data)
|
data)
|
||||||
|
|
||||||
def test_setup(self):
|
|
||||||
""" Test the setup method. """
|
|
||||||
# Bogus config
|
|
||||||
self.assertFalse(light.setup(self.hass, {}))
|
|
||||||
|
|
||||||
self.assertFalse(light.setup(self.hass, {light.DOMAIN: {}}))
|
|
||||||
|
|
||||||
# Test with non-existing component
|
|
||||||
self.assertFalse(light.setup(
|
|
||||||
self.hass, {light.DOMAIN: {CONF_TYPE: 'nonexisting'}}
|
|
||||||
))
|
|
||||||
|
|
||||||
# Test if light component returns 0 lightes
|
|
||||||
platform = loader.get_component('light.test')
|
|
||||||
platform.init(True)
|
|
||||||
|
|
||||||
self.assertEqual([], platform.get_lights(None, None))
|
|
||||||
|
|
||||||
self.assertFalse(light.setup(
|
|
||||||
self.hass, {light.DOMAIN: {CONF_TYPE: 'test'}}
|
|
||||||
))
|
|
||||||
|
|
||||||
def test_light_profiles(self):
|
def test_light_profiles(self):
|
||||||
""" Test light profiles. """
|
""" Test light profiles. """
|
||||||
platform = loader.get_component('light.test')
|
platform = loader.get_component('light.test')
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue