1
mirror of https://github.com/home-assistant/core synced 2024-08-02 23:40:32 +02:00

Migrated wemo component to be part of a switch component

This commit is contained in:
Paulus Schoutsen 2014-11-08 17:20:43 -08:00
parent 222d57bda7
commit 5770cc03a1
9 changed files with 269 additions and 193 deletions

View File

@ -182,13 +182,13 @@ Optional service data:
- `rgb_color` - three comma seperated integers that represent the color in RGB
- `brightness` - integer between 0 and 255 for how bright the color should be
**wemo**
Keeps track which WeMo switches are in the network, their state and allows you to control them.
**switch**
Keeps track which switches are in the network, their state and allows you to control them.
Registers services `wemo/turn_on` and `wemo/turn_off` to turn a or all wemo switches on or off.
Registers services `switch/turn_on` and `switch/turn_off` to turn a or all switches on or off.
Optional service data:
- `entity_id` - only act on specific WeMo switch. Else targets all.
- `entity_id` - only act on specific switch. Else targets all.
**device_sun_light_trigger**
Turns lights on or off using a light control component based on state of the sun and devices that are home.

View File

@ -23,9 +23,9 @@ password=PASSWORD
# instead of scanning the network
# hosts=192.168.1.9,192.168.1.12
[wemo]
# Optional: hard code the hosts (comma seperated) to find WeMos
# instead of scanning the network
[switch]
type=wemo
# Optional: hard code the hosts (comma seperated) to avoid scanning the network
# hosts=192.168.1.9,192.168.1.12
[downloader]

View File

@ -640,7 +640,14 @@ class Timer(threading.Thread):
class HomeAssistantError(Exception):
""" General Home Assistant exception occured. """
pass
class InvalidEntityFormatError(HomeAssistantError):
""" When an invalid formatted entity is encountered. """
pass
class NoEntitySpecifiedError(HomeAssistantError):
""" When no entity is specified. """
pass

View File

@ -74,20 +74,20 @@ def setup(hass, config):
group.setup_group(hass, GROUP_NAME_ALL_LIGHTS, lights, False)
# Setup Wemo
wemos = ['wemo.AC', 'wemo.Christmas_Lights']
# Setup switch
switches = ['switch.AC', 'switch.Christmas_Lights']
hass.services.register('wemo', SERVICE_TURN_ON, mock_turn_on)
hass.services.register('wemo', SERVICE_TURN_OFF, mock_turn_off)
hass.services.register('switch', SERVICE_TURN_ON, mock_turn_on)
hass.services.register('switch', SERVICE_TURN_OFF, mock_turn_off)
mock_turn_on(ha.ServiceCall('wemo', SERVICE_TURN_ON,
{'entity_id': wemos[0:1]}))
mock_turn_off(ha.ServiceCall('wemo', SERVICE_TURN_OFF,
{'entity_id': wemos[1:]}))
mock_turn_on(ha.ServiceCall('switch', SERVICE_TURN_ON,
{'entity_id': switches[0:1]}))
mock_turn_off(ha.ServiceCall('switch', SERVICE_TURN_OFF,
{'entity_id': switches[1:]}))
# Setup room groups
group.setup_group(hass, 'living_room', lights[0:3] + wemos[0:1])
group.setup_group(hass, 'bedroom', [lights[3]] + wemos[1:])
group.setup_group(hass, 'living_room', lights[0:3] + switches[0:1])
group.setup_group(hass, 'bedroom', [lights[3]] + switches[1:])
# Setup process
hass.states.set("process.XBMC", STATE_ON)

View File

@ -1,2 +1,2 @@
""" DO NOT MODIFY. Auto-generated by build_frontend script """
VERSION = "eabfdd5cb0e712c8d6d5d837fb9bfeb9"
VERSION = "6d353f9599942124690691fb22c115ee"

View File

@ -17747,8 +17747,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
case "device_tracker":
return "social:person";
case "wemo":
return "settings-input-svideo";
case "switch":
return "image:flash-on";
case "chromecast":
if(state && state != "idle") {

View File

@ -24,8 +24,8 @@
case "device_tracker":
return "social:person";
case "wemo":
return "settings-input-svideo";
case "switch":
return "image:flash-on";
case "chromecast":
if(state && state != "idle") {

View File

@ -0,0 +1,240 @@
"""
homeassistant.components.switch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component to interface with various switches that can be controlled remotely.
"""
import logging
from datetime import datetime, timedelta
import homeassistant as ha
import homeassistant.util as util
from homeassistant.components import (group, extract_entity_ids,
STATE_ON, STATE_OFF,
SERVICE_TURN_ON, SERVICE_TURN_OFF,
ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME)
DOMAIN = 'switch'
DEPENDENCIES = []
GROUP_NAME_ALL_SWITCHES = 'all_switches'
ENTITY_ID_ALL_SWITCHES = group.ENTITY_ID_FORMAT.format(
GROUP_NAME_ALL_SWITCHES)
ENTITY_ID_FORMAT = DOMAIN + '.{}'
ATTR_TODAY_KWH = "today_kwh"
ATTR_CURRENT_POWER = "current_power"
ATTR_TODAY_ON_TIME = "today_on_time"
ATTR_TODAY_STANDBY_TIME = "today_standby_time"
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
_LOGGER = logging.getLogger(__name__)
def is_on(hass, entity_id=None):
""" Returns if the switch is on based on the statemachine. """
entity_id = entity_id or ENTITY_ID_ALL_SWITCHES
return hass.states.is_state(entity_id, STATE_ON)
def turn_on(hass, entity_id=None):
""" Turns all or specified switch on. """
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.call_service(DOMAIN, SERVICE_TURN_ON, data)
def turn_off(hass, entity_id=None):
""" Turns all or specified switch off. """
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.call_service(DOMAIN, SERVICE_TURN_OFF, data)
# pylint: disable=too-many-branches
def setup(hass, config):
""" Track states and offer events for switches. """
logger = logging.getLogger(__name__)
if not util.validate_config(config, {DOMAIN: [ha.CONF_TYPE]}, logger):
return False
switch_type = config[DOMAIN][ha.CONF_TYPE]
if switch_type == 'wemo':
switch_init = get_wemo_switches
else:
logger.error("Unknown switch type specified: %s", switch_type)
return False
switches = switch_init(config[DOMAIN])
if len(switches) == 0:
logger.error("No switches found")
return False
# Setup a dict mapping entity IDs to devices
ent_to_switch = {}
no_name_count = 1
for switch in switches:
name = switch.get_name()
if name is None:
name = "Switch #{}".format(no_name_count)
no_name_count += 1
entity_id = util.ensure_unique_string(
ENTITY_ID_FORMAT.format(util.slugify(name)),
list(ent_to_switch.keys()))
switch.entity_id = entity_id
ent_to_switch[entity_id] = switch
# pylint: disable=unused-argument
def update_states(time, force_reload=False):
""" Update states of all switches. """
# First time this method gets called, force_reload should be True
if force_reload or \
datetime.now() - update_states.last_updated > \
MIN_TIME_BETWEEN_SCANS:
logger.info("Updating switch states")
update_states.last_updated = datetime.now()
for switch in switches:
switch.update_ha_state(hass)
update_states(None, True)
def handle_switch_service(service):
""" Handles calls to the switch services. """
devices = [ent_to_switch[entity_id] for entity_id
in extract_entity_ids(hass, service)
if entity_id in ent_to_switch]
if not devices:
devices = switches
for switch in devices:
if service.service == SERVICE_TURN_ON:
switch.turn_on()
else:
switch.turn_off()
switch.update_ha_state(hass)
# Track all wemos in a group
group.setup_group(hass, GROUP_NAME_ALL_SWITCHES,
ent_to_switch.keys(), False)
# Update state every 30 seconds
hass.track_time_change(update_states, second=[0, 30])
hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_switch_service)
hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_switch_service)
return True
class Switch(object):
""" ABC for Switches within Home Assistant. """
# pylint: disable=no-self-use
entity_id = None
def get_name(self):
""" Returns the name of the switch if any. """
return None
def turn_on(self, dimming=100):
"""
Turns the switch on.
Dimming is a number between 0-100 and specifies how much switch has
to be dimmed. There is no guarantee that the switch supports dimming.
"""
pass
def turn_off(self):
""" Turns the switch off. """
pass
def is_on(self):
""" True if switch is on. """
return False
def get_state_attributes(self):
""" Returns optional state attributes. """
return None
def update_ha_state(self, hass):
""" Updates Home Assistant with its current state. """
if self.entity_id is None:
raise ha.NoEntitySpecifiedError(
"No entity specified for switch {}".format(self.get_name()))
state = STATE_ON if self.is_on() else STATE_OFF
return hass.states.set(self.entity_id, state,
self.get_state_attributes())
def get_wemo_switches(config):
""" Find and return WeMo switches. """
try:
# Pylint does not play nice if not every folders has an __init__.py
# pylint: disable=no-name-in-module, import-error
import homeassistant.external.pywemo.pywemo as pywemo
except ImportError:
_LOGGER.exception((
"Wemo:Failed to import pywemo. "
"Did you maybe not run `git submodule init` "
"and `git submodule update`?"))
return []
if ha.CONF_HOSTS in config:
switches = (pywemo.device_from_host(host) for host
in config[ha.CONF_HOSTS].split(","))
else:
_LOGGER.info("Scanning for WeMo devices")
switches = pywemo.discover_devices()
# Filter out the switches and wrap in WemoSwitch object
return [WemoSwitch(switch) for switch in switches
if isinstance(switch, pywemo.Switch)]
class WemoSwitch(Switch):
""" represents a WeMo switch within home assistant. """
def __init__(self, wemo):
self.wemo = wemo
self.state_attr = {ATTR_FRIENDLY_NAME: wemo.name}
def get_name(self):
""" Returns the name of the switch if any. """
return self.wemo.name
def turn_on(self, dimming=100):
""" Turns the switch on. """
self.wemo.on()
def turn_off(self):
""" Turns the switch off. """
self.wemo.off()
def is_on(self):
""" True if switch is on. """
return self.wemo.get_state(True)
def get_state_attributes(self):
""" Returns optional state attributes. """
return self.state_attr

