Move WeMo discovery into a common component
This commit is contained in:
parent
4dad40fffb
commit
afe564fb3f
8 changed files with 147 additions and 102 deletions
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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':
|
||||
|
|
95
homeassistant/components/wemo.py
Normal file
95
homeassistant/components/wemo.py
Normal 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
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue