mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-17 21:03:30 +00:00
Compare commits
51 Commits
MSA-894-1
...
PROD_2016.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62a965d90b | ||
|
|
fb9f1dee47 | ||
|
|
3a433d3865 | ||
|
|
8f25ff4434 | ||
|
|
4da9730319 | ||
|
|
25db4f5235 | ||
|
|
eae2a9ca08 | ||
|
|
2dd2d7cba4 | ||
|
|
f5708bca8b | ||
|
|
a9da6d130a | ||
|
|
3a2c6f86be | ||
|
|
71d2b89a37 | ||
|
|
b131ba1507 | ||
|
|
f04a9e3f7a | ||
|
|
6a905e4380 | ||
|
|
442f16680d | ||
|
|
1c68099b52 | ||
|
|
cc9321ca9f | ||
|
|
515b268374 | ||
|
|
919c9b88ee | ||
|
|
2438942071 | ||
|
|
0d9bd98cfa | ||
|
|
9e33f190c3 | ||
|
|
c959691536 | ||
|
|
2cb687dca9 | ||
|
|
70ec8a28f8 | ||
|
|
e255316474 | ||
|
|
934449c326 | ||
|
|
9e37a37991 | ||
|
|
050da829d3 | ||
|
|
f616dcbdf6 | ||
|
|
8933510436 | ||
|
|
3130e6ad27 | ||
|
|
0c87601c64 | ||
|
|
d1a5a8631f | ||
|
|
d86dcfd82f | ||
|
|
2184c2b21a | ||
|
|
16126abb2d | ||
|
|
77525c3377 | ||
|
|
9b87d39fe8 | ||
|
|
c17b856e6b | ||
|
|
42b790ef10 | ||
|
|
a4ebe87f4e | ||
|
|
f84e21d83a | ||
|
|
a9c078c0cb | ||
|
|
a103d437c2 | ||
|
|
ae705deba4 | ||
|
|
69a6fc4f9e | ||
|
|
d82a387c68 | ||
|
|
bdd88deb99 | ||
|
|
20d660e236 |
23
.gitignore
vendored
Normal file
23
.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# 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
Normal file
57
build.gradle
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
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
Normal file
27
circle.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
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,10 +129,7 @@ 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 == "0000"){
|
if (description_map.cluster == "0001"){
|
||||||
/* 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"
|
||||||
@@ -158,6 +155,10 @@ 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(":")
|
||||||
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
if(nameAndValue.length == 2){
|
||||||
|
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
||||||
|
}else{
|
||||||
|
map += []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Ecobee Sensor
|
* Copyright 2015 SmartThings
|
||||||
*
|
|
||||||
* 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:
|
||||||
@@ -12,6 +10,9 @@
|
|||||||
* 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") {
|
||||||
@@ -26,7 +27,16 @@ 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:[
|
||||||
[value: 31, color: "#153591"],
|
// Celsius
|
||||||
|
[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"],
|
||||||
|
|||||||
@@ -45,7 +45,16 @@ 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:[
|
||||||
[value: 31, color: "#153591"],
|
// Celsius
|
||||||
|
[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"],
|
||||||
@@ -386,7 +395,7 @@ def generateModeEvent(mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def generateFanModeEvent(fanMode) {
|
def generateFanModeEvent(fanMode) {
|
||||||
sendEvent(name: "thermostatFanMode", value: fanMode, descriptionText: "$device.displayName fan is in ${mode} mode", displayed: true)
|
sendEvent(name: "thermostatFanMode", value: fanMode, descriptionText: "$device.displayName fan is in ${fanMode} mode", displayed: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateOperatingStateEvent(operatingState) {
|
def generateOperatingStateEvent(operatingState) {
|
||||||
@@ -421,6 +430,10 @@ def heat() {
|
|||||||
generateStatusEvent()
|
generateStatusEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def emergencyHeat() {
|
||||||
|
auxHeatOnly()
|
||||||
|
}
|
||||||
|
|
||||||
def auxHeatOnly() {
|
def auxHeatOnly() {
|
||||||
log.debug "auxHeatOnly"
|
log.debug "auxHeatOnly"
|
||||||
def deviceId = device.deviceNetworkId.split(/\./).last()
|
def deviceId = device.deviceNetworkId.split(/\./).last()
|
||||||
@@ -480,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
|
||||||
generateModeEvent(currentFanMode) // reset the tile back
|
generateFanModeEvent(currentFanMode) // reset the tile back
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,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
|
||||||
generateModeEvent(currentFanMode) // reset the tile back
|
generateFanModeEvent(currentFanMode) // reset the tile back
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Hue Bulb
|
* Hue Bulb
|
||||||
*
|
*
|
||||||
@@ -11,13 +10,14 @@ 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:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
multiAttributeTile(name:"rich-control", 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,23 +33,58 @@ 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"
|
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
||||||
|
}
|
||||||
|
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("reset", "device.reset", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
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 "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", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
standardTile("refresh", "device.switch", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
||||||
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"])
|
main(["switch"])
|
||||||
details(["switch", "levelSliderControl", "rgbSelector", "refresh", "reset"])
|
details(["rich-control", "colorTempSliderControl", "colorTemp", "reset", "refresh"])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse events into attributes
|
// parse events into attributes
|
||||||
@@ -68,17 +103,17 @@ def parse(description) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle commands
|
// handle commands
|
||||||
def on() {
|
void on() {
|
||||||
log.trace parent.on(this)
|
log.trace parent.on(this)
|
||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
void off() {
|
||||||
log.trace parent.off(this)
|
log.trace parent.off(this)
|
||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
|
|
||||||
def nextLevel() {
|
void 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
|
||||||
@@ -89,25 +124,25 @@ def nextLevel() {
|
|||||||
setLevel(level)
|
setLevel(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
def setLevel(percent) {
|
void 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
def setSaturation(percent) {
|
void 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
def setHue(percent) {
|
void 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
def setColor(value) {
|
void 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)}
|
||||||
@@ -117,14 +152,14 @@ def setColor(value) {
|
|||||||
if (value.switch) { sendEvent(name: "switch", value: value.switch)}
|
if (value.switch) { sendEvent(name: "switch", value: value.switch)}
|
||||||
}
|
}
|
||||||
|
|
||||||
def reset() {
|
void 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
def setAdjustedColor(value) {
|
void setAdjustedColor(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
log.trace "setAdjustedColor: ${value}"
|
log.trace "setAdjustedColor: ${value}"
|
||||||
def adjusted = value + [:]
|
def adjusted = value + [:]
|
||||||
@@ -135,7 +170,15 @@ def setAdjustedColor(value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh() {
|
void setColorTemperature(value) {
|
||||||
|
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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ metadata {
|
|||||||
state "level", action:"switch level.setLevel"
|
state "level", action:"switch level.setLevel"
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, 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"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,23 +74,23 @@ def parse(description) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle commands
|
// handle commands
|
||||||
def on() {
|
void on() {
|
||||||
parent.on(this)
|
parent.on(this)
|
||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
void off() {
|
||||||
parent.off(this)
|
parent.off(this)
|
||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
|
|
||||||
def setLevel(percent) {
|
void 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh() {
|
void refresh() {
|
||||||
log.debug "Executing 'refresh'"
|
log.debug "Executing 'refresh'"
|
||||||
parent.manualRefresh()
|
parent.manualRefresh()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ 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) {
|
||||||
@@ -97,6 +98,7 @@ 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) {
|
||||||
@@ -122,13 +124,15 @@ 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) {
|
||||||
sendEvent(name: "color", value: color.hex)
|
if (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) {
|
||||||
@@ -150,6 +154,7 @@ 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) {
|
||||||
@@ -165,6 +170,7 @@ def setColorTemperature(kelvin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
def on() {
|
def on() {
|
||||||
@@ -174,6 +180,7 @@ def on() {
|
|||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
def off() {
|
||||||
@@ -183,6 +190,7 @@ def off() {
|
|||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
def poll() {
|
def poll() {
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ 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) {
|
||||||
@@ -99,6 +100,7 @@ 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() {
|
||||||
@@ -108,6 +110,7 @@ def on() {
|
|||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
def off() {
|
||||||
@@ -117,6 +120,7 @@ def off() {
|
|||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
def poll() {
|
def poll() {
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#==============================================================================
|
||||||
|
# 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=부재중
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
# 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였습니다
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
# 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였습니다
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
# 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,9 +100,6 @@ 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:""
|
||||||
}
|
}
|
||||||
@@ -112,7 +109,7 @@ metadata {
|
|||||||
|
|
||||||
|
|
||||||
main(["status", "acceleration", "temperature"])
|
main(["status", "acceleration", "temperature"])
|
||||||
details(["status", "acceleration", "temperature", "3axis", "battery", "refresh"])
|
details(["status", "acceleration", "temperature", "battery", "refresh"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,15 +72,12 @@ 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", "3axis", "battery"])
|
details(["contact", "acceleration", "temperature", "battery"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,22 +23,14 @@
|
|||||||
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",
|
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"
|
||||||
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_LEVER_5", deviceJoinName: "Kwikset 5-Button Lever"
|
||||||
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_10", deviceJoinName: "Kwikset 10-Button Deadbolt"
|
||||||
manufacturer: "Kwikset", model: "SMARTCODE_LEVER_5", deviceJoinName: "Kwikset 5-Button Lever"
|
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"
|
||||||
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: "YRL220 TS LL", deviceJoinName: "Yale Touch Screen Lever 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: "YRD210 PB DB", deviceJoinName: "Yale Push Button 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: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt 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: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock"
|
||||||
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,6 +119,10 @@ 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")
|
||||||
|
|||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#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
Executable file
160
gradlew
vendored
Executable file
@@ -0,0 +1,160 @@
|
|||||||
|
#!/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
Normal file
90
gradlew.bat
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
@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
|
||||||
19
settings.gradle
Normal file
19
settings.gradle
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* 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'
|
||||||
@@ -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,6 +235,7 @@ 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}}'
|
||||||
|
|
||||||
@@ -251,7 +252,7 @@ def getEcobeeThermostats() {
|
|||||||
|
|
||||||
if (resp.status == 200) {
|
if (resp.status == 200) {
|
||||||
resp.data.thermostatList.each { stat ->
|
resp.data.thermostatList.each { stat ->
|
||||||
atomicState.remoteSensors = stat.remoteSensors
|
atomicState.remoteSensors = atomicState.remoteSensors == null ? 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)
|
||||||
}
|
}
|
||||||
@@ -273,11 +274,14 @@ def getEcobeeThermostats() {
|
|||||||
|
|
||||||
Map sensorsDiscovered() {
|
Map sensorsDiscovered() {
|
||||||
def map = [:]
|
def map = [:]
|
||||||
atomicState.remoteSensors.each {
|
log.info "list ${atomicState.remoteSensors}"
|
||||||
if (it.type != "thermostat") {
|
atomicState.remoteSensors.each { sensors ->
|
||||||
def value = "${it?.name}"
|
sensors.each {
|
||||||
def key = "ecobee_sensor-"+ it?.id + "-" + it?.code
|
if (it.type != "thermostat") {
|
||||||
map["${key}"] = value
|
def value = "${it?.name}"
|
||||||
|
def key = "ecobee_sensor-"+ it?.id + "-" + it?.code
|
||||||
|
map["${key}"] = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
atomicState.sensors = map
|
atomicState.sensors = map
|
||||||
|
|||||||
@@ -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 {
|
||||||
@@ -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")) {
|
} else if(headerString?.contains("json") && isValidSource(parsedEvent.mac)) {
|
||||||
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,6 +494,11 @@ def doDeviceSync(){
|
|||||||
discoverBridges()
|
discoverBridges()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def isValidSource(macAddress) {
|
||||||
|
def vbridges = getVerifiedHueBridges()
|
||||||
|
return (vbridges?.find {"${it.value.mac}" == macAddress}) != null
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
//CHILD DEVICE METHODS
|
//CHILD DEVICE METHODS
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
@@ -628,6 +633,14 @@ 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)
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ mappings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def getServerUrl() { return "https://graph.api.smartthings.com" }
|
def getServerUrl() { return "https://graph.api.smartthings.com" }
|
||||||
def getCallbackUrl() { "https://graph.api.smartthings.com/oauth/callback" }
|
def getServercallbackUrl() { "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: "${callbackUrl}" ]
|
def oauthParams = [client_id: "${appSettings.clientId}", scope: "remote", response_type: "code", redirect_uri: "${servercallbackUrl}" ]
|
||||||
redirect(location: "https://home.myharmony.com/oauth2/authorize?${toQueryString(oauthParams)}")
|
redirect(location: "https://home.myharmony.com/oauth2/authorize?${toQueryString(oauthParams)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,401 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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,8 +341,12 @@ 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)
|
||||||
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
if (child) {
|
||||||
child.poll()
|
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
||||||
|
child.poll()
|
||||||
|
} else {
|
||||||
|
log.debug "Device with mac $parsedEvent.mac not found"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -410,8 +414,12 @@ 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)
|
||||||
log.debug "updating ip and port, and resubscribing, for device with mac ${parsedEvent.mac}"
|
if (child) {
|
||||||
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
log.debug "updating ip and port, and resubscribing, for device with mac ${parsedEvent.mac}"
|
||||||
|
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
||||||
|
} else {
|
||||||
|
log.debug "Device with mac $parsedEvent.mac not found"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -463,8 +471,12 @@ 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)
|
||||||
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
if (child) {
|
||||||
child.poll()
|
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
||||||
|
child.poll()
|
||||||
|
} else {
|
||||||
|
log.debug "Device with mac $parsedEvent.mac not found"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -518,8 +530,12 @@ 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)
|
||||||
log.debug "updating ip and port, and resubscribing, for device with mac ${parsedEvent.mac}"
|
if (child) {
|
||||||
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
log.debug "updating ip and port, and resubscribing, for device with mac ${parsedEvent.mac}"
|
||||||
|
child.subscribe(parsedEvent.ip, parsedEvent.port)
|
||||||
|
} else {
|
||||||
|
log.debug "Device with mac $parsedEvent.mac not found"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user