Move WeMo discovery into a common component

This commit is contained in:
Jan Harkes 2016-02-19 01:57:32 -05:00
parent 4dad40fffb
commit afe564fb3f
8 changed files with 147 additions and 102 deletions

View file

@ -39,6 +39,9 @@ omit =
homeassistant/components/verisure.py
homeassistant/components/*/verisure.py
homeassistant/components/wemo.py
homeassistant/components/*/wemo.py
homeassistant/components/wink.py
homeassistant/components/*/wink.py
@ -91,7 +94,6 @@ omit =
homeassistant/components/light/hyperion.py
homeassistant/components/light/lifx.py
homeassistant/components/light/limitlessled.py
homeassistant/components/light/wemo.py
homeassistant/components/media_player/cast.py
homeassistant/components/media_player/denon.py
homeassistant/components/media_player/firetv.py
@ -149,7 +151,6 @@ omit =
homeassistant/components/switch/orvibo.py
homeassistant/components/switch/rest.py
homeassistant/components/switch/transmission.py
homeassistant/components/switch/wemo.py
homeassistant/components/thermostat/heatmiser.py
homeassistant/components/thermostat/homematic.py
homeassistant/components/thermostat/proliphix.py

View file

@ -27,7 +27,7 @@ SERVICE_SONOS = 'sonos'
SERVICE_PLEX = 'plex_mediaserver'
SERVICE_HANDLERS = {
SERVICE_WEMO: "switch",
SERVICE_WEMO: "wemo",
SERVICE_CAST: "media_player",
SERVICE_HUE: "light",
SERVICE_NETGEAR: 'device_tracker',

View file

@ -11,7 +11,7 @@ import os
import csv
from homeassistant.components import (
group, discovery, wink, isy994, zwave, insteon_hub, mysensors)
group, discovery, wemo, wink, isy994, zwave, insteon_hub, mysensors)
from homeassistant.config import load_yaml_config_file
from homeassistant.const import (
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE,
@ -59,6 +59,7 @@ LIGHT_PROFILES_FILE = "light_profiles.csv"
# Maps discovered services to their platforms
DISCOVERY_PLATFORMS = {
wemo.DISCOVER_LIGHTS: 'wemo',
wink.DISCOVER_LIGHTS: 'wink',
insteon_hub.DISCOVER_LIGHTS: 'insteon_hub',
isy994.DISCOVER_LIGHTS: 'isy994',

View file

@ -13,7 +13,8 @@ import homeassistant.util as util
from homeassistant.components.light import (
Light, ATTR_BRIGHTNESS)
# REQUIREMENTS = ['pywemo==0.3.12']
DEPENDENCIES = ['wemo']
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(milliseconds=100)
@ -21,8 +22,7 @@ _LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Find WeMo bridges and return connected lights. """
import pywemo
"""Probe WeMo bridges and register connected lights."""
import pywemo.discovery as discovery
if discovery_info is not None:
@ -30,28 +30,17 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
mac = discovery_info[3]
device = discovery.device_from_description(location, mac)
if device and isinstance(device, pywemo.Bridge):
setup_bridge(device, add_devices_callback)
return
_LOGGER.info("Scanning for WeMo devices.")
devices = pywemo.discover_devices()
# Filter out the bridges
for device in devices:
if isinstance(device, pywemo.Bridge):
_LOGGER.info("Found bridge %s.", device)
if device:
setup_bridge(device, add_devices_callback)
def setup_bridge(bridge, add_devices_callback):
""" Setup a WeMo link. """
"""Setup a WeMo link."""
lights = {}
@util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
def update_lights():
""" Updates the WeMo led objects with latest info from the bridge. """
"""Updates the WeMo led objects with latest info from the bridge."""
bridge.bridge_get_lights()
@ -59,8 +48,8 @@ def setup_bridge(bridge, add_devices_callback):
for light_id, info in bridge.Lights.items():
if light_id not in lights:
lights[light_id] = WemoLight(light_id, info,
bridge, update_lights)
lights[light_id] = WemoLight(bridge, light_id, info,
update_lights)
new_lights.append(lights[light_id])
else:
lights[light_id].info = info
@ -72,46 +61,46 @@ def setup_bridge(bridge, add_devices_callback):
class WemoLight(Light):
""" Represents a WeMo light """
"""Represents a WeMo light"""
def __init__(self, light_id, info, bridge, update_lights):
def __init__(self, bridge, light_id, info, update_lights):
self.bridge = bridge
self.light_id = light_id
self.info = info
self.bridge = bridge
self.update_lights = update_lights
@property
def unique_id(self):
""" Returns the id of this light """
"""Returns the id of this light"""
deviceid = self.bridge.light_get_id(self.info)
return "{}.{}".format(self.__class__, deviceid)
@property
def name(self):
""" Get the name of the light. """
"""Get the name of the light."""
return self.bridge.light_name(self.info)
@property
def brightness(self):
""" Brightness of this light between 0..255. """
"""Brightness of this light between 0..255."""
state = self.bridge.light_get_state(self.info)
return int(state['dim'])
@property
def is_on(self):
""" True if device is on. """
"""True if device is on."""
state = self.bridge.light_get_state(self.info)
return int(state['state'])
def turn_on(self, **kwargs):
""" Turn the light on. """
"""Turn the light on."""
dim = kwargs.get(ATTR_BRIGHTNESS, self.brightness)
self.bridge.light_set_state(self.info, state=1, dim=dim)
def turn_off(self, **kwargs):
""" Turn the light off. """
"""Turn the light off."""
self.bridge.light_set_state(self.info, state=0, dim=0)
def update(self):
""" Synchronize state with bridge. """
"""Synchronize state with bridge."""
self.update_lights(no_throttle=True)

View file

@ -18,7 +18,7 @@ from homeassistant.const import (
STATE_ON, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE,
ATTR_ENTITY_ID)
from homeassistant.components import (
group, discovery, wink, isy994, verisure, zwave, tellduslive, mysensors)
group, wemo, wink, isy994, verisure, zwave, tellduslive, mysensors)
DOMAIN = 'switch'
SCAN_INTERVAL = 30
@ -35,7 +35,7 @@ MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
# Maps discovered services to their platforms
DISCOVERY_PLATFORMS = {
discovery.SERVICE_WEMO: 'wemo',
wemo.DISCOVER_SWITCHES: 'wemo',
wink.DISCOVER_SWITCHES: 'wink',
isy994.DISCOVER_SWITCHES: 'isy994',
verisure.DISCOVER_SWITCHES: 'verisure',

View file

@ -9,14 +9,13 @@ https://home-assistant.io/components/switch.wemo/
import logging
from homeassistant.components.switch import SwitchDevice
from homeassistant.const import (
EVENT_HOMEASSISTANT_STOP, STATE_OFF, STATE_ON, STATE_STANDBY)
from homeassistant.const import STATE_OFF, STATE_ON, STATE_STANDBY
from homeassistant.loader import get_component
DEPENDENCIES = ['wemo']
REQUIREMENTS = ['pywemo==0.3.12']
_LOGGER = logging.getLogger(__name__)
_WEMO_SUBSCRIPTION_REGISTRY = None
ATTR_SENSOR_STATE = "sensor_state"
ATTR_SWITCH_MODE = "switch_mode"
@ -24,73 +23,33 @@ MAKER_SWITCH_MOMENTARY = "momentary"
MAKER_SWITCH_TOGGLE = "toggle"
def _find_manual_wemos(pywemo, static_config):
for address in static_config:
port = pywemo.ouimeaux_device.probe_wemo(address)
if not port:
_LOGGER.warning('Unable to probe wemo at %s', address)
continue
_LOGGER.info('Adding static wemo at %s:%i', address, port)
url = 'http://%s:%i/setup.xml' % (address, port)
yield pywemo.discovery.device_from_description(url, None)
# pylint: disable=unused-argument, too-many-function-args
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
""" Find and return WeMo switches. """
import pywemo
"""Register discovered WeMo switches."""
import pywemo.discovery as discovery
global _WEMO_SUBSCRIPTION_REGISTRY
if _WEMO_SUBSCRIPTION_REGISTRY is None:
_WEMO_SUBSCRIPTION_REGISTRY = pywemo.SubscriptionRegistry()
_WEMO_SUBSCRIPTION_REGISTRY.start()
def stop_wemo(event):
""" Shutdown Wemo subscriptions and subscription thread on exit"""
_LOGGER.info("Shutting down subscriptions.")
_WEMO_SUBSCRIPTION_REGISTRY.stop()
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_wemo)
if discovery_info is not None:
location = discovery_info[2]
mac = discovery_info[3]
device = discovery.device_from_description(location, mac)
if device and isinstance(device, pywemo.Switch):
if device:
add_devices_callback([WemoSwitch(device)])
return
_LOGGER.info("Scanning for WeMo devices.")
switches = pywemo.discover_devices()
# Filter out the switches and wrap in WemoSwitch object
add_devices_callback(
[WemoSwitch(switch) for switch in switches
if isinstance(switch, pywemo.Switch)])
# Add manually-defined wemo devices
if discovery_info is None and 'static' in config:
add_devices_callback(
[WemoSwitch(wemo)
for wemo in _find_manual_wemos(pywemo, config['static'])])
class WemoSwitch(SwitchDevice):
""" Represents a WeMo switch. """
def __init__(self, wemo):
self.wemo = wemo
"""Represents a WeMo switch."""
def __init__(self, device):
self.wemo = device
self.insight_params = None
self.maker_params = None
_WEMO_SUBSCRIPTION_REGISTRY.register(wemo)
_WEMO_SUBSCRIPTION_REGISTRY.on(
wemo, None, self._update_callback)
wemo = get_component('wemo')
wemo.SUBSCRIPTION_REGISTRY.register(self.wemo)
wemo.SUBSCRIPTION_REGISTRY.on(self.wemo, None, self._update_callback)
def _update_callback(self, _device, _params):
""" Called by the wemo device callback to update state. """
"""Called by the wemo device callback to update state."""
_LOGGER.info(
'Subscription update for %s',
_device)
@ -98,17 +57,17 @@ class WemoSwitch(SwitchDevice):
@property
def should_poll(self):
""" No polling needed with subscriptions """
"""No polling needed with subscriptions"""
return False
@property
def unique_id(self):
""" Returns the id of this WeMo switch """
"""Returns the id of this WeMo switch"""
return "{}.{}".format(self.__class__, self.wemo.serialnumber)
@property
def name(self):
""" Returns the name of the switch if any. """
"""Returns the name of the switch if any."""
return self.wemo.name
@property
@ -133,7 +92,7 @@ class WemoSwitch(SwitchDevice):
@property
def state(self):
""" Returns the state. """
"""Returns the state."""
is_on = self.is_on
if not is_on:
return STATE_OFF
@ -143,19 +102,19 @@ class WemoSwitch(SwitchDevice):
@property
def current_power_mwh(self):
""" Current power usage in mwh. """
"""Current power usage in mwh."""
if self.insight_params:
return self.insight_params['currentpower']
@property
def today_power_mw(self):
""" Today total power usage in mw. """
"""Today total power usage in mw."""
if self.insight_params:
return self.insight_params['todaymw']
@property
def is_standby(self):
""" Is the device on - or in standby. """
"""Is the device on - or in standby."""
if self.insight_params:
standby_state = self.insight_params['state']
# Standby is actually '8' but seems more defensive
@ -167,12 +126,12 @@ class WemoSwitch(SwitchDevice):
@property
def is_on(self):
""" True if switch is on. """
"""True if switch is on."""
return self.wemo.get_state()
@property
def available(self):
""" True if switch is available. """
"""True if switch is available."""
if (self.wemo.model_name == 'Insight' and
self.insight_params is None):
return False
@ -183,15 +142,15 @@ class WemoSwitch(SwitchDevice):
return True
def turn_on(self, **kwargs):
""" Turns the switch on. """
"""Turns the switch on."""
self.wemo.on()
def turn_off(self):
""" Turns the switch off. """
"""Turns the switch off."""
self.wemo.off()
def update(self):
""" Update WeMo state. """
"""Update WeMo state."""
try:
self.wemo.get_state(True)
if self.wemo.model_name == 'Insight':

View file

@ -0,0 +1,95 @@
"""
homeassistant.components.wemo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WeMo device discovery.
For more details about this component, please refer to the documentation at
https://home-assistant.io/components/wemo/
"""
import logging
from homeassistant.components import discovery
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
REQUIREMENTS = ['pywemo==0.3.12']
DOMAIN = 'wemo'
DISCOVER_LIGHTS = 'wemo.light'
DISCOVER_MOTION = 'wemo.motion'
DISCOVER_SWITCHES = 'wemo.switch'
# mapping from Wemo model_name to service
WEMO_MODEL_DISPATCH = {
'Bridge': DISCOVER_LIGHTS,
'Insight': DISCOVER_SWITCHES,
'Maker': DISCOVER_SWITCHES,
'Motion': DISCOVER_MOTION,
'Switch': DISCOVER_SWITCHES,
}
WEMO_SERVICE_DISPATCH = {
DISCOVER_LIGHTS: 'light',
DISCOVER_MOTION: 'binary_sensor',
DISCOVER_SWITCHES: 'switch',
}
SUBSCRIPTION_REGISTRY = None
KNOWN_DEVICES = []
_LOGGER = logging.getLogger(__name__)
# pylint: disable=unused-argument, too-many-function-args
def setup(hass, config):
"""Common set up for WeMo devices."""
import pywemo
global SUBSCRIPTION_REGISTRY
SUBSCRIPTION_REGISTRY = pywemo.SubscriptionRegistry()
SUBSCRIPTION_REGISTRY.start()
def stop_wemo(event):
"""Shutdown Wemo subscriptions and subscription thread on exit."""
_LOGGER.info("Shutting down subscriptions.")
SUBSCRIPTION_REGISTRY.stop()
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop_wemo)
def discovery_dispatch(service, discovery_info):
"""Dispatcher for WeMo discovery events."""
# name, model, location, mac
_, model_name, _, mac = discovery_info
# Only register a device once
if mac in KNOWN_DEVICES:
return
KNOWN_DEVICES.append(mac)
service = WEMO_MODEL_DISPATCH.get(model_name)
component = WEMO_SERVICE_DISPATCH.get(service)
if service is not None:
discovery.discover(hass, service, discovery_info,
component, config)
discovery.listen(hass, discovery.SERVICE_WEMO, discovery_dispatch)
_LOGGER.info("Scanning for WeMo devices.")
devices = [(device.host, device) for device in pywemo.discover_devices()]
# Add static devices from the config file
devices.extend((address, None) for address in config.get('static', []))
for address, device in devices:
port = pywemo.ouimeaux_device.probe_wemo(address)
if not port:
_LOGGER.warning('Unable to probe wemo at %s', address)
continue
_LOGGER.info('Adding wemo at %s:%i', address, port)
url = 'http://%s:%i/setup.xml' % (address, port)
if device is None:
device = pywemo.discovery.device_from_description(url, None)
discovery_info = (device.name, device.model_name, url, device.mac)
discovery.discover(hass, discovery.SERVICE_WEMO, discovery_info)
return True

View file

@ -216,7 +216,7 @@ pyuserinput==0.1.9
# homeassistant.components.switch.vera
pyvera==0.2.8
# homeassistant.components.switch.wemo
# homeassistant.components.wemo
pywemo==0.3.12
# homeassistant.components.thermostat.radiotherm