View File

@ -1,171 +0,0 @@
"""
Component to interface with WeMo devices on the network.
"""
import logging
from datetime import datetime, timedelta
import homeassistant as ha
import homeassistant.util as util
from homeassistant.components import (group, extract_entity_ids,
STATE_ON, STATE_OFF,
SERVICE_TURN_ON, SERVICE_TURN_OFF,
ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME)
DOMAIN = 'wemo'
DEPENDENCIES = []
GROUP_NAME_ALL_WEMOS = 'all_wemos'
ENTITY_ID_ALL_WEMOS = group.ENTITY_ID_FORMAT.format(
GROUP_NAME_ALL_WEMOS)
ENTITY_ID_FORMAT = DOMAIN + '.{}'
ATTR_TODAY_KWH = "today_kwh"
ATTR_CURRENT_POWER = "current_power"
ATTR_TODAY_ON_TIME = "today_on_time"
ATTR_TODAY_STANDBY_TIME = "today_standby_time"
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
def is_on(hass, entity_id=None):
""" Returns if the wemo is on based on the statemachine. """
entity_id = entity_id or ENTITY_ID_ALL_WEMOS
return hass.states.is_state(entity_id, STATE_ON)
def turn_on(hass, entity_id=None):
""" Turns all or specified wemo on. """
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.call_service(DOMAIN, SERVICE_TURN_ON, data)
def turn_off(hass, entity_id=None):
""" Turns all or specified wemo off. """
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
hass.call_service(DOMAIN, SERVICE_TURN_OFF, data)
# pylint: disable=too-many-branches
def setup(hass, config):
""" Track states and offer events for WeMo switches. """
logger = logging.getLogger(__name__)
try:
# Pylint does not play nice if not every folders has an __init__.py
# pylint: disable=no-name-in-module, import-error
import homeassistant.external.pywemo.pywemo as pywemo
except ImportError:
logger.exception((
"Failed to import pywemo. "
"Did you maybe not run `git submodule init` "
"and `git submodule update`?"))
return False
if ha.CONF_HOSTS in config[DOMAIN]:
devices = []
for host in config[DOMAIN][ha.CONF_HOSTS].split(","):
device = pywemo.device_from_host(host)
if device:
devices.append(device)
else:
logger.info("Scanning for WeMo devices")
devices = pywemo.discover_devices()
is_switch = lambda switch: isinstance(switch, pywemo.Switch)
switches = [device for device in devices if is_switch(device)]
if len(switches) == 0:
logger.error("No WeMo switches found")
return False
# Dict mapping serial no to entity IDs
sno_to_ent = {}
# Dict mapping entity IDs to devices
ent_to_dev = {}
def update_wemo_state(device):
""" Update the state of specified WeMo device. """
# We currently only support switches
if not is_switch(device):
return
try:
entity_id = sno_to_ent[device.serialnumber]
except KeyError:
# New device, set it up
entity_id = util.ensure_unique_string(
ENTITY_ID_FORMAT.format(util.slugify(device.name)),
list(ent_to_dev.keys()))
sno_to_ent[device.serialnumber] = entity_id
ent_to_dev[entity_id] = device
state = STATE_ON if device.get_state(True) else STATE_OFF
state_attr = {ATTR_FRIENDLY_NAME: device.name}
if isinstance(device, pywemo.Insight):
pass
# Should work but doesn't..
#state_attr[ATTR_TODAY_KWH] = device.today_kwh
#state_attr[ATTR_CURRENT_POWER] = device.current_power
#state_attr[ATTR_TODAY_ON_TIME] = device.today_on_time
#state_attr[ATTR_TODAY_STANDBY_TIME] = device.today_standby_time
hass.states.set(entity_id, state, state_attr)
# pylint: disable=unused-argument
def update_wemos_state(time, force_reload=False):
""" Update states of all WeMo devices. """
# First time this method gets called, force_reload should be True
if force_reload or \
datetime.now() - update_wemos_state.last_updated > \
MIN_TIME_BETWEEN_SCANS:
logger.info("Updating WeMo status")
update_wemos_state.last_updated = datetime.now()
for device in switches:
update_wemo_state(device)
update_wemos_state(None, True)
# Track all wemos in a group
group.setup_group(hass, GROUP_NAME_ALL_WEMOS, sno_to_ent.values(), False)
def handle_wemo_service(service):
""" Handles calls to the WeMo service. """
devices = [ent_to_dev[entity_id] for entity_id
in extract_entity_ids(hass, service)
if entity_id in ent_to_dev]
if not devices:
devices = ent_to_dev.values()
for device in devices:
if service.service == SERVICE_TURN_ON:
device.on()
else:
device.off()
update_wemo_state(device)
# Update WeMo state every 30 seconds
hass.track_time_change(update_wemos_state, second=[0, 30])
hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_wemo_service)
hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_wemo_service)
return True