Compare commits

...

14 Commits

Author SHA1 Message Date
Alexis Lutun
7650e0ebed MSA-895: Hello,
I'm working for NodOn, we are a z-wave plus devices design company : http://www.nodon.fr/en/

I'm a developper in NodOn and actually working on the integration of our products into the smarthings hub.
I'm submitting my first device type handler (more will follow soon),

The device that i'm submitting is this one : http://nodon.fr/en/z-wave/octan-remote_7-2

The Octan Remote is a magnetic remote and can be fixed on any king of metallic area but it is also delivered with its wall mounting plate which can be easily installed on a wall.

The device is attend to be use with the button capability with the pushed and held action, so 8 differents actions total.

Also in the device type handler i add four tiles that give the user the possiblites to send the same button event as if they use the remote. 

If there is anything i forgot or did wrong please let me know i will be more than happy to answer your request

Best Regars
2016-02-21 23:50:08 -06:00
Yaima
85175eb298 Merge pull request #529 from Yaima/master
Ecobee - Changed tiles order
2016-02-19 14:45:01 -08:00
Luke Bredeson
c75568bcf1 Merge pull request #518 from lbredeso/wemo-subscription-improvements
INSIDE-787: Improve Wemo (Connect) event subscriptions
2016-02-19 10:10:23 -06:00
Tom Manley
edc98e4840 Merge pull request #497 from tpmanley/feature/outlet_fingerprint
outlet: Added fingerprint for new ST outlet
2016-02-18 19:25:39 -06:00
Vinay Rao
fb2c2cb2a7 Merge pull request #530 from workingmonk/iris_motion_contact
[DEVC-259] Iris motion and contact sensor fingerprints
2016-02-18 17:22:56 -08:00
Vinay Rao
62aeb0533d Iris motion and contact sensor fingeprints 2016-02-18 17:07:11 -08:00
Yaima Valdivia
fb6cbcc35e Merge branch 'master' of github.com:SmartThingsCommunity/SmartThingsPublic
# Via Yaima
* 'master' of github.com:SmartThingsCommunity/SmartThingsPublic:
2016-02-18 15:50:54 -08:00
Yaima Valdivia
097584944e Ecobee - Changed tiles order 2016-02-18 15:48:30 -08:00
Yaima
01fae3dcd4 Merge pull request #525 from Yaima/master
Better exception handling for Ecobee
2016-02-18 15:13:34 -08:00
Yaima Valdivia
6c125fe80f Better exception handling of Ecobee
Refreshing only if status code 14 - Authentication token has expired.
Refresh your tokens.
2016-02-18 14:49:26 -08:00
Yaima
5728f08770 Merge pull request #522 from Yaima/master
Fixed Ecobee - HH errors
2016-02-17 13:28:40 -08:00
Yaima Valdivia
f073df0a57 Fixed Ecobee - HH errors 2016-02-17 13:28:10 -08:00
Luke Bredeson
9263107f0e INSIDE-787: Improve Wemo (Connect) event subscriptions 2016-02-16 17:05:09 -06:00
Tom Manley
6c5b93da87 outlet: Added fingerprint for new ST outlet
Resolves:
    https://smartthings.atlassian.net/browse/DVCSMP-1360
2016-02-10 10:43:21 -06:00
7 changed files with 412 additions and 105 deletions

View File

