mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-25 21:04:10 +00:00
Wemo refactor final (DVCSMP-1189)
https://smartthings.atlassian.net/browse/DVCSMP-1189 Detect and mark device offline within 5 minutes. Show Device offline in device tile. Show Device offline in Recent Activity. Log the current IP address to Recent Activity. Log the changed IP address to Recent Activity. Support 'Turning on' and 'Turning off' (blindly changing the state of device to ON or OFF without confirming bulb responded correctly) Turn on / off through Wemo-App reflected timely in SmartThings App/Ecosystem. Manual turn on / off of device is reflected timely in SmartThings App/Ecosystem. Lower case createEvent Bug Fixes Bug fixes setOffline Minor cosmetic fixes
This commit is contained in:
committed by
Yaima Valdivia
parent
fc587ef15a
commit
c473745e47
@@ -25,6 +25,8 @@ metadata {
|
|||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
|
attribute "currentIP", "string"
|
||||||
|
|
||||||
command "subscribe"
|
command "subscribe"
|
||||||
command "resubscribe"
|
command "resubscribe"
|
||||||
command "unsubscribe"
|
command "unsubscribe"
|
||||||
@@ -34,21 +36,36 @@ metadata {
|
|||||||
// simulator metadata
|
// simulator metadata
|
||||||
simulator {}
|
simulator {}
|
||||||
|
|
||||||
// UI tile definitions
|
// UI tile definitions
|
||||||
tiles {
|
tiles(scale: 2) {
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
|
||||||
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
state "turningOn", label:'${name}', icon:"st.switches.switch.on", backgroundColor:"#79b821"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
state "turningOff", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ffffff"
|
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
}
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
attributeState "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#ff0000"
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
}
|
||||||
}
|
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
|
||||||
|
attributeState "currentIP", label: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
main "switch"
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
details (["switch", "refresh"])
|
state "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
}
|
state "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
state "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
|
state "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
state "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#ff0000"
|
||||||
|
}
|
||||||
|
|
||||||
|
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {
|
||||||
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
}
|
||||||
|
|
||||||
|
main(["switch"])
|
||||||
|
details(["rich-control", "refresh"])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
@@ -68,6 +85,7 @@ def parse(String description) {
|
|||||||
def result = []
|
def result = []
|
||||||
def bodyString = msg.body
|
def bodyString = msg.body
|
||||||
if (bodyString) {
|
if (bodyString) {
|
||||||
|
unschedule("setOffline")
|
||||||
def body = new XmlSlurper().parseText(bodyString)
|
def body = new XmlSlurper().parseText(bodyString)
|
||||||
|
|
||||||
if (body?.property?.TimeSyncRequest?.text()) {
|
if (body?.property?.TimeSyncRequest?.text()) {
|
||||||
@@ -78,13 +96,14 @@ def parse(String description) {
|
|||||||
} else if (body?.property?.BinaryState?.text()) {
|
} else if (body?.property?.BinaryState?.text()) {
|
||||||
def value = body?.property?.BinaryState?.text().toInteger() == 1 ? "on" : "off"
|
def value = body?.property?.BinaryState?.text().toInteger() == 1 ? "on" : "off"
|
||||||
log.trace "Notify: BinaryState = ${value}"
|
log.trace "Notify: BinaryState = ${value}"
|
||||||
result << createEvent(name: "switch", value: value)
|
result << createEvent(name: "switch", value: value, descriptionText: "Switch is ${value}")
|
||||||
} else if (body?.property?.TimeZoneNotification?.text()) {
|
} else if (body?.property?.TimeZoneNotification?.text()) {
|
||||||
log.debug "Notify: TimeZoneNotification = ${body?.property?.TimeZoneNotification?.text()}"
|
log.debug "Notify: TimeZoneNotification = ${body?.property?.TimeZoneNotification?.text()}"
|
||||||
} else if (body?.Body?.GetBinaryStateResponse?.BinaryState?.text()) {
|
} else if (body?.Body?.GetBinaryStateResponse?.BinaryState?.text()) {
|
||||||
def value = body?.Body?.GetBinaryStateResponse?.BinaryState?.text().toInteger() == 1 ? "on" : "off"
|
def value = body?.Body?.GetBinaryStateResponse?.BinaryState?.text().toInteger() == 1 ? "on" : "off"
|
||||||
log.trace "GetBinaryResponse: BinaryState = ${value}"
|
log.trace "GetBinaryResponse: BinaryState = ${value}"
|
||||||
result << createEvent(name: "switch", value: value)
|
def dispaux = device.currentValue("switch") != value
|
||||||
|
result << createEvent(name: "switch", value: value, descriptionText: "Switch is ${value}", displayed: dispaux)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,14 +120,6 @@ private getCallBackAddress() {
|
|||||||
device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")
|
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() {
|
private getHostAddress() {
|
||||||
def ip = getDataValue("ip")
|
def ip = getDataValue("ip")
|
||||||
def port = getDataValue("port")
|
def port = getDataValue("port")
|
||||||
@@ -195,6 +206,8 @@ def subscribe(ip, port) {
|
|||||||
if (ip && ip != existingIp) {
|
if (ip && ip != existingIp) {
|
||||||
log.debug "Updating ip from $existingIp to $ip"
|
log.debug "Updating ip from $existingIp to $ip"
|
||||||
updateDataValue("ip", ip)
|
updateDataValue("ip", ip)
|
||||||
|
def ipvalue = convertHexToIP(getDataValue("ip"))
|
||||||
|
sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP changed to ${ipvalue}")
|
||||||
}
|
}
|
||||||
if (port && port != existingPort) {
|
if (port && port != existingPort) {
|
||||||
log.debug "Updating port from $existingPort to $port"
|
log.debug "Updating port from $existingPort to $port"
|
||||||
@@ -259,6 +272,8 @@ User-Agent: CyberGarage-HTTP/1.0
|
|||||||
|
|
||||||
def poll() {
|
def poll() {
|
||||||
log.debug "Executing 'poll'"
|
log.debug "Executing 'poll'"
|
||||||
|
if (device.currentValue("currentIP") != "Offline")
|
||||||
|
runIn(10, setOffline)
|
||||||
new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
|
new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
|
||||||
SOAPACTION: "urn:Belkin:service:basicevent:1#GetBinaryState"
|
SOAPACTION: "urn:Belkin:service:basicevent:1#GetBinaryState"
|
||||||
Content-Length: 277
|
Content-Length: 277
|
||||||
@@ -274,3 +289,15 @@ User-Agent: CyberGarage-HTTP/1.0
|
|||||||
</s:Body>
|
</s:Body>
|
||||||
</s:Envelope>""", physicalgraph.device.Protocol.LAN)
|
</s:Envelope>""", physicalgraph.device.Protocol.LAN)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def setOffline() {
|
||||||
|
sendEvent(name: "switch", value: "offline", descriptionText: "The device is offline")
|
||||||
|
}
|
||||||
|
|
||||||
|
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(".")
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
|
attribute "currentIP", "string"
|
||||||
|
|
||||||
command "subscribe"
|
command "subscribe"
|
||||||
command "resubscribe"
|
command "resubscribe"
|
||||||
command "unsubscribe"
|
command "unsubscribe"
|
||||||
@@ -31,17 +33,30 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UI tile definitions
|
// UI tile definitions
|
||||||
tiles {
|
tiles(scale: 2) {
|
||||||
|
multiAttributeTile(name:"rich-control", type: "motion", canChangeIcon: true){
|
||||||
|
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
|
||||||
|
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
||||||
|
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
||||||
|
attributeState "offline", label:'${name}', icon:"st.motion.motion.active", backgroundColor:"#ff0000"
|
||||||
|
}
|
||||||
|
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
|
||||||
|
attributeState "currentIP", label: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
standardTile("motion", "device.motion", width: 2, height: 2) {
|
standardTile("motion", "device.motion", width: 2, height: 2) {
|
||||||
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
|
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
|
||||||
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
|
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
|
||||||
}
|
state("offline", label:'${name}', icon:"st.motion.motion.inactive", backgroundColor:"#ff0000")
|
||||||
standardTile("refresh", "device.motion", inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {
|
||||||
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
}
|
||||||
|
|
||||||
main "motion"
|
main "motion"
|
||||||
details (["motion", "refresh"])
|
details (["rich-control", "refresh"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +77,7 @@ def parse(String description) {
|
|||||||
def result = []
|
def result = []
|
||||||
def bodyString = msg.body
|
def bodyString = msg.body
|
||||||
if (bodyString) {
|
if (bodyString) {
|
||||||
|
unschedule("setOffline")
|
||||||
def body = new XmlSlurper().parseText(bodyString)
|
def body = new XmlSlurper().parseText(bodyString)
|
||||||
|
|
||||||
if (body?.property?.TimeSyncRequest?.text()) {
|
if (body?.property?.TimeSyncRequest?.text()) {
|
||||||
@@ -72,7 +88,7 @@ def parse(String description) {
|
|||||||
} else if (body?.property?.BinaryState?.text()) {
|
} else if (body?.property?.BinaryState?.text()) {
|
||||||
def value = body?.property?.BinaryState?.text().toInteger() == 1 ? "active" : "inactive"
|
def value = body?.property?.BinaryState?.text().toInteger() == 1 ? "active" : "inactive"
|
||||||
log.debug "Notify - BinaryState = ${value}"
|
log.debug "Notify - BinaryState = ${value}"
|
||||||
result << createEvent(name: "motion", value: value)
|
result << createEvent(name: "motion", value: value, descriptionText: "Motion is ${value}")
|
||||||
} else if (body?.property?.TimeZoneNotification?.text()) {
|
} else if (body?.property?.TimeZoneNotification?.text()) {
|
||||||
log.debug "Notify: TimeZoneNotification = ${body?.property?.TimeZoneNotification?.text()}"
|
log.debug "Notify: TimeZoneNotification = ${body?.property?.TimeZoneNotification?.text()}"
|
||||||
}
|
}
|
||||||
@@ -91,14 +107,6 @@ private getCallBackAddress() {
|
|||||||
device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")
|
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() {
|
private getHostAddress() {
|
||||||
def ip = getDataValue("ip")
|
def ip = getDataValue("ip")
|
||||||
def port = getDataValue("port")
|
def port = getDataValue("port")
|
||||||
@@ -125,6 +133,8 @@ def refresh() {
|
|||||||
////////////////////////////
|
////////////////////////////
|
||||||
def getStatus() {
|
def getStatus() {
|
||||||
log.debug "Executing WeMo Motion 'getStatus'"
|
log.debug "Executing WeMo Motion 'getStatus'"
|
||||||
|
if (device.currentValue("currentIP") != "Offline")
|
||||||
|
runIn(10, setOffline)
|
||||||
new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
|
new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
|
||||||
SOAPACTION: "urn:Belkin:service:basicevent:1#GetBinaryState"
|
SOAPACTION: "urn:Belkin:service:basicevent:1#GetBinaryState"
|
||||||
Content-Length: 277
|
Content-Length: 277
|
||||||
@@ -165,7 +175,9 @@ def subscribe(ip, port) {
|
|||||||
def existingPort = getDataValue("port")
|
def existingPort = getDataValue("port")
|
||||||
if (ip && ip != existingIp) {
|
if (ip && ip != existingIp) {
|
||||||
log.debug "Updating ip from $existingIp to $ip"
|
log.debug "Updating ip from $existingIp to $ip"
|
||||||
updateDataValue("ip", ip)
|
updateDataValue("ip", ip)
|
||||||
|
def ipvalue = convertHexToIP(getDataValue("ip"))
|
||||||
|
sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP changed to ${ipvalue}")
|
||||||
}
|
}
|
||||||
if (port && port != existingPort) {
|
if (port && port != existingPort) {
|
||||||
log.debug "Updating port from $existingPort to $port"
|
log.debug "Updating port from $existingPort to $port"
|
||||||
@@ -226,3 +238,15 @@ User-Agent: CyberGarage-HTTP/1.0
|
|||||||
</s:Envelope>
|
</s:Envelope>
|
||||||
""", physicalgraph.device.Protocol.LAN)
|
""", physicalgraph.device.Protocol.LAN)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def setOffline() {
|
||||||
|
sendEvent(name: "motion", value: "offline", descriptionText: "The device is offline")
|
||||||
|
}
|
||||||
|
|
||||||
|
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(".")
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,120 +10,142 @@
|
|||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
* 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.
|
* for the specific language governing permissions and limitations under the License.
|
||||||
*
|
*
|
||||||
* Wemo Switch
|
* Wemo Switch
|
||||||
*
|
*
|
||||||
* Author: superuser
|
* Author: Juan Risso (SmartThings)
|
||||||
* Date: 2013-10-11
|
* Date: 2015-10-11
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Wemo Switch", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Wemo Switch", namespace: "smartthings", author: "SmartThings") {
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Polling"
|
capability "Polling"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
command "subscribe"
|
attribute "currentIP", "string"
|
||||||
command "resubscribe"
|
|
||||||
command "unsubscribe"
|
|
||||||
}
|
|
||||||
|
|
||||||
// simulator metadata
|
command "subscribe"
|
||||||
simulator {}
|
command "resubscribe"
|
||||||
|
command "unsubscribe"
|
||||||
|
}
|
||||||
|
|
||||||
// UI tile definitions
|
// simulator metadata
|
||||||
tiles {
|
simulator {}
|
||||||
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"
|
|
||||||
}
|
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
|
|
||||||
main "switch"
|
// UI tile definitions
|
||||||
details (["switch", "refresh"])
|
tiles(scale: 2) {
|
||||||
}
|
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
|
||||||
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
attributeState "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ff0000"
|
||||||
|
}
|
||||||
|
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
|
||||||
|
attributeState "currentIP", label: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
|
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
|
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
|
state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
state "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ff0000"
|
||||||
|
}
|
||||||
|
|
||||||
|
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {
|
||||||
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
|
}
|
||||||
|
|
||||||
|
main(["switch"])
|
||||||
|
details(["rich-control", "refresh"])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.debug "Parsing '${description}'"
|
log.debug "Parsing '${description}'"
|
||||||
|
|
||||||
def msg = parseLanMessage(description)
|
def msg = parseLanMessage(description)
|
||||||
def headerString = msg.header
|
def headerString = msg.header
|
||||||
|
|
||||||
if (headerString?.contains("SID: uuid:")) {
|
if (headerString?.contains("SID: uuid:")) {
|
||||||
def sid = (headerString =~ /SID: uuid:.*/) ? ( headerString =~ /SID: uuid:.*/)[0] : "0"
|
def sid = (headerString =~ /SID: uuid:.*/) ? ( headerString =~ /SID: uuid:.*/)[0] : "0"
|
||||||
sid -= "SID: uuid:".trim()
|
sid -= "SID: uuid:".trim()
|
||||||
|
|
||||||
updateDataValue("subscriptionId", sid)
|
updateDataValue("subscriptionId", sid)
|
||||||
}
|
}
|
||||||
|
|
||||||
def result = []
|
def result = []
|
||||||
def bodyString = msg.body
|
def bodyString = msg.body
|
||||||
if (bodyString) {
|
if (bodyString) {
|
||||||
def body = new XmlSlurper().parseText(bodyString)
|
unschedule("setOffline")
|
||||||
|
def body = new XmlSlurper().parseText(bodyString)
|
||||||
if (body?.property?.TimeSyncRequest?.text()) {
|
if (body?.property?.TimeSyncRequest?.text()) {
|
||||||
log.trace "Got TimeSyncRequest"
|
log.trace "Got TimeSyncRequest"
|
||||||
result << timeSyncResponse()
|
result << timeSyncResponse()
|
||||||
} else if (body?.Body?.SetBinaryStateResponse?.BinaryState?.text()) {
|
} else if (body?.Body?.SetBinaryStateResponse?.BinaryState?.text()) {
|
||||||
log.trace "Got SetBinaryStateResponse = ${body?.Body?.SetBinaryStateResponse?.BinaryState?.text()}"
|
log.trace "Got SetBinaryStateResponse = ${body?.Body?.SetBinaryStateResponse?.BinaryState?.text()}"
|
||||||
} else if (body?.property?.BinaryState?.text()) {
|
} else if (body?.property?.BinaryState?.text()) {
|
||||||
def value = body?.property?.BinaryState?.text().toInteger() == 1 ? "on" : "off"
|
def value = body?.property?.BinaryState?.text().substring(0, 1).toInteger() == 0 ? "off" : "on"
|
||||||
log.trace "Notify: BinaryState = ${value}"
|
log.trace "Notify: BinaryState = ${value}, ${body.property.BinaryState}"
|
||||||
result << createEvent(name: "switch", value: value)
|
def dispaux = device.currentValue("switch") != value
|
||||||
} else if (body?.property?.TimeZoneNotification?.text()) {
|
result << createEvent(name: "switch", value: value, descriptionText: "Switch is ${value}", displayed: dispaux)
|
||||||
log.debug "Notify: TimeZoneNotification = ${body?.property?.TimeZoneNotification?.text()}"
|
} else if (body?.property?.TimeZoneNotification?.text()) {
|
||||||
} else if (body?.Body?.GetBinaryStateResponse?.BinaryState?.text()) {
|
log.debug "Notify: TimeZoneNotification = ${body?.property?.TimeZoneNotification?.text()}"
|
||||||
def value = body?.Body?.GetBinaryStateResponse?.BinaryState?.text().toInteger() == 1 ? "on" : "off"
|
} else if (body?.Body?.GetBinaryStateResponse?.BinaryState?.text()) {
|
||||||
log.trace "GetBinaryResponse: BinaryState = ${value}"
|
def value = body?.Body?.GetBinaryStateResponse?.BinaryState?.text().substring(0, 1).toInteger() == 0 ? "off" : "on"
|
||||||
result << createEvent(name: "switch", value: value)
|
log.trace "GetBinaryResponse: BinaryState = ${value}, ${body.property.BinaryState}"
|
||||||
}
|
log.info "Connection: ${device.currentValue("connection")}"
|
||||||
}
|
if (device.currentValue("currentIP") == "Offline") {
|
||||||
|
def ipvalue = convertHexToIP(getDataValue("ip"))
|
||||||
result
|
sendEvent(name: "IP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
|
||||||
|
}
|
||||||
|
def dispaux2 = device.currentValue("switch") != value
|
||||||
|
result << createEvent(name: "switch", value: value, descriptionText: "Switch is ${value}", displayed: dispaux2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTime() {
|
private getTime() {
|
||||||
// This is essentially System.currentTimeMillis()/1000, but System is disallowed by the sandbox.
|
// This is essentially System.currentTimeMillis()/1000, but System is disallowed by the sandbox.
|
||||||
((new GregorianCalendar().time.time / 1000l).toInteger()).toString()
|
((new GregorianCalendar().time.time / 1000l).toInteger()).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCallBackAddress() {
|
private getCallBackAddress() {
|
||||||
device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")
|
device.hub.getDataValue("localIP") + ":" + device.hub.getDataValue("localSrvPortTCP")
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer convertHexToInt(hex) {
|
private Integer convertHexToInt(hex) {
|
||||||
Integer.parseInt(hex,16)
|
Integer.parseInt(hex,16)
|
||||||
}
|
}
|
||||||
|
|
||||||
private String convertHexToIP(hex) {
|
private String convertHexToIP(hex) {
|
||||||
[convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".")
|
[convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".")
|
||||||
}
|
}
|
||||||
|
|
||||||
private getHostAddress() {
|
private getHostAddress() {
|
||||||
def ip = getDataValue("ip")
|
def ip = getDataValue("ip")
|
||||||
def port = getDataValue("port")
|
def port = getDataValue("port")
|
||||||
|
if (!ip || !port) {
|
||||||
if (!ip || !port) {
|
def parts = device.deviceNetworkId.split(":")
|
||||||
def parts = device.deviceNetworkId.split(":")
|
if (parts.length == 2) {
|
||||||
if (parts.length == 2) {
|
ip = parts[0]
|
||||||
ip = parts[0]
|
port = parts[1]
|
||||||
port = parts[1]
|
} else {
|
||||||
} else {
|
log.warn "Can't figure out ip and port for device: ${device.id}"
|
||||||
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}"
|
||||||
log.debug "Using ip: ${ip} and port: ${port} for device: ${device.id}"
|
return convertHexToIP(ip) + ":" + convertHexToInt(port)
|
||||||
return convertHexToIP(ip) + ":" + convertHexToInt(port)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def on() {
|
def on() {
|
||||||
log.debug "Executing 'on'"
|
log.debug "Executing 'on'"
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
def turnOn = new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
|
def turnOn = new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
|
||||||
SOAPAction: "urn:Belkin:service:basicevent:1#SetBinaryState"
|
SOAPAction: "urn:Belkin:service:basicevent:1#SetBinaryState"
|
||||||
Host: ${getHostAddress()}
|
Host: ${getHostAddress()}
|
||||||
@@ -133,17 +155,16 @@ Content-Length: 333
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||||
<SOAP-ENV:Body>
|
<SOAP-ENV:Body>
|
||||||
<m:SetBinaryState xmlns:m="urn:Belkin:service:basicevent:1">
|
<m:SetBinaryState xmlns:m="urn:Belkin:service:basicevent:1">
|
||||||
<BinaryState>1</BinaryState>
|
<BinaryState>1</BinaryState>
|
||||||
</m:SetBinaryState>
|
</m:SetBinaryState>
|
||||||
</SOAP-ENV:Body>
|
</SOAP-ENV:Body>
|
||||||
</SOAP-ENV:Envelope>""", physicalgraph.device.Protocol.LAN)
|
</SOAP-ENV:Envelope>""", physicalgraph.device.Protocol.LAN)
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
def off() {
|
||||||
log.debug "Executing 'off'"
|
log.debug "Executing 'off'"
|
||||||
sendEvent(name: "switch", value: "off")
|
def turnOff = new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
|
||||||
def turnOff = new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
|
|
||||||
SOAPAction: "urn:Belkin:service:basicevent:1#SetBinaryState"
|
SOAPAction: "urn:Belkin:service:basicevent:1#SetBinaryState"
|
||||||
Host: ${getHostAddress()}
|
Host: ${getHostAddress()}
|
||||||
Content-Type: text/xml
|
Content-Type: text/xml
|
||||||
@@ -152,36 +173,13 @@ Content-Length: 333
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
||||||
<SOAP-ENV:Body>
|
<SOAP-ENV:Body>
|
||||||
<m:SetBinaryState xmlns:m="urn:Belkin:service:basicevent:1">
|
<m:SetBinaryState xmlns:m="urn:Belkin:service:basicevent:1">
|
||||||
<BinaryState>0</BinaryState>
|
<BinaryState>0</BinaryState>
|
||||||
</m:SetBinaryState>
|
</m:SetBinaryState>
|
||||||
</SOAP-ENV:Body>
|
</SOAP-ENV:Body>
|
||||||
</SOAP-ENV:Envelope>""", physicalgraph.device.Protocol.LAN)
|
</SOAP-ENV:Envelope>""", physicalgraph.device.Protocol.LAN)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*def refresh() {
|
|
||||||
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
|
|
||||||
|
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<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) {
|
def subscribe(hostAddress) {
|
||||||
log.debug "Executing 'subscribe()'"
|
log.debug "Executing 'subscribe()'"
|
||||||
def address = getCallBackAddress()
|
def address = getCallBackAddress()
|
||||||
@@ -200,27 +198,30 @@ def subscribe() {
|
|||||||
subscribe(getHostAddress())
|
subscribe(getHostAddress())
|
||||||
}
|
}
|
||||||
|
|
||||||
def subscribe(ip, port) {
|
def refresh() {
|
||||||
def existingIp = getDataValue("ip")
|
log.debug "Executing WeMo Switch 'subscribe', then 'timeSyncResponse', then 'poll'"
|
||||||
def existingPort = getDataValue("port")
|
[subscribe(), timeSyncResponse(), poll()]
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
def ipvalue = convertHexToIP(getDataValue("ip"))
|
||||||
|
sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP changed to ${ipvalue}")
|
||||||
|
}
|
||||||
|
if (port && port != existingPort) {
|
||||||
|
log.debug "Updating port from $existingPort to $port"
|
||||||
|
updateDataValue("port", port)
|
||||||
|
}
|
||||||
subscribe("${ip}:${port}")
|
subscribe("${ip}:${port}")
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////
|
|
||||||
def resubscribe() {
|
def resubscribe() {
|
||||||
log.debug "Executing 'resubscribe()'"
|
log.debug "Executing 'resubscribe()'"
|
||||||
|
def sid = getDeviceDataByName("subscriptionId")
|
||||||
def sid = getDeviceDataByName("subscriptionId")
|
|
||||||
|
|
||||||
new physicalgraph.device.HubAction("""SUBSCRIBE /upnp/event/basicevent1 HTTP/1.1
|
new physicalgraph.device.HubAction("""SUBSCRIBE /upnp/event/basicevent1 HTTP/1.1
|
||||||
HOST: ${getHostAddress()}
|
HOST: ${getHostAddress()}
|
||||||
SID: uuid:${sid}
|
SID: uuid:${sid}
|
||||||
@@ -228,12 +229,11 @@ TIMEOUT: Second-5400
|
|||||||
|
|
||||||
|
|
||||||
""", physicalgraph.device.Protocol.LAN)
|
""", physicalgraph.device.Protocol.LAN)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////
|
|
||||||
def unsubscribe() {
|
def unsubscribe() {
|
||||||
def sid = getDeviceDataByName("subscriptionId")
|
def sid = getDeviceDataByName("subscriptionId")
|
||||||
new physicalgraph.device.HubAction("""UNSUBSCRIBE publisher path HTTP/1.1
|
new physicalgraph.device.HubAction("""UNSUBSCRIBE publisher path HTTP/1.1
|
||||||
HOST: ${getHostAddress()}
|
HOST: ${getHostAddress()}
|
||||||
SID: uuid:${sid}
|
SID: uuid:${sid}
|
||||||
@@ -242,7 +242,7 @@ SID: uuid:${sid}
|
|||||||
""", physicalgraph.device.Protocol.LAN)
|
""", physicalgraph.device.Protocol.LAN)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////
|
|
||||||
//TODO: Use UTC Timezone
|
//TODO: Use UTC Timezone
|
||||||
def timeSyncResponse() {
|
def timeSyncResponse() {
|
||||||
log.debug "Executing 'timeSyncResponse()'"
|
log.debug "Executing 'timeSyncResponse()'"
|
||||||
@@ -267,9 +267,15 @@ User-Agent: CyberGarage-HTTP/1.0
|
|||||||
""", physicalgraph.device.Protocol.LAN)
|
""", physicalgraph.device.Protocol.LAN)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def setOffline() {
|
||||||
|
//sendEvent(name: "currentIP", value: "Offline", displayed: false)
|
||||||
|
sendEvent(name: "switch", value: "offline", descriptionText: "The device is offline")
|
||||||
|
}
|
||||||
|
|
||||||
def poll() {
|
def poll() {
|
||||||
log.debug "Executing 'poll'"
|
log.debug "Executing 'poll'"
|
||||||
|
if (device.currentValue("currentIP") != "Offline")
|
||||||
|
runIn(10, setOffline)
|
||||||
new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
|
new physicalgraph.device.HubAction("""POST /upnp/control/basicevent1 HTTP/1.1
|
||||||
SOAPACTION: "urn:Belkin:service:basicevent:1#GetBinaryState"
|
SOAPACTION: "urn:Belkin:service:basicevent:1#GetBinaryState"
|
||||||
Content-Length: 277
|
Content-Length: 277
|
||||||
|
|||||||
@@ -61,10 +61,7 @@ def firstPage()
|
|||||||
|
|
||||||
log.debug "REFRESH COUNT :: ${refreshCount}"
|
log.debug "REFRESH COUNT :: ${refreshCount}"
|
||||||
|
|
||||||
if(!state.subscribe) {
|
subscribe(location, null, locationHandler, [filterEvents:false])
|
||||||
subscribe(location, null, locationHandler, [filterEvents:false])
|
|
||||||
state.subscribe = true
|
|
||||||
}
|
|
||||||
|
|
||||||
//ssdp request every 25 seconds
|
//ssdp request every 25 seconds
|
||||||
if((refreshCount % 5) == 0) {
|
if((refreshCount % 5) == 0) {
|
||||||
@@ -168,21 +165,30 @@ def getWemoLightSwitches()
|
|||||||
def installed() {
|
def installed() {
|
||||||
log.debug "Installed with settings: ${settings}"
|
log.debug "Installed with settings: ${settings}"
|
||||||
initialize()
|
initialize()
|
||||||
|
|
||||||
runIn(5, "subscribeToDevices") //initial subscriptions delayed by 5 seconds
|
|
||||||
runIn(10, "refreshDevices") //refresh devices, delayed by 10 seconds
|
|
||||||
runIn(900, "doDeviceSync" , [overwrite: false]) //setup ip:port syncing every 15 minutes
|
|
||||||
|
|
||||||
// SUBSCRIBE responses come back with TIMEOUT-1801 (30 minutes), so we refresh things a bit before they expire (29 minutes)
|
|
||||||
runIn(1740, "refresh", [overwrite: false])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated() {
|
def updated() {
|
||||||
log.debug "Updated with settings: ${settings}"
|
log.debug "Updated with settings: ${settings}"
|
||||||
initialize()
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
runIn(5, "subscribeToDevices") //subscribe again to new/old devices wait 5 seconds
|
def initialize() {
|
||||||
runIn(10, "refreshDevices") //refresh devices again, delayed by 10 seconds
|
unsubscribe()
|
||||||
|
unschedule()
|
||||||
|
subscribe(location, null, locationHandler, [filterEvents:false])
|
||||||
|
|
||||||
|
if (selectedSwitches)
|
||||||
|
addSwitches()
|
||||||
|
|
||||||
|
if (selectedMotions)
|
||||||
|
addMotions()
|
||||||
|
|
||||||
|
if (selectedLightSwitches)
|
||||||
|
addLightSwitches()
|
||||||
|
|
||||||
|
runIn(5, "subscribeToDevices") //initial subscriptions delayed by 5 seconds
|
||||||
|
runIn(10, "refreshDevices") //refresh devices, delayed by 10 seconds
|
||||||
|
runEvery5Minutes("refresh")
|
||||||
}
|
}
|
||||||
|
|
||||||
def resubscribe() {
|
def resubscribe() {
|
||||||
@@ -192,8 +198,7 @@ def resubscribe() {
|
|||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
log.debug "refresh() called"
|
log.debug "refresh() called"
|
||||||
//reschedule the refreshes
|
doDeviceSync()
|
||||||
runIn(1740, "refresh", [overwrite: false])
|
|
||||||
refreshDevices()
|
refreshDevices()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +241,8 @@ def addSwitches() {
|
|||||||
"port": selectedSwitch.value.port
|
"port": selectedSwitch.value.port
|
||||||
]
|
]
|
||||||
])
|
])
|
||||||
|
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}"
|
log.debug "Created ${d.displayName} with id: ${d.id}, dni: ${d.deviceNetworkId}"
|
||||||
} else {
|
} else {
|
||||||
log.debug "found ${d.displayName} with id $dni already exists"
|
log.debug "found ${d.displayName} with id $dni already exists"
|
||||||
@@ -266,8 +272,9 @@ def addMotions() {
|
|||||||
"port": selectedMotion.value.port
|
"port": selectedMotion.value.port
|
||||||
]
|
]
|
||||||
])
|
])
|
||||||
|
def ipvalue = convertHexToIP(selectedMotion.value.ip)
|
||||||
log.debug "Created ${d.displayName} with id: ${d.id}, dni: ${d.deviceNetworkId}"
|
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
|
||||||
|
log.debug "Created ${d.displayName} with id: ${d.id}, dni: ${d.deviceNetworkId}"
|
||||||
} else {
|
} else {
|
||||||
log.debug "found ${d.displayName} with id $dni already exists"
|
log.debug "found ${d.displayName} with id $dni already exists"
|
||||||
}
|
}
|
||||||
@@ -296,7 +303,8 @@ def addLightSwitches() {
|
|||||||
"port": selectedLightSwitch.value.port
|
"port": selectedLightSwitch.value.port
|
||||||
]
|
]
|
||||||
])
|
])
|
||||||
|
def ipvalue = convertHexToIP(selectedLightSwitch.value.ip)
|
||||||
|
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
|
||||||
log.debug "created ${d.displayName} with id $dni"
|
log.debug "created ${d.displayName} with id $dni"
|
||||||
} else {
|
} else {
|
||||||
log.debug "found ${d.displayName} with id $dni already exists"
|
log.debug "found ${d.displayName} with id $dni already exists"
|
||||||
@@ -304,27 +312,6 @@ def addLightSwitches() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def initialize() {
|
|
||||||
// remove location subscription afterwards
|
|
||||||
unsubscribe()
|
|
||||||
state.subscribe = false
|
|
||||||
|
|
||||||
if (selectedSwitches)
|
|
||||||
{
|
|
||||||
addSwitches()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedMotions)
|
|
||||||
{
|
|
||||||
addMotions()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedLightSwitches)
|
|
||||||
{
|
|
||||||
addLightSwitches()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def locationHandler(evt) {
|
def locationHandler(evt) {
|
||||||
def description = evt.description
|
def description = evt.description
|
||||||
def hub = evt?.hubId
|
def hub = evt?.hubId
|
||||||
@@ -333,53 +320,32 @@ def locationHandler(evt) {
|
|||||||
log.debug parsedEvent
|
log.debug parsedEvent
|
||||||
|
|
||||||
if (parsedEvent?.ssdpTerm?.contains("Belkin:device:controllee") || parsedEvent?.ssdpTerm?.contains("Belkin:device:insight")) {
|
if (parsedEvent?.ssdpTerm?.contains("Belkin:device:controllee") || parsedEvent?.ssdpTerm?.contains("Belkin:device:insight")) {
|
||||||
|
|
||||||
def switches = getWemoSwitches()
|
def switches = getWemoSwitches()
|
||||||
|
if (!(switches."${parsedEvent.ssdpUSN.toString()}")) {
|
||||||
if (!(switches."${parsedEvent.ssdpUSN.toString()}"))
|
//if it doesn't already exist
|
||||||
{ //if it doesn't already exist
|
|
||||||
switches << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
|
switches << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{ // just update the values
|
|
||||||
|
|
||||||
log.debug "Device was already found in state..."
|
log.debug "Device was already found in state..."
|
||||||
|
|
||||||
def d = switches."${parsedEvent.ssdpUSN.toString()}"
|
def d = switches."${parsedEvent.ssdpUSN.toString()}"
|
||||||
boolean deviceChangedValues = false
|
boolean deviceChangedValues = false
|
||||||
|
log.debug "$d.ip <==> $parsedEvent.ip"
|
||||||
if(d.ip != parsedEvent.ip || d.port != parsedEvent.port) {
|
if(d.ip != parsedEvent.ip || d.port != parsedEvent.port) {
|
||||||
d.ip = parsedEvent.ip
|
d.ip = parsedEvent.ip
|
||||||
d.port = parsedEvent.port
|
d.port = parsedEvent.port
|
||||||
deviceChangedValues = true
|
deviceChangedValues = true
|
||||||
log.debug "Device's port or ip changed..."
|
log.debug "Device's port or ip changed..."
|
||||||
|
def child = getChildDevice(parsedEvent.mac)
|
||||||
|
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
||||||
|
child.poll()
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (parsedEvent?.ssdpTerm?.contains("Belkin:device:sensor")) {
|
else if (parsedEvent?.ssdpTerm?.contains("Belkin:device:sensor")) {
|
||||||
|
|
||||||
def motions = getWemoMotions()
|
def motions = getWemoMotions()
|
||||||
|
if (!(motions."${parsedEvent.ssdpUSN.toString()}")) {
|
||||||
if (!(motions."${parsedEvent.ssdpUSN.toString()}"))
|
//if it doesn't already exist
|
||||||
{ //if it doesn't already exist
|
|
||||||
motions << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
|
motions << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
|
||||||
}
|
} else { // just update the values
|
||||||
else
|
|
||||||
{ // just update the values
|
|
||||||
|
|
||||||
log.debug "Device was already found in state..."
|
log.debug "Device was already found in state..."
|
||||||
|
|
||||||
def d = motions."${parsedEvent.ssdpUSN.toString()}"
|
def d = motions."${parsedEvent.ssdpUSN.toString()}"
|
||||||
@@ -412,10 +378,7 @@ def locationHandler(evt) {
|
|||||||
if (!(lightSwitches."${parsedEvent.ssdpUSN.toString()}"))
|
if (!(lightSwitches."${parsedEvent.ssdpUSN.toString()}"))
|
||||||
{ //if it doesn't already exist
|
{ //if it doesn't already exist
|
||||||
lightSwitches << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
|
lightSwitches << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{ // just update the values
|
|
||||||
|
|
||||||
log.debug "Device was already found in state..."
|
log.debug "Device was already found in state..."
|
||||||
|
|
||||||
def d = lightSwitches."${parsedEvent.ssdpUSN.toString()}"
|
def d = lightSwitches."${parsedEvent.ssdpUSN.toString()}"
|
||||||
@@ -426,21 +389,11 @@ def locationHandler(evt) {
|
|||||||
d.port = parsedEvent.port
|
d.port = parsedEvent.port
|
||||||
deviceChangedValues = true
|
deviceChangedValues = true
|
||||||
log.debug "Device's port or ip changed..."
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (parsedEvent.headers && parsedEvent.body) {
|
else if (parsedEvent.headers && parsedEvent.body) {
|
||||||
String headerString = new String(parsedEvent.headers.decodeBase64())?.toLowerCase()
|
String headerString = new String(parsedEvent.headers.decodeBase64())?.toLowerCase()
|
||||||
@@ -580,73 +533,30 @@ private def parseDiscoveryMessage(String description) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
device
|
device
|
||||||
}
|
}
|
||||||
|
|
||||||
def doDeviceSync(){
|
def doDeviceSync(){
|
||||||
log.debug "Doing Device Sync!"
|
log.debug "Doing Device Sync!"
|
||||||
runIn(900, "doDeviceSync" , [overwrite: false]) //schedule to run again in 15 minutes
|
|
||||||
|
|
||||||
if(!state.subscribe) {
|
|
||||||
subscribe(location, null, locationHandler, [filterEvents:false])
|
|
||||||
state.subscribe = true
|
|
||||||
}
|
|
||||||
|
|
||||||
discoverAllWemoTypes()
|
discoverAllWemoTypes()
|
||||||
}
|
}
|
||||||
|
|
||||||
def pollChildren() {
|
private String convertHexToIP(hex) {
|
||||||
def devices = getAllChildDevices()
|
[convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".")
|
||||||
devices.each { d ->
|
|
||||||
//only poll switches?
|
|
||||||
d.poll()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def delayPoll() {
|
private Integer convertHexToInt(hex) {
|
||||||
log.debug "Executing 'delayPoll'"
|
Integer.parseInt(hex,16)
|
||||||
|
|
||||||
runIn(5, "pollChildren")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*def poll() {
|
private Boolean canInstallLabs() {
|
||||||
log.debug "Executing 'poll'"
|
|
||||||
runIn(600, "poll", [overwrite: false]) //schedule to run again in 10 minutes
|
|
||||||
|
|
||||||
def lastPoll = getLastPollTime()
|
|
||||||
def currentTime = now()
|
|
||||||
def lastPollDiff = currentTime - lastPoll
|
|
||||||
log.debug "lastPoll: $lastPoll, currentTime: $currentTime, lastPollDiff: $lastPollDiff"
|
|
||||||
setLastPollTime(currentTime)
|
|
||||||
|
|
||||||
doDeviceSync()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def setLastPollTime(currentTime) {
|
|
||||||
state.lastpoll = currentTime
|
|
||||||
}
|
|
||||||
|
|
||||||
def getLastPollTime() {
|
|
||||||
state.lastpoll ?: now()
|
|
||||||
}
|
|
||||||
|
|
||||||
def now() {
|
|
||||||
new Date().getTime()
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private Boolean canInstallLabs()
|
|
||||||
{
|
|
||||||
return hasAllHubsOver("000.011.00603")
|
return hasAllHubsOver("000.011.00603")
|
||||||
}
|
}
|
||||||
|
|
||||||
private Boolean hasAllHubsOver(String desiredFirmware)
|
private Boolean hasAllHubsOver(String desiredFirmware) {
|
||||||
{
|
|
||||||
return realHubFirmwareVersions.every { fw -> fw >= desiredFirmware }
|
return realHubFirmwareVersions.every { fw -> fw >= desiredFirmware }
|
||||||
}
|
}
|
||||||
|
|
||||||
private List getRealHubFirmwareVersions()
|
private List getRealHubFirmwareVersions() {
|
||||||
{
|
|
||||||
return location.hubs*.firmwareVersionString.findAll { it }
|
return location.hubs*.firmwareVersionString.findAll { it }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user