mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-08 05:31:56 +00:00
Compare commits
1 Commits
PROD_2017.
...
MSA-1739-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2fd0bed4a |
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Hunter Douglas Platinum Gateway Scene Control Switch for SmartThings
|
||||
* Schwark Satyavolu
|
||||
* Originally based on: Allan Klein's (@allanak) and Mike Maxwell's code
|
||||
*
|
||||
* Usage:
|
||||
* 1. Add this code as a device handler in the SmartThings IDE
|
||||
* 3. Create a device using PlatinumGatewaySceneSwitch as the device handler using a hexadecimal representation of IP:port as the device network ID value
|
||||
* For example, a gateway at 192.168.1.222:522 would have a device network ID of C0A801DE:20A
|
||||
* Note: Port 522 is the default Hunter Douglas Platinum Gateway port so you shouldn't need to change anything after the colon
|
||||
* 4. Enjoy the new functionality of the SmartThings app
|
||||
*
|
||||
* 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: "Platinum Gateway Scene Switch", namespace: "schwark", author: "Schwark Satyavolu") {
|
||||
capability "Switch"
|
||||
command "setSceneNo", ["string"]
|
||||
command "runScene"
|
||||
}
|
||||
|
||||
simulator {
|
||||
// TODO: define status and reply messages here
|
||||
}
|
||||
|
||||
tiles {
|
||||
standardTile("switch", "device.switch", width: 1, height: 1, 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"
|
||||
}
|
||||
}
|
||||
|
||||
preferences {
|
||||
}
|
||||
|
||||
main "switch"
|
||||
details(["switch"])
|
||||
}
|
||||
|
||||
def updated() {
|
||||
}
|
||||
|
||||
def runScene() {
|
||||
parent.runScene(state.sceneNo)
|
||||
}
|
||||
|
||||
def on() {
|
||||
runScene()
|
||||
sendEvent(name: "switch", value: "on")
|
||||
}
|
||||
|
||||
def off() {
|
||||
runScene()
|
||||
sendEvent(name: "switch", value: "off")
|
||||
}
|
||||
|
||||
def setSceneNo(sceneNo) {
|
||||
state.sceneNo = sceneNo
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Hunter Douglas Platinum Gateway Shade Control Switch for SmartThings
|
||||
* Schwark Satyavolu
|
||||
* Originally based on: Allan Klein's (@allanak) and Mike Maxwell's code
|
||||
*
|
||||
* Usage:
|
||||
* 1. Add this code as a device handler in the SmartThings IDE
|
||||
* 3. Create a device using PlatinumGatewayShadeSwitch as the device handler using a hexadecimal representation of IP:port as the device network ID value
|
||||
* For example, a gateway at 192.168.1.222:522 would have a device network ID of C0A801DE:20A
|
||||
* Note: Port 522 is the default Hunter Douglas Platinum Gateway port so you shouldn't need to change anything after the colon
|
||||
* 4. Enjoy the new functionality of the SmartThings app
|
||||
*
|
||||
* 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: "Platinum Gateway Shade Switch", namespace: "schwark", author: "Schwark Satyavolu") {
|
||||
capability "Switch"
|
||||
capability "Switch Level"
|
||||
command "setShadeNo", ["string"]
|
||||
}
|
||||
|
||||
simulator {
|
||||
// TODO: define status and reply messages here
|
||||
}
|
||||
|
||||
tiles {
|
||||
standardTile("switch", "device.switch", width: 1, height: 1, 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"
|
||||
}
|
||||
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false) {
|
||||
state "level", action:"switch level.setLevel"
|
||||
}
|
||||
}
|
||||
|
||||
preferences {
|
||||
}
|
||||
|
||||
main "switch"
|
||||
details(["switch", "levelSliderControl"])
|
||||
}
|
||||
|
||||
def installed() {
|
||||
log.debug("installed Shade with settings ${settings}")
|
||||
initialize()
|
||||
}
|
||||
|
||||
def initialize() {
|
||||
}
|
||||
|
||||
def updated() {
|
||||
}
|
||||
|
||||
def on() {
|
||||
return setLevel(100)
|
||||
}
|
||||
|
||||
def off() {
|
||||
return setLevel(0)
|
||||
}
|
||||
|
||||
def setLevel(percent) {
|
||||
parent.setShadeLevel(state.shadeNo, percent)
|
||||
if(percent == 100) {
|
||||
sendEvent(name: "switch", value: "on")
|
||||
} else if (percent == 0) {
|
||||
sendEvent(name: "switch", value: "off")
|
||||
}
|
||||
sendEvent(name: "level", value: percent)
|
||||
}
|
||||
|
||||
def setShadeNo(shadeNo) {
|
||||
state.shadeNo = shadeNo
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,347 @@
|
||||
/**
|
||||
* PlatinumGateway Service Manager
|
||||
*
|
||||
* Author: Schwark Satyavolu
|
||||
*. nc -i3 <ip-address-of-gateway> 522 < input.txt > output.txt
|
||||
*
|
||||
*/
|
||||
definition(
|
||||
name: "Hunter Douglas Platinum Gateway",
|
||||
namespace: "schwark",
|
||||
author: "Schwark Satyavolu",
|
||||
description: "Allows you to connect your Hunter Douglas Platinum Gateway shades with SmartThings and control them from your Things area or Dashboard in the SmartThings Mobile app. Adjust colors by going to the Thing detail screen for your PlatinumGateway shades (tap the gear on PlatinumGateway tiles).",
|
||||
category: "SmartThings Labs",
|
||||
iconUrl: "https://lh5.ggpht.com/FN3-xG6R0q9VjJHYE1iK5K2J11rTphiDEePr8XluI6o_s52xfPoHwt0-TZxc0qlVSQ=w300",
|
||||
iconX2Url: "https://lh5.ggpht.com/FN3-xG6R0q9VjJHYE1iK5K2J11rTphiDEePr8XluI6o_s52xfPoHwt0-TZxc0qlVSQ=w300",
|
||||
singleInstance: true
|
||||
)
|
||||
|
||||
preferences {
|
||||
input("gatewayIP", "string", title:"Gateway IP Address", description: "Please enter your gateway's IP Address", required: true, displayDuringSetup: true)
|
||||
input("statusURL", "string", title:"Gateway Status URL", description: "Please enter the URL to download status", required: true, displayDuringSetup: true)
|
||||
input("scenePrefix", "string", title:"Scene Name Prefix", description: "Please choose a prefix to add to all the Scenes", required: false, displayDuringSetup: true, defaultValue: "Shade Scene " )
|
||||
input("shadePrefix", "string", title:"Shade Name Prefix", description: "Please choose a prefix to add to all the Shades", required: false, displayDuringSetup: true, defaultValue: "Shade " )
|
||||
input("wantShades", "bool", title:"Do you want to add each Shade as a Switch?", description: "Turning this on will add one switch for EACH shade in your house", required: false, displayDuringSetup: true, defaultValue: false )
|
||||
}
|
||||
|
||||
def makeNetworkId(ipaddr, port) {
|
||||
String hexIp = ipaddr.tokenize('.').collect {String.format('%02X', it.toInteger()) }.join()
|
||||
String hexPort = String.format('%04X', port.toInteger())
|
||||
log.debug "The target device is configured as: ${hexIp}:${hexPort}"
|
||||
return "${hexIp}:${hexPort}"
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
def installed() {
|
||||
log.debug "Installed with settings: ${settings}"
|
||||
initialize()
|
||||
}
|
||||
|
||||
def uninstalled() {
|
||||
log.debug("Uninstalling with settings: ${settings}")
|
||||
unschedule()
|
||||
if(state.scenes) {
|
||||
// remove scene child devices
|
||||
state.scenes = [:]
|
||||
}
|
||||
if(state.shades) {
|
||||
// remove window child devices
|
||||
state.shades = [:]
|
||||
}
|
||||
|
||||
removeChildDevices(getChildDevices())
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
def updated() {
|
||||
//log.debug "Updated with settings: ${settings}"
|
||||
unsubscribe()
|
||||
initialize()
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
def initialize() {
|
||||
// remove location subscription aftwards
|
||||
unsubscribe()
|
||||
state.subscribe = false
|
||||
log.debug("gatewayIP is ${gatewayIP}")
|
||||
|
||||
if (gatewayIP) {
|
||||
addgateway()
|
||||
}
|
||||
|
||||
runEvery5Minutes(doDeviceSync)
|
||||
}
|
||||
|
||||
def getHubId() {
|
||||
return state.hubId ? state.hubId : location.hubs[0].id
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
def addgateway() {
|
||||
if(!state.gatewayHex) {
|
||||
state.gatewayHex = makeNetworkId(gatewayIP,522)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////
|
||||
def locationHandler(evt) {
|
||||
log.debug "$locationHandler(evt.description)"
|
||||
def description = evt.description
|
||||
def hub = evt?.hubId
|
||||
state.hubId = hub
|
||||
log.debug("location handler: event description is ${description}")
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
private def parseEventMessage(Map event) {
|
||||
//handles gateway attribute events
|
||||
return event
|
||||
}
|
||||
|
||||
private def parseEventMessage(String description) {
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
def doDeviceSync(){
|
||||
log.debug "Doing Platinum Gateway Device Sync!"
|
||||
|
||||
if(!state.subscribe) {
|
||||
subscribe(location, null, locationHandler, [filterEvents:false])
|
||||
state.subscribe = true
|
||||
}
|
||||
|
||||
if(statusURL) {
|
||||
try {
|
||||
|
||||
httpGet(statusURL) { resp ->
|
||||
resp.headers.each {
|
||||
log.debug "${it.name} : ${it.value}"
|
||||
}
|
||||
log.debug "response contentType: ${resp.contentType}"
|
||||
//log.trace "response data: ${resp.data}"
|
||||
if(resp.status == 200) {
|
||||
state.statusText = resp.data
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
log.error "something went wrong: $e"
|
||||
}
|
||||
}
|
||||
|
||||
updateStatus()
|
||||
}
|
||||
|
||||
def processState(info) {
|
||||
log.debug("processing state...")
|
||||
def DB = ['rooms':[:], 'shades':[:], 'scenes':[:]]
|
||||
def prefix = ""
|
||||
//def lines = info.split(/[\n\r]+/)
|
||||
|
||||
info.eachLine() { line ->
|
||||
line = line.trim()
|
||||
if(!prefix) {
|
||||
prefix = line[0..1]
|
||||
log.debug("prefix is set to ${prefix}")
|
||||
}
|
||||
else if(!line.startsWith(prefix)) {
|
||||
return
|
||||
}
|
||||
|
||||
line = line.drop(2)
|
||||
//log.trace("processing line ${line}")
|
||||
if(line.startsWith("\$cr")) {
|
||||
// name of room
|
||||
def room_id = line[3..4]
|
||||
def room_name = line.split('-')[-1].trim()
|
||||
log.debug("found room with ${room_id} and ${room_name}")
|
||||
DB['rooms'][room_id] = ['name':room_name, 'id':room_id, 'search':room_name.toLowerCase()]
|
||||
} else if(line.startsWith("\$cm")) {
|
||||
// name of scene
|
||||
def scene_id = line[3..4]
|
||||
def scene_name = line.split('-')[-1].trim()
|
||||
log.debug("found scene with ${scene_id} and ${scene_name}")
|
||||
DB['scenes'][scene_id] = ['name':scene_name, 'id':scene_id, 'search':scene_name.toLowerCase()]
|
||||
} else if(line.startsWith("\$cs")) {
|
||||
// name of a shade
|
||||
def parts = line.split('-')
|
||||
def shade_id = line[3..4]
|
||||
def shade_name = parts[-1].trim()
|
||||
def room_id = parts[1]
|
||||
log.debug("found shade with ${shade_id} and ${shade_name}")
|
||||
DB['shades'][shade_id] = ['name':shade_name, 'id':shade_id, 'search':shade_name.toLowerCase(), 'room': room_id]
|
||||
} else if(line.startsWith("\$cp")) {
|
||||
// state of a shade
|
||||
def shade_id = line[3..4]
|
||||
def stateTxt = line[-4..-2]
|
||||
def state = stateTxt.toInteger()/255.0
|
||||
log.debug("found shade state with ${shade_id} and ${state}")
|
||||
def shade = DB['shades'][shade_id]
|
||||
if(shade) {
|
||||
DB['shades'][shade_id]['state'] = state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("DB is ${DB}")
|
||||
return DB
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////
|
||||
//CHILD DEVICE METHODS
|
||||
/////////////////////////////////////
|
||||
def parse(childDevice, description) {
|
||||
def parsedEvent = parseEventMessage(description)
|
||||
|
||||
if (parsedEvent.headers && parsedEvent.body) {
|
||||
def headerString = new String(parsedEvent.headers.decodeBase64())
|
||||
def bodyString = new String(parsedEvent.body.decodeBase64())
|
||||
log.debug "parse() - ${bodyString}"
|
||||
} else {
|
||||
log.debug "parse - got something other than headers,body..."
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
def sendMessage(params) {
|
||||
def newDNI = state.gatewayHex
|
||||
if(newDNI) {
|
||||
log.debug("sending ${params.msg} to ${newDNI}")
|
||||
def ha = new physicalgraph.device.HubAction(params.msg,physicalgraph.device.Protocol.LAN, newDNI)
|
||||
sendHubCommand(ha)
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
def runScene(sceneID) {
|
||||
log.debug "Running Scene ${sceneID}"
|
||||
sceneID = String.format('%02d',sceneID.toInteger())
|
||||
def msg = "\$inm${sceneID}-"
|
||||
sendMessage(["msg":msg])
|
||||
}
|
||||
|
||||
def setShadeLevel(shadeNo, percent) {
|
||||
log.debug "Setting Shade level on Shade ${shadeNo} to ${percent}%"
|
||||
def shadeValue = 255 - (percent * 2.55).toInteger()
|
||||
log.debug "Setting Shade level on Shade ${shadeNo} to ${shadeValue} value"
|
||||
def msg = String.format("\$pss%s-04-%03d",shadeNo,shadeValue)
|
||||
sendMessage(["msg":msg])
|
||||
runIn(1, "sendMessage", [overwrite: false, data:["msg":"\$rls"]])
|
||||
}
|
||||
|
||||
def updateScenes(DB) {
|
||||
log.debug("Updating Scenes...")
|
||||
if(!state.scenes) {
|
||||
state.scenes = [:]
|
||||
}
|
||||
state.scenes.each() { id, sceneDevice ->
|
||||
if(DB['scenes'][id]) {
|
||||
// update device
|
||||
if(DB['scenes'][id]['name'] != sceneDevice.label) {
|
||||
log.debug("processing scene ${id} from name ${sceneDevice.label} to ${DB['scenes'][id]['name']}")
|
||||
sceneDevice.sendEvent(name:'label', value: DB['scenes'][id]['name'], isStateChange: true)
|
||||
}
|
||||
DB['scenes'].remove(id)
|
||||
} else {
|
||||
// remove device
|
||||
log.debug("removing scene ${id} from name ${sceneDevice.displayName}")
|
||||
deleteChildDevice(sceneDevice.deviceNetworkId)
|
||||
}
|
||||
}
|
||||
def namePrefix = scenePrefix
|
||||
if(namePrefix) {
|
||||
namePrefix = namePrefix.trim()+" "
|
||||
}
|
||||
DB['scenes']?.each() { id, sceneMap ->
|
||||
def name = sceneMap['name']
|
||||
log.debug("processing scene ${id} with name ${name}")
|
||||
def PREFIX = "PLATINUMGATEWAYSCENE"
|
||||
def hubId = getHubId()
|
||||
def sceneDevice = addChildDevice("schwark", "Platinum Gateway Scene Switch", "${PREFIX}${id}", hubId, ["name": "PlatinumScene.${id}", "label": "${namePrefix}${name}", "completedSetup": true])
|
||||
log.debug("created child device ${PREFIX}${id} for scene ${id} with name ${name} and hub ${hubId}")
|
||||
sceneDevice.setSceneNo(id)
|
||||
state.scenes[id] = sceneDevice
|
||||
}
|
||||
}
|
||||
|
||||
def updateShades(DB) {
|
||||
if(!wantShades) return
|
||||
log.debug("Updating Shades...")
|
||||
|
||||
if(!state.shades) {
|
||||
state.shades = [:]
|
||||
}
|
||||
state.shades.each() { id, shadeDevice ->
|
||||
if(DB['shades'][id]) {
|
||||
// update device
|
||||
if(DB['shades'][id]['name'] != shadeDevice.label) {
|
||||
log.debug("processing shade rename ${id} from name ${shadeDevice.label} to ${DB['shades'][id]['name']}")
|
||||
shadeDevice.sendEvent(name:'label', value: DB['shades'][id]['name'], isStateChange: true)
|
||||
}
|
||||
DB['shades'].remove(id)
|
||||
} else {
|
||||
// remove device
|
||||
log.debug("removing shade ${id} from name ${shadeDevice.displayName}")
|
||||
deleteChildDevice(shadeDevice.deviceNetworkId)
|
||||
}
|
||||
}
|
||||
def namePrefix = shadePrefix
|
||||
if(namePrefix) {
|
||||
namePrefix = namePrefix.trim()+" "
|
||||
}
|
||||
DB['shades']?.each() { id, shadeMap ->
|
||||
def name = shadeMap['name']
|
||||
log.debug("processing shade ${id} with name ${name}")
|
||||
def PREFIX = "PLATINUMGATEWAYSHADE"
|
||||
def hubId = getHubId()
|
||||
def shadeDevice = addChildDevice("schwark", "Platinum Gateway Shade Switch", "${PREFIX}${id}", hubId, ["name": "PlatinumShade.${id}", "label": "${namePrefix}${name}", "completedSetup": true])
|
||||
log.debug("created child device ${PREFIX}${id} for shade ${id} with name ${name} and hub ${hubId}")
|
||||
shadeDevice.setShadeNo(id)
|
||||
state.shades[id] = shadeDevice
|
||||
}
|
||||
}
|
||||
|
||||
def updateStatus() {
|
||||
if(!state.statusText) {
|
||||
log.debug("statusText is empty - ${state.statusText}.")
|
||||
return
|
||||
}
|
||||
log.debug ("Updating status")
|
||||
|
||||
def DB = processState(state.statusText)
|
||||
updateScenes(DB)
|
||||
updateShades(DB)
|
||||
}
|
||||
|
||||
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 Boolean canInstallLabs()
|
||||
{
|
||||
return hasAllHubsOver("000.011.00603")
|
||||
}
|
||||
|
||||
private Boolean hasAllHubsOver(String desiredFirmware)
|
||||
{
|
||||
return realHubFirmwareVersions.every { fw -> fw >= desiredFirmware }
|
||||
}
|
||||
|
||||
private List getRealHubFirmwareVersions()
|
||||
{
|
||||
return location.hubs*.firmwareVersionString.findAll { it }
|
||||
}
|
||||
|
||||
private removeChildDevices(data) {
|
||||
data.delete.each {
|
||||
deleteChildDevice(it.deviceNetworkId)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user