@@ -0,0 +1,201 @@
/**
* Copyright 2015 NodOn
*
* 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.
*
*/
metadata {
definition (name: "Nodon Octan Remote", namespace: "NodOn", author: "Alexis Lutun") {
capability "Actuator"
capability "Button"
capability "Configuration"
capability "Sleep Sensor"
capability "Battery"
command "pushButtonOne"
command "pushButtonTwo"
command "pushButtonThree"
command "pushButtonFour"
command "buttonEvent"
command "buttonPushed"
command "buttonPushed", [int]
command "refresh"
fingerprint deviceId: "0x0101", inClusters: "0x5E,0x85,0x59,0x80,0x5B,0x70,0x5A,0x72,0x73,0x86,0x84,0xEF,0x5E,0x5B,0x2B,0x27,0x22,0x20,0x26,0x84"
}
tiles(scale: 2) {
standardTile("Octan", "device.button", width: 1, height: 1)
{
state "default", label: "", icon:"http://nodon.fr/smarthings/octan-remote/octanfullicon.png", backgroundColor: "#ffffff"
}
multiAttributeTile(name:"BatteryTile", type: "generic", width: 6, height: 4)
{
tileAttribute ("device.battery", key: "PRIMARY_CONTROL")
{
attributeState "default", icon:"http://nodon.fr/smarthings/octan-remote/octanfullicon.png" , backgroundColor: "#f58220", decoration: "flat"
}
tileAttribute ("device.battery", key: "SECONDARY_CONTROL")
{
attributeState "default", label:'${currentValue}% battery', unit:"%"
}
}
standardTile("button One", "device.button", width: 2, height: 2, decoration: "flat")
{
state "default", label: "", action: "pushButtonOne", icon:"http://nodon.fr/smarthings/octan-remote/1line.png",defaultState: true, backgroundColor: "#ffffff"
state "pushed", label: "", action: "pushButtonOne", icon:"http://nodon.fr/smarthings/octan-remote/1fill.png", backgroundColor: "#ffffff"
}
standardTile("button Two", "device.button", width: 2, height: 2, decoration: "flat")
{
state "default", label: "",action: "pushButtonTwo", icon:"http://nodon.fr/smarthings/octan-remote/2line.png", defaultState: true, backgroundColor: "#ffffff"
state "pushed", label: "",action: "pushButtonTwo", icon:"http://nodon.fr/smarthings/octan-remote/2fill.png", backgroundColor: "#ffffff"
}
standardTile("button Three", "device.button", width: 2, height: 2, decoration: "flat")
{
state "default", label: "", action: "pushButtonThree", icon: "http://nodon.fr/smarthings/octan-remote/3line.png", defaultState: true, backgroundColor: "#ffffff"
state "pushed", label: "", action: "pushButtonThree", icon: "http://nodon.fr/smarthings/octan-remote/3fill.png", backgroundColor: "#ffffff"
}
standardTile("button Four", "device.button", width: 2, height: 2,decoration: "flat")
{
state "default", label: "",action: "pushButtonFour", icon:"http://nodon.fr/smarthings/octan-remote/4line.png", defaultState: true, backgroundColor: "#ffffff"
state "pushed", label: "",action: "pushButtonFour", icon:"http://nodon.fr/smarthings/octan-remote/4fill.png", backgroundColor: "#ffffff"
}
standardTile("refresh", "generic", inactiveLabel: false, decoration: "flat", width: 2, height: 2)
{
state "default", label:'', action: "refresh", icon:"st.secondary.refresh"
}
standardTile("configure", "device.Configuration", decoration: "flat", width: 2, height: 2)
{
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
}
main "Octan"
details(["BatteryTile", "button One", "button Two", "configure", "button Three", "button Four", "refresh"])
}
}
def parse(String description)
{
def results = []
if (description.startsWith("Err"))
{
results = createEvent(descriptionText:description, displayed:true)
}
else
{
def cmd = zwave.parse(description, [0x5B: 1, 0x80: 1, 0x84: 1]) //Central Scene , battery, wake up
if(cmd) results += zwaveEvent(cmd)
if(!results) results = [ descriptionText: cmd, displayed: false ]
}
//log.debug("Parsed '$description' to $results")
return results
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
{
def results = [createEvent(descriptionText: "$device.displayName woke up", isStateChange: false)]
def prevBattery = device.currentState("battery")
if (!prevBattery || (new Date().time - prevBattery.date.time)/60000 >= 60 * 53) //
{
results << response(zwave.batteryV1.batteryGet().format())
createEvent(name: "battery", value: "10", descriptionText: "battery is now ${currentValue}%", isStateChange: true, displayed: true)
}
results << response(zwave.wakeUpV1.wakeUpNoMoreInformation().format())
//log.debug("Wake up")
return results
}
def buttonEvent(button, attribute)
{
if (attribute)
{
createEvent(name: "button", value: "pushed", data: [buttonNumber: button, action: "held"] ,descriptionText: "$device.displayName button $button was held", icon:"http://nodon.fr/smarthings/octan-remote/octandiskfill.png", isStateChange: true, displayed: true)
}
else
{
createEvent(name: "button", value: "pushed", data: [buttonNumber: button, action: "pushed"] ,descriptionText: "$device.displayName button $button was pressed", icon:"http://nodon.fr/smarthings/octan-remote/octandiskfill.png", isStateChange: true, displayed: true)
}
}
def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd)
{
Integer sceneNumber = cmd.sceneNumber as Integer
Integer keyAttributes = cmd.keyAttributes as Integer
Integer sequenceNumber = cmd.sequenceNumber as Integer
buttonEvent(sceneNumber, keyAttributes)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd)
{
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF)
{
map.value = 1
map.descriptionText = "${device.displayName} has a low battery"
}
else
{
map.value = cmd.batteryLevel
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.Command cmd)
{
[ descriptionText: "$device.displayName: $cmd", linkText:device.displayName, displayed: false ]
}
def configurationCmds()
{
[
zwave.configurationV1.configurationSet(parameterNumber: 8, scaledConfigurationValue:2).format(), //Configure LED to feedback user when command of button has been acknowloedge by the static controller
zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId).format() // Set hub id in lifeline of product so product know the destination of the central scene notification command
]
}
def refresh()
{
def cmd = zwave.batteryV1.batteryGet().format()
return (response(cmd))
}
def configure()
{
def cmd = configurationCmds()
log.debug("Sending configuration: $cmd")
return response(cmd)
}
def pushButtonOne()
{
buttonPushed(1)
}
def pushButtonTwo()
{
buttonPushed(2)
}
def buttonPushed(button)
{
sendEvent(name: "button", value: "pushed", data: [buttonNumber: button, action: "pushed"], descriptionText: "$device.displayName button $button was pushed", icon:"http://nodon.fr/smarthings/octan-remote/octanfullicon.png", isStateChange: true)
}
def pushButtonThree()
{
buttonPushed(3)
}
def pushButtonFour()
{
buttonPushed(4)
}

