# WeMo
Discover, monitor and control [Belkin WeMo](http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/) devices on your local network
## Supported Devices
* LightSwitch
* Insight
* Switch
* Coffee Maker
* Humidifier
* More coming soon.
* Or feel free to add your favorite.
* Feel free to reach out if you need some help.
## Installation
1. git clone https://github.com/NationalAssociationOfRealtors/ex_wemo.git
2. cd wemo
3. mix do deps.get, deps.compile
4. iex -S mix
5. WeMo.Client.start(host_ip \\ nil)
6. WeMo.register()
7. SSDP.Client.start()
## Usage
`WeMo.Client.start` registers the WeMo library with the `SSDP.Registry`. You can pass `WeMo.Client.start` your IP address, or it will attempt to ascertain it by iterating over your network interfaces and using the first non-local ipv4 address it finds. The IP is for setting the `CALLBACK` url for the `SOAP` actions. Calling `WeMo.Client.start` allows you to wait for the network to be up, especially helpful when dealing with [Nerves](http://nerves-project.org) systems.
The WeMo library runs a small cowboy server on port `8083` by default, this is overridable via `:ex_wemo, :http_port`, for receiving subscription events from the devices. You should see some success and error messages if you ran the interactive terminal session in the installation section.
Calling `WeMo.register()`, registers your process with the `WeMo.Registry`. All events and action results are published over this registry. You can handle events using `handle_info({:device, device})` in the process that called `WeMo.register()`. Where device is the device state shown below.
Once everything is configured we start the `SSDP.Client`, again this allows us to wait until the network is up before looking for devices.
## Events and Action Results
The events and action results are the same thing, just the most up-to-date state object from the device. They are both broadcast over the registry in the form `{:device, device}` where the device is a State object for the given device type. Each device type `Insight, LightSwitch, etc` writes it's unique state to the `values` key.
### Insight values
```elixir
%WeMo.Device.Insight.Values{
average_power: 0,
current_power: 0,
energy_today: 630892,
energy_total: 1128564767,
last_changed_at: 1507047806,
last_on_for: 3,
on_today: 231,
on_total: 1036198,
standby_limit: 0,
state: :off,
timespan: 70729
}
```
### Insight Device State
The full device state also includes the SSDP device state `device`, subscription registration ids `sids`, `host_ip` and the `pid` of the device process.
```elixir
{:device,
%WeMo.Device.Insight.State{
device: %{
device: %{
device_type: 'urn:Belkin:device:insight:1',
friendly_name: 'Home Lab Insight',
icon_list: [%{depth: '100', height: '100', mime_type: 'jpg', url: 'icon.jpg', width: '100'}],
manufacturer: 'Belkin International Inc.',
manufacturer_url: 'http://www.belkin.com',
model_description: 'Belkin Insight 1.0', model_name: 'Insight',
model_number: '1.0', model_url: 'http://www.belkin.com/plugin/',
presentation_url: '/pluginpres.html', serial_number: nil,
service_list: [%{control_url: '/upnp/control/WiFiSetup1',
event_sub_url: '/upnp/event/WiFiSetup1', scpd_url: '/setupservice.xml',
service_id: 'urn:Belkin:serviceId:WiFiSetup1',
service_type: 'urn:Belkin:service:WiFiSetup:1'},
%{control_url: '/upnp/control/timesync1',
event_sub_url: '/upnp/event/timesync1',
scpd_url: '/timesyncservice.xml',
service_id: 'urn:Belkin:serviceId:timesync1',
service_type: 'urn:Belkin:service:timesync:1'},
%{control_url: '/upnp/control/basicevent1',
event_sub_url: '/upnp/event/basicevent1',
scpd_url: '/eventservice.xml',
service_id: 'urn:Belkin:serviceId:basicevent1',
service_type: 'urn:Belkin:service:basicevent:1'},
%{control_url: '/upnp/control/firmwareupdate1',
event_sub_url: '/upnp/event/firmwareupdate1',
scpd_url: '/firmwareupdate.xml',
service_id: 'urn:Belkin:serviceId:firmwareupdate1',
service_type: 'urn:Belkin:service:firmwareupdate:1'},
%{control_url: '/upnp/control/rules1',
event_sub_url: '/upnp/event/rules1', scpd_url: '/rulesservice.xml',
service_id: 'urn:Belkin:serviceId:rules1',
service_type: 'urn:Belkin:service:rules:1'},
%{control_url: '/upnp/control/metainfo1',
event_sub_url: '/upnp/event/metainfo1',
scpd_url: '/metainfoservice.xml',
service_id: 'urn:Belkin:serviceId:metainfo1',
service_type: 'urn:Belkin:service:metainfo:1'},
%{control_url: '/upnp/control/remoteaccess1',
event_sub_url: '/upnp/event/remoteaccess1',
scpd_url: '/remoteaccess.xml',
service_id: 'urn:Belkin:serviceId:remoteaccess1',
service_type: 'urn:Belkin:service:remoteaccess:1'},
%{control_url: '/upnp/control/deviceinfo1',
event_sub_url: '/upnp/event/deviceinfo1',
scpd_url: '/deviceinfoservice.xml',
service_id: 'urn:Belkin:serviceId:deviceinfo1',
service_type: 'urn:Belkin:service:deviceinfo:1'},
%{control_url: '/upnp/control/insight1',
event_sub_url: '/upnp/event/insight1', scpd_url: '/insightservice.xml',
service_id: 'urn:Belkin:serviceId:insight1',
service_type: 'urn:Belkin:service:insight:1'},
%{control_url: '/upnp/control/smartsetup1',
event_sub_url: '/upnp/event/smartsetup1', scpd_url: '/smartsetup.xml',
service_id: 'urn:Belkin:serviceId:smartsetup1',
service_type: 'urn:Belkin:service:smartsetup:1'},
%{control_url: '/upnp/control/manufacture1',
event_sub_url: '/upnp/event/manufacture1',
scpd_url: '/manufacture.xml',
service_id: 'urn:Belkin:serviceId:manufacture1',
service_type: 'urn:Belkin:service:manufacture:1'}
],
udn: 'uuid:Insight-1_0-221350K12000B5',
upc: nil
},
uri: %URI{
authority: "192.168.10.19:49153",
fragment: nil,
host: "192.168.10.19",
path: "/setup.xml",
port: 49153,
query: nil,
scheme: "http",
userinfo: nil
},
url: nil,
version: %{major: '1', minor: '0'}
},
host_ip: {192, 168, 10, 5},
pid: :"uuid:Insight-1_0-221350K12000B5",
sids: ["uuid:33db5c96-1dd2-11b2-a2a3-c9a4beb5df50",
"uuid:33dd9164-1dd2-11b2-a2a3-c9a4beb5df50",
"uuid:33e04242-1dd2-11b2-a2a3-c9a4beb5df50",
"uuid:33e1ef3e-1dd2-11b2-a2a3-c9a4beb5df50",
"uuid:347f752e-1dd2-11b2-a2a3-c9a4beb5df50",
"uuid:3481cbc6-1dd2-11b2-a2a3-c9a4beb5df50"
],
values: %WeMo.Device.Insight.Values{
average_power: 0,
current_power: 0,
energy_today: 630892,
energy_total: 1128564767,
last_changed_at: 1507047806,
last_on_for: 3,
on_today: 231,
on_total: 1036198,
standby_limit: 0,
state: :off,
timespan: 70729
}
}
}
```
Here is the simple test to check an actual WeMo Insight on your network.
```elixir
defmodule WemoTest do
use ExUnit.Case
doctest WeMo
test "test actual Insight device on network" do
WeMo.Client.start()
WeMo.register()
SSDP.Client.start()
assert_receive {:device, %{device: %{device: %{device_type: 'urn:Belkin:device:insight:1'}}} = device}, 65_000
device.pid |> WeMo.Device.Insight.on()
assert_receive {:device, %{device: %{device: %{device_type: 'urn:Belkin:device:insight:1'}}, values: %{state: :on}} = device}, 10_000
:timer.sleep(800)
device.pid |> WeMo.Device.Insight.off()
assert_receive {:device, %{device: %{device: %{device_type: 'urn:Belkin:device:insight:1'}}, values: %{state: :off}} = device}, 10_000
end
end
```
If you have more than one Insight on your network, you may want to pattern match on `{:device, %{device: %{device: %{udn: device_udn}}}}`