Anyone who managed to have their insight switch working and displaying the energy consumption data?
I’ve adapted the Smartthings sample code for Wemo Switches to work for Wemo Insight Switches. There are still a few problems with it. The code overrides the device handler for Wemo Switch but cannot deal with old (non-insight) Wemo Switches. Therefore, it is only suitable if you only have Wemo Insight Switches and no Wemo Switches.
The device handler adds a Power Meter capability and can respond to changes in energy consumption. I use it to monitor our washing machine and dryer in an outbuilding and send me a notification when they are done.
The device handler reports:
- Energy consumption.
- The correct on/off status of the device (previously, Wemo Insight Switches that were on but consumed little energy were reported as off.
- Time on now
- Time on today
To install the code,
-
Create or overwrite the Wemo Switch device handler with the code below.
-
Run the Wemo (Connect) SmartApp on your mobile device.
/**
-
Copyright 2015 SmartThings
-
Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except
-
in compliance with the License. You may obtain a copy of the License at:
-
http://www.apache.org/licenses/LICENSE-2.0
-
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
-
on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
-
for the specific language governing permissions and limitations under the License.
-
Wemo Switch
-
Author: superuser
-
Date: 2013-10-11
-
Updated for Wemo Insight Switch
-
Author: Jeroen Keppens, 14/3/2016
*/
metadata {
definition (name: “Wemo Switch”, namespace: “smartthings”, author: “SmartThings”) {
capability “Actuator”
capability “Switch”
capability “Polling”
capability “Power Meter”
capability “Refresh”
capability “Sensor”attribute "status", "string" attribute "onNow", "string" attribute "onToday", "string" command "subscribe" command "resubscribe" command "unsubscribe"
}
// simulator metadata
simulator {}// UI tile definitions
tiles {
standardTile(“switch”, “device.switch”, width: 2, height: 2, canChangeIcon: true) {
state “on”, label:’{name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821" state "off", label:'{name}’, action:“switch.on”, icon:“st.switches.switch.off”, backgroundColor:"#ffffff"
}
valueTile(“power”, “device.power”, decoration: “flat”, width: 1, height: 1) {
state “power”, label:’{currentValue} W' } standardTile("status", "device.status", width: 1, height: 1 ) { state( "on", label: 'ON', backgroundColor: "#79b821" ) state( "standby", label: 'STANDBY', backgroundColor: "#FFA500" ) state( "off", label: 'OFF', backgroundColor: "#ffffff" ) } valueTile("onNow", "device.onNow", decoration: "flat", width: 1, height: 1) { state "onNow", label:'{currentValue}’
}
valueTile(“onToday”, “device.onToday”, decoration: “flat”, width: 1, height: 1) {
state “onToday”, label:’${currentValue}’
}
standardTile(“refresh”, “device.switch”, inactiveLabel: false, decoration: “flat”, width: 1, height: 1) {
state “default”, label:’’, action:“refresh.refresh”, icon:“st.secondary.refresh”
}main "switch" details (["switch", "power", "status", "onNow", "onToday", "refresh"])
}
}
private def parseBinaryStateString(stateString) {
//log.debug “stateString: stateString" //log.debug "stateString.size(): {stateString.size()}”
def states =
def token = “”
for(int i=0; i<stateString.size(); i++) {
if (stateString[i] ==~ /[0-9]/) {
//log.debug “symbol: ${stateString[i]}”
token = token + stateString[i]
} else {
//log.debug “adding token: $token”
int state = token.toLong()
states << state
token = “”
}
}
//log.debug “states: $states”
return states
}private def convertSecondsToTimeString(seconds) {
log.debug “convertSecondsToTimeString of $seconds seconds”
int h = seconds.intdiv(3600)
int m = (seconds-h3600).intdiv(60)
int s = seconds-(h3600)-(m*60)
log.debug “h: $h, m: $m, s: $s”
def timeString = “”
if (h==0) {
timeString = timeString + “00”
} else if (h<=9) {
timeString = timeString + “0$h”
} else {
timeString = timeString + “$h”
}
if (m==0) {
timeString = timeString + “:00”
} else if (m<=9) {
timeString = timeString + “:0$m”
} else {
timeString = timeString + “:$m”
}
if (s==0) {
timeString = timeString + “:00”
} else if (s<=9) {
timeString = timeString + “:0$s”
} else {
timeString = timeString + “:$s”
}
return timeString
}// parse events into attributes
def parse(String description) {
log.debug “Parsing ‘${description}’”def msg = parseLanMessage(description) def headerString = msg.header if (headerString?.contains("SID: uuid:")) { def sid = (headerString =~ /SID: uuid:.*/) ? ( headerString =~ /SID: uuid:.*/)[0] : "0" sid -= "SID: uuid:".trim() updateDataValue("subscriptionId", sid) } def result = [] def bodyString = msg.body if (bodyString) { def body = new XmlSlurper().parseText(bodyString) //log.info "Line 67 bodyString: $bodyString" //log.info "Line 68 body: $body" if (body?.property?.TimeSyncRequest?.text()) { log.trace "Got TimeSyncRequest" result << timeSyncResponse() } else if (body?.Body?.SetBinaryStateResponse?.BinaryState?.text()) { log.trace "Got SetBinaryStateResponse = ${body?.Body?.SetBinaryStateResponse?.BinaryState?.text()}" } else if (body?.property?.BinaryState?.text()) { // To Do: Refactor def wemoStateString = body?.property?.BinaryState?.text() log.info "State string: $wemoStateString" def states = parseBinaryStateString(wemoStateString) def value = states[0] == 0 ? "off" : "on" log.trace "Notify: BinaryState = ${value}" result << createEvent(name: "switch", value: value) if (states[0]==0) { result << createEvent(name: "status", value: "off") } else if (states[0]==1) { result << createEvent(name: "status", value: "on") } else { result << createEvent(name: "status", value: "standby") } if (states[2] != null) { log.debug "states[2]: ${states[2]}" def onNow = convertSecondsToTimeString(states[2]) log.trace "Notify: Time on now = ${onNow}" result << createEvent(name: "onNow", value: "on now $onNow") } if (states[3] != null) { log.debug "states[3]: ${states[3]}" def onToday = convertSecondsToTimeString(states[3]) log.trace "Notify: Time on today = ${onToday}" result << createEvent(name: "onToday", value: "on today $onToday") } if (states[7] != null) { log.debug "states[7]: ${states[7]}" def power = (int)Math.round(states[7]/1000) log.trace "Notify: Current power consumption = ${power}" result << createEvent(name: "power", value: power) } //def value = body?.property?.BinaryState?.text().toInteger() == 1 ? "on" : "off" //log.trace "Notify: BinaryState = ${value}" } else if (body?.property?.TimeZoneNotification?.text()) { log.debug "Notify: TimeZoneNotification = ${body?.property?.TimeZoneNotification?.text()}" } else if (body?.Body?.GetBinaryStateResponse?.BinaryState?.text()) { // To Do: Revise def wemoStateString = body?.Body?.GetBinaryStateResponse?.BinaryState?.text() log.info "Binary State Response (not processed at this point): $wemoStateString" } } result
}
private getTime() {
// This is essentially System.currentTimeMillis()/1000, but System is disallowed by the sandbox.
((new GregorianCalendar().time.time / 1000l).toInteger()).toString()
}private getCallBackAddress() {
device.hub.getDataValue(“localIP”) + “:” + device.hub.getDataValue(“localSrvPortTCP”)
}private Integer convertHexToInt(hex) {
Integer.parseInt(hex,16)
}private String convertHexToIP(hex) {
[convertHexToInt(hex[0…1]),convertHexToInt(hex[2…3]),convertHexToInt(hex[4…5]),convertHexToInt(hex[6…7])].join(".")
}private getHostAddress() {
def ip = getDataValue(“ip”)
def port = getDataValue(“port”)if (!ip || !port) { def parts = device.deviceNetworkId.split(":") if (parts.length == 2) { ip = parts[0] port = parts[1] } else { log.warn "Can't figure out ip and port for device: ${device.id}" } } log.debug "Using ip: ${ip} and port: ${port} for device: ${device.id}" return convertHexToIP(ip) + ":" + convertHexToInt(port)
}
def on() {
<?xml version="1.0"?>
log.debug “Executing ‘on’”
sendEvent(name: “switch”, value: “on”)
def turnOn = new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
SOAPAction: “urn:Belkin:service:basicevent:1#SetBinaryState”
Host: ${getHostAddress()}
Content-Type: text/xml
Content-Length: 333<SOAP-ENV:Envelope xmlns:SOAP-ENV=“http://schemas.xmlsoap.org/soap/envelope/” SOAP-ENV:encodingStyle=“http://schemas.xmlsoap.org/soap/encoding/”>
SOAP-ENV:Body
<m:SetBinaryState xmlns:m=“urn:Belkin:service:basicevent:1”>
1
</m:SetBinaryState>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>""", physicalgraph.device.Protocol.LAN)
}def off() {
<?xml version="1.0"?>
log.debug “Executing ‘off’”
sendEvent(name: “switch”, value: “off”)
def turnOff = new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
SOAPAction: “urn:Belkin:service:basicevent:1#SetBinaryState”
Host: ${getHostAddress()}
Content-Type: text/xml
Content-Length: 333<SOAP-ENV:Envelope xmlns:SOAP-ENV=“http://schemas.xmlsoap.org/soap/envelope/” SOAP-ENV:encodingStyle=“http://schemas.xmlsoap.org/soap/encoding/”>
SOAP-ENV:Body
<m:SetBinaryState xmlns:m=“urn:Belkin:service:basicevent:1”>
0
</m:SetBinaryState>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>""", physicalgraph.device.Protocol.LAN)
}/*def refresh() {
<?xml version="1.0" encoding="utf-8"?>
log.debug “Executing ‘refresh’”
new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
SOAPACTION: “urn:Belkin:service:basicevent:1#GetBinaryState”
Content-Length: 277
Content-Type: text/xml; charset=“utf-8”
HOST: ${getHostAddress()}
User-Agent: CyberGarage-HTTP/1.0<s:Envelope xmlns:s=“http://schemas.xmlsoap.org/soap/envelope/” s:encodingStyle=“http://schemas.xmlsoap.org/soap/encoding/”>
<s:Body>
<u:GetBinaryState xmlns:u=“urn:Belkin:service:basicevent:1”>
</u:GetBinaryState>
</s:Body>
</s:Envelope>""", physicalgraph.device.Protocol.LAN)
}*/def refresh() {
log.debug “Executing WeMo Switch ‘subscribe’, then ‘timeSyncResponse’, then ‘poll’”
[subscribe(), timeSyncResponse(), poll()]
}def subscribe(hostAddress) {
log.debug “Executing ‘subscribe()’”
def address = getCallBackAddress()
new physicalgraph.device.HubAction("""SUBSCRIBE /upnp/event/basicevent1 HTTP/1.1
HOST: {hostAddress} CALLBACK: <http://{address}/>
NT: upnp:event
TIMEOUT: Second-5400
User-Agent: CyberGarage-HTTP/1.0“”", physicalgraph.device.Protocol.LAN)
}def subscribe() {
subscribe(getHostAddress())
}def subscribe(ip, port) {
def existingIp = getDataValue(“ip”)
def existingPort = getDataValue(“port”)
if (ip && ip != existingIp) {
log.debug “Updating ip from $existingIp to $ip”
updateDataValue(“ip”, ip)
}
if (port && port != existingPort) {
log.debug “Updating port from $existingPort to $port”
updateDataValue(“port”, port)
}subscribe("${ip}:${port}")
}
////////////////////////////
def resubscribe() {
log.debug “Executing ‘resubscribe()’”def sid = getDeviceDataByName(“subscriptionId”)
new physicalgraph.device.HubAction("""SUBSCRIBE /upnp/event/basicevent1 HTTP/1.1
HOST: {getHostAddress()} SID: uuid:{sid}
TIMEOUT: Second-5400“”", physicalgraph.device.Protocol.LAN)
}
////////////////////////////
def unsubscribe() {
def sid = getDeviceDataByName(“subscriptionId”)
new physicalgraph.device.HubAction("""UNSUBSCRIBE publisher path HTTP/1.1
HOST: {getHostAddress()} SID: uuid:{sid}“”", physicalgraph.device.Protocol.LAN)
}////////////////////////////
<?xml version="1.0" encoding="utf-8"?>
//TODO: Use UTC Timezone
def timeSyncResponse() {
log.debug “Executing ‘timeSyncResponse()’”
new physicalgraph.device.HubAction("""POST /upnp/control/timesync1 HTTP/1.1
Content-Type: text/xml; charset=“utf-8”
SOAPACTION: “urn:Belkin:service:timesync:1#TimeSync”
Content-Length: 376
HOST: ${getHostAddress()}
User-Agent: CyberGarage-HTTP/1.0<s:Envelope xmlns:s=“http://schemas.xmlsoap.org/soap/envelope/” s:encodingStyle=“http://schemas.xmlsoap.org/soap/encoding/”>
<s:Body>
<u:TimeSync xmlns:u=“urn:Belkin:service:timesync:1”>
${getTime()}
-05.00
1
1
</u:TimeSync>
</s:Body>
</s:Envelope>
“”", physicalgraph.device.Protocol.LAN)
}def poll() {
<?xml version="1.0" encoding="utf-8"?>
log.debug “Executing ‘poll’”
new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
SOAPACTION: “urn:Belkin:service:basicevent:1#GetBinaryState”
Content-Length: 277
Content-Type: text/xml; charset=“utf-8”
HOST: ${getHostAddress()}
User-Agent: CyberGarage-HTTP/1.0<s:Envelope xmlns:s=“http://schemas.xmlsoap.org/soap/envelope/” s:encodingStyle=“http://schemas.xmlsoap.org/soap/encoding/”>
<s:Body>
<u:GetBinaryState xmlns:u=“urn:Belkin:service:basicevent:1”>
</u:GetBinaryState>
</s:Body>
</s:Envelope>""", physicalgraph.device.Protocol.LAN)
} -
I’m trying to set this up, but it’s not reporting power data. The on/off function is working tho. Any idea how to fix this?
Is there a way to estimate the cost using this code? Like this device https://github.com/bigpunk6/device-type.AeonSmartEnergySwitch-
Installed this today, its awesome compared the stock Wemo Switch device handler. Thanks.
Can you create a GitHub like [RELEASE] Iris Smart Plug (3210-L) Zigbee Plug with Z-wave Repeater has for us to connect to? Makes monitoring for and getting updates much easier as well as allows submission of suggested improvements.
Better yet maybe just submit a MR to this one that people are already using: https://github.com/zzarbi/smartthings/tree/master/wemo
awesome! hope that some day this will support both standard and insight switches. I have both
I’m getting the following error after adding switches…
physicalgraph.app.exception.UnknownDeviceTypeException: Device type ‘Wemo Switch’ in namespace ‘mujica’ not found. @ line 323
has anyone experienced this?
Thanks for this update. It’s working.
[quote=“canadadry, post:59, topic:1704, full:true”]
I’m getting the following error after adding switches…
physicalgraph.app.exception.UnknownDeviceTypeException: Device type ‘Wemo Switch’ in namespace ‘mujica’ not found. @ line 323
Details:
-All WeMo items show up in the WeMo app
-Can’t add outlets with the Smart things app function find things
-Some outlets connect to the main network via a wireless repeater and the ones that do show the MAC address of the repeater not the device
-WeMo outlets both insight and regular are set to static IPs
It appears my wemo insight switches are now LAN Wemo Switches and this no longer works
It is a known issue caused by who knows what. Mine are all not working also.
I’m not having issues with my Switch or Insight.
I have allocated mine fixed ip addresses when I first got them 18 months ago.
Do you guys who are having issues use static ip?
I’m just trying to help and make suggestions.
Sorry, I meant that the switch still works but it’s gone back to being just switch. The custom code allowed for power usage monitoring. It worked really well until the update and I had notifications when the power usage dropped between a certain wattage. Now all I can do is turn it on and off
Hmm… I just found this, and I went an changed the device type in the ide from lan Wemo switch to the device handler listed here and clicked save Seems to be working for that paricular insight
Uh duh. I’m an idiot. Thank you so much for that!! What an easy fix!! Thanks!!!
Running into some problems though, it’s not refreshing automatically the power usage. Trying to figure out core, with some minimal luck… if you get somewhere with that let us know,
Mine’s back to working as normal. Just ran the dryer for 20 seconds. I did press refresh to see the power usage. Then I turned the dryer off and walked away and got my notification that power usage had dropped below my set 7W down to 3W. All is well in the world again