View File

@@ -103,7 +103,7 @@ metadata {
state "humidity", label:'${currentValue}%'
}
main "temperature"
details(["temperature", "upButtonControl", "thermostatSetpoint", "currentStatus", "downButtonControl", "mode", "fanMode","resumeProgram", "humidity", "refresh"])
details(["temperature", "upButtonControl", "thermostatSetpoint", "currentStatus", "downButtonControl", "mode", "fanMode","humidity", "resumeProgram", "refresh"])
}
preferences {
@@ -204,11 +204,11 @@ private getThermostatDescriptionText(name, value, linkText) {
void setHeatingSetpoint(setpoint) {
log.debug "***heating setpoint $setpoint"
def heatingSetpoint = setpoint.toDouble()
def coolingSetpoint = device.currentValue("coolingSetpoint").toDouble()
def heatingSetpoint = setpoint
def coolingSetpoint = device.currentValue("coolingSetpoint")
def deviceId = device.deviceNetworkId.split(/\./).last()
def maxHeatingSetpoint = device.currentValue("maxHeatingSetpoint").toDouble()
def minHeatingSetpoint = device.currentValue("minHeatingSetpoint").toDouble()
def maxHeatingSetpoint = device.currentValue("maxHeatingSetpoint")
def minHeatingSetpoint = device.currentValue("minHeatingSetpoint")
//enforce limits of heatingSetpoint
if (heatingSetpoint > maxHeatingSetpoint) {
@@ -241,11 +241,11 @@ void setHeatingSetpoint(setpoint) {
void setCoolingSetpoint(setpoint) {
log.debug "***cooling setpoint $setpoint"
def heatingSetpoint = device.currentValue("heatingSetpoint").toDouble()
def coolingSetpoint = setpoint.toDouble()
def heatingSetpoint = device.currentValue("heatingSetpoint")
def coolingSetpoint = setpoint
def deviceId = device.deviceNetworkId.split(/\./).last()
def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint").toDouble()
def minCoolingSetpoint = device.currentValue("minCoolingSetpoint").toDouble()
def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint")
def minCoolingSetpoint = device.currentValue("minCoolingSetpoint")
if (coolingSetpoint > maxCoolingSetpoint) {
@@ -505,9 +505,6 @@ def fanAuto() {
}
}
def generateSetpointEvent() {
log.debug "Generate SetPoint Event"
@@ -536,6 +533,7 @@ def generateSetpointEvent() {
coolingSetpoint = roundC(coolingSetpoint)
}
sendEvent("name":"maxHeatingSetpoint", "value":maxHeatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"maxCoolingSetpoint", "value":maxCoolingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"minHeatingSetpoint", "value":minHeatingSetpoint, "unit":location.temperatureScale)

View File

@@ -29,6 +29,7 @@ metadata {
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3305"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3325"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326-L", deviceJoinName: "Iris Motion Sensor"
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv4", deviceJoinName: "Motion Sensor"
}

View File

@@ -16,17 +16,18 @@
metadata {
definition (name: "SmartSense Open/Closed Sensor", namespace: "smartthings", author: "SmartThings") {
capability "Battery"
capability "Battery"
capability "Configuration"
capability "Contact Sensor"
capability "Contact Sensor"
capability "Refresh"
capability "Temperature Measurement"
command "enrollResponse"
command "enrollResponse"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300-S"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300"
fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3320-L", deviceJoinName: "Iris Contact Sensor"
}
simulator {

View File

@@ -25,6 +25,7 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "0003, 000A, 0019", manufacturer: "Jasco Products", model: "45853", deviceJoinName: "GE ZigBee Plug-In Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45856", deviceJoinName: "GE ZigBee In-Wall Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 000F, 0B04", outClusters: "0019", manufacturer: "SmartThings", model: "outletv4", deviceJoinName: "Outlet"
}
tiles(scale: 2) {

View File

@@ -257,21 +257,16 @@ def getEcobeeThermostats() {
}
} else {
log.debug "http status: ${resp.status}"
//refresh the auth token
if (resp.data.status.code == 14) {
log.debug "Storing the failed action to try later"
atomicState.action = "getEcobeeThermostats"
log.debug "Refreshing your auth_token!"
refreshAuthToken()
} else {
log.error "Authentication error, invalid authentication method, lack of credentials, etc."
}
}
}
} catch(Exception e) {
log.debug "___exception getEcobeeThermostats(): " + e
refreshAuthToken()
}
} catch (groovyx.net.http.HttpResponseException e) {
log.trace "Exception polling children: " + e.response.data.status
if (e.response.data.status.code == 14) {
atomicState.action = "getEcobeeThermostats"
log.debug "Refreshing your auth_token!"
refreshAuthToken()
}
}
atomicState.thermostats = stats
return stats
}
@@ -450,23 +445,15 @@ def pollChildren(child = null) {
}
result = true
log.debug "updated ${atomicState.thermostats?.size()} stats: ${atomicState.thermostats}"
} else {
log.error "polling children & got http status ${resp.status}"
//refresh the auth token
if (resp.data.status.code == 14) {
atomicState.action = "pollChildren"
log.debug "Refreshing your auth_token!"
refreshAuthToken()
}
else {
log.error "Authentication error, invalid authentication method, lack of credentials, etc."
}
}
}
} catch(Exception e) {
log.debug "___exception polling children: " + e
refreshAuthToken()
} catch (groovyx.net.http.HttpResponseException e) {
log.trace "Exception polling children: " + e.response.data.status
if (e.response.data.status.code == 14) {
atomicState.action = "pollChildren"
log.debug "Refreshing your auth_token!"
refreshAuthToken()
}
}
return result
}
@@ -642,16 +629,14 @@ private refreshAuthToken() {
}
atomicState.action = ""
} else {
log.debug "refresh failed ${resp.status} : ${resp.status.code}"
}
}
} catch (groovyx.net.http.HttpResponseException e) {
log.error "refreshAuthToken() >> Error: e.statusCode ${e.statusCode}"
def reAttemptPeriod = 300 // in sec
if (e.statusCode != 401) { //this issue might comes from exceed 20sec app execution, connectivity issue etc.
if (e.statusCode != 401) { // this issue might comes from exceed 20sec app execution, connectivity issue etc.
runIn(reAttemptPeriod, "refreshAuthToken")
} else if (e.statusCode == 401) { //refresh token is expired
} else if (e.statusCode == 401) { // unauthorized
atomicState.reAttempt = atomicState.reAttempt + 1
log.warn "reAttempt refreshAuthToken to try = ${atomicState.reAttempt}"
if (atomicState.reAttempt <= 3) {
@@ -724,29 +709,21 @@ def sendJson(child = null, String jsonBody) {
log.debug "Error return code = ${resp.data.status.code}"
debugEvent("Error return code = ${resp.data.status.code}")
}
} else {
log.error "sent Json & got http status ${resp.status} - ${resp.status.code}"
debugEvent ("sent Json & got http status ${resp.status} - ${resp.status.code}")
//refresh the auth token
if (resp.status.code == 14) {
log.debug "Refreshing your auth_token!"
debugEvent ("Refreshing OAUTH Token")
refreshAuthToken()
return false
} else {
debugEvent ("Authentication error, invalid authentication method, lack of credentials, etc.")
log.error "Authentication error, invalid authentication method, lack of credentials, etc."
return false
}
}
}
} catch(Exception e) {
log.debug "Exception Sending Json: " + e
debugEvent ("Exception Sending JSON: " + e)
refreshAuthToken()
return false
}
} catch (groovyx.net.http.HttpResponseException e) {
log.trace "Exception Sending Json: " + e.response.data.status
debugEvent ("sent Json & got http status ${e.statusCode} - ${e.response.data.status.code}")
if (e.response.data.status.code == 14) {
atomicState.action = "pollChildren"
log.debug "Refreshing your auth_token!"
refreshAuthToken()
}
else {
debugEvent("Authentication error, invalid authentication method, lack of credentials, etc.")
log.error "Authentication error, invalid authentication method, lack of credentials, etc."
}
}
if (returnStatus == 0)
return true

