Added WeMo support

This commit is contained in:
Paulus Schoutsen 2014-03-23 12:03:34 -07:00
parent bb771d802d
commit 6063ffeb5b
4 changed files with 164 additions and 11 deletions

View File

@ -5,37 +5,37 @@ Home Assistant provides a platform for home automation. It does so by having mod
It is currently able to do the following things:
* Track if devices are home by monitoring connected devices to a wireless router (currently supporting modern Netgear routers or routers running Tomato firmware)
* Track which lights are on
* Track what your Chromecasts are up to
* Track and control lights
* Track and control WeMo switches
* Track and control Chromecasts
* Turn on the lights when people get home when the sun is setting or has set
* Slowly turn on the lights to compensate for light loss when the sun sets and people are home
* Turn off lights and connected devices when everybody leaves the house
* Start YouTube videos on the Chromecast
* Quit current running application on a Chromecast
* Download files to the host machine
* Open a url in the default browser at the host machine
* Simulate key presses on the host for Play/Pause, Next track, Prev track, Volume up, Volume Down
* Controllable via a REST API and web interface
* Support for thin client Home Assistant instances that will forward all their commands to the main instance
* Android Tasker project to control Home Assistant from your phone and report charging state. Combine it with AutoVoice to be able to tell your phones to turn the lights off!
* Support for remoting Home Assistant instances through a Python API
* Android Tasker project to control Home Assistant from your phone and report charging state.
![screenshot-states](https://raw.github.com/balloob/home-assistant/master/docs/states.png)
Current compatible devices:
* Wireless router running [Tomato firmware](http://www.polarcloud.com/tomato)
* Netgear wireless routers (tested with R6300)
* [WeMo switches](http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/)
* [Philips Hue](http://meethue.com)
* [Google Chromecast](http://www.google.com/intl/en/chrome/devices/chromecast)
* Wireless router running [Tomato firmware](http://www.polarcloud.com/tomato)
* Netgear wireless routers (tested with R6300)
The system is built modular so support for other wireless routers, other devices or actions can be implemented easily.
The system is built modular so support for other devices or actions can be implemented easily.
Installation instructions
-------------------------
* Install python modules [PyEphem](http://rhodesmill.org/pyephem/), [Requests](http://python-requests.org) and [PHue](https://github.com/studioimaginaire/phue): `pip install pyephem requests phue`
* The core depends on [PyEphem](http://rhodesmill.org/pyephem/) and [Requests](http://python-requests.org). Depending on the components you would like to use you will need [PHue](https://github.com/studioimaginaire/phue) for Philips Hue support, [PyChromecast](https://github.com/balloob/pychromecast) for Chromecast support and [ouimeaux](https://github.com/iancmcc/ouimeaux) for WeMo support. Install these using `pip install pyephem requests phue ouimeaux pychromecast`.
* Clone the repository and pull in the submodules `git clone --recursive https://github.com/balloob/home-assistant.git`
* Copy home-assistant.conf.default to home-assistant.conf and adjust the config values to match your setup.
* For Tomato you will have to not only setup your host, username and password but also a http_id. The http_id can be retrieved by going to the admin console of your router, view the source of any of the pages and search for `http_id`.
* Setup PHue by running `python -m phue --host HUE_BRIDGE_IP_ADDRESS` from the commandline.
* If you want to use Hue, setup PHue by running `python -m phue --host HUE_BRIDGE_IP_ADDRESS` from the commandline and follow the instructions.
* While running the script it will create and maintain a file called `known_devices.csv` which will contain the detected devices. Adjust the track variable for the devices you want the script to act on and restart the script or call the service `device_tracker/reload_devices_csv`.
Done. Start it now by running `python start.py`
@ -205,6 +205,9 @@ Action: sets the state per device and maintains a combined state called `all_dev
**Light**
Keeps track which lights are turned on and can control the lights.
**WeMo**
Keeps track which WeMo switches are in the network and allows you to control them.
**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.
Depends on: light control, track_sun, DeviceTracker

View File

@ -128,6 +128,12 @@ def from_config_file(config_path):
else:
chromecast_started = False
# WeMo
if has_section("wemo"):
wemo = load_module('wemo')
add_status("WeMo", wemo.setup(bus, statemachine))
# Light control
if has_section("light.hue"):
light = load_module('light')

View File

@ -21,6 +21,7 @@ import homeassistant as ha
import homeassistant.util as util
ATTR_ENTITY_ID = 'entity_id'
ATTR_FRIENDLY_NAME = "friendly_name"
STATE_ON = 'on'
STATE_OFF = 'off'

View File

@ -0,0 +1,143 @@
"""
Component to interface with WeMo devices on the network.
"""
import logging
import socket
from datetime import datetime, timedelta
import homeassistant as ha
import homeassistant.util as util
from homeassistant.components import (group, STATE_ON, STATE_OFF,
SERVICE_TURN_ON, SERVICE_TURN_OFF,
ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME)
DOMAIN = 'wemo'
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)
# pylint: disable=too-many-branches
def setup(bus, statemachine):
""" Track states and offer events for WeMo switches. """
logger = logging.getLogger(__name__)
try:
import ouimeaux.environment as wemo_env
import ouimeaux.device.switch as wemo_switch
import ouimeaux.device.insight as wemo_insight
except ImportError:
logger.exception(("Failed to import ouimeaux. "
"Did you maybe not install the 'ouimeaux' "
"dependency?"))
return False
env = wemo_env.Environment()
try:
env.start()
except socket.error:
# If the socket is already in use
logger.exception("Error starting WeMo environment")
return False
env.discover(5)
if len(env.list_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 isinstance(device, wemo_switch.Switch):
return
try:
entity_id = sno_to_ent[device.serialnumber]
except KeyError:
# New device, set it up
entity_id = ENTITY_ID_FORMAT.format(util.slugify(device.name))
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, wemo_insight.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
statemachine.set_state(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 env:
_update_wemo_state(device)
_update_wemos_state(None, True)
# Track all lights in a group
group.setup(bus, statemachine,
GROUP_NAME_ALL_WEMOS, sno_to_ent.values())
def _handle_wemo_service(service):
""" Handles calls to the WeMo service. """
dat = service.data
if ATTR_ENTITY_ID in dat:
device = ent_to_dev.get(dat[ATTR_ENTITY_ID])
devices = [device] if device is not None else []
else:
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
ha.track_time_change(bus, _update_wemos_state, second=[0, 30])
bus.register_service(DOMAIN, SERVICE_TURN_OFF, _handle_wemo_service)
bus.register_service(DOMAIN, SERVICE_TURN_ON, _handle_wemo_service)
return True