mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-18 13:20:53 +00:00
Compare commits
1 Commits
PROD_2016.
...
MSA-899-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb3d2d001d |
23
.gitignore
vendored
23
.gitignore
vendored
@@ -1,23 +0,0 @@
|
|||||||
# Eclipse files
|
|
||||||
/.settings
|
|
||||||
/.classpath
|
|
||||||
/.project
|
|
||||||
/eclipse/
|
|
||||||
/target-eclipse
|
|
||||||
|
|
||||||
# IntelliJ files
|
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
.idea
|
|
||||||
/out
|
|
||||||
*.ipr
|
|
||||||
|
|
||||||
# Gradle files
|
|
||||||
.gradletasknamecache
|
|
||||||
.gradle/
|
|
||||||
|
|
||||||
# Mac OS files
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# Build files
|
|
||||||
/build
|
|
||||||
57
build.gradle
57
build.gradle
@@ -1,57 +0,0 @@
|
|||||||
import java.nio.charset.StandardCharsets
|
|
||||||
import java.nio.file.Paths
|
|
||||||
|
|
||||||
apply plugin: 'groovy'
|
|
||||||
apply plugin: 'smartthings-executable-deployment'
|
|
||||||
apply plugin: 'smartthings-hipchat'
|
|
||||||
|
|
||||||
buildscript {
|
|
||||||
dependencies {
|
|
||||||
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.3"
|
|
||||||
}
|
|
||||||
repositories {
|
|
||||||
jcenter()
|
|
||||||
maven {
|
|
||||||
credentials {
|
|
||||||
username smartThingsArtifactoryUserName
|
|
||||||
password smartThingsArtifactoryPassword
|
|
||||||
}
|
|
||||||
url "http://artifactory.smartthings.com/libs-release-local"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
}
|
|
||||||
|
|
||||||
hipchatShareFile {
|
|
||||||
List<String> archives = []
|
|
||||||
File rootDir = new File("${project.buildDir}/archives")
|
|
||||||
if (rootDir.exists()) {
|
|
||||||
// Create a list of archives which were deployed.
|
|
||||||
java.nio.file.Path rootPath = Paths.get(rootDir.absolutePath)
|
|
||||||
rootDir.eachFileRecurse { File file ->
|
|
||||||
if (file.name.endsWith('.tar.gz')) {
|
|
||||||
java.nio.file.Path archivePath = Paths.get(file.absolutePath)
|
|
||||||
archives.add(rootPath.relativize(archivePath).toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set task properties
|
|
||||||
data = archives.join('\n').getBytes(StandardCharsets.UTF_8)
|
|
||||||
fileName = 'deployment-notes.txt'
|
|
||||||
contentType = 'text/html'
|
|
||||||
}
|
|
||||||
|
|
||||||
hipchatSendNotification {
|
|
||||||
String branch = project.hasProperty('branch') ? project.property('branch') : 'unknown'
|
|
||||||
message = "Began executable deploy of SmartThingsPublic(${branch})."
|
|
||||||
color = branch == 'master' ? 'yellow' : 'red'
|
|
||||||
notify = true
|
|
||||||
}
|
|
||||||
27
circle.yml
27
circle.yml
@@ -1,27 +0,0 @@
|
|||||||
machine:
|
|
||||||
java:
|
|
||||||
version:
|
|
||||||
oraclejdk8
|
|
||||||
|
|
||||||
dependencies:
|
|
||||||
override:
|
|
||||||
- echo "Nothing to do."
|
|
||||||
|
|
||||||
test:
|
|
||||||
override:
|
|
||||||
- echo "We don't have any tests :-("
|
|
||||||
|
|
||||||
deployment:
|
|
||||||
develop:
|
|
||||||
branch: master
|
|
||||||
commands:
|
|
||||||
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Ps3BucketName=$S3_BUCKET_NAME_PREPROD_DEV
|
|
||||||
- ./gradlew hipchatSendNotification -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Pbranch=$CIRCLE_BRANCH
|
|
||||||
- ./gradlew hipchatShareFile -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD
|
|
||||||
|
|
||||||
stage:
|
|
||||||
branch: staging
|
|
||||||
commands:
|
|
||||||
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Ps3BucketName=$S3_BUCKET_NAME_PREPROD_STAGING
|
|
||||||
- ./gradlew hipchatSendNotification -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Pbranch=$CIRCLE_BRANCH
|
|
||||||
- ./gradlew hipchatShareFile -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD
|
|
||||||
@@ -120,7 +120,7 @@ def setInstallSmartApp(value){
|
|||||||
}
|
}
|
||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.debug description
|
|
||||||
def description_map = parseDescriptionAsMap(description)
|
def description_map = parseDescriptionAsMap(description)
|
||||||
def event_name = ""
|
def event_name = ""
|
||||||
def measurement_map = [
|
def measurement_map = [
|
||||||
@@ -129,7 +129,10 @@ def parse(String description) {
|
|||||||
zigbeedeviceid: device.zigbeeId,
|
zigbeedeviceid: device.zigbeeId,
|
||||||
created: new Date().time /1000 as int
|
created: new Date().time /1000 as int
|
||||||
]
|
]
|
||||||
if (description_map.cluster == "0001"){
|
if (description_map.cluster == "0000"){
|
||||||
|
/* version number, not used */
|
||||||
|
|
||||||
|
} else if (description_map.cluster == "0001"){
|
||||||
/* battery voltage in mV (device needs minimium 2.1v to run) */
|
/* battery voltage in mV (device needs minimium 2.1v to run) */
|
||||||
log.debug "PlantLink - id ${device.zigbeeId} battery ${description_map.value}"
|
log.debug "PlantLink - id ${device.zigbeeId} battery ${description_map.value}"
|
||||||
event_name = "battery_status"
|
event_name = "battery_status"
|
||||||
@@ -155,10 +158,6 @@ def parse(String description) {
|
|||||||
def parseDescriptionAsMap(description) {
|
def parseDescriptionAsMap(description) {
|
||||||
(description - "read attr - ").split(",").inject([:]) { map, param ->
|
(description - "read attr - ").split(",").inject([:]) { map, param ->
|
||||||
def nameAndValue = param.split(":")
|
def nameAndValue = param.split(":")
|
||||||
if(nameAndValue.length == 2){
|
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
||||||
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
|
||||||
}else{
|
|
||||||
map += []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright 2015 SmartThings
|
* Ecobee Sensor
|
||||||
|
*
|
||||||
|
* Copyright 2015 Juan Risso
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
* 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:
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
@@ -10,9 +12,6 @@
|
|||||||
* 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.
|
||||||
*
|
*
|
||||||
* Ecobee Sensor
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
definition (name: "Ecobee Sensor", namespace: "smartthings", author: "SmartThings") {
|
definition (name: "Ecobee Sensor", namespace: "smartthings", author: "SmartThings") {
|
||||||
@@ -27,16 +26,7 @@ metadata {
|
|||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||||
state("temperature", label:'${currentValue}°', unit:"F",
|
state("temperature", label:'${currentValue}°', unit:"F",
|
||||||
backgroundColors:[
|
backgroundColors:[
|
||||||
// Celsius
|
[value: 31, color: "#153591"],
|
||||||
[value: 0, color: "#153591"],
|
|
||||||
[value: 7, color: "#1e9cbb"],
|
|
||||||
[value: 15, color: "#90d2a7"],
|
|
||||||
[value: 23, color: "#44b621"],
|
|
||||||
[value: 28, color: "#f1d801"],
|
|
||||||
[value: 35, color: "#d04e00"],
|
|
||||||
[value: 37, color: "#bc2323"],
|
|
||||||
// Fahrenheit
|
|
||||||
[value: 40, color: "#153591"],
|
|
||||||
[value: 44, color: "#1e9cbb"],
|
[value: 44, color: "#1e9cbb"],
|
||||||
[value: 59, color: "#90d2a7"],
|
[value: 59, color: "#90d2a7"],
|
||||||
[value: 74, color: "#44b621"],
|
[value: 74, color: "#44b621"],
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ def generateModeEvent(mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def generateFanModeEvent(fanMode) {
|
def generateFanModeEvent(fanMode) {
|
||||||
sendEvent(name: "thermostatFanMode", value: fanMode, descriptionText: "$device.displayName fan is in ${fanMode} mode", displayed: true)
|
sendEvent(name: "thermostatFanMode", value: fanMode, descriptionText: "$device.displayName fan is in ${mode} mode", displayed: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateOperatingStateEvent(operatingState) {
|
def generateOperatingStateEvent(operatingState) {
|
||||||
@@ -493,7 +493,7 @@ def fanOn() {
|
|||||||
} else {
|
} else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
def currentFanMode = device.currentState("thermostatFanMode")?.value
|
def currentFanMode = device.currentState("thermostatFanMode")?.value
|
||||||
generateFanModeEvent(currentFanMode) // reset the tile back
|
generateModeEvent(currentFanMode) // reset the tile back
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,7 +514,7 @@ def fanAuto() {
|
|||||||
} else {
|
} else {
|
||||||
log.debug "Error setting new mode."
|
log.debug "Error setting new mode."
|
||||||
def currentFanMode = device.currentState("thermostatFanMode")?.value
|
def currentFanMode = device.currentState("thermostatFanMode")?.value
|
||||||
generateFanModeEvent(currentFanMode) // reset the tile back
|
generateModeEvent(currentFanMode) // reset the tile back
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Hue Bulb
|
* Hue Bulb
|
||||||
*
|
*
|
||||||
@@ -10,14 +11,13 @@ metadata {
|
|||||||
capability "Switch Level"
|
capability "Switch Level"
|
||||||
capability "Actuator"
|
capability "Actuator"
|
||||||
capability "Color Control"
|
capability "Color Control"
|
||||||
capability "Color Temperature"
|
|
||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
command "setAdjustedColor"
|
command "setAdjustedColor"
|
||||||
command "reset"
|
command "reset"
|
||||||
command "refresh"
|
command "refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -25,7 +25,7 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tiles (scale: 2){
|
tiles (scale: 2){
|
||||||
multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
@@ -33,58 +33,23 @@ metadata {
|
|||||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
attributeState "level", action:"switch level.setLevel"
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
|
|
||||||
attributeState "level", label: 'Level ${currentValue}%'
|
|
||||||
}
|
}
|
||||||
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
||||||
attributeState "color", action:"setAdjustedColor"
|
attributeState "color", action:"setAdjustedColor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("reset", "device.reset", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
state "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
|
||||||
state "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
|
||||||
}
|
|
||||||
|
|
||||||
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2000..6500)") {
|
|
||||||
state "colorTemperature", action:"color temperature.setColorTemperature"
|
|
||||||
}
|
|
||||||
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "colorTemperature", label: '${currentValue} K'
|
|
||||||
}
|
|
||||||
|
|
||||||
standardTile("reset", "device.reset", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single"
|
state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single"
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.switch", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
|
|
||||||
state "level", action:"switch level.setLevel"
|
|
||||||
}
|
|
||||||
valueTile("level", "device.level", inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "level", label: 'Level ${currentValue}%'
|
|
||||||
}
|
|
||||||
controlTile("saturationSliderControl", "device.saturation", "slider", height: 1, width: 2, inactiveLabel: false) {
|
|
||||||
state "saturation", action:"color control.setSaturation"
|
|
||||||
}
|
|
||||||
valueTile("saturation", "device.saturation", inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "saturation", label: 'Sat ${currentValue} '
|
|
||||||
}
|
|
||||||
controlTile("hueSliderControl", "device.hue", "slider", height: 1, width: 2, inactiveLabel: false) {
|
|
||||||
state "hue", action:"color control.setHue"
|
|
||||||
}
|
|
||||||
valueTile("hue", "device.hue", inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "hue", label: 'Hue ${currentValue} '
|
|
||||||
}
|
|
||||||
|
|
||||||
main(["switch"])
|
|
||||||
details(["rich-control", "colorTempSliderControl", "colorTemp", "reset", "refresh"])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main(["switch"])
|
||||||
|
details(["switch", "levelSliderControl", "rgbSelector", "refresh", "reset"])
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
@@ -103,17 +68,17 @@ def parse(description) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle commands
|
// handle commands
|
||||||
void on() {
|
def on() {
|
||||||
log.trace parent.on(this)
|
log.trace parent.on(this)
|
||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
|
|
||||||
void off() {
|
def off() {
|
||||||
log.trace parent.off(this)
|
log.trace parent.off(this)
|
||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
|
|
||||||
void nextLevel() {
|
def nextLevel() {
|
||||||
def level = device.latestValue("level") as Integer ?: 0
|
def level = device.latestValue("level") as Integer ?: 0
|
||||||
if (level <= 100) {
|
if (level <= 100) {
|
||||||
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
|
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
|
||||||
@@ -124,25 +89,25 @@ void nextLevel() {
|
|||||||
setLevel(level)
|
setLevel(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLevel(percent) {
|
def setLevel(percent) {
|
||||||
log.debug "Executing 'setLevel'"
|
log.debug "Executing 'setLevel'"
|
||||||
parent.setLevel(this, percent)
|
parent.setLevel(this, percent)
|
||||||
sendEvent(name: "level", value: percent)
|
sendEvent(name: "level", value: percent)
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSaturation(percent) {
|
def setSaturation(percent) {
|
||||||
log.debug "Executing 'setSaturation'"
|
log.debug "Executing 'setSaturation'"
|
||||||
parent.setSaturation(this, percent)
|
parent.setSaturation(this, percent)
|
||||||
sendEvent(name: "saturation", value: percent)
|
sendEvent(name: "saturation", value: percent)
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHue(percent) {
|
def setHue(percent) {
|
||||||
log.debug "Executing 'setHue'"
|
log.debug "Executing 'setHue'"
|
||||||
parent.setHue(this, percent)
|
parent.setHue(this, percent)
|
||||||
sendEvent(name: "hue", value: percent)
|
sendEvent(name: "hue", value: percent)
|
||||||
}
|
}
|
||||||
|
|
||||||
void setColor(value) {
|
def setColor(value) {
|
||||||
log.debug "setColor: ${value}, $this"
|
log.debug "setColor: ${value}, $this"
|
||||||
parent.setColor(this, value)
|
parent.setColor(this, value)
|
||||||
if (value.hue) { sendEvent(name: "hue", value: value.hue)}
|
if (value.hue) { sendEvent(name: "hue", value: value.hue)}
|
||||||
@@ -152,33 +117,25 @@ void setColor(value) {
|
|||||||
if (value.switch) { sendEvent(name: "switch", value: value.switch)}
|
if (value.switch) { sendEvent(name: "switch", value: value.switch)}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
def reset() {
|
||||||
log.debug "Executing 'reset'"
|
log.debug "Executing 'reset'"
|
||||||
def value = [level:100, hex:"#90C638", saturation:56, hue:23]
|
def value = [level:100, hex:"#90C638", saturation:56, hue:23]
|
||||||
setAdjustedColor(value)
|
setAdjustedColor(value)
|
||||||
parent.poll()
|
parent.poll()
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAdjustedColor(value) {
|
def setAdjustedColor(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
log.trace "setAdjustedColor: ${value}"
|
log.trace "setAdjustedColor: ${value}"
|
||||||
def adjusted = value + [:]
|
def adjusted = value + [:]
|
||||||
adjusted.hue = adjustOutgoingHue(value.hue)
|
adjusted.hue = adjustOutgoingHue(value.hue)
|
||||||
// Needed because color picker always sends 100
|
// Needed because color picker always sends 100
|
||||||
adjusted.level = null
|
adjusted.level = null
|
||||||
setColor(adjusted)
|
setColor(adjusted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setColorTemperature(value) {
|
def refresh() {
|
||||||
if (value) {
|
|
||||||
log.trace "setColorTemperature: ${value}k"
|
|
||||||
parent.setColorTemperature(this, value)
|
|
||||||
sendEvent(name: "colorTemperature", value: value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void refresh() {
|
|
||||||
log.debug "Executing 'refresh'"
|
log.debug "Executing 'refresh'"
|
||||||
parent.manualRefresh()
|
parent.manualRefresh()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ metadata {
|
|||||||
capability "Switch"
|
capability "Switch"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
|
|
||||||
command "refresh"
|
command "refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
// TODO: define status and reply messages here
|
// TODO: define status and reply messages here
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"rich-control", type: "lighting", canChangeIcon: true){
|
multiAttributeTile(name:"rich-control", type: "lighting", canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
@@ -35,25 +35,25 @@ metadata {
|
|||||||
attributeState "level", label: 'Level ${currentValue}%'
|
attributeState "level", label: 'Level ${currentValue}%'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
state "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
state "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
state "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
state "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
|
|
||||||
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
|
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
|
||||||
state "level", action:"switch level.setLevel"
|
state "level", action:"switch level.setLevel"
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
main(["switch"])
|
main(["switch"])
|
||||||
details(["rich-control", "refresh"])
|
details(["rich-control", "refresh"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
@@ -74,23 +74,23 @@ def parse(description) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle commands
|
// handle commands
|
||||||
void on() {
|
def on() {
|
||||||
parent.on(this)
|
parent.on(this)
|
||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
|
|
||||||
void off() {
|
def off() {
|
||||||
parent.off(this)
|
parent.off(this)
|
||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLevel(percent) {
|
def setLevel(percent) {
|
||||||
log.debug "Executing 'setLevel'"
|
log.debug "Executing 'setLevel'"
|
||||||
parent.setLevel(this, percent)
|
parent.setLevel(this, percent)
|
||||||
sendEvent(name: "level", value: percent)
|
sendEvent(name: "level", value: percent)
|
||||||
}
|
}
|
||||||
|
|
||||||
void refresh() {
|
def refresh() {
|
||||||
log.debug "Executing 'refresh'"
|
log.debug "Executing 'refresh'"
|
||||||
parent.manualRefresh()
|
parent.manualRefresh()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ def setHue(percentage) {
|
|||||||
log.error("Bad setHue result: [${resp.status}] ${resp.data}")
|
log.error("Bad setHue result: [${resp.status}] ${resp.data}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def setSaturation(percentage) {
|
def setSaturation(percentage) {
|
||||||
@@ -98,7 +97,6 @@ def setSaturation(percentage) {
|
|||||||
log.error("Bad setSaturation result: [${resp.status}] ${resp.data}")
|
log.error("Bad setSaturation result: [${resp.status}] ${resp.data}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def setColor(Map color) {
|
def setColor(Map color) {
|
||||||
@@ -124,15 +122,13 @@ def setColor(Map color) {
|
|||||||
parent.logErrors(logObject:log) {
|
parent.logErrors(logObject:log) {
|
||||||
def resp = parent.apiPUT("/lights/${selector()}/state", [color: attrs.join(" "), power: "on"])
|
def resp = parent.apiPUT("/lights/${selector()}/state", [color: attrs.join(" "), power: "on"])
|
||||||
if (resp.status < 300) {
|
if (resp.status < 300) {
|
||||||
if (color.hex)
|
sendEvent(name: "color", value: color.hex)
|
||||||
sendEvent(name: "color", value: color.hex)
|
|
||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
events.each { sendEvent(it) }
|
events.each { sendEvent(it) }
|
||||||
} else {
|
} else {
|
||||||
log.error("Bad setColor result: [${resp.status}] ${resp.data}")
|
log.error("Bad setColor result: [${resp.status}] ${resp.data}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def setLevel(percentage) {
|
def setLevel(percentage) {
|
||||||
@@ -154,7 +150,6 @@ def setLevel(percentage) {
|
|||||||
log.error("Bad setLevel result: [${resp.status}] ${resp.data}")
|
log.error("Bad setLevel result: [${resp.status}] ${resp.data}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def setColorTemperature(kelvin) {
|
def setColorTemperature(kelvin) {
|
||||||
@@ -170,7 +165,6 @@ def setColorTemperature(kelvin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def on() {
|
def on() {
|
||||||
@@ -180,7 +174,6 @@ def on() {
|
|||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
def off() {
|
||||||
@@ -190,7 +183,6 @@ def off() {
|
|||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def poll() {
|
def poll() {
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ def setLevel(percentage) {
|
|||||||
log.error("Bad setLevel result: [${resp.status}] ${resp.data}")
|
log.error("Bad setLevel result: [${resp.status}] ${resp.data}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def setColorTemperature(kelvin) {
|
def setColorTemperature(kelvin) {
|
||||||
@@ -100,7 +99,6 @@ def setColorTemperature(kelvin) {
|
|||||||
log.error("Bad setColorTemperature result: [${resp.status}] ${resp.data}")
|
log.error("Bad setColorTemperature result: [${resp.status}] ${resp.data}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def on() {
|
def on() {
|
||||||
@@ -110,7 +108,6 @@ def on() {
|
|||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
def off() {
|
||||||
@@ -120,7 +117,6 @@ def off() {
|
|||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def poll() {
|
def poll() {
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
#==============================================================================
|
|
||||||
# Copyright 2016 SmartThings
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
# use this file except in compliance with the License. You may obtain a copy
|
|
||||||
# of the License at:
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
#==============================================================================
|
|
||||||
# Purpose: Mobile Presence i18n Translation File
|
|
||||||
#
|
|
||||||
# Filename: mobile-presence.src/i18n/messages.properties
|
|
||||||
#
|
|
||||||
# Change History:
|
|
||||||
# 1. 20160205 TW Initial release with informal Korean translation.
|
|
||||||
#==============================================================================
|
|
||||||
# Korean (ko)
|
|
||||||
# Device Preferences
|
|
||||||
'''Give your device a name'''.ko=기기 이름 바꾸기
|
|
||||||
'''Set Device Image'''.ko=디바이스 이미지 설정
|
|
||||||
# Events / Notifications
|
|
||||||
'''{{ linkText }} has left'''.ko={{ linkText }}님이 나갔습니다
|
|
||||||
'''{{ linkText }} has arrived'''.ko={{ linkText }}님이 도착했습니다
|
|
||||||
'''present'''.ko=집안
|
|
||||||
'''not present'''.ko=부재중
|
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2015 SmartThings
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
* Samsung TV
|
||||||
|
*
|
||||||
|
* Author: SmartThings (juano23@gmail.com)
|
||||||
|
* Date: 2015-01-08
|
||||||
|
*/
|
||||||
|
|
||||||
|
metadata {
|
||||||
|
definition (name: "Samsung Smart TV", namespace: "smartthings", author: "SmartThings") {
|
||||||
|
capability "switch"
|
||||||
|
|
||||||
|
command "mute"
|
||||||
|
command "source"
|
||||||
|
command "menu"
|
||||||
|
command "tools"
|
||||||
|
command "HDMI"
|
||||||
|
command "Sleep"
|
||||||
|
command "Up"
|
||||||
|
command "Down"
|
||||||
|
command "Left"
|
||||||
|
command "Right"
|
||||||
|
command "chup"
|
||||||
|
command "chdown"
|
||||||
|
command "prech"
|
||||||
|
command "volup"
|
||||||
|
command "voldown"
|
||||||
|
command "Enter"
|
||||||
|
command "Return"
|
||||||
|
command "Exit"
|
||||||
|
command "Info"
|
||||||
|
command "Size"
|
||||||
|
}
|
||||||
|
|
||||||
|
standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
|
||||||
|
state "default", label:'TV', action:"switch.off", icon:"st.Electronics.electronics15", backgroundColor:"#ffffff"
|
||||||
|
}
|
||||||
|
standardTile("power", "device.switch", width: 1, height: 1, canChangeIcon: false) {
|
||||||
|
state "default", label:'', action:"switch.off", decoration: "flat", icon:"st.thermostat.heating-cooling-off", backgroundColor:"#ffffff"
|
||||||
|
}
|
||||||
|
standardTile("mute", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Mute', action:"mute", icon:"st.custom.sonos.muted", backgroundColor:"#ffffff"
|
||||||
|
}
|
||||||
|
standardTile("source", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Source', action:"source", icon:"st.Electronics.electronics15"
|
||||||
|
}
|
||||||
|
standardTile("tools", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Tools', action:"tools", icon:"st.secondary.tools"
|
||||||
|
}
|
||||||
|
standardTile("menu", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Menu', action:"menu", icon:"st.vents.vent"
|
||||||
|
}
|
||||||
|
standardTile("HDMI", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Source', action:"HDMI", icon:"st.Electronics.electronics15"
|
||||||
|
}
|
||||||
|
standardTile("Sleep", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Sleep', action:"Sleep", icon:"st.Bedroom.bedroom10"
|
||||||
|
}
|
||||||
|
standardTile("Up", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Up', action:"Up", icon:"st.thermostat.thermostat-up"
|
||||||
|
}
|
||||||
|
standardTile("Down", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Down', action:"Down", icon:"st.thermostat.thermostat-down"
|
||||||
|
}
|
||||||
|
standardTile("Left", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Left', action:"Left", icon:"st.thermostat.thermostat-left"
|
||||||
|
}
|
||||||
|
standardTile("Right", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Right', action:"Right", icon:"st.thermostat.thermostat-right"
|
||||||
|
}
|
||||||
|
standardTile("chup", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'CH Up', action:"chup", icon:"st.thermostat.thermostat-up"
|
||||||
|
}
|
||||||
|
standardTile("chdown", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'CH Down', action:"chdown", icon:"st.thermostat.thermostat-down"
|
||||||
|
}
|
||||||
|
standardTile("prech", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Pre CH', action:"prech", icon:"st.secondary.refresh-icon"
|
||||||
|
}
|
||||||
|
standardTile("volup", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Vol Up', action:"volup", icon:"st.thermostat.thermostat-up"
|
||||||
|
}
|
||||||
|
standardTile("voldown", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Vol Down', action:"voldown", icon:"st.thermostat.thermostat-down"
|
||||||
|
}
|
||||||
|
standardTile("Enter", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Enter', action:"Enter", icon:"st.illuminance.illuminance.dark"
|
||||||
|
}
|
||||||
|
standardTile("Return", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Return', action:"Return", icon:"st.secondary.refresh-icon"
|
||||||
|
}
|
||||||
|
standardTile("Exit", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Exit', action:"Exit", icon:"st.locks.lock.unlocked"
|
||||||
|
}
|
||||||
|
standardTile("Info", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Info', action:"Info", icon:"st.motion.acceleration.active"
|
||||||
|
}
|
||||||
|
standardTile("Size", "device.switch", decoration: "flat", canChangeIcon: false) {
|
||||||
|
state "default", label:'Picture Size', action:"Size", icon:"st.contact.contact.open"
|
||||||
|
}
|
||||||
|
main "switch"
|
||||||
|
details (["power","HDMI","Sleep","chup","prech","volup","chdown","mute","voldown", "menu", "Up", "tools", "Left", "Enter", "Right", "Return", "Down", "Exit", "Info","Size"])
|
||||||
|
}
|
||||||
|
|
||||||
|
def parse(String description) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
def off() {
|
||||||
|
log.debug "Turning TV OFF"
|
||||||
|
parent.tvAction("POWEROFF",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command", value: "Power Off", displayed: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def mute() {
|
||||||
|
log.trace "MUTE pressed"
|
||||||
|
parent.tvAction("MUTE",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command", value: "Mute", displayed: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def source() {
|
||||||
|
log.debug "SOURCE pressed"
|
||||||
|
parent.tvAction("SOURCE",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command", value: "Source", displayed: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def menu() {
|
||||||
|
log.debug "MENU pressed"
|
||||||
|
parent.tvAction("MENU",device.deviceNetworkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
def tools() {
|
||||||
|
log.debug "TOOLS pressed"
|
||||||
|
parent.tvAction("TOOLS",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command", value: "Tools", displayed: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def HDMI() {
|
||||||
|
log.debug "HDMI pressed"
|
||||||
|
parent.tvAction("HDMI",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command sent", value: "Source", displayed: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Sleep() {
|
||||||
|
log.debug "SLEEP pressed"
|
||||||
|
parent.tvAction("SLEEP",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command", value: "Sleep", displayed: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Up() {
|
||||||
|
log.debug "UP pressed"
|
||||||
|
parent.tvAction("UP",device.deviceNetworkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Down() {
|
||||||
|
log.debug "DOWN pressed"
|
||||||
|
parent.tvAction("DOWN",device.deviceNetworkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Left() {
|
||||||
|
log.debug "LEFT pressed"
|
||||||
|
parent.tvAction("LEFT",device.deviceNetworkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Right() {
|
||||||
|
log.debug "RIGHT pressed"
|
||||||
|
parent.tvAction("RIGHT",device.deviceNetworkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
def chup() {
|
||||||
|
log.debug "CHUP pressed"
|
||||||
|
parent.tvAction("CHUP",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command", value: "Channel Up", displayed: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def chdown() {
|
||||||
|
log.debug "CHDOWN pressed"
|
||||||
|
parent.tvAction("CHDOWN",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command", value: "Channel Down", displayed: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def prech() {
|
||||||
|
log.debug "PRECH pressed"
|
||||||
|
parent.tvAction("PRECH",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command", value: "Prev Channel", displayed: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Exit() {
|
||||||
|
log.debug "EXIT pressed"
|
||||||
|
parent.tvAction("EXIT",device.deviceNetworkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
def volup() {
|
||||||
|
log.debug "VOLUP pressed"
|
||||||
|
parent.tvAction("VOLUP",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command", value: "Volume Up", displayed: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def voldown() {
|
||||||
|
log.debug "VOLDOWN pressed"
|
||||||
|
parent.tvAction("VOLDOWN",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command", value: "Volume Down", displayed: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Enter() {
|
||||||
|
log.debug "ENTER pressed"
|
||||||
|
parent.tvAction("ENTER",device.deviceNetworkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Return() {
|
||||||
|
log.debug "RETURN pressed"
|
||||||
|
parent.tvAction("RETURN",device.deviceNetworkId)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Info() {
|
||||||
|
log.debug "INFO pressed"
|
||||||
|
parent.tvAction("INFO",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command", value: "Info", displayed: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Size() {
|
||||||
|
log.debug "PICTURE_SIZE pressed"
|
||||||
|
parent.tvAction("PICTURE_SIZE",device.deviceNetworkId)
|
||||||
|
sendEvent(name:"Command", value: "Picture Size", displayed: true)
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
|
|
||||||
# Generated on Wed Feb 24 14:28:26 CST 2016 by dylan
|
|
||||||
'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
|
|
||||||
'''Degrees'''.ko=온도
|
|
||||||
'''Temperature Offset'''.ko=온도 직접 설정
|
|
||||||
'''This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.'''.ko=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다.
|
|
||||||
'''battery'''.ko=배터리
|
|
||||||
'''dry'''.ko=건조
|
|
||||||
'''wet'''.ko=누수
|
|
||||||
'''{{ device.displayName }} battery has too much power: (> 3.5) volts.'''.ko={{ device.displayName }} 배터리 전력이 너무 높습니다(3.5볼트 초과).
|
|
||||||
'''{{ device.displayName }} battery was {{ value }}'''.ko={{ device.displayName }} 배터리가 {{ value }}였습니다
|
|
||||||
'''{{ device.displayName }} is {{ value | translate }}'''.ko={{ device.displayName }}이(가) {{ value | translate }}입니다
|
|
||||||
'''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}이(가) {{ value }}°C였습니다
|
|
||||||
'''{{ device.displayName }} was {{ value }}°F'''.ko={{ device.displayName }}이(가) {{ value }}°F였습니다
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
|
|
||||||
# Generated on Wed Feb 24 14:28:26 CST 2016 by dylan
|
|
||||||
'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
|
|
||||||
'''Degrees'''.ko=온도
|
|
||||||
'''Temperature Offset'''.ko=온도 직접 설정
|
|
||||||
'''This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.'''.ko=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다.
|
|
||||||
'''battery'''.ko=배터리
|
|
||||||
'''{{ device.displayName }} battery has too much power: (> 3.5) volts.'''.ko={{ device.displayName }} 배터리 전력이 너무 높습니다(3.5볼트 초과).
|
|
||||||
'''{{ device.displayName }} battery was {{ value }}'''.ko={{ device.displayName }} 배터리가 {{ value }}였습니다
|
|
||||||
'''{{ device.displayName }} detected motion'''.ko={{ device.displayName }}가 움직임을 감지하였습니다.
|
|
||||||
'''{{ device.displayName }} motion has stopped'''.ko={{ device.displayName }} 동작이 중단되었습니다
|
|
||||||
'''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}이(가) {{ value }}°C였습니다
|
|
||||||
'''{{ device.displayName }} was {{ value }}°F'''.ko={{ device.displayName }}이(가) {{ value }}°F였습니다
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
|
|
||||||
# Generated on Wed Feb 24 14:28:26 CST 2016 by dylan
|
|
||||||
'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
|
|
||||||
'''Degrees'''.ko=온도
|
|
||||||
'''Do you want to use this sensor on a garage door?'''.ko=차고 문의 센서 사용 설정하기
|
|
||||||
'''No'''.ko=아니요
|
|
||||||
'''Tap to set'''.ko=눌러서 설정
|
|
||||||
'''Temperature Offset'''.ko=온도 직접 설정
|
|
||||||
'''This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.'''.ko=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다.
|
|
||||||
'''Updating device to garage sensor'''.ko=기기-차고 센서 업데이트 중
|
|
||||||
'''Updating device to open/close sensor'''.ko=기기-열림/닫힘 센서 업데이트 중
|
|
||||||
'''Yes'''.ko=예
|
|
||||||
'''{{ device.displayName }} status was closed'''.ko={{ device.displayName }}은(는) 닫힌 상태입니다
|
|
||||||
'''{{ device.displayName }} status was opened'''.ko={{ device.displayName }}은(는) 열린 상태입니다
|
|
||||||
'''{{ device.displayName }} was active'''.ko={{ device.displayName }}이(가) 활성화되었습니다
|
|
||||||
'''{{ device.displayName }} was closed'''.ko={{ device.displayName }}이(가) 닫혔습니다
|
|
||||||
'''{{ device.displayName }} was inactive'''.ko={{ device.displayName }}이(가) 비활성화되었습니다
|
|
||||||
'''{{ device.displayName }} was opened'''.ko={{ device.displayName }}이(가) 열렸습니다
|
|
||||||
'''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}이(가) {{ value }}°C였습니다
|
|
||||||
'''{{ device.displayName }} was {{ value }}°F'''.ko={{ device.displayName }}이(가) {{ value }}°F였습니다
|
|
||||||
@@ -100,6 +100,9 @@ metadata {
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
valueTile("3axis", "device.threeAxis", decoration: "flat", wordWrap: false, width: 2, height: 2) {
|
||||||
|
state("threeAxis", label:'${currentValue}', unit:"", backgroundColor:"#ffffff")
|
||||||
|
}
|
||||||
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
}
|
}
|
||||||
@@ -109,7 +112,7 @@ metadata {
|
|||||||
|
|
||||||
|
|
||||||
main(["status", "acceleration", "temperature"])
|
main(["status", "acceleration", "temperature"])
|
||||||
details(["status", "acceleration", "temperature", "battery", "refresh"])
|
details(["status", "acceleration", "temperature", "3axis", "battery", "refresh"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,12 +72,15 @@ metadata {
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
valueTile("3axis", "device.threeAxis", decoration: "flat", wordWrap: false, width: 2, height: 2) {
|
||||||
|
state("threeAxis", label:'${currentValue}', unit:"", backgroundColor:"#ffffff")
|
||||||
|
}
|
||||||
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
}
|
}
|
||||||
|
|
||||||
main(["contact", "acceleration", "temperature"])
|
main(["contact", "acceleration", "temperature"])
|
||||||
details(["contact", "acceleration", "temperature", "battery"])
|
details(["contact", "acceleration", "temperature", "3axis", "battery"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,14 +23,22 @@
|
|||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Configuration"
|
capability "Configuration"
|
||||||
|
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_5", deviceJoinName: "Kwikset 5-Button Deadbolt"
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019",
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_LEVER_5", deviceJoinName: "Kwikset 5-Button Lever"
|
manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_5", deviceJoinName: "Kwikset 5-Button Deadbolt"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10", deviceJoinName: "Kwikset 10-Button Deadbolt"
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019",
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10T", deviceJoinName: "Kwikset 10-Button Touch Deadbolt"
|
manufacturer: "Kwikset", model: "SMARTCODE_LEVER_5", deviceJoinName: "Kwikset 5-Button Lever"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL220 TS LL", deviceJoinName: "Yale Touch Screen Lever Lock"
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019",
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock"
|
manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10", deviceJoinName: "Kwikset 10-Button Deadbolt"
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019",
|
||||||
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock"
|
manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10T", deviceJoinName: "Kwikset 10-Button Touch Deadbolt"
|
||||||
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019",
|
||||||
|
manufacturer: "Yale", model: "YRL220 TS LL", deviceJoinName: "Yale Touch Screen Lever Lock"
|
||||||
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019",
|
||||||
|
manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock"
|
||||||
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019",
|
||||||
|
manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
|
||||||
|
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019",
|
||||||
|
manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock"
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
|
|||||||
@@ -119,10 +119,6 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm
|
|||||||
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
|
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
|
||||||
{
|
{
|
||||||
def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)]
|
def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)]
|
||||||
|
|
||||||
if (state.MSR == "011A-0601-0901" && device.currentState('motion') == null) { // Enerwave motion doesn't always get the associationSet that the hub sends on join
|
|
||||||
result << response(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId))
|
|
||||||
}
|
|
||||||
if (!state.lastbat || (new Date().time) - state.lastbat > 53*60*60*1000) {
|
if (!state.lastbat || (new Date().time) - state.lastbat > 53*60*60*1000) {
|
||||||
result << response(zwave.batteryV1.batteryGet())
|
result << response(zwave.batteryV1.batteryGet())
|
||||||
result << response("delay 1200")
|
result << response("delay 1200")
|
||||||
@@ -183,4 +179,4 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
|
|||||||
|
|
||||||
result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false)
|
result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false)
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +0,0 @@
|
|||||||
#Thu Feb 25 08:56:06 CST 2016
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip
|
|
||||||
160
gradlew
vendored
160
gradlew
vendored
@@ -1,160 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
##
|
|
||||||
## Gradle start up script for UN*X
|
|
||||||
##
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
DEFAULT_JVM_OPTS=""
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=`basename "$0"`
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
||||||
MAX_FD="maximum"
|
|
||||||
|
|
||||||
warn ( ) {
|
|
||||||
echo "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
die ( ) {
|
|
||||||
echo
|
|
||||||
echo "$*"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
|
||||||
cygwin=false
|
|
||||||
msys=false
|
|
||||||
darwin=false
|
|
||||||
case "`uname`" in
|
|
||||||
CYGWIN* )
|
|
||||||
cygwin=true
|
|
||||||
;;
|
|
||||||
Darwin* )
|
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
PRG="$0"
|
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
|
||||||
ls=`ls -ld "$PRG"`
|
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
|
||||||
PRG="$link"
|
|
||||||
else
|
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >/dev/null
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
|
||||||
else
|
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
|
||||||
fi
|
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
JAVACMD="java"
|
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
|
||||||
if [ $? -eq 0 ] ; then
|
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
ulimit -n $MAX_FD
|
|
||||||
if [ $? -ne 0 ] ; then
|
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin, switch paths to Windows format before running java
|
|
||||||
if $cygwin ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=$((i+1))
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
(0) set -- ;;
|
|
||||||
(1) set -- "$args0" ;;
|
|
||||||
(2) set -- "$args0" "$args1" ;;
|
|
||||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
|
||||||
function splitJvmOpts() {
|
|
||||||
JVM_OPTS=("$@")
|
|
||||||
}
|
|
||||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
|
||||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
|
||||||
|
|
||||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
|
||||||
90
gradlew.bat
vendored
90
gradlew.bat
vendored
@@ -1,90 +0,0 @@
|
|||||||
@if "%DEBUG%" == "" @echo off
|
|
||||||
@rem ##########################################################################
|
|
||||||
@rem
|
|
||||||
@rem Gradle startup script for Windows
|
|
||||||
@rem
|
|
||||||
@rem ##########################################################################
|
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS=
|
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
|
||||||
set APP_BASE_NAME=%~n0
|
|
||||||
set APP_HOME=%DIRNAME%
|
|
||||||
|
|
||||||
@rem Find java.exe
|
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:init
|
|
||||||
@rem Get command-line arguments, handling Windowz variants
|
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
|
||||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
|
||||||
|
|
||||||
:win9xME_args
|
|
||||||
@rem Slurp the command line arguments.
|
|
||||||
set CMD_LINE_ARGS=
|
|
||||||
set _SKIP=2
|
|
||||||
|
|
||||||
:win9xME_args_slurp
|
|
||||||
if "x%~1" == "x" goto execute
|
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
|
||||||
goto execute
|
|
||||||
|
|
||||||
:4NT_args
|
|
||||||
@rem Get arguments from the 4NT Shell from JP Software
|
|
||||||
set CMD_LINE_ARGS=%$
|
|
||||||
|
|
||||||
:execute
|
|
||||||
@rem Setup the command line
|
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
|
||||||
|
|
||||||
:end
|
|
||||||
@rem End local scope for the variables with windows NT shell
|
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
|
||||||
exit /b 1
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* This settings file was auto generated by the Gradle buildInit task
|
|
||||||
* by 'jblaisdell' at '2/25/16 8:56 AM' with Gradle 2.10
|
|
||||||
*
|
|
||||||
* The settings file is used to specify which projects to include in your build.
|
|
||||||
* In a single project build this file can be empty or even removed.
|
|
||||||
*
|
|
||||||
* Detailed information about configuring a multi-project build in Gradle can be found
|
|
||||||
* in the user guide at https://docs.gradle.org/2.10/userguide/multi_project_builds.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
// To declare projects as part of a multi-project build use the 'include' method
|
|
||||||
include 'shared'
|
|
||||||
include 'api'
|
|
||||||
include 'services:webservice'
|
|
||||||
*/
|
|
||||||
|
|
||||||
rootProject.name = 'SmartThingsPublic'
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -353,7 +353,7 @@ def onLocation(evt) {
|
|||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
lanEvent.headers && lanEvent.body &&
|
lanEvent.headers && lanEvent.body &&
|
||||||
lanEvent.headers."content-type"?.contains("xml")
|
lanEvent.headers."content-type".contains("xml")
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
def parsers = getParsers()
|
def parsers = getParsers()
|
||||||
|
|||||||
@@ -235,7 +235,6 @@ def connectionStatus(message, redirectUrl = null) {
|
|||||||
|
|
||||||
def getEcobeeThermostats() {
|
def getEcobeeThermostats() {
|
||||||
log.debug "getting device list"
|
log.debug "getting device list"
|
||||||
atomicState.remoteSensors = []
|
|
||||||
|
|
||||||
def requestBody = '{"selection":{"selectionType":"registered","selectionMatch":"","includeRuntime":true,"includeSensors":true}}'
|
def requestBody = '{"selection":{"selectionType":"registered","selectionMatch":"","includeRuntime":true,"includeSensors":true}}'
|
||||||
|
|
||||||
@@ -252,7 +251,7 @@ def getEcobeeThermostats() {
|
|||||||
|
|
||||||
if (resp.status == 200) {
|
if (resp.status == 200) {
|
||||||
resp.data.thermostatList.each { stat ->
|
resp.data.thermostatList.each { stat ->
|
||||||
atomicState.remoteSensors = atomicState.remoteSensors == null ? stat.remoteSensors : atomicState.remoteSensors << stat.remoteSensors
|
atomicState.remoteSensors = stat.remoteSensors
|
||||||
def dni = [app.id, stat.identifier].join('.')
|
def dni = [app.id, stat.identifier].join('.')
|
||||||
stats[dni] = getThermostatDisplayName(stat)
|
stats[dni] = getThermostatDisplayName(stat)
|
||||||
}
|
}
|
||||||
@@ -274,14 +273,11 @@ def getEcobeeThermostats() {
|
|||||||
|
|
||||||
Map sensorsDiscovered() {
|
Map sensorsDiscovered() {
|
||||||
def map = [:]
|
def map = [:]
|
||||||
log.info "list ${atomicState.remoteSensors}"
|
atomicState.remoteSensors.each {
|
||||||
atomicState.remoteSensors.each { sensors ->
|
if (it.type != "thermostat") {
|
||||||
sensors.each {
|
def value = "${it?.name}"
|
||||||
if (it.type != "thermostat") {
|
def key = "ecobee_sensor-"+ it?.id + "-" + it?.code
|
||||||
def value = "${it?.name}"
|
map["${key}"] = value
|
||||||
def key = "ecobee_sensor-"+ it?.id + "-" + it?.code
|
|
||||||
map["${key}"] = value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
atomicState.sensors = map
|
atomicState.sensors = map
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
* for the specific language governing permissions and limitations under the License.
|
* for the specific language governing permissions and limitations under the License.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
definition(
|
definition(
|
||||||
name: "Hue (Connect)",
|
name: "Hue (Connect)",
|
||||||
namespace: "smartthings",
|
namespace: "smartthings",
|
||||||
@@ -24,7 +24,7 @@ definition(
|
|||||||
category: "SmartThings Labs",
|
category: "SmartThings Labs",
|
||||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/hue.png",
|
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/hue.png",
|
||||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/hue@2x.png",
|
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/hue@2x.png",
|
||||||
//singleInstance: true
|
singleInstance: true
|
||||||
)
|
)
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
@@ -58,7 +58,7 @@ def bridgeDiscovery(params=[:])
|
|||||||
state.bridges = [:]
|
state.bridges = [:]
|
||||||
state.bridgeRefreshCount = 0
|
state.bridgeRefreshCount = 0
|
||||||
app.updateSetting("selectedHue", "")
|
app.updateSetting("selectedHue", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(location, null, locationHandler, [filterEvents:false])
|
subscribe(location, null, locationHandler, [filterEvents:false])
|
||||||
|
|
||||||
@@ -130,8 +130,8 @@ def bulbDiscovery() {
|
|||||||
def bulboptions = bulbsDiscovered() ?: [:]
|
def bulboptions = bulbsDiscovered() ?: [:]
|
||||||
def numFound = bulboptions.size() ?: 0
|
def numFound = bulboptions.size() ?: 0
|
||||||
if (numFound == 0)
|
if (numFound == 0)
|
||||||
app.updateSetting("selectedBulbs", "")
|
app.updateSetting("selectedBulbs", "")
|
||||||
|
|
||||||
if((bulbRefreshCount % 5) == 0) {
|
if((bulbRefreshCount % 5) == 0) {
|
||||||
discoverHueBulbs()
|
discoverHueBulbs()
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ def bulbDiscovery() {
|
|||||||
section("Please wait while we discover your Hue Bulbs. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
|
section("Please wait while we discover your Hue Bulbs. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
|
||||||
input "selectedBulbs", "enum", required:false, title:"Select Hue Bulbs (${numFound} found)", multiple:true, options:bulboptions
|
input "selectedBulbs", "enum", required:false, title:"Select Hue Bulbs (${numFound} found)", multiple:true, options:bulboptions
|
||||||
}
|
}
|
||||||
section {
|
section {
|
||||||
def title = getBridgeIP() ? "Hue bridge (${getBridgeIP()})" : "Find bridges"
|
def title = getBridgeIP() ? "Hue bridge (${getBridgeIP()})" : "Find bridges"
|
||||||
href "bridgeDiscovery", title: title, description: "", state: selectedHue ? "complete" : "incomplete", params: [override: true]
|
href "bridgeDiscovery", title: title, description: "", state: selectedHue ? "complete" : "incomplete", params: [override: true]
|
||||||
|
|
||||||
@@ -246,13 +246,13 @@ def installed() {
|
|||||||
|
|
||||||
def updated() {
|
def updated() {
|
||||||
log.trace "Updated with settings: ${settings}"
|
log.trace "Updated with settings: ${settings}"
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
unschedule()
|
unschedule()
|
||||||
initialize()
|
initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
def initialize() {
|
def initialize() {
|
||||||
log.debug "Initializing"
|
log.debug "Initializing"
|
||||||
unsubscribe(bridge)
|
unsubscribe(bridge)
|
||||||
state.inBulbDiscovery = false
|
state.inBulbDiscovery = false
|
||||||
state.bridgeRefreshCount = 0
|
state.bridgeRefreshCount = 0
|
||||||
@@ -281,18 +281,18 @@ def uninstalled(){
|
|||||||
def bulbListHandler(hub, data = "") {
|
def bulbListHandler(hub, data = "") {
|
||||||
def msg = "Bulbs list not processed. Only while in settings menu."
|
def msg = "Bulbs list not processed. Only while in settings menu."
|
||||||
def bulbs = [:]
|
def bulbs = [:]
|
||||||
if (state.inBulbDiscovery) {
|
if (state.inBulbDiscovery) {
|
||||||
def logg = ""
|
def logg = ""
|
||||||
log.trace "Adding bulbs to state..."
|
log.trace "Adding bulbs to state..."
|
||||||
state.bridgeProcessedLightList = true
|
state.bridgeProcessedLightList = true
|
||||||
def object = new groovy.json.JsonSlurper().parseText(data)
|
def object = new groovy.json.JsonSlurper().parseText(data)
|
||||||
object.each { k,v ->
|
object.each { k,v ->
|
||||||
if (v instanceof Map)
|
if (v instanceof Map)
|
||||||
bulbs[k] = [id: k, name: v.name, type: v.type, hub:hub]
|
bulbs[k] = [id: k, name: v.name, type: v.type, hub:hub]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def bridge = null
|
def bridge = null
|
||||||
if (selectedHue)
|
if (selectedHue)
|
||||||
bridge = getChildDevice(selectedHue)
|
bridge = getChildDevice(selectedHue)
|
||||||
bridge.sendEvent(name: "bulbList", value: hub, data: bulbs, isStateChange: true, displayed: false)
|
bridge.sendEvent(name: "bulbList", value: hub, data: bulbs, isStateChange: true, displayed: false)
|
||||||
msg = "${bulbs.size()} bulbs found. ${bulbs}"
|
msg = "${bulbs.size()} bulbs found. ${bulbs}"
|
||||||
@@ -318,7 +318,7 @@ def addBulbs() {
|
|||||||
} else {
|
} else {
|
||||||
log.debug "$dni in not longer paired to the Hue Bridge or ID changed"
|
log.debug "$dni in not longer paired to the Hue Bridge or ID changed"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//backwards compatable
|
//backwards compatable
|
||||||
newHueBulb = bulbs.find { (app.id + "/" + it.id) == dni }
|
newHueBulb = bulbs.find { (app.id + "/" + it.id) == dni }
|
||||||
d = addChildDevice("smartthings", "Hue Bulb", dni, newHueBulb?.hub, ["label":newHueBulb?.name])
|
d = addChildDevice("smartthings", "Hue Bulb", dni, newHueBulb?.hub, ["label":newHueBulb?.name])
|
||||||
@@ -344,7 +344,7 @@ def addBridge() {
|
|||||||
def d = getChildDevice(selectedHue)
|
def d = getChildDevice(selectedHue)
|
||||||
if(!d) {
|
if(!d) {
|
||||||
// compatibility with old devices
|
// compatibility with old devices
|
||||||
def newbridge = true
|
def newbridge = true
|
||||||
childDevices.each {
|
childDevices.each {
|
||||||
if (it.getDeviceDataByName("mac")) {
|
if (it.getDeviceDataByName("mac")) {
|
||||||
def newDNI = "${it.getDeviceDataByName("mac")}"
|
def newDNI = "${it.getDeviceDataByName("mac")}"
|
||||||
@@ -354,10 +354,10 @@ def addBridge() {
|
|||||||
it.setDeviceNetworkId("${newDNI}")
|
it.setDeviceNetworkId("${newDNI}")
|
||||||
if (oldDNI == selectedHue)
|
if (oldDNI == selectedHue)
|
||||||
app.updateSetting("selectedHue", newDNI)
|
app.updateSetting("selectedHue", newDNI)
|
||||||
newbridge = false
|
newbridge = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (newbridge) {
|
if (newbridge) {
|
||||||
d = addChildDevice("smartthings", "Hue Bridge", selectedHue, vbridge.value.hub)
|
d = addChildDevice("smartthings", "Hue Bridge", selectedHue, vbridge.value.hub)
|
||||||
log.debug "created ${d.displayName} with id ${d.deviceNetworkId}"
|
log.debug "created ${d.displayName} with id ${d.deviceNetworkId}"
|
||||||
@@ -368,13 +368,13 @@ def addBridge() {
|
|||||||
childDevice.sendEvent(name: "networkAddress", value: vbridge.value.ip + ":" + vbridge.value.port)
|
childDevice.sendEvent(name: "networkAddress", value: vbridge.value.ip + ":" + vbridge.value.port)
|
||||||
childDevice.updateDataValue("networkAddress", vbridge.value.ip + ":" + vbridge.value.port)
|
childDevice.updateDataValue("networkAddress", vbridge.value.ip + ":" + vbridge.value.port)
|
||||||
} else {
|
} else {
|
||||||
childDevice.sendEvent(name: "networkAddress", value: convertHexToIP(vbridge.value.ip) + ":" + convertHexToInt(vbridge.value.port))
|
childDevice.sendEvent(name: "networkAddress", value: convertHexToIP(vbridge.value.ip) + ":" + convertHexToInt(vbridge.value.port))
|
||||||
childDevice.updateDataValue("networkAddress", convertHexToIP(vbridge.value.ip) + ":" + convertHexToInt(vbridge.value.port))
|
childDevice.updateDataValue("networkAddress", convertHexToIP(vbridge.value.ip) + ":" + convertHexToInt(vbridge.value.port))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
childDevice.sendEvent(name: "networkAddress", value: convertHexToIP(vbridge.value.networkAddress) + ":" + convertHexToInt(vbridge.value.deviceAddress))
|
childDevice.sendEvent(name: "networkAddress", value: convertHexToIP(vbridge.value.networkAddress) + ":" + convertHexToInt(vbridge.value.deviceAddress))
|
||||||
childDevice.updateDataValue("networkAddress", convertHexToIP(vbridge.value.networkAddress) + ":" + convertHexToInt(vbridge.value.deviceAddress))
|
childDevice.updateDataValue("networkAddress", convertHexToIP(vbridge.value.networkAddress) + ":" + convertHexToInt(vbridge.value.deviceAddress))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug "found ${d.displayName} with id $selectedHue already exists"
|
log.debug "found ${d.displayName} with id $selectedHue already exists"
|
||||||
@@ -436,7 +436,7 @@ def locationHandler(evt) {
|
|||||||
dstate.name = "Philips hue ($ip)"
|
dstate.name = "Philips hue ($ip)"
|
||||||
d.sendEvent(name:"networkAddress", value: host)
|
d.sendEvent(name:"networkAddress", value: host)
|
||||||
d.updateDataValue("networkAddress", host)
|
d.updateDataValue("networkAddress", host)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -455,7 +455,7 @@ def locationHandler(evt) {
|
|||||||
log.error "/description.xml returned a bridge that didn't exist"
|
log.error "/description.xml returned a bridge that didn't exist"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(headerString?.contains("json") && isValidSource(parsedEvent.mac)) {
|
} else if(headerString?.contains("json")) {
|
||||||
log.trace "description.xml response (application/json)"
|
log.trace "description.xml response (application/json)"
|
||||||
def body = new groovy.json.JsonSlurper().parseText(parsedEvent.body)
|
def body = new groovy.json.JsonSlurper().parseText(parsedEvent.body)
|
||||||
if (body.success != null) {
|
if (body.success != null) {
|
||||||
@@ -494,21 +494,16 @@ def doDeviceSync(){
|
|||||||
discoverBridges()
|
discoverBridges()
|
||||||
}
|
}
|
||||||
|
|
||||||
def isValidSource(macAddress) {
|
|
||||||
def vbridges = getVerifiedHueBridges()
|
|
||||||
return (vbridges?.find {"${it.value.mac}" == macAddress}) != null
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
//CHILD DEVICE METHODS
|
//CHILD DEVICE METHODS
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
|
|
||||||
def parse(childDevice, description) {
|
def parse(childDevice, description) {
|
||||||
def parsedEvent = parseLanMessage(description)
|
def parsedEvent = parseLanMessage(description)
|
||||||
if (parsedEvent.headers && parsedEvent.body) {
|
if (parsedEvent.headers && parsedEvent.body) {
|
||||||
def headerString = parsedEvent.headers.toString()
|
def headerString = parsedEvent.headers.toString()
|
||||||
def bodyString = parsedEvent.body.toString()
|
def bodyString = parsedEvent.body.toString()
|
||||||
if (headerString?.contains("json")) {
|
if (headerString?.contains("json")) {
|
||||||
def body
|
def body
|
||||||
try {
|
try {
|
||||||
body = new groovy.json.JsonSlurper().parseText(bodyString)
|
body = new groovy.json.JsonSlurper().parseText(bodyString)
|
||||||
@@ -516,11 +511,11 @@ def parse(childDevice, description) {
|
|||||||
log.warn "Parsing Body failed - trying again..."
|
log.warn "Parsing Body failed - trying again..."
|
||||||
poll()
|
poll()
|
||||||
}
|
}
|
||||||
if (body instanceof java.util.HashMap) {
|
if (body instanceof java.util.HashMap) {
|
||||||
//poll response
|
//poll response
|
||||||
def bulbs = getChildDevices()
|
def bulbs = getChildDevices()
|
||||||
for (bulb in body) {
|
for (bulb in body) {
|
||||||
def d = bulbs.find{it.deviceNetworkId == "${app.id}/${bulb.key}"}
|
def d = bulbs.find{it.deviceNetworkId == "${app.id}/${bulb.key}"}
|
||||||
if (d) {
|
if (d) {
|
||||||
if (bulb.value.state?.reachable) {
|
if (bulb.value.state?.reachable) {
|
||||||
sendEvent(d.deviceNetworkId, [name: "switch", value: bulb.value?.state?.on ? "on" : "off"])
|
sendEvent(d.deviceNetworkId, [name: "switch", value: bulb.value?.state?.on ? "on" : "off"])
|
||||||
@@ -535,18 +530,18 @@ def parse(childDevice, description) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sendEvent(d.deviceNetworkId, [name: "switch", value: "off"])
|
sendEvent(d.deviceNetworkId, [name: "switch", value: "off"])
|
||||||
sendEvent(d.deviceNetworkId, [name: "level", value: 100])
|
sendEvent(d.deviceNetworkId, [name: "level", value: 100])
|
||||||
if (bulb.value.state.sat) {
|
if (bulb.value.state.sat) {
|
||||||
def hue = 23
|
def hue = 23
|
||||||
def sat = 56
|
def sat = 56
|
||||||
def hex = colorUtil.hslToHex(23, 56)
|
def hex = colorUtil.hslToHex(23, 56)
|
||||||
sendEvent(d.deviceNetworkId, [name: "color", value: hex])
|
sendEvent(d.deviceNetworkId, [name: "color", value: hex])
|
||||||
sendEvent(d.deviceNetworkId, [name: "hue", value: hue])
|
sendEvent(d.deviceNetworkId, [name: "hue", value: hue])
|
||||||
sendEvent(d.deviceNetworkId, [name: "saturation", value: sat])
|
sendEvent(d.deviceNetworkId, [name: "saturation", value: sat])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ //put response
|
{ //put response
|
||||||
@@ -595,7 +590,7 @@ def parse(childDevice, description) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug "parse - got something other than headers,body..."
|
log.debug "parse - got something other than headers,body..."
|
||||||
return []
|
return []
|
||||||
@@ -616,7 +611,7 @@ def off(childDevice) {
|
|||||||
|
|
||||||
def setLevel(childDevice, percent) {
|
def setLevel(childDevice, percent) {
|
||||||
log.debug "Executing 'setLevel'"
|
log.debug "Executing 'setLevel'"
|
||||||
def level
|
def level
|
||||||
if (percent == 1) level = 1 else level = Math.min(Math.round(percent * 255 / 100), 255)
|
if (percent == 1) level = 1 else level = Math.min(Math.round(percent * 255 / 100), 255)
|
||||||
put("lights/${getId(childDevice)}/state", [bri: level, on: percent > 0])
|
put("lights/${getId(childDevice)}/state", [bri: level, on: percent > 0])
|
||||||
}
|
}
|
||||||
@@ -633,14 +628,6 @@ def setHue(childDevice, percent) {
|
|||||||
put("lights/${getId(childDevice)}/state", [hue: level])
|
put("lights/${getId(childDevice)}/state", [hue: level])
|
||||||
}
|
}
|
||||||
|
|
||||||
def setColorTemperature(childDevice, huesettings) {
|
|
||||||
log.debug "Executing 'setColorTemperature($huesettings)'"
|
|
||||||
def ct = Math.round(Math.abs((huesettings / 12.96829971181556) - 654))
|
|
||||||
def value = [ct: ct, on: true]
|
|
||||||
log.trace "sending command $value"
|
|
||||||
put("lights/${getId(childDevice)}/state", value)
|
|
||||||
}
|
|
||||||
|
|
||||||
def setColor(childDevice, huesettings) {
|
def setColor(childDevice, huesettings) {
|
||||||
log.debug "Executing 'setColor($huesettings)'"
|
log.debug "Executing 'setColor($huesettings)'"
|
||||||
def hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
|
def hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
|
||||||
@@ -697,7 +684,7 @@ HOST: ${host}
|
|||||||
}
|
}
|
||||||
|
|
||||||
private put(path, body) {
|
private put(path, body) {
|
||||||
def host = getBridgeIP()
|
def host = getBridgeIP()
|
||||||
def uri = "/api/${state.username}/$path"
|
def uri = "/api/${state.username}/$path"
|
||||||
def bodyJSON = new groovy.json.JsonBuilder(body).toString()
|
def bodyJSON = new groovy.json.JsonBuilder(body).toString()
|
||||||
def length = bodyJSON.getBytes().size().toString()
|
def length = bodyJSON.getBytes().size().toString()
|
||||||
@@ -723,11 +710,11 @@ private getBridgeIP() {
|
|||||||
host = d.getDeviceDataByName("networkAddress")
|
host = d.getDeviceDataByName("networkAddress")
|
||||||
else
|
else
|
||||||
host = d.latestState('networkAddress').stringValue
|
host = d.latestState('networkAddress').stringValue
|
||||||
}
|
}
|
||||||
if (host == null || host == "") {
|
if (host == null || host == "") {
|
||||||
def serialNumber = selectedHue
|
def serialNumber = selectedHue
|
||||||
def bridge = getHueBridges().find { it?.value?.serialNumber?.equalsIgnoreCase(serialNumber) }?.value
|
def bridge = getHueBridges().find { it?.value?.serialNumber?.equalsIgnoreCase(serialNumber) }?.value
|
||||||
if (!bridge) {
|
if (!bridge) {
|
||||||
bridge = getHueBridges().find { it?.value?.mac?.equalsIgnoreCase(serialNumber) }?.value
|
bridge = getHueBridges().find { it?.value?.mac?.equalsIgnoreCase(serialNumber) }?.value
|
||||||
}
|
}
|
||||||
if (bridge?.ip && bridge?.port) {
|
if (bridge?.ip && bridge?.port) {
|
||||||
@@ -737,9 +724,9 @@ private getBridgeIP() {
|
|||||||
host = "${convertHexToIP(bridge?.ip)}:${convertHexToInt(bridge?.port)}"
|
host = "${convertHexToIP(bridge?.ip)}:${convertHexToInt(bridge?.port)}"
|
||||||
} else if (bridge?.networkAddress && bridge?.deviceAddress)
|
} else if (bridge?.networkAddress && bridge?.deviceAddress)
|
||||||
host = "${convertHexToIP(bridge?.networkAddress)}:${convertHexToInt(bridge?.deviceAddress)}"
|
host = "${convertHexToIP(bridge?.networkAddress)}:${convertHexToInt(bridge?.deviceAddress)}"
|
||||||
}
|
}
|
||||||
log.trace "Bridge: $selectedHue - Host: $host"
|
log.trace "Bridge: $selectedHue - Host: $host"
|
||||||
}
|
}
|
||||||
return host
|
return host
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ mappings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def getServerUrl() { return "https://graph.api.smartthings.com" }
|
def getServerUrl() { return "https://graph.api.smartthings.com" }
|
||||||
def getServercallbackUrl() { "https://graph.api.smartthings.com/oauth/callback" }
|
def getCallbackUrl() { "https://graph.api.smartthings.com/oauth/callback" }
|
||||||
def getBuildRedirectUrl() { "${serverUrl}/oauth/initialize?appId=${app.id}&access_token=${state.accessToken}&apiServerUrl=${apiServerUrl}" }
|
def getBuildRedirectUrl() { "${serverUrl}/oauth/initialize?appId=${app.id}&access_token=${state.accessToken}&apiServerUrl=${apiServerUrl}" }
|
||||||
|
|
||||||
def authPage() {
|
def authPage() {
|
||||||
@@ -166,7 +166,7 @@ def callback() {
|
|||||||
|
|
||||||
def init() {
|
def init() {
|
||||||
log.debug "Requesting Code"
|
log.debug "Requesting Code"
|
||||||
def oauthParams = [client_id: "${appSettings.clientId}", scope: "remote", response_type: "code", redirect_uri: "${servercallbackUrl}" ]
|
def oauthParams = [client_id: "${appSettings.clientId}", scope: "remote", response_type: "code", redirect_uri: "${callbackUrl}" ]
|
||||||
redirect(location: "https://home.myharmony.com/oauth2/authorize?${toQueryString(oauthParams)}")
|
redirect(location: "https://home.myharmony.com/oauth2/authorize?${toQueryString(oauthParams)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,401 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2015 SmartThings
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
* Samsung TV Service Manager
|
||||||
|
*
|
||||||
|
* Author: SmartThings (Juan Risso)
|
||||||
|
*/
|
||||||
|
|
||||||
|
definition(
|
||||||
|
name: "Samsung TV (Connect)",
|
||||||
|
namespace: "smartthings",
|
||||||
|
author: "SmartThings",
|
||||||
|
description: "Allows you to control your Samsung TV from the SmartThings app. Perform basic functions like power Off, source, volume, channels and other remote control functions.",
|
||||||
|
category: "SmartThings Labs",
|
||||||
|
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Samsung/samsung-remote%402x.png",
|
||||||
|
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Samsung/samsung-remote%403x.png",
|
||||||
|
singleInstance: true
|
||||||
|
)
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
page(name:"samsungDiscovery", title:"Samsung TV Setup", content:"samsungDiscovery", refreshTimeout:5)
|
||||||
|
}
|
||||||
|
|
||||||
|
def getDeviceType() {
|
||||||
|
return "urn:samsung.com:device:RemoteControlReceiver:1"
|
||||||
|
}
|
||||||
|
|
||||||
|
//PAGES
|
||||||
|
def samsungDiscovery()
|
||||||
|
{
|
||||||
|
if(canInstallLabs())
|
||||||
|
{
|
||||||
|
int samsungRefreshCount = !state.samsungRefreshCount ? 0 : state.samsungRefreshCount as int
|
||||||
|
state.samsungRefreshCount = samsungRefreshCount + 1
|
||||||
|
def refreshInterval = 3
|
||||||
|
|
||||||
|
def options = samsungesDiscovered() ?: []
|
||||||
|
|
||||||
|
def numFound = options.size() ?: 0
|
||||||
|
|
||||||
|
if(!state.subscribe) {
|
||||||
|
log.trace "subscribe to location"
|
||||||
|
subscribe(location, null, locationHandler, [filterEvents:false])
|
||||||
|
state.subscribe = true
|
||||||
|
}
|
||||||
|
|
||||||
|
//samsung discovery request every 5 //25 seconds
|
||||||
|
if((samsungRefreshCount % 5) == 0) {
|
||||||
|
log.trace "Discovering..."
|
||||||
|
discoversamsunges()
|
||||||
|
}
|
||||||
|
|
||||||
|
//setup.xml request every 3 seconds except on discoveries
|
||||||
|
if(((samsungRefreshCount % 1) == 0) && ((samsungRefreshCount % 8) != 0)) {
|
||||||
|
log.trace "Verifing..."
|
||||||
|
verifysamsungPlayer()
|
||||||
|
}
|
||||||
|
|
||||||
|
return dynamicPage(name:"samsungDiscovery", title:"Discovery Started!", nextPage:"", refreshInterval:refreshInterval, install:true, uninstall: true) {
|
||||||
|
section("Please wait while we discover your Samsung TV. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
|
||||||
|
input "selectedsamsung", "enum", required:false, title:"Select Samsung TV (${numFound} found)", multiple:true, options:options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
def upgradeNeeded = """To use SmartThings Labs, your Hub should be completely up to date.
|
||||||
|
|
||||||
|
To update your Hub, access Location Settings in the Main Menu (tap the gear next to your location name), select your Hub, and choose "Update Hub"."""
|
||||||
|
|
||||||
|
return dynamicPage(name:"samsungDiscovery", title:"Upgrade needed!", nextPage:"", install:true, uninstall: true) {
|
||||||
|
section("Upgrade") {
|
||||||
|
paragraph "$upgradeNeeded"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
log.trace "Installed with settings: ${settings}"
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
log.trace "Updated with settings: ${settings}"
|
||||||
|
unschedule()
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def uninstalled() {
|
||||||
|
def devices = getChildDevices()
|
||||||
|
log.trace "deleting ${devices.size()} samsung"
|
||||||
|
devices.each {
|
||||||
|
deleteChildDevice(it.deviceNetworkId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
// remove location subscription afterwards
|
||||||
|
if (selectedsamsung) {
|
||||||
|
addsamsung()
|
||||||
|
}
|
||||||
|
//Check every 5 minutes for IP change
|
||||||
|
runEvery5Minutes("discoversamsunges")
|
||||||
|
}
|
||||||
|
|
||||||
|
//CHILD DEVICE METHODS
|
||||||
|
def addsamsung() {
|
||||||
|
def players = getVerifiedsamsungPlayer()
|
||||||
|
log.trace "Adding childs"
|
||||||
|
selectedsamsung.each { dni ->
|
||||||
|
def d = getChildDevice(dni)
|
||||||
|
if(!d) {
|
||||||
|
def newPlayer = players.find { (it.value.ip + ":" + it.value.port) == dni }
|
||||||
|
log.trace "newPlayer = $newPlayer"
|
||||||
|
log.trace "dni = $dni"
|
||||||
|
d = addChildDevice("smartthings", "Samsung Smart TV", dni, newPlayer?.value.hub, [label:"${newPlayer?.value.name}"])
|
||||||
|
log.trace "created ${d.displayName} with id $dni"
|
||||||
|
|
||||||
|
d.setModel(newPlayer?.value.model)
|
||||||
|
log.trace "setModel to ${newPlayer?.value.model}"
|
||||||
|
} else {
|
||||||
|
log.trace "found ${d.displayName} with id $dni already exists"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private tvAction(key,deviceNetworkId) {
|
||||||
|
log.debug "Executing ${tvCommand}"
|
||||||
|
|
||||||
|
def tvs = getVerifiedsamsungPlayer()
|
||||||
|
def thetv = tvs.find { (it.value.ip + ":" + it.value.port) == deviceNetworkId }
|
||||||
|
|
||||||
|
// Standard Connection Data
|
||||||
|
def appString = "iphone..iapp.samsung"
|
||||||
|
def appStringLength = appString.getBytes().size()
|
||||||
|
|
||||||
|
def tvAppString = "iphone.UN60ES8000.iapp.samsung"
|
||||||
|
def tvAppStringLength = tvAppString.getBytes().size()
|
||||||
|
|
||||||
|
def remoteName = "SmartThings".encodeAsBase64().toString()
|
||||||
|
def remoteNameLength = remoteName.getBytes().size()
|
||||||
|
|
||||||
|
// Device Connection Data
|
||||||
|
def ipAddress = convertHexToIP(thetv?.value.ip).encodeAsBase64().toString()
|
||||||
|
def ipAddressHex = deviceNetworkId.substring(0,8)
|
||||||
|
def ipAddressLength = ipAddress.getBytes().size()
|
||||||
|
|
||||||
|
def macAddress = thetv?.value.mac.encodeAsBase64().toString()
|
||||||
|
def macAddressLength = macAddress.getBytes().size()
|
||||||
|
|
||||||
|
// The Authentication Message
|
||||||
|
def authenticationMessage = "${(char)0x64}${(char)0x00}${(char)ipAddressLength}${(char)0x00}${ipAddress}${(char)macAddressLength}${(char)0x00}${macAddress}${(char)remoteNameLength}${(char)0x00}${remoteName}"
|
||||||
|
def authenticationMessageLength = authenticationMessage.getBytes().size()
|
||||||
|
|
||||||
|
def authenticationPacket = "${(char)0x00}${(char)appStringLength}${(char)0x00}${appString}${(char)authenticationMessageLength}${(char)0x00}${authenticationMessage}"
|
||||||
|
|
||||||
|
// If our initial run, just send the authentication packet so the prompt appears on screen
|
||||||
|
if (key == "AUTHENTICATE") {
|
||||||
|
sendHubCommand(new physicalgraph.device.HubAction(authenticationPacket, physicalgraph.device.Protocol.LAN, "${ipAddressHex}:D6D8"))
|
||||||
|
} else {
|
||||||
|
// Build the command we will send to the Samsung TV
|
||||||
|
def command = "KEY_${key}".encodeAsBase64().toString()
|
||||||
|
def commandLength = command.getBytes().size()
|
||||||
|
|
||||||
|
def actionMessage = "${(char)0x00}${(char)0x00}${(char)0x00}${(char)commandLength}${(char)0x00}${command}"
|
||||||
|
def actionMessageLength = actionMessage.getBytes().size()
|
||||||
|
|
||||||
|
def actionPacket = "${(char)0x00}${(char)tvAppStringLength}${(char)0x00}${tvAppString}${(char)actionMessageLength}${(char)0x00}${actionMessage}"
|
||||||
|
|
||||||
|
// Send both the authentication and action at the same time
|
||||||
|
sendHubCommand(new physicalgraph.device.HubAction(authenticationPacket + actionPacket, physicalgraph.device.Protocol.LAN, "${ipAddressHex}:D6D8"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private discoversamsunges()
|
||||||
|
{
|
||||||
|
sendHubCommand(new physicalgraph.device.HubAction("lan discovery ${getDeviceType()}", physicalgraph.device.Protocol.LAN))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private verifysamsungPlayer() {
|
||||||
|
def devices = getsamsungPlayer().findAll { it?.value?.verified != true }
|
||||||
|
|
||||||
|
if(devices) {
|
||||||
|
log.warn "UNVERIFIED PLAYERS!: $devices"
|
||||||
|
}
|
||||||
|
|
||||||
|
devices.each {
|
||||||
|
verifysamsung((it?.value?.ip + ":" + it?.value?.port), it?.value?.ssdpPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private verifysamsung(String deviceNetworkId, String devicessdpPath) {
|
||||||
|
log.trace "dni: $deviceNetworkId, ssdpPath: $devicessdpPath"
|
||||||
|
String ip = getHostAddress(deviceNetworkId)
|
||||||
|
log.trace "ip:" + ip
|
||||||
|
sendHubCommand(new physicalgraph.device.HubAction("""GET ${devicessdpPath} HTTP/1.1\r\nHOST: $ip\r\n\r\n""", physicalgraph.device.Protocol.LAN, "${deviceNetworkId}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
Map samsungesDiscovered() {
|
||||||
|
def vsamsunges = getVerifiedsamsungPlayer()
|
||||||
|
def map = [:]
|
||||||
|
vsamsunges.each {
|
||||||
|
def value = "${it.value.name}"
|
||||||
|
def key = it.value.ip + ":" + it.value.port
|
||||||
|
map["${key}"] = value
|
||||||
|
}
|
||||||
|
log.trace "Devices discovered $map"
|
||||||
|
map
|
||||||
|
}
|
||||||
|
|
||||||
|
def getsamsungPlayer()
|
||||||
|
{
|
||||||
|
state.samsunges = state.samsunges ?: [:]
|
||||||
|
}
|
||||||
|
|
||||||
|
def getVerifiedsamsungPlayer()
|
||||||
|
{
|
||||||
|
getsamsungPlayer().findAll{ it?.value?.verified == true }
|
||||||
|
}
|
||||||
|
|
||||||
|
def locationHandler(evt) {
|
||||||
|
def description = evt.description
|
||||||
|
def hub = evt?.hubId
|
||||||
|
def parsedEvent = parseEventMessage(description)
|
||||||
|
parsedEvent << ["hub":hub]
|
||||||
|
log.trace "${parsedEvent}"
|
||||||
|
log.trace "${getDeviceType()} - ${parsedEvent.ssdpTerm}"
|
||||||
|
if (parsedEvent?.ssdpTerm?.contains(getDeviceType()))
|
||||||
|
{ //SSDP DISCOVERY EVENTS
|
||||||
|
|
||||||
|
log.trace "TV found"
|
||||||
|
def samsunges = getsamsungPlayer()
|
||||||
|
|
||||||
|
if (!(samsunges."${parsedEvent.ssdpUSN.toString()}"))
|
||||||
|
{ //samsung does not exist
|
||||||
|
log.trace "Adding Device to state..."
|
||||||
|
samsunges << ["${parsedEvent.ssdpUSN.toString()}":parsedEvent]
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // update the values
|
||||||
|
|
||||||
|
log.trace "Device was already found in state..."
|
||||||
|
|
||||||
|
def d = samsunges."${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.trace "Device's port or ip changed..."
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceChangedValues) {
|
||||||
|
def children = getChildDevices()
|
||||||
|
children.each {
|
||||||
|
if (it.getDeviceDataByName("mac") == parsedEvent.mac) {
|
||||||
|
log.trace "updating dni for device ${it} with mac ${parsedEvent.mac}"
|
||||||
|
it.setDeviceNetworkId((parsedEvent.ip + ":" + parsedEvent.port)) //could error if device with same dni already exists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (parsedEvent.headers && parsedEvent.body)
|
||||||
|
{ // samsung RESPONSES
|
||||||
|
def deviceHeaders = parseLanMessage(description, false)
|
||||||
|
def type = deviceHeaders.headers."content-type"
|
||||||
|
def body
|
||||||
|
log.trace "REPONSE TYPE: $type"
|
||||||
|
if (type?.contains("xml"))
|
||||||
|
{ // description.xml response (application/xml)
|
||||||
|
body = new XmlSlurper().parseText(deviceHeaders.body)
|
||||||
|
log.debug body.device.deviceType.text()
|
||||||
|
if (body?.device?.deviceType?.text().contains(getDeviceType()))
|
||||||
|
{
|
||||||
|
def samsunges = getsamsungPlayer()
|
||||||
|
def player = samsunges.find {it?.key?.contains(body?.device?.UDN?.text())}
|
||||||
|
if (player)
|
||||||
|
{
|
||||||
|
player.value << [name:body?.device?.friendlyName?.text(),model:body?.device?.modelName?.text(), serialNumber:body?.device?.serialNum?.text(), verified: true]
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.error "The xml file returned a device that didn't exist"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(type?.contains("json"))
|
||||||
|
{ //(application/json)
|
||||||
|
body = new groovy.json.JsonSlurper().parseText(bodyString)
|
||||||
|
log.trace "GOT JSON $body"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.trace "TV not found..."
|
||||||
|
//log.trace description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def parseEventMessage(String description) {
|
||||||
|
def event = [:]
|
||||||
|
def parts = description.split(',')
|
||||||
|
parts.each { part ->
|
||||||
|
part = part.trim()
|
||||||
|
if (part.startsWith('devicetype:')) {
|
||||||
|
part -= "devicetype:"
|
||||||
|
event.devicetype = part.trim()
|
||||||
|
}
|
||||||
|
else if (part.startsWith('mac:')) {
|
||||||
|
part -= "mac:"
|
||||||
|
event.mac = part.trim()
|
||||||
|
}
|
||||||
|
else if (part.startsWith('networkAddress:')) {
|
||||||
|
part -= "networkAddress:"
|
||||||
|
event.ip = part.trim()
|
||||||
|
}
|
||||||
|
else if (part.startsWith('deviceAddress:')) {
|
||||||
|
part -= "deviceAddress:"
|
||||||
|
event.port = part.trim()
|
||||||
|
}
|
||||||
|
else if (part.startsWith('ssdpPath:')) {
|
||||||
|
part -= "ssdpPath:"
|
||||||
|
event.ssdpPath = part.trim()
|
||||||
|
}
|
||||||
|
else if (part.startsWith('ssdpUSN:')) {
|
||||||
|
part -= "ssdpUSN:"
|
||||||
|
event.ssdpUSN = part.trim()
|
||||||
|
}
|
||||||
|
else if (part.startsWith('ssdpTerm:')) {
|
||||||
|
part -= "ssdpTerm:"
|
||||||
|
event.ssdpTerm = part.trim()
|
||||||
|
}
|
||||||
|
else if (part.startsWith('headers')) {
|
||||||
|
part -= "headers:"
|
||||||
|
event.headers = part.trim()
|
||||||
|
}
|
||||||
|
else if (part.startsWith('body')) {
|
||||||
|
part -= "body:"
|
||||||
|
event.body = part.trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event
|
||||||
|
}
|
||||||
|
|
||||||
|
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.trace "parse() - ${bodyString}"
|
||||||
|
|
||||||
|
def body = new groovy.json.JsonSlurper().parseText(bodyString)
|
||||||
|
} else {
|
||||||
|
log.trace "parse - got something other than headers,body..."
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(d) {
|
||||||
|
def parts = d.split(":")
|
||||||
|
def ip = convertHexToIP(parts[0])
|
||||||
|
def port = convertHexToInt(parts[1])
|
||||||
|
return ip + ":" + port
|
||||||
|
}
|
||||||
|
|
||||||
|
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 }
|
||||||
|
}
|
||||||
@@ -341,12 +341,8 @@ def ssdpSwitchHandler(evt) {
|
|||||||
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)
|
def child = getChildDevice(parsedEvent.mac)
|
||||||
if (child) {
|
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
||||||
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
child.poll()
|
||||||
child.poll()
|
|
||||||
} else {
|
|
||||||
log.debug "Device with mac $parsedEvent.mac not found"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -414,12 +410,8 @@ def ssdpLightSwitchHandler(evt) {
|
|||||||
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)
|
def child = getChildDevice(parsedEvent.mac)
|
||||||
if (child) {
|
log.debug "updating ip and port, and resubscribing, for device with mac ${parsedEvent.mac}"
|
||||||
log.debug "updating ip and port, and resubscribing, for device with mac ${parsedEvent.mac}"
|
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
||||||
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
|
||||||
} else {
|
|
||||||
log.debug "Device with mac $parsedEvent.mac not found"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -471,12 +463,8 @@ def locationHandler(evt) {
|
|||||||
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)
|
def child = getChildDevice(parsedEvent.mac)
|
||||||
if (child) {
|
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
||||||
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
child.poll()
|
||||||
child.poll()
|
|
||||||
} else {
|
|
||||||
log.debug "Device with mac $parsedEvent.mac not found"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -530,12 +518,8 @@ def locationHandler(evt) {
|
|||||||
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)
|
def child = getChildDevice(parsedEvent.mac)
|
||||||
if (child) {
|
log.debug "updating ip and port, and resubscribing, for device with mac ${parsedEvent.mac}"
|
||||||
log.debug "updating ip and port, and resubscribing, for device with mac ${parsedEvent.mac}"
|
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
||||||
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
|
||||||
} else {
|
|
||||||
log.debug "Device with mac $parsedEvent.mac not found"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user