View File

@@ -16,14 +16,14 @@
* Date: 2013-09-06
*/
definition(
name: "Wemo (Connect)",
namespace: "smartthings",
author: "SmartThings",
description: "Allows you to integrate your WeMo Switch and Wemo Motion sensor with SmartThings.",
category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/wemo.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/wemo@2x.png",
singleInstance: true
name: "Wemo (Connect)",
namespace: "smartthings",
author: "SmartThings",
description: "Allows you to integrate your WeMo Switch and Wemo Motion sensor with SmartThings.",
category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/wemo.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/wemo@2x.png",
singleInstance: true
)
preferences {
@@ -39,7 +39,7 @@ private getFriendlyName(String deviceNetworkId) {
sendHubCommand(new physicalgraph.device.HubAction("""GET /setup.xml HTTP/1.1
HOST: ${deviceNetworkId}
""", physicalgraph.device.Protocol.LAN, "${deviceNetworkId}"))
""", physicalgraph.device.Protocol.LAN, "${deviceNetworkId}", [callback: "setupHandler"]))
}
private verifyDevices() {
@@ -52,6 +52,13 @@ private verifyDevices() {
}
}
void ssdpSubscribe() {
subscribe(location, "ssdpTerm.urn:Belkin:device:insight:1", ssdpSwitchHandler)
subscribe(location, "ssdpTerm.urn:Belkin:device:controllee:1", ssdpSwitchHandler)
subscribe(location, "ssdpTerm.urn:Belkin:device:sensor:1", ssdpMotionHandler)
subscribe(location, "ssdpTerm.urn:Belkin:device:lightswitch:1", ssdpLightSwitchHandler)
}
def firstPage()
{
if(canInstallLabs())
@@ -62,7 +69,7 @@ def firstPage()
log.debug "REFRESH COUNT :: ${refreshCount}"
subscribe(location, null, locationHandler, [filterEvents:false])
ssdpSubscribe()
//ssdp request every 25 seconds
if((refreshCount % 5) == 0) {
@@ -105,9 +112,7 @@ def devicesDiscovered() {
def motions = getWemoMotions()
def lightSwitches = getWemoLightSwitches()
def devices = switches + motions + lightSwitches
def list = []
list = devices?.collect{ [app.id, it.ssdpUSN].join('.') }
devices?.collect{ [app.id, it.ssdpUSN].join('.') }
}
def switchesDiscovered() {
@@ -175,8 +180,9 @@ def updated() {
def initialize() {
unsubscribe()
unschedule()
subscribe(location, null, locationHandler, [filterEvents:false])
unschedule()
ssdpSubscribe()
if (selectedSwitches)
addSwitches()
@@ -189,7 +195,7 @@ def initialize() {
runIn(5, "subscribeToDevices") //initial subscriptions delayed by 5 seconds
runIn(10, "refreshDevices") //refresh devices, delayed by 10 seconds
runEvery5Minutes("refresh")
runEvery5Minutes("refresh")
}
def resubscribe() {
@@ -199,7 +205,7 @@ def resubscribe() {
def refresh() {
log.debug "refresh() called"
doDeviceSync()
doDeviceSync()
refreshDevices()
}
@@ -235,14 +241,14 @@ def addSwitches() {
if (!d) {
log.debug "Creating WeMo Switch with dni: ${selectedSwitch.value.mac}"
d = addChildDevice("smartthings", "Wemo Switch", selectedSwitch.value.mac, selectedSwitch?.value.hub, [
"label": selectedSwitch?.value?.name ?: "Wemo Switch",
"data": [
"mac": selectedSwitch.value.mac,
"ip": selectedSwitch.value.ip,
"port": selectedSwitch.value.port
]
"label": selectedSwitch?.value?.name ?: "Wemo Switch",
"data": [
"mac": selectedSwitch.value.mac,
"ip": selectedSwitch.value.ip,
"port": selectedSwitch.value.port
]
])
def ipvalue = convertHexToIP(selectedSwitch.value.ip)
def ipvalue = convertHexToIP(selectedSwitch.value.ip)
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
log.debug "Created ${d.displayName} with id: ${d.id}, dni: ${d.deviceNetworkId}"
} else {
@@ -273,9 +279,9 @@ def addMotions() {
"port": selectedMotion.value.port
]
])
def ipvalue = convertHexToIP(selectedMotion.value.ip)
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
log.debug "Created ${d.displayName} with id: ${d.id}, dni: ${d.deviceNetworkId}"
def ipvalue = convertHexToIP(selectedMotion.value.ip)
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
log.debug "Created ${d.displayName} with id: ${d.id}, dni: ${d.deviceNetworkId}"
} else {
log.debug "found ${d.displayName} with id $dni already exists"
}
@@ -304,26 +310,147 @@ def addLightSwitches() {
"port": selectedLightSwitch.value.port
]
])
def ipvalue = convertHexToIP(selectedLightSwitch.value.ip)
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
def ipvalue = convertHexToIP(selectedLightSwitch.value.ip)
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
log.debug "created ${d.displayName} with id $dni"
} else {
log.debug "found ${d.displayName} with id $dni already exists"
log.debug "found ${d.displayName} with id $dni already exists"
}
}
}
def ssdpSwitchHandler(evt) {
def description = evt.description
def hub = evt?.hubId
def parsedEvent = parseDiscoveryMessage(description)
parsedEvent << ["hub":hub]
log.debug parsedEvent
def switches = getWemoSwitches()
if (!(switches."${parsedEvent.ssdpUSN.toString()}")) {
//if it doesn't already exist
switches << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
} else {
log.debug "Device was already found in state..."
def d = switches."${parsedEvent.ssdpUSN.toString()}"
boolean deviceChangedValues = false
log.debug "$d.ip <==> $parsedEvent.ip"
if(d.ip != parsedEvent.ip || d.port != parsedEvent.port) {
d.ip = parsedEvent.ip
d.port = parsedEvent.port
deviceChangedValues = true
log.debug "Device's port or ip changed..."
def child = getChildDevice(parsedEvent.mac)
child.subscribe(parsedEvent.ip, parsedEvent.port)
child.poll()
}
}
}
def ssdpMotionHandler(evt) {
log.info("ssdpMotionHandler")
def description = evt.description
def hub = evt?.hubId
def parsedEvent = parseDiscoveryMessage(description)
parsedEvent << ["hub":hub]
log.debug parsedEvent
def motions = getWemoMotions()
if (!(motions."${parsedEvent.ssdpUSN.toString()}")) {
//if it doesn't already exist
motions << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
} else { // just update the values
log.debug "Device was already found in state..."
def d = motions."${parsedEvent.ssdpUSN.toString()}"
boolean deviceChangedValues = false
if(d.ip != parsedEvent.ip || d.port != parsedEvent.port) {
d.ip = parsedEvent.ip
d.port = parsedEvent.port
deviceChangedValues = true
log.debug "Device's port or ip changed..."
}
if (deviceChangedValues) {
def children = getChildDevices()
log.debug "Found children ${children}"
children.each {
if (it.getDeviceDataByName("mac") == parsedEvent.mac) {
log.debug "updating ip and port, and resubscribing, for device ${it} with mac ${parsedEvent.mac}"
it.subscribe(parsedEvent.ip, parsedEvent.port)
}
}
}
}
}
def ssdpLightSwitchHandler(evt) {
log.info("ssdpLightSwitchHandler")
def description = evt.description
def hub = evt?.hubId
def parsedEvent = parseDiscoveryMessage(description)
parsedEvent << ["hub":hub]
log.debug parsedEvent
def lightSwitches = getWemoLightSwitches()
if (!(lightSwitches."${parsedEvent.ssdpUSN.toString()}")) {
//if it doesn't already exist
lightSwitches << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
} else {
log.debug "Device was already found in state..."
def d = lightSwitches."${parsedEvent.ssdpUSN.toString()}"
boolean deviceChangedValues = false
if(d.ip != parsedEvent.ip || d.port != parsedEvent.port) {
d.ip = parsedEvent.ip
d.port = parsedEvent.port
deviceChangedValues = true
log.debug "Device's port or ip changed..."
def child = getChildDevice(parsedEvent.mac)
log.debug "updating ip and port, and resubscribing, for device with mac ${parsedEvent.mac}"
child.subscribe(parsedEvent.ip, parsedEvent.port)
}
}
}
void setupHandler(hubResponse) {
String contentType = hubResponse?.headers['Content-Type']
if (contentType != null && contentType == 'text/xml') {
def body = hubResponse.xml
def wemoDevices = []
String deviceType = body?.device?.deviceType?.text() ?: ""
if (deviceType.startsWith("urn:Belkin:device:controllee:1") || deviceType.startsWith("urn:Belkin:device:insight:1")) {
wemoDevices = getWemoSwitches()
} else if (deviceType.startsWith("urn:Belkin:device:sensor")) {
wemoDevices = getWemoMotions()
} else if (deviceType.startsWith("urn:Belkin:device:lightswitch")) {
wemoDevices = getWemoLightSwitches()
}
def wemoDevice = wemoDevices.find {it?.key?.contains(body?.device?.UDN?.text())}
if (wemoDevice) {
wemoDevice.value << [name:body?.device?.friendlyName?.text(), verified: true]
} else {
log.error "/setup.xml returned a wemo device that didn't exist"
}
}
}
@Deprecated
def locationHandler(evt) {
def description = evt.description
def hub = evt?.hubId
def parsedEvent = parseDiscoveryMessage(description)
parsedEvent << ["hub":hub]
log.debug parsedEvent
log.debug parsedEvent
if (parsedEvent?.ssdpTerm?.contains("Belkin:device:controllee") || parsedEvent?.ssdpTerm?.contains("Belkin:device:insight")) {
def switches = getWemoSwitches()
if (!(switches."${parsedEvent.ssdpUSN.toString()}")) {
//if it doesn't already exist
//if it doesn't already exist
switches << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
} else {
log.debug "Device was already found in state..."
@@ -335,16 +462,16 @@ def locationHandler(evt) {
d.port = parsedEvent.port
deviceChangedValues = true
log.debug "Device's port or ip changed..."
def child = getChildDevice(parsedEvent.mac)
def child = getChildDevice(parsedEvent.mac)
child.subscribe(parsedEvent.ip, parsedEvent.port)
child.poll()
child.poll()
}
}
}
else if (parsedEvent?.ssdpTerm?.contains("Belkin:device:sensor")) {
def motions = getWemoMotions()
if (!(motions."${parsedEvent.ssdpUSN.toString()}")) {
//if it doesn't already exist
//if it doesn't already exist
motions << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
} else { // just update the values
log.debug "Device was already found in state..."
@@ -459,6 +586,7 @@ def locationHandler(evt) {
}
}
@Deprecated
private def parseXmlBody(def body) {
def decodedBytes = body.decodeBase64()
def bodyString
@@ -540,4 +668,4 @@ private Boolean hasAllHubsOver(String desiredFirmware) {
private List getRealHubFirmwareVersions() {
return location.hubs*.firmwareVersionString.findAll { it }
}
}