Compare commits

..

1 Commits

Author SHA1 Message Date
테스터1
61992677e7 MSA-978: test 2016-03-23 02:23:50 -05:00
43 changed files with 254 additions and 3898 deletions

View File

@@ -1,18 +1,15 @@
import java.nio.charset.StandardCharsets
import java.nio.file.Paths
import com.smartthings.deployment.slack.FileUpload
import com.smartthings.deployment.slack.Message
apply plugin: 'groovy'
apply plugin: 'smartthings-executable-deployment'
apply plugin: 'smartthings-slack'
apply plugin: 'smartthings-hipchat'
buildscript {
dependencies {
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.7"
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.3"
}
repositories {
mavenLocal()
jcenter()
maven {
credentials {
@@ -32,43 +29,7 @@ repositories {
dependencies {
}
slackSendMessage {
String branch = project.hasProperty('branch') ? project.property('branch') : 'unknown'
String token = project.hasProperty('slackToken') ? project.property('slackToken') : null
String webhookUrl = project.hasProperty('slackWebhookUrl') ? project.property('slackWebhookUrl') : null
String channel = project.hasProperty('slackChannel') ? project.property('slackChannel') : null
String drinks = 'https://dl.dropboxusercontent.com/s/m1z5mpd3c83lwev/minion_beer.jpeg?dl=0'
String wolverine = 'https://dl.dropboxusercontent.com/s/4lbjqzvm2v033u9/minion_wolverine.jpg?dl=0'
String beach = 'https://dl.dropboxusercontent.com/s/rqrfgxk53gfng69/minion_beach.png?dl=0'
String iconUrl
String color
String messageText
String username
switch (branch) {
case 'master':
username = 'Hickory'
iconUrl = wolverine
color = '#35D0F2'
messageText = 'Began deployment of _SmartThingsPublic[master]_ branch to the _Dev_ environments.'
break
case 'staging':
username = 'Dickory'
iconUrl = beach
color = '#FFDE20'
messageText = 'Began deployment of _SmartThingsPublic[staging]_ branch to the _Staging_ environments.'
break
case 'production':
username = 'Dock'
iconUrl = drinks
color = '#FF1D23'
messageText = 'Began deployment of _SmartThingsPublic[production]_ branch to the _Prod_ environments.'
break
default:
username = 'Hickory'
iconUrl = wolverine
color = '#35D0F2'
messageText = "Began deployment of an _SmartThingsPublic[${branch}]_ branch. Have no idea what's going on."
}
hipchatShareFile {
List<String> archives = []
File rootDir = new File("${project.buildDir}/archives")
if (rootDir.exists()) {
@@ -81,25 +42,19 @@ slackSendMessage {
}
}
}
Date date = new Date()
String fileDate = date.format('yyyy-MM-dd_HH-mm-ss', TimeZone.getTimeZone('GMT'))
// Required Task Arguments.
file = new FileUpload(
data: archives.join('\n').getBytes(StandardCharsets.UTF_8),
filename: "deployment-notes-${fileDate}.txt",
title: 'Deployment Notes',
channels: channel,
token: token,
color: color
)
message = new Message(
webhookUrl: webhookUrl,
username: username,
asUser: true,
iconUrl: iconUrl,
channel: channel,
fallback: 'Deployment Notification',
text: messageText
)
// 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})."
if (branch == 'master') {
message += ' (dev shards)'
}
color = branch == 'master' ? 'yellow' : 'red'
notify = true
}

View File

@@ -15,11 +15,13 @@ deployment:
develop:
branch: master
commands:
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Ps3Buckets="$S3_BUCKETS_DEV"
- ./gradlew slackSendMessage -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Pbranch="$CIRCLE_BRANCH" -PslackToken="$SLACK_TOKEN" -PslackWebhookUrl="$SLACK_WEBHOOK_URL" -PslackChannel="$SLACK_CHANNEL" --stacktrace
- ./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" -Ps3Buckets="$S3_BUCKETS_STAGE"
- ./gradlew slackSendMessage -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Pbranch="$CIRCLE_BRANCH" -PslackToken="$SLACK_TOKEN" -PslackWebhookUrl="$SLACK_WEBHOOK_URL" -PslackChannel="$SLACK_CHANNEL" --stacktrace
- ./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

View File

@@ -1,272 +0,0 @@
/**
* Fibaro Door/Window Sensor ZW5
*
* Copyright 2016 Fibar Group S.A.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "Fibaro Door/Window Sensor ZW5 with Temperature", namespace: "fibargroup", author: "Fibar Group S.A.") {
capability "Battery"
capability "Contact Sensor"
capability "Sensor"
capability "Configuration"
capability "Tamper Alert"
capability "Temperature Measurement"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x31, 0x86", outClusters: ""
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x31, 0x86, 0x84", outClusters: ""//actual NIF
}
simulator {
}
tiles(scale: 2) {
multiAttributeTile(name:"FGK", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.contact", key:"PRIMARY_CONTROL") {
attributeState("open", icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
attributeState("closed", icon:"st.contact.contact.closed", backgroundColor:"#79b821")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
}
}
valueTile("battery", "device.battery", inactiveLabel: false, , width: 2, height: 2, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""
}
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°',
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
main "FGK"
details(["FGK","battery", "temperature"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
def result = []
if (description.startsWith("Err 106")) {
if (state.sec) {
result = createEvent(descriptionText:description, displayed:false)
} else {
result = createEvent(
descriptionText: "FGK failed to complete the network security key exchange. If you are unable to receive data from it, you must remove it from your network and add it again.",
eventType: "ALERT",
name: "secureInclusion",
value: "failed",
displayed: true,
)
}
} else if (description == "updated") {
return null
} else {
def cmd = zwave.parse(description, [0x31: 5, 0x56: 1, 0x71: 3, 0x72: 2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (cmd) {
log.debug "Parsed '${cmd}'"
zwaveEvent(cmd)
}
}
}
//security
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x71: 3, 0x84: 2, 0x85: 2, 0x98: 1])
if (encapsulatedCommand) {
return zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
//crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{
def versions = [0x31: 5, 0x72: 2, 0x80: 1, 0x86: 1]
def version = versions[cmd.commandClass as Integer]
def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
if (!encapsulatedCommand) {
log.debug "Could not extract command from $cmd"
} else {
zwaveEvent(encapsulatedCommand)
}
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
//it is assumed that default notification events are used
//(parameter 20 was not changed before device's re-inclusion)
def map = [:]
if (cmd.notificationType == 6) {
switch (cmd.event) {
case 22:
map.name = "contact"
map.value = "open"
map.descriptionText = "${device.displayName}: is open"
break
case 23:
map.name = "contact"
map.value = "closed"
map.descriptionText = "${device.displayName}: is closed"
break
}
} else if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
map.name = "tamper"
map.value = "inactive"
map.descriptionText = "${device.displayName}: tamper alarm has been deactivated"
break
case 3:
map.name = "tamper"
map.value = "active"
map.descriptionText = "${device.displayName}: tamper alarm activated"
break
}
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [:]
map.name = "battery"
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
map.unit = "%"
map.displayed = true
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
def cmds = []
cmds << encap(zwave.batteryV1.batteryGet())
cmds << "delay 500"
cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
cmds << "delay 1200"
cmds << encap(zwave.wakeUpV1.wakeUpNoMoreInformation())
[event, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format
String serialNumber = "h'"
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
}
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
def map = [:]
if (cmd.sensorType == 1) {
// temperature
def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
map.name = "temperature"
map.displayed = true
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
log.info "${device.displayName}: received command: $cmd - device has reset itself"
}
def configure() {
log.debug "Executing 'configure'"
def cmds = []
cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds:21600, nodeid: zwaveHubNodeId)//FGK's default wake up interval
cmds += zwave.manufacturerSpecificV2.manufacturerSpecificGet()
cmds += zwave.manufacturerSpecificV2.deviceSpecificGet()
cmds += zwave.versionV1.versionGet()
cmds += zwave.batteryV1.batteryGet()
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0)
cmds += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
cmds += zwave.wakeUpV2.wakeUpNoMoreInformation()
encapSequence(cmds, 500)
}
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000"
}
private encapSequence(commands, delay=200) {
delayBetween(commands.collect{ encap(it) }, delay)
}
private encap(physicalgraph.zwave.Command cmd) {
def secureClasses = [0x20, 0x2B, 0x30, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C]
//todo: check if secure inclusion was successful
//if not do not send security-encapsulated command
if (secureClasses.find{ it == cmd.commandClassId }) {
secure(cmd)
} else {
crc16(cmd)
}
}

View File

@@ -1,239 +0,0 @@
/**
* Fibaro Door/Window Sensor ZW5
*
* Copyright 2016 Fibar Group S.A.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "Fibaro Door/Window Sensor ZW5", namespace: "fibargroup", author: "Fibar Group S.A.") {
capability "Battery"
capability "Contact Sensor"
capability "Sensor"
capability "Configuration"
capability "Tamper Alert"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x86, 0x84", outClusters: ""
}
simulator {
}
tiles(scale: 2) {
multiAttributeTile(name:"FGK", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.contact", key:"PRIMARY_CONTROL") {
attributeState("open", icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
attributeState("closed", icon:"st.contact.contact.closed", backgroundColor:"#79b821")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
}
}
valueTile("battery", "device.battery", inactiveLabel: false, , width: 2, height: 2, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""
}
main "FGK"
details(["FGK","battery"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
def result = []
if (description.startsWith("Err 106")) {
if (state.sec) {
result = createEvent(descriptionText:description, displayed:false)
} else {
result = createEvent(
descriptionText: "FGK failed to complete the network security key exchange. If you are unable to receive data from it, you must remove it from your network and add it again.",
eventType: "ALERT",
name: "secureInclusion",
value: "failed",
displayed: true,
)
}
} else if (description == "updated") {
return null
} else {
def cmd = zwave.parse(description, [0x56: 1, 0x71: 3, 0x72: 2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (cmd) {
log.debug "Parsed '${cmd}'"
zwaveEvent(cmd)
}
}
}
//security
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x71: 3, 0x84: 2, 0x85: 2, 0x98: 1])
if (encapsulatedCommand) {
return zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
//crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{
def versions = [0x72: 2, 0x80: 1, 0x86: 1]
def version = versions[cmd.commandClass as Integer]
def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
if (!encapsulatedCommand) {
log.debug "Could not extract command from $cmd"
} else {
zwaveEvent(encapsulatedCommand)
}
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
//it is assumed that default notification events are used
//(parameter 20 was not changed before device's re-inclusion)
def map = [:]
if (cmd.notificationType == 6) {
switch (cmd.event) {
case 22:
map.name = "contact"
map.value = "open"
map.descriptionText = "${device.displayName}: is open"
break
case 23:
map.name = "contact"
map.value = "closed"
map.descriptionText = "${device.displayName}: is closed"
break
}
} else if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
map.name = "tamper"
map.value = "inactive"
map.descriptionText = "${device.displayName}: tamper alarm has been deactivated"
break
case 3:
map.name = "tamper"
map.value = "active"
map.descriptionText = "${device.displayName}: tamper alarm activated"
break
}
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [:]
map.name = "battery"
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
map.unit = "%"
map.displayed = true
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
def cmds = []
cmds << encap(zwave.batteryV1.batteryGet())
cmds << "delay 1200"
cmds << encap(zwave.wakeUpV1.wakeUpNoMoreInformation())
[event, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format
String serialNumber = "h'"
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
}
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
log.info "${device.displayName}: received command: $cmd - device has reset itself"
}
def configure() {
log.debug "Executing 'configure'"
def cmds = []
cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds:21600, nodeid: zwaveHubNodeId)//FGK's default wake up interval
cmds += zwave.manufacturerSpecificV2.manufacturerSpecificGet()
cmds += zwave.manufacturerSpecificV2.deviceSpecificGet()
cmds += zwave.versionV1.versionGet()
cmds += zwave.batteryV1.batteryGet()
cmds += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
cmds += zwave.wakeUpV2.wakeUpNoMoreInformation()
encapSequence(cmds, 500)
}
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000"
}
private encapSequence(commands, delay=200) {
delayBetween(commands.collect{ encap(it) }, delay)
}
private encap(physicalgraph.zwave.Command cmd) {
def secureClasses = [0x20, 0x2B, 0x30, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C]
//todo: check if secure inclusion was successful
//if not do not send security-encapsulated command
if (secureClasses.find{ it == cmd.commandClassId }) {
secure(cmd)
} else {
crc16(cmd)
}
}

View File

@@ -1,269 +0,0 @@
/**
* Fibaro Flood Sensor ZW5
*
* Copyright 2016 Fibar Group S.A.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "Fibaro Flood Sensor ZW5", namespace: "fibargroup", author: "Fibar Group S.A.") {
capability "Battery"
capability "Configuration"
capability "Sensor"
capability "Tamper Alert"
capability "Temperature Measurement"
capability "Water Sensor"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x22, 0x85, 0x59, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x9C, 0x31, 0x86", outClusters: ""
}
simulator {
}
tiles(scale: 2) {
multiAttributeTile(name:"FGFS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.water", key:"PRIMARY_CONTROL") {
attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#79b821")
attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#ffa81e")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
}
}
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°',
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
main "FGFS"
details(["FGFS","battery", "temperature"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
def result = []
if (description.startsWith("Err 106")) {
if (state.sec) {
result = createEvent(descriptionText:description, displayed:false)
} else {
result = createEvent(
descriptionText: "FGFS failed to complete the network security key exchange. If you are unable to receive data from it, you must remove it from your network and add it again.",
eventType: "ALERT",
name: "secureInclusion",
value: "failed",
displayed: true,
)
}
} else if (description == "updated") {
return null
} else {
def cmd = zwave.parse(description, [0x31: 5, 0x56: 1, 0x71: 3, 0x72:2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (cmd) {
log.debug "Parsed '${cmd}'"
zwaveEvent(cmd)
}
}
}
//security
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x71: 3, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (encapsulatedCommand) {
return zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
//crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{
def versions = [0x31: 5, 0x72: 2, 0x80: 1]
def version = versions[cmd.commandClass as Integer]
def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
if (!encapsulatedCommand) {
log.debug "Could not extract command from $cmd"
} else {
zwaveEvent(encapsulatedCommand)
}
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd)
{
def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
def cmds = []
cmds << encap(zwave.batteryV1.batteryGet())
cmds << "delay 500"
cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
cmds << "delay 1200"
cmds << encap(zwave.wakeUpV1.wakeUpNoMoreInformation())
[event, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format
String serialNumber = "h'"
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [:]
map.name = "battery"
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
map.unit = "%"
map.displayed = true
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
def map = [:]
if (cmd.notificationType == 5) {
switch (cmd.event) {
case 2:
map.name = "water"
map.value = "wet"
map.descriptionText = "${device.displayName} is ${map.value}"
break
case 0:
map.name = "water"
map.value = "dry"
map.descriptionText = "${device.displayName} is ${map.value}"
break
}
} else if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
map.name = "tamper"
map.value = "inactive"
map.descriptionText = "${device.displayName}: tamper alarm has been deactivated"
break
case 3:
map.name = "tamper"
map.value = "active"
map.descriptionText = "${device.displayName}: tamper alarm activated"
break
}
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
def map = [:]
if (cmd.sensorType == 1) {
// temperature
def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
map.name = "temperature"
map.displayed = true
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
log.info "${device.displayName}: received command: $cmd - device has reset itself"
}
def configure() {
log.debug "Executing 'configure'"
def cmds = []
cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds:21600, nodeid: zwaveHubNodeId)//FGFS' default wake up interval
cmds += zwave.manufacturerSpecificV2.manufacturerSpecificGet()
cmds += zwave.manufacturerSpecificV2.deviceSpecificGet()
cmds += zwave.versionV1.versionGet()
cmds += zwave.batteryV1.batteryGet()
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0)
cmds += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
cmds += zwave.wakeUpV2.wakeUpNoMoreInformation()
encapSequence(cmds, 500)
}
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000"
}
private encapSequence(commands, delay=200) {
delayBetween(commands.collect{ encap(it) }, delay)
}
private encap(physicalgraph.zwave.Command cmd) {
def secureClasses = [0x20, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C]
//todo: check if secure inclusion was successful
//if not do not send security-encapsulated command
if (secureClasses.find{ it == cmd.commandClassId }) {
secure(cmd)
} else {
crc16(cmd)
}
}

View File

@@ -1,281 +0,0 @@
/**
* Fibaro Motion Sensor ZW5
*
* Copyright 2016 Fibar Group S.A.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "Fibaro Motion Sensor ZW5", namespace: "fibargroup", author: "Fibar Group S.A.") {
capability "Battery"
capability "Configuration"
capability "Illuminance Measurement"
capability "Motion Sensor"
capability "Sensor"
capability "Tamper Alert"
capability "Temperature Measurement"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x20, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x30, 0x9C, 0x98, 0x7A", outClusters: ""
}
simulator {
}
tiles(scale: 2) {
multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.motion", key:"PRIMARY_CONTROL") {
attributeState("inactive", icon:"st.motion.motion.inactive", backgroundColor:"#79b821")
attributeState("active", icon:"st.motion.motion.active", backgroundColor:"#ffa81e")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
}
}
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°',
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
state "luminosity", label:'${currentValue} ${unit}', unit:"lux"
}
valueTile("battery", "device.battery", inactiveLabel: false, width: 2, height: 2, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""
}
main "FGMS"
details(["FGMS","battery","temperature","illuminance"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
def result = []
if (description.startsWith("Err 106")) {
if (state.sec) {
result = createEvent(descriptionText:description, displayed:false)
} else {
result = createEvent(
descriptionText: "FGK failed to complete the network security key exchange. If you are unable to receive data from it, you must remove it from your network and add it again.",
eventType: "ALERT",
name: "secureInclusion",
value: "failed",
displayed: true,
)
}
} else if (description == "updated") {
return null
} else {
def cmd = zwave.parse(description, [0x31: 5, 0x56: 1, 0x71: 3, 0x72: 2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (cmd) {
log.debug "Parsed '${cmd}'"
zwaveEvent(cmd)
}
}
}
//security
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x71: 3, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (encapsulatedCommand) {
return zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
//crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{
def versions = [0x31: 5, 0x71: 3, 0x72: 2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1]
def version = versions[cmd.commandClass as Integer]
def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
if (!encapsulatedCommand) {
log.debug "Could not extract command from $cmd"
} else {
zwaveEvent(encapsulatedCommand)
}
}
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
def map = [ displayed: true ]
switch (cmd.sensorType) {
case 1:
map.name = "temperature"
map.unit = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, map.unit, cmd.precision)
break
case 3:
map.name = "illuminance"
map.value = cmd.scaledSensorValue.toInteger().toString()
map.unit = "lux"
break
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
def map = [:]
if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
if (cmd.eventParameter[0] == 3) {
map.name = "tamper"
map.value = "inactive"
map.descriptionText = "${device.displayName}: tamper alarm has been deactivated"
}
if (cmd.eventParameter[0] == 8) {
map.name = "motion"
map.value = "inactive"
map.descriptionText = "${device.displayName}: motion has stopped"
}
break
case 3:
map.name = "tamper"
map.value = "active"
map.descriptionText = "${device.displayName}: tamper alarm activated"
break
case 8:
map.name = "motion"
map.value = "active"
map.descriptionText = "${device.displayName}: motion detected"
break
}
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [:]
map.name = "battery"
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
map.unit = "%"
map.displayed = true
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd)
{
def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
def cmds = []
cmds << encap(zwave.batteryV1.batteryGet())
cmds << "delay 500"
cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
cmds << "delay 500"
cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 3, scale: 1))
cmds << "delay 1200"
cmds << encap(zwave.wakeUpV1.wakeUpNoMoreInformation())
[event, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format
String serialNumber = "h'"
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
}
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
log.info "${device.displayName}: received command: $cmd - device has reset itself"
}
def configure() {
log.debug "Executing 'configure'"
def cmds = []
cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds: 7200, nodeid: zwaveHubNodeId)//FGMS' default wake up interval
cmds += zwave.manufacturerSpecificV2.manufacturerSpecificGet()
cmds += zwave.manufacturerSpecificV2.deviceSpecificGet()
cmds += zwave.versionV1.versionGet()
cmds += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId])
cmds += zwave.batteryV1.batteryGet()
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0)
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 3, scale: 1)
cmds += zwave.wakeUpV2.wakeUpNoMoreInformation()
encapSequence(cmds, 500)
}
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16encapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000"
}
private encapSequence(commands, delay=200) {
delayBetween(commands.collect{ encap(it) }, delay)
}
private encap(physicalgraph.zwave.Command cmd) {
def secureClasses = [0x20, 0x30, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C]
//todo: check if secure inclusion was successful
//if not do not send security-encapsulated command
if (secureClasses.find{ it == cmd.commandClassId }) {
secure(cmd)
} else {
crc16(cmd)
}
}

View File

@@ -1,351 +0,0 @@
/**
* Melissa Climate
*
* Copyright 2016 Kiril Maslenkov
*
* 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.
*
*/
preferences {
input "email", "text", title: "Email", description: "Your Email", required: true
input "password", "password", title: "Password", description: "Your Melissa Password", required: true
input "mac", "text", title: "Melissa MAC Address", description: "Melissa Mac Address", required: true
}
metadata {
definition (name: "Melissa Climate", namespace: "Melissa", author: "Melissa Climate") {
capability "Thermostat"
command temperatureUp
command temperatureDown
command sendCommand
command switchMode
command switchFanMode
command switchingState
command refreshApp
}
simulator { }
tiles(scale: 2) {
multiAttributeTile(name:"status", type: "thermostat", width: 6, height: 4){
tileAttribute("device.temperature", key:"PRIMARY_CONTROL"){
attributeState("default", label:'${currentValue}°', unit: "df", backgroundColor: '#4b8df8')
}
tileAttribute("device.humidity", key: "SECONDARY_CONTROL") {
attributeState("default", label:'${currentValue}%', unit:"%")
}
tileAttribute("device.temperature", key: "VALUE_CONTROL") {
attributeState("VALUE_UP", action: "temperatureUp")
attributeState("VALUE_DOWN", action: "temperatureDown")
}
}
standardTile("mode", "device.mode", decoration: "flat", width: 3, height: 2) {
state "auto", action:"switchMode", label: '${name}', nextState: "cool", icon: "http://server.seemelissa.com/smartthings/icons/modes/auto-2.png"
state "cool", action:"switchMode", label: '${name}', nextState: "heat", icon: "http://server.seemelissa.com/smartthings/icons/modes/cool.png"
state "heat", action:"switchMode", label: '${name}', nextState: "dry", icon: "http://server.seemelissa.com/smartthings/icons/modes/heat.png"
state "dry", action:"switchMode", label: '${name}', nextState: "auto", icon: "http://server.seemelissa.com/smartthings/icons/modes/dry.png"
}
standardTile("fan", "device.fan", decoration: "flat", width: 3, height: 2, canChangeIcon: true, canChangeBackground: true) {
state "auto", action:"switchFanMode", label: '${name}', nextState: "high", icon: "http://server.seemelissa.com/smartthings/icons/modes/auto-2.png"
state "high", action:"switchFanMode", label: '${name}', nextState: "medium", icon: "http://server.seemelissa.com/smartthings/icons/fan/fan1.png"
state "medium", action:"switchFanMode", label: '${name}', nextState: "low", icon: "http://server.seemelissa.com/smartthings/icons/fan/fan2.png"
state "low", action:"switchFanMode", label: '${name}', nextState: "auto", icon: "http://server.seemelissa.com/smartthings/icons/fan/fan3.png"
}
standardTile("switchState", "device.switchState", width: 3, height: 2, decoration: "flat", canChangeIcon: true, canChangeBackground: true) {
state "on", label: '${name}', action: "switchingState", nextState: "off", icon: "http://server.seemelissa.com/smartthings/icons/on_off/turn-on-off-white.png", backgroundColor: "#79b821"
state "off", label: '${name}', action: "switchingState", nextState: "on", icon: "http://server.seemelissa.com/smartthings/icons/on_off/turn-on-off.png", backgroundColor: "#ffffff"
//state "on", label: '${name}', action: "switchState.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
//state "off", label: '${name}', action: "switchState.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
}
standardTile("send", "device.send", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", action:"sendCommand", label: 'Send Command'
}
standardTile("refresh", "device.send2", inactiveLabel: false, decoration: "flat", width: 3, height: 2) {
state "default", action:"refreshApp", icon: "st.secondary.refresh"
}
standardTile("username", "device.username", inactiveLabel: false, decoration: "flat", width: 6, height: 2) {
state "default", label:'${currentValue}'
}
main(["status", "mode", "fan", "send"])
//details(["status", "mode", "fan", "refresh", "switchState", "username"])
details(["status", "mode", "fan", "refresh", "switchState"])
}
}
def switchingState() {
if (state.ac_state == "on") {
state.ac_state = "off"
} else {
state.ac_state = "on"
}
sendEvent(name: "switchState", value: state.ac_state);
sendCommand()
}
/* SWITCHING MODES Auto, Cool, Heat, Dry*/
def switchMode() {
switch (state.mode) {
case "auto":
state.mode = "cool";
break;
case "cool":
state.mode = "heat";
break;
case "heat":
state.mode = "dry";
break;
case "dry":
state.mode = "auto";
break;
}
//sendEvent(name: "username", value: state.mode)
sendCommand()
// log.debug state.mode
}
/* SWITCHING FAN MODES*/
def switchFanMode() {
switch (state.fan) {
case "auto":
state.fan = "high";
break;
case "high":
state.fan = "medium";
break;
case "medium":
state.fan = "low";
break;
case "low":
state.fan = "auto";
break;
}
sendEvent(name: "username", value: state.fan)
sendCommand()
//log.debug state.fan
}
def refreshApp() {
def params = [
uri: 'http://api2.seemelissa.com/user/login',
body: [
email: "k.maslenkov@sabev.at",
password: "xxxxx"
//email: settings.email,
//password: settings.password
]
]
try {
httpPost(params) {resp ->
/*
log.debug "resp data: ${resp.data}"
log.debug resp.data
log.debug resp
*/
def _try = resp.data
def slurper = new groovy.json.JsonSlurper()
def results = slurper.parseText("${resp.data}")
state.token = results.Data
settings.mac = "OIEQ321TGR6"
def getParams = [
uri: "http://api2.seemelissa.com",
path: "/testusers/getMelissaData/${settings.mac}"
//path: "/testusers/getMelissaData/OIEQ321TGR6"
]
try {
httpGet(getParams) {response->
def getResult = slurper.parseText("${response.data}")
state.temp = getResult.temp as int
state.humidity = getResult.humidity
state.codeset = getResult.codeset_id as int
switch (getResult.mode) {
case "0":
state.mode = "auto";
break;
case "1":
state.mode = "fan";
break;
case "2":
state.mode = "heat";
break;
case "3":
state.mode = "cool";
break;
case "4":
state.mode = "dry";
break;
}
switch (getResult.fan) {
case "0":
state.fan = "auto";
break;
case "1":
state.fan = "low";
break;
case "2":
state.fan = "medium";
break;
case "3":
state.fan = "high";
break;
}
if (getResult.state == "0") {
state.ac_state = "off"
} else {
state.ac_state = "on"
}
sendEvent(name: "mode", value: state.mode)
sendEvent(name: "fan", value: state.fan)
sendEvent(name: "temperature", value: state.temp)
sendEvent(name: "humidity", value: state.humidity)
sendEvent(name: "switchState", value: state.ac_state)
}
}
catch (e) {
log.error "error: $e"
}
}
} catch (e) {
log.error "error: $e"
}
}
def sendCommand () {
log.error state
def params = [
uri: 'http://api2.seemelissa.com/testusers/sendCommand',
body: [
mac: "OIEQ321TGR6",
//mac: settings.mac,
temp: state.temp,
token: state.token,
fan: state.fan,
mode: state.mode,
ac_state: state.ac_state,
codeset: state.codeset
]
]
try {
httpPost(params) {resp ->
log.debug "Send command done"
log.debug "resp data: ${resp.data}"
}
} catch (e) {
log.error "error: $e"
}
}
def updated() {
//log.debug "Updated !!!"
login()
}
def temperatureDown() {
if (state.temp != 18) {
state.temp = state.temp - 1
}
sendEvent(name: "temperature", value: state.temp)
sendCommand()
}
def temperatureUp() {
if (state.temp != 30) {
state.temp = state.temp + 1
}
sendEvent(name: "temperature", value: state.temp)
sendCommand()
}
def login() {
refreshApp()
/*
def params = [
uri: 'http://api2.seemelissa.com/user/login',
body: [
email: settings.email,
password: settings.password
]
]
try {
httpPost(params) {resp ->
log.debug "resp data: ${resp.data}"
log.debug "Response Received: Status [$resp.status]"
def _try = resp.data
def slurper = new groovy.json.JsonSlurper()
def results = slurper.parseText("${resp.data}")
state.token = results.Data
state.temp = 18
state.humidity = 40
sendEvent(name: "temperature", value: state.temp)
sendEvent(name: "humidity", value: state.humidity)
sendEvent(name: "username", value: state.token)
}
} catch (e) {
log.error "error: $e"
}
*/
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
}

View File

@@ -1,16 +1,16 @@
#==============================================================================
# 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
# 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
# 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: Arrival Sensor HA i18n Translation File
@@ -23,14 +23,13 @@
#==============================================================================
# Korean (ko)
# Device Preferences
'''Give your device a name'''.ko=기기 이름 설정
'''Give your device a name'''.ko=기기 이름 바꾸기
'''Set Device Image'''.ko=기기 이미지 설정
'''Presence timeout (minutes)'''.ko=알람 유예 시간 설정 (분)
'''Presence timeout (minutes)'''.ko=시간 초과. 스마트폰 위치 정보
'''Tap to set'''.ko=눌러서 설정
'''Arrival Sensor'''.ko=도착알림 센서
'''${currentValue}% battery'''.ko=${currentValue}% 배터리
# Events / Notifications
'''{{ linkText }} battery was {{ value }}'''.ko={{ linkText }}의 남은 배터리 {{ value }}
'''{{ linkText }} has arrived'''.ko={{ linkText }} 귀가
'''{{ linkText }} has left'''.ko={{ linkText }} 외출
'''{{ linkText }} battery was {{ value }}'''.ko={{ linkText }}남아있는 배터리 {{ value }}입니다.
'''{{ linkText }} has arrived'''.ko={{ linkText }}집에 도착했습니다.
'''{{ linkText }} has left'''.ko={{ linkText }}집을 나갔습니다.
#==============================================================================

View File

@@ -1,227 +0,0 @@
/**
* Hue Bloom
*
* Philips Hue Type "Color Light"
*
* Author: SmartThings
*/
// for the UI
metadata {
// Automatically generated. Make future change here.
definition (name: "Hue Bloom", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level"
capability "Actuator"
capability "Color Control"
capability "Switch"
capability "Refresh"
capability "Sensor"
command "setAdjustedColor"
command "reset"
command "refresh"
}
simulator {
// TODO: define status and reply messages here
}
tiles (scale: 2){
multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
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") {
attributeState "color", action:"setAdjustedColor"
}
}
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"
}
standardTile("refresh", "device.refresh", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
main(["rich-control"])
details(["rich-control", "colorTempSliderControl", "colorTemp", "reset", "refresh"])
}
}
// parse events into attributes
def parse(description) {
log.debug "parse() - $description"
def results = []
def map = description
if (description instanceof String) {
log.debug "Hue Bulb stringToMap - ${map}"
map = stringToMap(description)
}
if (map?.name && map?.value) {
results << createEvent(name: "${map?.name}", value: "${map?.value}")
}
results
}
// handle commands
void on() {
log.trace parent.on(this)
sendEvent(name: "switch", value: "on")
}
void off() {
log.trace parent.off(this)
sendEvent(name: "switch", value: "off")
}
void nextLevel() {
def level = device.latestValue("level") as Integer ?: 0
if (level <= 100) {
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
}
else {
level = 25
}
setLevel(level)
}
void setLevel(percent) {
log.debug "Executing 'setLevel'"
if (verifyPercent(percent)) {
parent.setLevel(this, percent)
sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
sendEvent(name: "switch", value: "on")
}
}
void setSaturation(percent) {
log.debug "Executing 'setSaturation'"
if (verifyPercent(percent)) {
parent.setSaturation(this, percent)
sendEvent(name: "saturation", value: percent, displayed: false)
}
}
void setHue(percent) {
log.debug "Executing 'setHue'"
if (verifyPercent(percent)) {
parent.setHue(this, percent)
sendEvent(name: "hue", value: percent, displayed: false)
}
}
void setColor(value) {
log.debug "setColor: ${value}, $this"
def events = []
def validValues = [:]
if (verifyPercent(value.hue)) {
events << createEvent(name: "hue", value: value.hue, displayed: false)
validValues.hue = value.hue
}
if (verifyPercent(value.saturation)) {
events << createEvent(name: "saturation", value: value.saturation, displayed: false)
validValues.saturation = value.saturation
}
if (value.hex != null) {
if (value.hex ==~ /^\#([A-Fa-f0-9]){6}$/) {
events << createEvent(name: "color", value: value.hex)
validValues.hex = value.hex
} else {
log.warn "$value.hex is not a valid color"
}
}
if (verifyPercent(value.level)) {
events << createEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")
validValues.level = value.level
}
if (value.switch == "off" || (value.level != null && value.level <= 0)) {
events << createEvent(name: "switch", value: "off")
validValues.switch = "off"
} else {
events << createEvent(name: "switch", value: "on")
validValues.switch = "on"
}
if (!events.isEmpty()) {
parent.setColor(this, validValues)
}
events.each {
sendEvent(it)
}
}
void reset() {
log.debug "Executing 'reset'"
def value = [level:100, saturation:56, hue:23]
setAdjustedColor(value)
parent.poll()
}
void setAdjustedColor(value) {
if (value) {
log.trace "setAdjustedColor: ${value}"
def adjusted = value + [:]
adjusted.hue = adjustOutgoingHue(value.hue)
// Needed because color picker always sends 100
adjusted.level = null
setColor(adjusted)
} else {
log.warn "Invalid color input"
}
}
void setColorTemperature(value) {
if (value) {
log.trace "setColorTemperature: ${value}k"
parent.setColorTemperature(this, value)
sendEvent(name: "colorTemperature", value: value)
sendEvent(name: "switch", value: "on")
} else {
log.warn "Invalid color temperature"
}
}
void refresh() {
log.debug "Executing 'refresh'"
parent.manualRefresh()
}
def adjustOutgoingHue(percent) {
def adjusted = percent
if (percent > 31) {
if (percent < 63.0) {
adjusted = percent + (7 * (percent -30 ) / 32)
}
else if (percent < 73.0) {
adjusted = 69 + (5 * (percent - 62) / 10)
}
else {
adjusted = percent + (2 * (100 - percent) / 28)
}
}
log.info "percent: $percent, adjusted: $adjusted"
adjusted
}
def verifyPercent(percent) {
if (percent == null)
return false
else if (percent >= 0 && percent <= 100) {
return true
} else {
log.warn "$percent is not 0-100"
return false
}
}

View File

@@ -1,8 +1,6 @@
/**
* Hue Bulb
*
* Philips Hue Type "Extended Color Light"
*
* Author: SmartThings
*/
@@ -30,10 +28,10 @@ metadata {
tiles (scale: 2){
multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
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 "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
@@ -71,13 +69,11 @@ metadata {
def parse(description) {
log.debug "parse() - $description"
def results = []
def map = description
if (description instanceof String) {
log.debug "Hue Bulb stringToMap - ${map}"
map = stringToMap(description)
}
if (map?.name && map?.value) {
results << createEvent(name: "${map?.name}", value: "${map?.value}")
}
@@ -107,104 +103,62 @@ void nextLevel() {
}
void setLevel(percent) {
log.debug "Executing 'setLevel'"
if (verifyPercent(percent)) {
parent.setLevel(this, percent)
sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
sendEvent(name: "switch", value: "on")
}
log.debug "Executing 'setLevel'"
parent.setLevel(this, percent)
sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
}
void setSaturation(percent) {
log.debug "Executing 'setSaturation'"
if (verifyPercent(percent)) {
parent.setSaturation(this, percent)
sendEvent(name: "saturation", value: percent, displayed: false)
}
log.debug "Executing 'setSaturation'"
parent.setSaturation(this, percent)
sendEvent(name: "saturation", value: percent, displayed: false)
}
void setHue(percent) {
log.debug "Executing 'setHue'"
if (verifyPercent(percent)) {
parent.setHue(this, percent)
sendEvent(name: "hue", value: percent, displayed: false)
}
log.debug "Executing 'setHue'"
parent.setHue(this, percent)
sendEvent(name: "hue", value: percent, displayed: false)
}
void setColor(value) {
log.debug "setColor: ${value}, $this"
def events = []
def validValues = [:]
if (verifyPercent(value.hue)) {
events << createEvent(name: "hue", value: value.hue, displayed: false)
validValues.hue = value.hue
}
if (verifyPercent(value.saturation)) {
events << createEvent(name: "saturation", value: value.saturation, displayed: false)
validValues.saturation = value.saturation
}
if (value.hex != null) {
if (value.hex ==~ /^\#([A-Fa-f0-9]){6}$/) {
events << createEvent(name: "color", value: value.hex)
validValues.hex = value.hex
} else {
log.warn "$value.hex is not a valid color"
}
}
if (verifyPercent(value.level)) {
events << createEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")
validValues.level = value.level
}
if (value.switch == "off" || (value.level != null && value.level <= 0)) {
events << createEvent(name: "switch", value: "off")
validValues.switch = "off"
} else {
events << createEvent(name: "switch", value: "on")
validValues.switch = "on"
}
if (!events.isEmpty()) {
parent.setColor(this, validValues)
}
events.each {
sendEvent(it)
}
log.debug "setColor: ${value}, $this"
parent.setColor(this, value)
if (value.hue) { sendEvent(name: "hue", value: value.hue, displayed: false)}
if (value.saturation) { sendEvent(name: "saturation", value: value.saturation, displayed: false)}
if (value.hex) { sendEvent(name: "color", value: value.hex)}
if (value.level) { sendEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")}
sendEvent(name: "switch", value: "on")
}
void reset() {
log.debug "Executing 'reset'"
log.debug "Executing 'reset'"
def value = [level:100, saturation:56, hue:23]
setAdjustedColor(value)
parent.poll()
parent.poll()
}
void setAdjustedColor(value) {
if (value) {
if (value) {
log.trace "setAdjustedColor: ${value}"
def adjusted = value + [:]
adjusted.hue = adjustOutgoingHue(value.hue)
// Needed because color picker always sends 100
adjusted.level = null
setColor(adjusted)
} else {
log.warn "Invalid color input"
}
}
void setColorTemperature(value) {
if (value) {
if (value) {
log.trace "setColorTemperature: ${value}k"
parent.setColorTemperature(this, value)
sendEvent(name: "colorTemperature", value: value)
sendEvent(name: "switch", value: "on")
} else {
log.warn "Invalid color temperature"
}
}
}
void refresh() {
log.debug "Executing 'refresh'"
parent.manualRefresh()
log.debug "Executing 'refresh'"
parent.manualRefresh()
}
def adjustOutgoingHue(percent) {
@@ -223,14 +177,3 @@ def adjustOutgoingHue(percent) {
log.info "percent: $percent, adjusted: $adjusted"
adjusted
}
def verifyPercent(percent) {
if (percent == null)
return false
else if (percent >= 0 && percent <= 100) {
return true
} else {
log.warn "$percent is not 0-100"
return false
}
}

View File

@@ -1,8 +1,6 @@
/**
* Hue Lux Bulb
*
* Philips Hue Type "Dimmable Light"
*
* Author: SmartThings
*/
// for the UI
@@ -25,10 +23,10 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"rich-control", type: "lighting", canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
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 "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
@@ -70,24 +68,19 @@ def parse(description) {
// handle commands
void on() {
log.trace parent.on(this)
parent.on(this)
sendEvent(name: "switch", value: "on")
}
void off() {
log.trace parent.off(this)
parent.off(this)
sendEvent(name: "switch", value: "off")
}
void setLevel(percent) {
log.debug "Executing 'setLevel'"
if (percent != null && percent >= 0 && percent <= 100) {
parent.setLevel(this, percent)
sendEvent(name: "level", value: percent)
sendEvent(name: "switch", value: "on")
} else {
log.warn "$percent is not 0-100"
}
parent.setLevel(this, percent)
sendEvent(name: "level", value: percent)
}
void refresh() {

View File

@@ -23,10 +23,10 @@
#==============================================================================
# Korean (ko)
# Device Preferences
'''Give your device a name'''.ko=기기 이름 설정
'''Give your device a name'''.ko=기기 이름 바꾸기
'''Set Device Image'''.ko=기기 이미지 설정
# Events / Notifications
'''{{ linkText }} has left'''.ko={{ linkText }} 외출
'''{{ linkText }} has arrived'''.ko={{ linkText }} 귀가
'''{{ linkText }} has left'''.ko={{ linkText }}집을 나갔습니다.
'''{{ linkText }} has arrived'''.ko={{ linkText }}집에 도착했습니다.
'''present'''.ko=집안
'''not present'''.ko=외출

View File

@@ -22,14 +22,10 @@
#==============================================================================
# Korean (ko)
# Device Preferences
'''Give your device a name'''.ko=기기 이름 설정
'''Outlet'''.ko= 스마트 플러그
'''Give your device a name'''.ko=기기 이름 바꾸기
'''Outlet'''.ko=플러그
# Events descriptionText
'''{{ device.displayName }} is On'''.ko={{ device.displayName }} 켜짐
'''{{ device.displayName }} is Off'''.ko={{ device.displayName }} 꺼짐
'''{{ device.displayName }} power is {{ value }} Watts'''.ko={{ device.displayName }} 전은 {{ value }}와트입니다.
'''On'''.ko= 켜짐
'''Off'''.ko=꺼짐
'''Turning On'''.ko=켜는 중
'''Turning Off'''.ko=끄는 중
'''{{ device.displayName }} is On'''.ko={{ device.displayName }}켜졌습니다.
'''{{ device.displayName }} is Off'''.ko={{ device.displayName }}꺼졌습니다.
'''{{ device.displayName }} power is {{ value }} Watts'''.ko={{ device.displayName }} 전은 {{ value }}와트입니다
#==============================================================================

View File

@@ -65,10 +65,10 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label: 'On', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
attributeState "off", label: 'Off', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
attributeState "turningOn", label: 'Turning On', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
attributeState "turningOff", label: 'Turning Off', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
}
tileAttribute ("power", key: "SECONDARY_CONTROL") {
attributeState "power", label:'${currentValue} W'

View File

@@ -22,8 +22,6 @@
#==============================================================================
# Korean (ko)
# Device Preferences
'''Dry'''.ko=건조
'''Wet'''.ko=누수
'''dry'''.ko=건조
'''wet'''.ko=누수
'''battery'''.ko=배터리
@@ -31,14 +29,13 @@
'''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=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다.
'''Degrees'''.ko=온도
'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
'''Give your device a name'''.ko=기기 이름 설정
'''Water Leak Sensor'''.ko=누수감지 센서
'''${currentValue}% battery'''.ko=${currentValue}% 배터리
'''Give your device a name'''.ko=기기 이름 바꾸기
'''Water Leak Sensor'''.ko=누수센서
# Events descriptionText
'''{{ device.displayName }} is dry'''.ko={{ device.displayName }}가 건조
'''{{ device.displayName }} is wet'''.ko={{ device.displayName }}누수
'''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}에서 {{ value }}°C 감지
'''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}이(가) {{ value }}°C였습니다
'''{{ device.displayName }} was {{ value }}°F'''.ko={{ device.displayName }}이(가) {{ value }}°F였습니다
'''{{ 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 }} battery was {{ value }}%'''.ko={{ device.displayName }}남아있는 배터리 {{ value }}%입니다.
#==============================================================================

View File

@@ -28,16 +28,13 @@
'''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=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다.
'''Degrees'''.ko=온도
'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
'''Give your device a name'''.ko=기기 이름 설정
'''Give your device a name'''.ko=기기 이름 바꾸기
'''Motion Sensor'''.ko=모션 센서
'''motion'''.ko= 동작 감지
'''no motion'''.ko=동작 없음
'''${currentValue}% battery'''.ko=${currentValue}% 배터리
# Events descriptionText
'''{{ 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 }} 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였습니다
'''{{ 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 }} battery was {{ value }}%'''.ko={{ device.displayName }}남아있는 배터리 {{ value }}%입니다.
#==============================================================================

View File

@@ -31,20 +31,15 @@
'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오
'''Do you want to use this sensor on a garage door?'''.ko=차고 문의 센서 사용 설정하기
'''Tap to set'''.ko=눌러서 설정
'''Give your device a name'''.ko=기기 이름 설정
'''Multipurpose Sensor'''.ko=문 및 창 센서
'''Give your device a name'''.ko=기기 이름 바꾸기
'''Multipurpose Sensor'''.ko=멀티 센서
# Events descriptionText
'''{{ device.displayName }} was opened'''.ko={{ device.displayName }}에서 열림 감지되었습니다.
'''{{ device.displayName }} was closed'''.ko={{ device.displayName }}에서 닫힘이 감지되었습니다.
'''{{ device.displayName }} was active'''.ko={{ device.displayName }} 활성화
'''{{ device.displayName }} was inactive'''.ko={{ device.displayName }} 비활성화
'''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}에서 {{ value }}°C 감지
'''{{ device.displayName }} was opened'''.ko={{ device.displayName }}열림 감지하였습니다.
'''{{ device.displayName }} was closed'''.ko={{ device.displayName }}닫혔습니다.
'''{{ device.displayName }} was active'''.ko={{ device.displayName }}활성화되었습니다.
'''{{ device.displayName }} was inactive'''.ko={{ device.displayName }}비활성화되었습니다.
'''{{ device.displayName }} was {{ value }}°C'''.ko={{ device.displayName }}이(가){{ value }}°C였습니다.
'''{{ device.displayName }} was {{ value }}°F'''.ko={{ device.displayName }}이(가) {{ value }}°F였습니다
'''{{ device.displayName }} battery was {{ value }}%'''.ko={{ device.displayName }}의 남은 배터리 {{ value }}%
'''{{ device.displayName }} battery was {{ value }}%'''.ko={{ device.displayName }}남아있는 배터리 {{ value }}%입니다.
'''Updating device to garage sensor'''.ko=기기-차고 센서 업데이트 중
'''Updating device to open/close sensor'''.ko=기기-열림/닫힘 센서 업데이트 중
'''Inactive'''.ko=비활성 상태
'''Active'''.ko=활성 상태
'''Open'''.ko= 열림이 감지될 때
'''Closed'''.ko=닫힘
'''${currentValue}% battery'''.ko=${currentValue}% 배터리

View File

@@ -83,19 +83,19 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"status", type: "generic", width: 6, height: 4){
tileAttribute ("device.status", key: "PRIMARY_CONTROL") {
attributeState "open", label:'Open', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
attributeState "closed", label:'Closed', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
attributeState "garage-open", label:'Open', icon:"st.doors.garage.garage-open", backgroundColor:"#ffa81e"
attributeState "garage-closed", label:'Closed', icon:"st.doors.garage.garage-closed", backgroundColor:"#79b821"
}
}
standardTile("contact", "device.contact", width: 2, height: 2) {
state("open", label:'Open', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
state("closed", label:'Closed', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
}
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
state("active", label:'Active', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
state("inactive", label:'Inactive', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
state("inactive", label:'${name}', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
}
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label:'${currentValue}°',

View File

@@ -203,7 +203,7 @@ private List parseContactMessage(String description) {
parts.each { part ->
part = part.trim()
if (part.startsWith('contactState:')) {
results.addAll(getContactResult(part, description))
results << getContactResult(part, description)
}
else if (part.startsWith('accelerationState:')) {
results << getAccelerationResult(part, description)
@@ -316,7 +316,7 @@ private List getContactResult(part, description) {
results
}
private Map getAccelerationResult(part, description) {
private getAccelerationResult(part, description) {
def name = "acceleration"
def value = part.endsWith("1") ? "active" : "inactive"
def linkText = getLinkText(device)
@@ -335,7 +335,7 @@ private Map getAccelerationResult(part, description) {
]
}
private Map getTempResult(part, description) {
private getTempResult(part, description) {
def name = "temperature"
def temperatureScale = getTemperatureScale()
def value = zigbee.parseSmartThingsTemperatureValue(part, "temp: ", temperatureScale)
@@ -360,7 +360,7 @@ private Map getTempResult(part, description) {
]
}
private Map getXyzResult(results, description) {
private getXyzResult(results, description) {
def name = "threeAxis"
def value = "${results.x},${results.y},${results.z}"
def linkText = getLinkText(device)
@@ -379,7 +379,7 @@ private Map getXyzResult(results, description) {
]
}
private Map getBatteryResult(part, description) {
private getBatteryResult(part, description) {
def batteryDivisor = description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"} ? description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"}.split(":")[1].trim() : null
def name = "battery"
def value = zigbee.parseSmartThingsBatteryValue(part, batteryDivisor)
@@ -400,7 +400,7 @@ private Map getBatteryResult(part, description) {
]
}
private Map getRssiResult(part, description, lastHop=false) {
private getRssiResult(part, description, lastHop=false) {
def name = lastHop ? "lastHopRssi" : "rssi"
def valueString = part.split(":")[1].trim()
def value = (Integer.parseInt(valueString) - 128).toString()
@@ -431,7 +431,7 @@ private Map getRssiResult(part, description, lastHop=false) {
* Note: To make the signal strength indicator more accurate, we could combine
* LQI with RSSI.
*/
private Map getLqiResult(part, description, lastHop=false) {
private getLqiResult(part, description, lastHop=false) {
def name = lastHop ? "lastHopLqi" : "lqi"
def valueString = part.split(":")[1].trim()
def percentageOf = 255

View File

@@ -1,225 +0,0 @@
/**
* Copyright 2016 SmartThings, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (
name: "carouselDeviceTile",
namespace: "smartthings/tile-ux",
author: "SmartThings") {
capability "Thermostat"
capability "Relative Humidity Measurement"
command "tempUp"
command "tempDown"
command "heatUp"
command "heatDown"
command "coolUp"
command "coolDown"
command "setTemperature", ["number"]
}
tiles(scale: 2) {
multiAttributeTile(name:"thermostatMulti", type:"thermostat", width:6, height:4) {
tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
attributeState("default", label:'${currentValue}', unit:"dF")
}
tileAttribute("device.temperature", key: "VALUE_CONTROL") {
attributeState("default", action: "setTemperature")
}
tileAttribute("device.humidity", key: "SECONDARY_CONTROL") {
attributeState("default", label:'${currentValue}%', unit:"%")
}
tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") {
attributeState("idle", backgroundColor:"#44b621")
attributeState("heating", backgroundColor:"#ffa81e")
attributeState("cooling", backgroundColor:"#269bd2")
}
tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") {
attributeState("off", label:'${name}')
attributeState("heat", label:'${name}')
attributeState("cool", label:'${name}')
attributeState("auto", label:'${name}')
}
tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") {
attributeState("default", label:'${currentValue}', unit:"dF")
}
tileAttribute("device.coolingSetpoint", key: "COOLING_SETPOINT") {
attributeState("default", label:'${currentValue}', unit:"dF")
}
}
main("thermostatMulti")
details([
"thermostatMulti"
])
}
}
def installed() {
sendEvent(name: "temperature", value: 72, unit: "F")
sendEvent(name: "heatingSetpoint", value: 70, unit: "F")
sendEvent(name: "thermostatSetpoint", value: 70, unit: "F")
sendEvent(name: "coolingSetpoint", value: 76, unit: "F")
sendEvent(name: "thermostatMode", value: "off")
sendEvent(name: "thermostatFanMode", value: "fanAuto")
sendEvent(name: "thermostatOperatingState", value: "idle")
sendEvent(name: "humidity", value: 53, unit: "%")
}
def parse(String description) {
}
def evaluate(temp, heatingSetpoint, coolingSetpoint) {
log.debug "evaluate($temp, $heatingSetpoint, $coolingSetpoint"
def threshold = 1.0
def current = device.currentValue("thermostatOperatingState")
def mode = device.currentValue("thermostatMode")
def heating = false
def cooling = false
def idle = false
if (mode in ["heat","emergency heat","auto"]) {
if (heatingSetpoint - temp >= threshold) {
heating = true
sendEvent(name: "thermostatOperatingState", value: "heating")
}
else if (temp - heatingSetpoint >= threshold) {
idle = true
}
sendEvent(name: "thermostatSetpoint", value: heatingSetpoint)
}
if (mode in ["cool","auto"]) {
if (temp - coolingSetpoint >= threshold) {
cooling = true
sendEvent(name: "thermostatOperatingState", value: "cooling")
}
else if (coolingSetpoint - temp >= threshold && !heating) {
idle = true
}
sendEvent(name: "thermostatSetpoint", value: coolingSetpoint)
}
else {
sendEvent(name: "thermostatSetpoint", value: heatingSetpoint)
}
if (idle && !heating && !cooling) {
sendEvent(name: "thermostatOperatingState", value: "idle")
}
}
def setHeatingSetpoint(Double degreesF) {
log.debug "setHeatingSetpoint($degreesF)"
sendEvent(name: "heatingSetpoint", value: degreesF)
evaluate(device.currentValue("temperature"), degreesF, device.currentValue("coolingSetpoint"))
}
def setCoolingSetpoint(Double degreesF) {
log.debug "setCoolingSetpoint($degreesF)"
sendEvent(name: "coolingSetpoint", value: degreesF)
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), degreesF)
}
def setThermostatMode(String value) {
sendEvent(name: "thermostatMode", value: value)
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def setThermostatFanMode(String value) {
sendEvent(name: "thermostatFanMode", value: value)
}
def off() {
sendEvent(name: "thermostatMode", value: "off")
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def heat() {
sendEvent(name: "thermostatMode", value: "heat")
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def auto() {
sendEvent(name: "thermostatMode", value: "auto")
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def emergencyHeat() {
sendEvent(name: "thermostatMode", value: "emergency heat")
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def cool() {
sendEvent(name: "thermostatMode", value: "cool")
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def fanOn() {
sendEvent(name: "thermostatFanMode", value: "fanOn")
}
def fanAuto() {
sendEvent(name: "thermostatFanMode", value: "fanAuto")
}
def fanCirculate() {
sendEvent(name: "thermostatFanMode", value: "fanCirculate")
}
def tempUp() {
def ts = device.currentState("temperature")
def value = ts ? ts.integerValue + 1 : 72
sendEvent(name:"temperature", value: value)
evaluate(value, device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def tempDown() {
def ts = device.currentState("temperature")
def value = ts ? ts.integerValue - 1 : 72
sendEvent(name:"temperature", value: value)
evaluate(value, device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def setTemperature(value) {
def ts = device.currentState("temperature")
sendEvent(name:"temperature", value: value)
evaluate(value, device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def heatUp() {
def ts = device.currentState("heatingSetpoint")
def value = ts ? ts.integerValue + 1 : 68
sendEvent(name:"heatingSetpoint", value: value)
evaluate(device.currentValue("temperature"), value, device.currentValue("coolingSetpoint"))
}
def heatDown() {
def ts = device.currentState("heatingSetpoint")
def value = ts ? ts.integerValue - 1 : 68
sendEvent(name:"heatingSetpoint", value: value)
evaluate(device.currentValue("temperature"), value, device.currentValue("coolingSetpoint"))
}
def coolUp() {
def ts = device.currentState("coolingSetpoint")
def value = ts ? ts.integerValue + 1 : 76
sendEvent(name:"coolingSetpoint", value: value)
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), value)
}
def coolDown() {
def ts = device.currentState("coolingSetpoint")
def value = ts ? ts.integerValue - 1 : 76
sendEvent(name:"coolingSetpoint", value: value)
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), value)
}

View File

@@ -1,52 +0,0 @@
/**
* Copyright 2016 SmartThings, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (
name: "colorWheelDeviceTile",
namespace: "smartthings/tile-ux",
author: "SmartThings") {
capability "Color Control"
}
tiles(scale: 2) {
valueTile("currentColor", "device.color") {
state "default", label: '${currentValue}'
}
controlTile("rgbSelector", "device.color", "color", height: 6, width: 6, inactiveLabel: false) {
state "color", action: "color control.setColor"
}
main("currentColor")
details([
"rgbSelector"
])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
}
def setSaturation(percent) {
log.debug "Executing 'setSaturation'"
sendEvent(name: "saturation", value: percent)
}
def setHue(percent) {
log.debug "Executing 'setHue'"
sendEvent(name: "hue", value: percent)
}

View File

@@ -1,63 +0,0 @@
/**
* Copyright 2016 SmartThings, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (
name: "presenceDeviceTile",
namespace: "smartthings/tile-ux",
author: "SmartThings") {
capability "Presence Sensor"
command "arrived"
command "departed"
}
tiles(scale: 2) {
// You only get a presence tile view when the size is 3x3 otherwise it's a value tile
standardTile("presence", "device.presence", width: 3, height: 3, canChangeBackground: true) {
state("present", labelIcon:"st.presence.tile.mobile-present", backgroundColor:"#53a7c0")
state("not present", labelIcon:"st.presence.tile.mobile-not-present", backgroundColor:"#ebeef2")
}
standardTile("notPresentBtn", "device.fake", width: 3, height: 3, decoration: "flat") {
state("not present", label:'not present', backgroundColor:"#ffffff", action:"departed")
}
standardTile("presentBtn", "device.fake", width: 3, height: 3, decoration: "flat") {
state("present", label:'present', backgroundColor:"#53a7c0", action:"arrived")
}
main("presence")
details([
"presence", "presenceControl", "notPresentBtn", "presentBtn"
])
}
}
def installed() {
sendEvent(name: "presence", value: "present")
}
def parse(String description) {
}
def arrived() {
log.trace "Executing 'arrived'"
sendEvent(name: "presence", value: "present")
}
def departed() {
log.trace "Executing 'arrived'"
sendEvent(name: "presence", value: "not present")
}

View File

@@ -1,75 +0,0 @@
/**
* Copyright 2016 SmartThings, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (
name: "sliderDeviceTile",
namespace: "smartthings/tile-ux",
author: "SmartThings") {
capability "Switch Level"
command "setRangedLevel", ["number"]
}
tiles(scale: 2) {
controlTile("tinySlider", "device.level", "slider", height: 2, width: 2, inactiveLabel: false) {
state "level", action:"switch level.setLevel"
}
controlTile("mediumSlider", "device.level", "slider", height: 2, width: 4, inactiveLabel: false) {
state "level", action:"switch level.setLevel"
}
controlTile("largeSlider", "device.level", "slider", decoration: "flat", height: 2, width: 6, inactiveLabel: false) {
state "level", action:"switch level.setLevel"
}
controlTile("rangeSlider", "device.rangedLevel", "slider", height: 2, width: 4, range: "(20..80)") {
state "level", action:"setRangedLevel"
}
valueTile("rangeValue", "device.rangedLevel", height: 2, width: 2) {
state "default", label:'${currentValue}'
}
controlTile("rangeSliderConstrained", "device.rangedLevel", "slider", height: 2, width: 4, range: "(40..60)") {
state "level", action:"setRangedLevel"
}
main("rangeValue")
details([
"tinySlider", "mediumSlider",
"largeSlider",
"rangeSlider", "rangeValue",
"rangeSliderConstrained"
])
}
}
def installed() {
sendEvent(name: "level", value: 63)
sendEvent(name: "rangedLevel", value: 47)
}
def parse(String description) {
}
def setLevel(value) {
log.debug "setting level to $value"
sendEvent(name:"level", value:value)
}
def setRangedLevel(value) {
log.debug "setting ranged level to $value"
sendEvent(name:"rangedLevel", value:value)
}

View File

@@ -1,109 +0,0 @@
/**
* Copyright 2016 SmartThings, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (
name: "standardDeviceTile",
namespace: "smartthings/tile-ux",
author: "SmartThings") {
capability "Switch"
}
tiles(scale: 2) {
// standard tile with actions
standardTile("actionRings", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "off", label: '${currentValue}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
state "on", label: '${currentValue}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
}
// standard flat tile with actions
standardTile("actionFlat", "device.switch", width: 2, height: 2, canChangeIcon: true, decoration: "flat") {
state "off", label: '${currentValue}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
state "on", label: '${currentValue}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
}
// standard flat tile without actions
standardTile("noActionFlat", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "off", label: '${currentValue}',icon: "st.switches.switch.off", backgroundColor: "#ffffff"
state "on", label: '${currentValue}', icon: "st.switches.switch.on", backgroundColor: "#79b821"
}
// standard flat tile with only a label
standardTile("flatLabel", "device.switch", width: 2, height: 2, decoration: "flat") {
state "default", label: 'On Action', action: "switch.on", backgroundColor: "#ffffff"
}
// standard flat tile with icon and label
standardTile("flatIconLabel", "device.switch", width: 2, height: 2, decoration: "flat") {
state "default", label: 'Off Action', action: "switch.off", icon:"st.switches.switch.off", backgroundColor: "#ffffff"
}
// standard flat tile with only icon (Refreh text is IN the icon file)
standardTile("flatIcon", "device.switch", width: 2, height: 2, decoration: "flat") {
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
}
// standard with defaultState = true
standardTile("flatDefaultState", "null", width: 2, height: 2, decoration: "flat") {
state "off", label: 'Fail!', icon: "st.switches.switch.off"
state "on", label: 'Pass!', icon: "st.switches.switch.on", defaultState: true
}
// standard with implicit defaultState based on order (0 index is selected)
standardTile("flatImplicitDefaultState1", "null", width: 2, height: 2, decoration: "flat") {
state "on", label: 'Pass!', icon: "st.switches.switch.on"
state "off", label: 'Fail!', icon: "st.switches.switch.off"
}
// standard with implicit defaultState based on state.name == default
standardTile("flatImplicitDefaultState2", "null", width: 2, height: 2, decoration: "flat") {
state "off", label: 'Fail!', icon: "st.switches.switch.off"
state "default", label: 'Pass!', icon: "st.switches.switch.on"
}
// utility tiles to fill the spaces
standardTile("empty2x2", "null", width: 2, height: 2, decoration: "flat") {
state "default", label:''
}
standardTile("empty4x2", "null", width: 4, height: 2, decoration: "flat") {
state "default", label:''
}
main("standard1")
details([
"actionRings", "actionFlat", "noActionFlat",
"flatLabel", "flatIconLabel", "flatIcon",
"flatDefaultState", "flatImplicitDefaultState1", "flatImplicitDefaultState2",
])
}
}
def installed() {
sendEvent(name: "switch", value: "off")
}
def parse(String description) {
}
def on() {
log.debug "on()"
sendEvent(name: "switch", value: "on")
}
def off() {
log.debug "off()"
sendEvent(name: "switch", value: "off")
}

View File

@@ -1,96 +0,0 @@
/**
* Copyright 2016 SmartThings, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (
name: "valueDeviceTile",
namespace: "smartthings/tile-ux",
author: "SmartThings") {
capability "Sensor"
}
tiles(scale: 2) {
valueTile("text", "device.text", width: 2, height: 2) {
state "default", label:'${currentValue}'
}
valueTile("longText", "device.longText", width: 2, height: 2) {
state "default", label:'${currentValue}'
}
valueTile("integer", "device.integer", width: 2, height: 2) {
state "default", label:'${currentValue}'
}
valueTile("integerFloat", "device.integerFloat", width: 2, height: 2) {
state "default", label:'${currentValue}'
}
valueTile("pi", "device.pi", width: 2, height: 2) {
state "default", label:'${currentValue}'
}
valueTile("floatAsText", "device.floatAsText", width: 2, height: 2) {
state "default", label:'${currentValue}'
}
valueTile("bgColor", "device.integer", width: 2, height: 2) {
state "default", label:'${currentValue}', backgroundColor: "#e86d13"
}
valueTile("bgColorRange", "device.integer", width: 2, height: 2) {
state "default", label:'${currentValue}', backgroundColors: [
[value: 10, color: "#ff0000"],
[value: 90, color: "#0000ff"]
]
}
valueTile("bgColorRangeSingleItem", "device.integer", width: 2, height: 2) {
state "default", label:'${currentValue}', backgroundColors: [
[value: 10, color: "#333333"]
]
}
valueTile("bgColorRangeConflict", "device.integer", width: 2, height: 2) {
state "default", label:'${currentValue}', backgroundColors: [
[value: 10, color: "#990000"],
[value: 10, color: "#000099"]
]
}
valueTile("noValue", "device.nada", width: 2, height: 2) {
state "default", label:'${currentValue}'
}
main("text")
details([
"text", "longText", "integer",
"integerFloat", "pi", "floatAsText",
"bgColor", "bgColorRange", "bgColorRangeSingleItem",
"bgColorRangeConflict", "noValue"
])
}
}
def installed() {
sendEvent(name: "text", value: "Test")
sendEvent(name: "longText", value: "The Longer The Text, The Better The Test")
sendEvent(name: "integer", value: 47)
sendEvent(name: "integerFloat", value: 47.0)
sendEvent(name: "pi", value: 3.14159)
sendEvent(name: "floatAsText", value: "3.14159")
}
def parse(String description) {
}

View File

@@ -1,118 +0,0 @@
/**
* Copyright 2016 SmartThings, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "genericDeviceTile", namespace: "smartthings/tile-ux", author: "SmartThings") {
capability "Actuator"
capability "Switch"
capability "Switch Level"
command "levelUp"
command "levelDown"
command "randomizeLevel"
}
tiles(scale: 2) {
multiAttributeTile(name:"basicTile", type:"generic", width:6, height:4) {
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
}
multiAttributeTile(name:"sliderTile", type:"generic", width:6, height:4) {
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute("device.level", key: "SECONDARY_CONTROL") {
attributeState "default", icon: 'st.Weather.weather1', action:"randomizeLevel"
}
tileAttribute("device.level", key: "SLIDER_CONTROL") {
attributeState "default", action:"switch level.setLevel"
}
}
multiAttributeTile(name:"valueTile", type:"generic", width:6, height:4) {
tileAttribute("device.level", key: "PRIMARY_CONTROL") {
attributeState "default", label:'${currentValue}', backgroundColors:[
[value: 0, color: "#ff0000"],
[value: 20, color: "#ffff00"],
[value: 40, color: "#00ff00"],
[value: 60, color: "#00ffff"],
[value: 80, color: "#0000ff"],
[value: 100, color: "#ff00ff"]
]
}
tileAttribute("device.switch", key: "SECONDARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'…', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'…', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute("device.level", key: "VALUE_CONTROL") {
attributeState "VALUE_UP", action: "levelUp"
attributeState "VALUE_DOWN", action: "levelDown"
}
}
main(["basicTile"])
details(["basicTile", "sliderTile", "valueTile"])
}
}
def installed() {
}
def parse() {
// This is a simulated device. No incoming data to parse.
}
def on() {
log.debug "turningOn"
sendEvent(name: "switch", value: "on")
}
def off() {
log.debug "turningOff"
sendEvent(name: "switch", value: "off")
}
def setLevel(percent) {
log.debug "setLevel: ${percent}, this"
sendEvent(name: "level", value: percent)
}
def randomizeLevel() {
def level = Math.round(Math.random() * 100)
setLevel(level)
}
def levelUp() {
def level = device.latestValue("level") as Integer ?: 0
if (level < 100) {
level = level + 1
}
setLevel(level)
}
def levelDown() {
def level = device.latestValue("level") as Integer ?: 0
if (level > 0) {
level = level - 1
}
setLevel(level)
}

View File

@@ -1,211 +0,0 @@
/**
* Copyright 2016 SmartThings, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (
name: "lightingDeviceTile",
namespace: "smartthings/tile-ux",
author: "SmartThings") {
capability "Switch Level"
capability "Actuator"
capability "Color Control"
capability "Power Meter"
capability "Switch"
capability "Refresh"
capability "Sensor"
command "setAdjustedColor"
command "reset"
command "refresh"
}
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) {
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
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 "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.power", key: "SECONDARY_CONTROL") {
attributeState "power", label:'Power level: ${currentValue}W', icon: "st.Appliances.appliances17"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel"
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
attributeState "color", action:"setAdjustedColor"
}
}
multiAttributeTile(name:"switchNoPower", type: "lighting", width: 6, height: 4, canChangeIcon: true) {
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
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 "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel"
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
attributeState "color", action:"setAdjustedColor"
}
}
multiAttributeTile(name:"switchNoSlider", type: "lighting", width: 6, height: 4, canChangeIcon: true) {
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
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 "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.power", key: "SECONDARY_CONTROL") {
attributeState "power", label:'The power level is currently: ${currentValue}W', icon: "st.Appliances.appliances17"
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
attributeState "color", action:"setAdjustedColor"
}
}
multiAttributeTile(name:"switchNoSliderOrColor", type: "lighting", width: 6, height: 4, canChangeIcon: true) {
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
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 "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.power", key: "SECONDARY_CONTROL") {
attributeState "power", label:'The light is currently consuming this amount of power: ${currentValue}W', icon: "st.Appliances.appliances17"
}
}
valueTile("color", "device.color", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "color", label: '${currentValue}'
}
standardTile("reset", "device.reset", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
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) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
main(["switch"])
details(["switch", "switchNoPower", "switchNoSlider", "switchNoSliderOrColor", "color", "refresh", "reset"])
}
}
// parse events into attributes
def parse(description) {
log.debug "parse() - $description"
def results = []
def map = description
if (description instanceof String) {
log.debug "Hue Bulb stringToMap - ${map}"
map = stringToMap(description)
}
if (map?.name && map?.value) {
results << createEvent(name: "${map?.name}", value: "${map?.value}")
}
results
}
// handle commands
def on() {
//log.trace parent.on(this)
sendEvent(name: "switch", value: "on")
}
def off() {
//log.trace parent.off(this)
sendEvent(name: "switch", value: "off")
}
def nextLevel() {
def level = device.latestValue("level") as Integer ?: 0
if (level <= 100) {
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
}
else {
level = 25
}
setLevel(level)
}
def setLevel(percent) {
log.debug "setLevel: ${percent}, this"
sendEvent(name: "level", value: percent)
def power = Math.round(percent / 1.175) * 0.1
sendEvent(name: "power", value: power)
}
def setSaturation(percent) {
log.debug "setSaturation: ${percent}, $this"
sendEvent(name: "saturation", value: percent)
}
def setHue(percent) {
log.debug "setHue: ${percent}, $this"
sendEvent(name: "hue", value: percent)
}
def setColor(value) {
log.debug "setColor: ${value}, $this"
if (value.hue) { sendEvent(name: "hue", value: value.hue)}
if (value.saturation) { sendEvent(name: "saturation", value: value.saturation)}
if (value.hex) { sendEvent(name: "color", value: value.hex)}
if (value.level) { sendEvent(name: "level", value: value.level)}
if (value.switch) { sendEvent(name: "switch", value: value.switch)}
}
def reset() {
log.debug "Executing 'reset'"
setAdjustedColor([level:100, hex:"#90C638", saturation:56, hue:23])
//parent.poll()
}
def setAdjustedColor(value) {
if (value) {
log.trace "setAdjustedColor: ${value}"
def adjusted = value + [:]
adjusted.hue = adjustOutgoingHue(value.hue)
// Needed because color picker always sends 100
adjusted.level = null
setColor(adjusted)
}
}
def refresh() {
log.debug "Executing 'refresh'"
//parent.manualRefresh()
}
def adjustOutgoingHue(percent) {
def adjusted = percent
if (percent > 31) {
if (percent < 63.0) {
adjusted = percent + (7 * (percent -30 ) / 32)
}
else if (percent < 73.0) {
adjusted = 69 + (5 * (percent - 62) / 10)
}
else {
adjusted = percent + (2 * (100 - percent) / 28)
}
}
log.info "percent: $percent, adjusted: $adjusted"
adjusted
}

View File

@@ -1,122 +0,0 @@
/**
* Copyright 2016 SmartThings, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (
name: "mediaPlayerDeviceTile",
namespace: "smartthings/tile-ux",
author: "SmartThings") {
capability "Actuator"
capability "Switch"
capability "Refresh"
capability "Sensor"
capability "Music Player"
}
tiles(scale: 2) {
multiAttributeTile(name: "mediaMulti", type:"mediaPlayer", width:6, height:4) {
tileAttribute("device.status", key: "PRIMARY_CONTROL") {
attributeState("paused", label:"Paused",)
attributeState("playing", label:"Playing")
attributeState("stopped", label:"Stopped")
}
tileAttribute("device.status", key: "MEDIA_STATUS") {
attributeState("paused", label:"Paused", action:"music Player.play", nextState: "playing")
attributeState("playing", label:"Playing", action:"music Player.pause", nextState: "paused")
attributeState("stopped", label:"Stopped", action:"music Player.play", nextState: "playing")
}
tileAttribute("device.status", key: "PREVIOUS_TRACK") {
attributeState("default", action:"music Player.previousTrack")
}
tileAttribute("device.status", key: "NEXT_TRACK") {
attributeState("default", action:"music Player.nextTrack")
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState("level", action:"music Player.setLevel")
}
tileAttribute ("device.mute", key: "MEDIA_MUTED") {
attributeState("unmuted", action:"music Player.mute", nextState: "muted")
attributeState("muted", action:"music Player.unmute", nextState: "unmuted")
}
tileAttribute("device.trackDescription", key: "MARQUEE") {
attributeState("default", label:"${currentValue}")
}
}
main "mediaMulti"
details(["mediaMulti"])
}
}
def installed() {
state.tracks = [
"Gangnam Style (강남스타일)\nPSY\nPsy 6 (Six Rules), Part 1",
"Careless Whisper\nWham!\nMake It Big",
"Never Gonna Give You Up\nRick Astley\nWhenever You Need Somebody",
"Shake It Off\nTaylor Swift\n1989",
"Ironic\nAlanis Morissette\nJagged Little Pill",
"Hotline Bling\nDrake\nHotline Bling - Single"
]
state.currentTrack = 0
sendEvent(name: "level", value: 72)
sendEvent(name: "mute", value: "unmuted")
sendEvent(name: "status", value: "stopped")
}
def parse(description) {
// No parsing will happen with this simulated device.
}
def play() {
sendEvent(name: "status", value: "playing")
sendEvent(name: "trackDescription", value: state.tracks[state.currentTrack])
}
def pause() {
sendEvent(name: "status", value: "paused")
sendEvent(name: "trackDescription", value: state.tracks[state.currentTrack])
}
def stop() {
sendEvent(name: "status", value: "stopped")
}
def previousTrack() {
state.currentTrack = state.currentTrack - 1
if (state.currentTrack < 0)
state.currentTrack = state.tracks.size()-1
sendEvent(name: "trackDescription", value: state.tracks[state.currentTrack])
}
def nextTrack() {
state.currentTrack = state.currentTrack + 1
if (state.currentTrack == state.tracks.size())
state.currentTrack = 0
sendEvent(name: "trackDescription", value: state.tracks[state.currentTrack])
}
def mute() {
sendEvent(name: "mute", value: "muted")
}
def unmute() {
sendEvent(name: "mute", value: "unmuted")
}
def setLevel(level) {
sendEvent(name: "level", value: level)
}

View File

@@ -1,341 +0,0 @@
/**
* Copyright 2016 SmartThings, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (
name: "thermostatDeviceTile",
namespace: "smartthings/tile-ux",
author: "SmartThings") {
capability "Thermostat"
capability "Relative Humidity Measurement"
command "tempUp"
command "tempDown"
command "heatUp"
command "heatDown"
command "coolUp"
command "coolDown"
command "setTemperature", ["number"]
}
tiles(scale: 2) {
multiAttributeTile(name:"thermostatFull", type:"thermostat", width:6, height:4) {
tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
attributeState("default", label:'${currentValue}', unit:"dF")
}
tileAttribute("device.temperature", key: "VALUE_CONTROL") {
attributeState("VALUE_UP", action: "tempUp")
attributeState("VALUE_DOWN", action: "tempDown")
}
tileAttribute("device.humidity", key: "SECONDARY_CONTROL") {
attributeState("default", label:'${currentValue}%', unit:"%")
}
tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") {
attributeState("idle", backgroundColor:"#44b621")
attributeState("heating", backgroundColor:"#ffa81e")
attributeState("cooling", backgroundColor:"#269bd2")
}
tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") {
attributeState("off", label:'${name}')
attributeState("heat", label:'${name}')
attributeState("cool", label:'${name}')
attributeState("auto", label:'${name}')
}
tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") {
attributeState("default", label:'${currentValue}', unit:"dF")
}
tileAttribute("device.coolingSetpoint", key: "COOLING_SETPOINT") {
attributeState("default", label:'${currentValue}', unit:"dF")
}
}
multiAttributeTile(name:"thermostatNoHumidity", type:"thermostat", width:6, height:4) {
tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
attributeState("default", label:'${currentValue}', unit:"dF")
}
tileAttribute("device.temperature", key: "VALUE_CONTROL") {
attributeState("VALUE_UP", action: "tempUp")
attributeState("VALUE_DOWN", action: "tempDown")
}
tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") {
attributeState("idle", backgroundColor:"#44b621")
attributeState("heating", backgroundColor:"#ffa81e")
attributeState("cooling", backgroundColor:"#269bd2")
}
tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") {
attributeState("off", label:'${name}')
attributeState("heat", label:'${name}')
attributeState("cool", label:'${name}')
attributeState("auto", label:'${name}')
}
tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") {
attributeState("default", label:'${currentValue}', unit:"dF")
}
tileAttribute("device.coolingSetpoint", key: "COOLING_SETPOINT") {
attributeState("default", label:'${currentValue}', unit:"dF")
}
}
multiAttributeTile(name:"thermostatBasic", type:"thermostat", width:6, height:4) {
tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
attributeState("default", label:'${currentValue}', unit:"dF",
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
])
}
tileAttribute("device.temperature", key: "VALUE_CONTROL") {
attributeState("VALUE_UP", action: "tempUp")
attributeState("VALUE_DOWN", action: "tempDown")
}
}
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label:'${currentValue}', unit:"dF",
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
)
}
standardTile("tempDown", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'down', action:"tempDown"
}
standardTile("tempUp", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'up', action:"tempUp"
}
valueTile("heatingSetpoint", "device.heatingSetpoint", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "heat", label:'${currentValue} heat', unit: "F", backgroundColor:"#ffffff"
}
standardTile("heatDown", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'down', action:"heatDown"
}
standardTile("heatUp", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'up', action:"heatUp"
}
valueTile("coolingSetpoint", "device.coolingSetpoint", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "cool", label:'${currentValue} cool', unit:"F", backgroundColor:"#ffffff"
}
standardTile("coolDown", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'down', action:"coolDown"
}
standardTile("coolUp", "device.temperature", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'up', action:"coolUp"
}
standardTile("mode", "device.thermostatMode", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "off", label:'${name}', action:"thermostat.heat", backgroundColor:"#ffffff"
state "heat", label:'${name}', action:"thermostat.cool", backgroundColor:"#ffa81e"
state "cool", label:'${name}', action:"thermostat.auto", backgroundColor:"#269bd2"
state "auto", label:'${name}', action:"thermostat.off", backgroundColor:"#79b821"
}
standardTile("fanMode", "device.thermostatFanMode", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "fanAuto", label:'${name}', action:"thermostat.fanOn", backgroundColor:"#ffffff"
state "fanOn", label:'${name}', action:"thermostat.fanCirculate", backgroundColor:"#ffffff"
state "fanCirculate", label:'${name}', action:"thermostat.fanAuto", backgroundColor:"#ffffff"
}
standardTile("operatingState", "device.thermostatOperatingState", width: 2, height: 2) {
state "idle", label:'${name}', backgroundColor:"#ffffff"
state "heating", label:'${name}', backgroundColor:"#ffa81e"
state "cooling", label:'${name}', backgroundColor:"#269bd2"
}
main("thermostatFull")
details([
"thermostatFull", "thermostatNoHumidity", "thermostatBasic",
"temperature","tempDown","tempUp",
"mode", "fanMode", "operatingState",
"heatingSetpoint", "heatDown", "heatUp",
"coolingSetpoint", "coolDown", "coolUp"
])
}
}
def installed() {
sendEvent(name: "temperature", value: 72, unit: "F")
sendEvent(name: "heatingSetpoint", value: 70, unit: "F")
sendEvent(name: "thermostatSetpoint", value: 70, unit: "F")
sendEvent(name: "coolingSetpoint", value: 76, unit: "F")
sendEvent(name: "thermostatMode", value: "off")
sendEvent(name: "thermostatFanMode", value: "fanAuto")
sendEvent(name: "thermostatOperatingState", value: "idle")
sendEvent(name: "humidity", value: 53, unit: "%")
}
def parse(String description) {
}
def evaluate(temp, heatingSetpoint, coolingSetpoint) {
log.debug "evaluate($temp, $heatingSetpoint, $coolingSetpoint"
def threshold = 1.0
def current = device.currentValue("thermostatOperatingState")
def mode = device.currentValue("thermostatMode")
def heating = false
def cooling = false
def idle = false
if (mode in ["heat","emergency heat","auto"]) {
if (heatingSetpoint - temp >= threshold) {
heating = true
sendEvent(name: "thermostatOperatingState", value: "heating")
}
else if (temp - heatingSetpoint >= threshold) {
idle = true
}
sendEvent(name: "thermostatSetpoint", value: heatingSetpoint)
}
if (mode in ["cool","auto"]) {
if (temp - coolingSetpoint >= threshold) {
cooling = true
sendEvent(name: "thermostatOperatingState", value: "cooling")
}
else if (coolingSetpoint - temp >= threshold && !heating) {
idle = true
}
sendEvent(name: "thermostatSetpoint", value: coolingSetpoint)
}
else {
sendEvent(name: "thermostatSetpoint", value: heatingSetpoint)
}
if (mode == "off") {
idle = true
}
if (idle && !heating && !cooling) {
sendEvent(name: "thermostatOperatingState", value: "idle")
}
}
def setHeatingSetpoint(Double degreesF) {
log.debug "setHeatingSetpoint($degreesF)"
sendEvent(name: "heatingSetpoint", value: degreesF)
evaluate(device.currentValue("temperature"), degreesF, device.currentValue("coolingSetpoint"))
}
def setCoolingSetpoint(Double degreesF) {
log.debug "setCoolingSetpoint($degreesF)"
sendEvent(name: "coolingSetpoint", value: degreesF)
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), degreesF)
}
def setThermostatMode(String value) {
sendEvent(name: "thermostatMode", value: value)
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def setThermostatFanMode(String value) {
sendEvent(name: "thermostatFanMode", value: value)
}
def off() {
sendEvent(name: "thermostatMode", value: "off")
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def heat() {
sendEvent(name: "thermostatMode", value: "heat")
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def auto() {
sendEvent(name: "thermostatMode", value: "auto")
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def emergencyHeat() {
sendEvent(name: "thermostatMode", value: "emergency heat")
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def cool() {
sendEvent(name: "thermostatMode", value: "cool")
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def fanOn() {
sendEvent(name: "thermostatFanMode", value: "fanOn")
}
def fanAuto() {
sendEvent(name: "thermostatFanMode", value: "fanAuto")
}
def fanCirculate() {
sendEvent(name: "thermostatFanMode", value: "fanCirculate")
}
def poll() {
null
}
def tempUp() {
def ts = device.currentState("temperature")
def value = ts ? ts.integerValue + 1 : 72
sendEvent(name:"temperature", value: value)
evaluate(value, device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def tempDown() {
def ts = device.currentState("temperature")
def value = ts ? ts.integerValue - 1 : 72
sendEvent(name:"temperature", value: value)
evaluate(value, device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def setTemperature(value) {
def ts = device.currentState("temperature")
sendEvent(name:"temperature", value: value)
evaluate(value, device.currentValue("heatingSetpoint"), device.currentValue("coolingSetpoint"))
}
def heatUp() {
def ts = device.currentState("heatingSetpoint")
def value = ts ? ts.integerValue + 1 : 68
sendEvent(name:"heatingSetpoint", value: value)
evaluate(device.currentValue("temperature"), value, device.currentValue("coolingSetpoint"))
}
def heatDown() {
def ts = device.currentState("heatingSetpoint")
def value = ts ? ts.integerValue - 1 : 68
sendEvent(name:"heatingSetpoint", value: value)
evaluate(device.currentValue("temperature"), value, device.currentValue("coolingSetpoint"))
}
def coolUp() {
def ts = device.currentState("coolingSetpoint")
def value = ts ? ts.integerValue + 1 : 76
sendEvent(name:"coolingSetpoint", value: value)
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), value)
}
def coolDown() {
def ts = device.currentState("coolingSetpoint")
def value = ts ? ts.integerValue - 1 : 76
sendEvent(name:"coolingSetpoint", value: value)
evaluate(device.currentValue("temperature"), device.currentValue("heatingSetpoint"), value)
}

View File

@@ -1,169 +0,0 @@
/**
* Copyright 2016 SmartThings, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (
name: "videoPlayerDeviceTile",
namespace: "smartthings/tile-ux",
author: "SmartThings") {
capability "Configuration"
capability "Video Camera"
capability "Video Capture"
capability "Refresh"
capability "Switch"
// custom commands
command "start"
command "stop"
command "setProfileHD"
command "setProfileSDH"
command "setProfileSDL"
}
tiles(scale: 2) {
multiAttributeTile(name: "videoPlayer", type: "videoPlayer", width: 6, height: 4) {
tileAttribute("device.switch", key: "CAMERA_STATUS") {
attributeState("on", label: "Active", icon: "st.camera.dlink-indoor", action: "switch.off", backgroundColor: "#79b821", defaultState: true)
attributeState("off", label: "Inactive", icon: "st.camera.dlink-indoor", action: "switch.on", backgroundColor: "#ffffff")
attributeState("restarting", label: "Connecting", icon: "st.camera.dlink-indoor", backgroundColor: "#53a7c0")
attributeState("unavailable", label: "Unavailable", icon: "st.camera.dlink-indoor", action: "refresh.refresh", backgroundColor: "#F22000")
}
tileAttribute("device.errorMessage", key: "CAMERA_ERROR_MESSAGE") {
attributeState("errorMessage", label: "", value: "", defaultState: true)
}
tileAttribute("device.camera", key: "PRIMARY_CONTROL") {
attributeState("on", label: "Active", icon: "st.camera.dlink-indoor", backgroundColor: "#79b821", defaultState: true)
attributeState("off", label: "Inactive", icon: "st.camera.dlink-indoor", backgroundColor: "#ffffff")
attributeState("restarting", label: "Connecting", icon: "st.camera.dlink-indoor", backgroundColor: "#53a7c0")
attributeState("unavailable", label: "Unavailable", icon: "st.camera.dlink-indoor", backgroundColor: "#F22000")
}
tileAttribute("device.startLive", key: "START_LIVE") {
attributeState("live", action: "start", defaultState: true)
}
tileAttribute("device.stream", key: "STREAM_URL") {
attributeState("activeURL", defaultState: true)
}
tileAttribute("device.profile", key: "STREAM_QUALITY") {
attributeState("1", label: "720p", action: "setProfileHD", defaultState: true)
attributeState("2", label: "h360p", action: "setProfileSDH", defaultState: true)
attributeState("3", label: "l360p", action: "setProfileSDL", defaultState: true)
}
tileAttribute("device.betaLogo", key: "BETA_LOGO") {
attributeState("betaLogo", label: "", value: "", defaultState: true)
}
}
multiAttributeTile(name: "videoPlayerMin", type: "videoPlayer", width: 6, height: 4) {
tileAttribute("device.switch", key: "CAMERA_STATUS") {
attributeState("on", label: "Active", icon: "st.camera.dlink-indoor", action: "switch.off", backgroundColor: "#79b821", defaultState: true)
attributeState("off", label: "Inactive", icon: "st.camera.dlink-indoor", action: "switch.on", backgroundColor: "#ffffff")
attributeState("restarting", label: "Connecting", icon: "st.camera.dlink-indoor", backgroundColor: "#53a7c0")
attributeState("unavailable", label: "Unavailable", icon: "st.camera.dlink-indoor", action: "refresh.refresh", backgroundColor: "#F22000")
}
tileAttribute("device.errorMessage", key: "CAMERA_ERROR_MESSAGE") {
attributeState("errorMessage", label: "", value: "", defaultState: true)
}
tileAttribute("device.camera", key: "PRIMARY_CONTROL") {
attributeState("on", label: "Active", icon: "st.camera.dlink-indoor", backgroundColor: "#79b821", defaultState: true)
attributeState("off", label: "Inactive", icon: "st.camera.dlink-indoor", backgroundColor: "#ffffff")
attributeState("restarting", label: "Connecting", icon: "st.camera.dlink-indoor", backgroundColor: "#53a7c0")
attributeState("unavailable", label: "Unavailable", icon: "st.camera.dlink-indoor", backgroundColor: "#F22000")
}
tileAttribute("device.startLive", key: "START_LIVE") {
attributeState("live", action: "start", defaultState: true)
}
tileAttribute("device.stream", key: "STREAM_URL") {
attributeState("activeURL", defaultState: true)
}
}
main("videoPlayer")
details([
"videoPlayer", "videoPlayerMin"
])
}
}
def installed() {
}
def parse(String description) {
}
def refresh() {
log.trace "refresh()"
// no-op
}
def on() {
log.trace "on()"
// no-op
}
def off() {
log.trace "off()"
// no-op
}
def setProfile(profile) {
log.trace "setProfile(): ${profile}"
sendEvent(name: "profile", value: profile, displayed: false)
}
def setProfileHD() {
setProfile(1)
}
def setProfileSDH() {
setProfile(2)
}
def setProfileSDL() {
setProfile(3)
}
def start() {
log.trace "start()"
def dataLiveVideo = [
OutHomeURL : "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8",
InHomeURL : "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8",
ThumbnailURL: "http://cdn.device-icons.smartthings.com/camera/dlink-indoor@2x.png",
cookie : [key: "key", value: "value"]
]
def event = [
name : "stream",
value : groovy.json.JsonOutput.toJson(dataLiveVideo).toString(),
data : groovy.json.JsonOutput.toJson(dataLiveVideo),
descriptionText: "Starting the livestream",
eventType : "VIDEO",
displayed : false,
isStateChange : true
]
sendEvent(event)
}
def stop() {
log.trace "stop()"
}

View File

@@ -1,194 +0,0 @@
/**
* Iris Smart Fob
*
* Copyright 2015 Mitch Pond
* Presence code adapted from SmartThings Arrival Sensor HA device type
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "ZigBee Button", namespace: "smartthings", author: "Mitch Pond") {
capability "Battery"
capability "Button"
capability "Configuration"
capability "Presence Sensor"
capability "Sensor"
//fingerprint endpointId: "01", profileId: "0104", inClusters: "0000,0001,0003,0007,0020,0B05", outClusters: "0003,0006,0019", model:"3450-L", manufacturer: "CentraLite"
}
preferences{
input ("holdTime", "number", title: "Minimum time in seconds for a press to count as \"held\"",
defaultValue: 3, displayDuringSetup: false)
input "checkInterval", "enum", title: "Presence timeout (minutes)",
defaultValue:"2", options: ["2", "3", "5"], displayDuringSetup: false
input "logging", "bool", title: "Enable debug logging",
defaultValue: false, displayDuringSetup: false
}
tiles(scale: 2) {
standardTile("presence", "device.presence", width: 4, height: 4, canChangeBackground: true) {
state "present", label: "Present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff"
}
standardTile("button", "device.button", decoration: "flat", width: 2, height: 2) {
state "default", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff"
}
valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
main (["presence"])
details(["presence","button","battery"])
}
}
def parse(String description) {
def descMap = zigbee.parseDescriptionAsMap(description)
logIt descMap
state.lastCheckin = now()
logIt "lastCheckin = ${state.lastCheckin}"
handlePresenceEvent(true)
def results = []
if (description?.startsWith('catchall:'))
results = parseCatchAllMessage(descMap)
else if (description?.startsWith('read attr -'))
results = parseReportAttributeMessage(descMap)
else logIt(descMap, "trace")
return results;
}
def updated() {
startTimer()
configure()
}
def configure(){
logIt "Configuring Smart Fob..."
[
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 2 1 6 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 3 1 6 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 4 1 6 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}", "delay 200"
] +
zigbee.configureReporting(0x0001,0x0020,0x20,20,20,0x01)
}
def parseCatchAllMessage(descMap) {
if (descMap?.clusterId == "0006" && descMap?.command == "01") //button pressed
handleButtonPress(descMap.sourceEndpoint as int)
else if (descMap?.clusterId == "0006" && descMap?.command == "00") //button released
handleButtonRelease(descMap.sourceEndpoint as int)
else logIt("Parse: Unhandled message: ${descMap}","trace")
}
def parseReportAttributeMessage(descMap) {
if (descMap?.cluster == "0001" && descMap?.attrId == "0020") createBatteryEvent(getBatteryLevel(descMap.value))
else logIt descMap
}
private createBatteryEvent(percent) {
logIt "Battery level at " + percent
return createEvent([name: "battery", value: percent])
}
//this method determines if a press should count as a push or a hold and returns the relevant event type
private handleButtonRelease(button) {
logIt "lastPress state variable: ${state.lastPress}"
def sequenceError = {logIt("Uh oh...missed a message? Dropping this event.", "error"); state.lastPress = null; return []}
if (!state.lastPress) return sequenceError()
else if (state.lastPress.button != button) return sequenceError()
def currentTime = now()
def startOfPress = state.lastPress?.time
def timeDif = currentTime - startOfPress
def holdTimeMillisec = (settings.holdTime?:3).toInteger() * 1000
state.lastPress = null //we're done with this. clear it to make error conditions easier to catch
if (timeDif < 0)
//likely a message sequence issue or dropped packet. Drop this press and wait for another.
return sequenceError()
else if (timeDif < holdTimeMillisec)
return createButtonEvent(button,"pushed")
else
return createButtonEvent(button,"held")
}
private handleButtonPress(button) {
state.lastPress = [button: button, time: now()]
}
private createButtonEvent(button,action) {
logIt "Button ${button} ${action}"
return createEvent([
name: "button",
value: action,
data:[buttonNumber: button],
descriptionText: "${device.displayName} button ${button} was ${action}",
isStateChange: true,
displayed: true])
}
private getBatteryLevel(rawValue) {
def intValue = Integer.parseInt(rawValue,16)
def min = 2.1
def max = 3.0
def vBatt = intValue / 10
return ((vBatt - min) / (max - min) * 100) as int
}
private handlePresenceEvent(present) {
def wasPresent = device.currentState("presence")?.value == "present"
if (!wasPresent && present) {
logIt "Sensor is present"
startTimer()
} else if (!present) {
logIt "Sensor is not present"
stopTimer()
}
def linkText = getLinkText(device)
def eventMap = [
name: "presence",
value: present ? "present" : "not present",
linkText: linkText,
descriptionText: "${linkText} has ${present ? 'arrived' : 'left'}",
]
logIt "Creating presence event: ${eventMap}"
sendEvent(eventMap)
}
private startTimer() {
logIt "Scheduling periodic timer"
schedule("0 * * * * ?", checkPresenceCallback)
}
private stopTimer() {
logIt "Stopping periodic timer"
unschedule()
}
def checkPresenceCallback() {
def timeSinceLastCheckin = (now() - state.lastCheckin) / 1000
def theCheckInterval = (checkInterval ? checkInterval as int : 2) * 60
logIt "Sensor checked in ${timeSinceLastCheckin} seconds ago"
if (timeSinceLastCheckin >= theCheckInterval) {
handlePresenceEvent(false)
}
}
// ****** Utility functions ******
private logIt(str, logLevel = 'debug') {if (settings.logging) log."$logLevel"(str) }

View File

@@ -56,17 +56,21 @@ metadata {
def parse(String description) {
log.debug "description is $description"
def event = zigbee.getEvent(description)
if (event) {
log.info event
if (event.name == "power") {
def resultMap = zigbee.getKnownDescription(description)
if (resultMap) {
log.info resultMap
if (resultMap.type == "update") {
log.info "$device updates: ${resultMap.value}"
}
else if (resultMap.type == "power") {
def powerValue
if (device.getDataValue("manufacturer") != "OSRAM") { //OSRAM devices do not reliably update power
event.value = (event.value as Integer) / 10 //TODO: The divisor value needs to be set as part of configuration
sendEvent(event)
powerValue = (resultMap.value as Integer)/10 //TODO: The divisor value needs to be set as part of configuration
sendEvent(name: "power", value: powerValue)
}
}
else {
sendEvent(event)
sendEvent(name: resultMap.type, value: resultMap.value)
}
}
else {

View File

@@ -51,9 +51,15 @@ metadata {
def parse(String description) {
log.debug "description is $description"
def event = zigbee.getEvent(description)
if (event) {
sendEvent(event)
def resultMap = zigbee.getKnownDescription(description)
if (resultMap) {
log.info resultMap
if (resultMap.type == "update") {
log.info "$device updates: ${resultMap.value}"
}
else {
sendEvent(name: resultMap.type, value: resultMap.value)
}
}
else {
log.warn "DID NOT PARSE MESSAGE for description : $description"

View File

@@ -83,19 +83,32 @@ def uninstalled() {
}
def configure() {
/*
def cmds =
zigbee.configureReporting(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE,
TYPE_ENUM8, 0, 3600, null) +
zigbee.configureReporting(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING,
TYPE_U8, 600, 21600, 0x01)
zigbee.configSetup("${CLUSTER_DOORLOCK}", "${DOORLOCK_ATTR_LOCKSTATE}",
"${TYPE_ENUM8}", 0, 3600, "{01}") +
zigbee.configSetup("${CLUSTER_POWER}", "${POWER_ATTR_BATTERY_PERCENTAGE_REMAINING}",
"${TYPE_U8}", 600, 21600, "{01}")
*/
def zigbeeId = device.zigbeeId
def cmds =
[
"zdo bind 0x${device.deviceNetworkId} 0x${device.endpointId} 1 ${CLUSTER_DOORLOCK} {$zigbeeId} {}", "delay 200",
"zcl global send-me-a-report ${CLUSTER_DOORLOCK} ${DOORLOCK_ATTR_LOCKSTATE} ${TYPE_ENUM8} 0 3600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 0x${device.endpointId}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 0x${device.endpointId} 1 ${CLUSTER_POWER} {$zigbeeId} {}", "delay 200",
"zcl global send-me-a-report ${CLUSTER_POWER} ${POWER_ATTR_BATTERY_PERCENTAGE_REMAINING} ${TYPE_U8} 600 21600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 0x${device.endpointId}", "delay 200",
]
log.info "configure() --- cmds: $cmds"
return cmds + refresh() // send refresh cmds as part of config
}
def refresh() {
def cmds =
zigbee.readAttribute(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE) +
zigbee.readAttribute(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING)
zigbee.refreshData("${CLUSTER_DOORLOCK}", "${DOORLOCK_ATTR_LOCKSTATE}") +
zigbee.refreshData("${CLUSTER_POWER}", "${POWER_ATTR_BATTERY_PERCENTAGE_REMAINING}")
log.info "refresh() --- cmds: $cmds"
return cmds
}
@@ -108,27 +121,34 @@ def parse(String description) {
map = parseReportAttributeMessage(description)
}
log.debug "parse() --- Parse returned $map"
def result = map ? createEvent(map) : null
log.debug "parse() --- returned: $result"
return result
}
// Lock capability commands
def lock() {
def cmds = zigbee.command(CLUSTER_DOORLOCK, DOORLOCK_CMD_LOCK_DOOR)
log.info "lock() -- cmds: $cmds"
return cmds
//def cmds = zigbee.zigbeeCommand("${CLUSTER_DOORLOCK}", "${DOORLOCK_CMD_LOCK_DOOR}", "{}")
//log.info "lock() -- cmds: $cmds"
//return cmds
"st cmd 0x${device.deviceNetworkId} 0x${device.endpointId} ${CLUSTER_DOORLOCK} ${DOORLOCK_CMD_LOCK_DOOR} {}"
}
def unlock() {
def cmds = zigbee.command(CLUSTER_DOORLOCK, DOORLOCK_CMD_UNLOCK_DOOR)
log.info "unlock() -- cmds: $cmds"
return cmds
//def cmds = zigbee.zigbeeCommand("${CLUSTER_DOORLOCK}", "${DOORLOCK_CMD_UNLOCK_DOOR}", "{}")
//log.info "unlock() -- cmds: $cmds"
//return cmds
"st cmd 0x${device.deviceNetworkId} 0x${device.endpointId} ${CLUSTER_DOORLOCK} ${DOORLOCK_CMD_UNLOCK_DOOR} {}"
}
// Private methods
private Map parseReportAttributeMessage(String description) {
log.trace "parseReportAttributeMessage() --- description: $description"
Map descMap = zigbee.parseDescriptionAsMap(description)
log.debug "parseReportAttributeMessage() --- descMap: $descMap"
Map resultMap = [:]
if (descMap.clusterInt == CLUSTER_POWER && descMap.attrInt == POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) {
resultMap.name = "battery"
@@ -136,24 +156,18 @@ private Map parseReportAttributeMessage(String description) {
if (device.getDataValue("manufacturer") == "Yale") { //Handling issue with Yale locks incorrect battery reporting
resultMap.value = Integer.parseInt(descMap.value, 16)
}
log.info "parseReportAttributeMessage() --- battery: ${resultMap.value}"
}
else if (descMap.clusterInt == CLUSTER_DOORLOCK && descMap.attrInt == DOORLOCK_ATTR_LOCKSTATE) {
def value = Integer.parseInt(descMap.value, 16)
def linkText = getLinkText(device)
resultMap.name = "lock"
if (value == 0) {
resultMap.value = "unknown"
resultMap.descriptionText = "${linkText} is not fully locked"
} else if (value == 1) {
resultMap.value = "locked"
resultMap.descriptionText = "${linkText} is locked"
} else if (value == 2) {
resultMap.value = "unlocked"
resultMap.descriptionText = "${linkText} is unlocked"
} else {
resultMap.value = "unknown"
resultMap.descriptionText = "${linkText} is in unknown lock state"
}
resultMap.putAll([0:["value":"unknown",
"descriptionText":"Not fully locked"],
1:["value":"locked"],
2:["value":"unlocked"]].get(value,
["value":"unknown",
"descriptionText":"Unknown lock state"]))
log.info "parseReportAttributeMessage() --- lock: ${resultMap.value}"
}
else {
log.debug "parseReportAttributeMessage() --- ignoring attribute"

View File

@@ -51,15 +51,22 @@ metadata {
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
def event = zigbee.getEvent(description)
if (event) {
if (event.name == "power") {
def resultMap = zigbee.getKnownDescription(description)
if (resultMap) {
log.info resultMap
if (resultMap.type == "update") {
log.info "$device updates: ${resultMap.value}"
}
else if (resultMap.type == "power") {
def powerValue
powerValue = (event.value as Integer)/10 //TODO: The divisor value needs to be set as part of configuration
sendEvent(name: "power", value: powerValue)
if (device.getDataValue("manufacturer") != "OSRAM") { //OSRAM devices do not reliably update power
powerValue = (resultMap.value as Integer)/10 //TODO: The divisor value needs to be set as part of configuration
sendEvent(name: "power", value: powerValue)
}
}
else {
sendEvent(event)
sendEvent(name: resultMap.type, value: resultMap.value)
}
}
else {

View File

@@ -53,9 +53,16 @@ metadata {
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
def event = zigbee.getEvent(description)
if (event) {
sendEvent(event)
def resultMap = zigbee.getKnownDescription(description)
if (resultMap) {
log.info resultMap
if (resultMap.type == "update") {
log.info "$device updates: ${resultMap.value}"
}
else {
sendEvent(name: resultMap.type, value: resultMap.value)
}
}
else {
log.warn "DID NOT PARSE MESSAGE for description : $description"

View File

@@ -73,9 +73,16 @@ metadata {
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
def event = zigbee.getEvent(description)
if (event) {
sendEvent(event)
def finalResult = zigbee.getKnownDescription(description)
if (finalResult) {
log.info finalResult
if (finalResult.type == "update") {
log.info "$device updates: ${finalResult.value}"
}
else {
sendEvent(name: finalResult.type, value: finalResult.value)
}
}
else {
log.warn "DID NOT PARSE MESSAGE for description : $description"

View File

@@ -245,7 +245,6 @@ def retypeBasedOnMSR() {
break
case "011F-0001-0001": // Schlage motion
case "014A-0001-0001": // Ecolink motion
case "014A-0004-0001": // Ecolink motion +
case "0060-0001-0002": // Everspring SP814
case "0060-0001-0003": // Everspring HSP02
case "011A-0601-0901": // Enerwave ZWN-BPC

View File

@@ -51,4 +51,4 @@ def changedLocationMode(evt) {
def appTouch(evt) {
log.debug "appTouch: $evt"
switches?.off()
}
}

View File

@@ -161,7 +161,7 @@ private sendDeveloperReq() {
headers: [
HOST: host
],
body: [devicetype: "$token-0"]], "${selectedHue}"))
body: [devicetype: "$token-0", username: "$token-0"]], "${selectedHue}"))
}
private discoverHueBulbs() {
@@ -289,7 +289,7 @@ def bulbListHandler(hub, data = "") {
def object = new groovy.json.JsonSlurper().parseText(data)
object.each { k,v ->
if (v instanceof Map)
bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:hub]
bulbs[k] = [id: k, name: v.name, type: v.type, hub:hub]
}
}
def bridge = null
@@ -300,40 +300,6 @@ def bulbListHandler(hub, data = "") {
return msg
}
private upgradeDeviceType(device, newHueType) {
def deviceType = getDeviceType(newHueType)
// Automatically change users Hue bulbs to correct device types
if (deviceType && !(device?.typeName?.equalsIgnoreCase(deviceType))) {
log.debug "Update device type: \"$device.label\" ${device?.typeName}->$deviceType"
device.setDeviceType(deviceType)
}
}
private getDeviceType(hueType) {
// Determine ST device type based on Hue classification of light
if (hueType?.equalsIgnoreCase("Dimmable light"))
return "Hue Lux Bulb"
else if (hueType?.equalsIgnoreCase("Extended Color Light"))
return "Hue Bulb"
else if (hueType?.equalsIgnoreCase("Color Light"))
return "Hue Bloom"
else
return null
}
private addChildBulb(dni, hueType, name, hub, update=false, device = null) {
def deviceType = getDeviceType(hueType)
if (deviceType) {
return addChildDevice("smartthings", deviceType, dni, hub, ["label": name])
}
else {
log.warn "Device type $hueType not supported"
return null
}
}
def addBulbs() {
def bulbs = getHueBulbs()
selectedBulbs?.each { dni ->
@@ -343,7 +309,11 @@ def addBulbs() {
if (bulbs instanceof java.util.Map) {
newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni }
if (newHueBulb != null) {
d = addChildBulb(dni, newHueBulb?.value?.type, newHueBulb?.value?.name, newHueBulb?.value?.hub)
if (newHueBulb?.value?.type?.equalsIgnoreCase("Dimmable light") ) {
d = addChildDevice("smartthings", "Hue Lux Bulb", dni, newHueBulb?.value.hub, ["label":newHueBulb?.value.name])
} else {
d = addChildDevice("smartthings", "Hue Bulb", dni, newHueBulb?.value.hub, ["label":newHueBulb?.value.name])
}
log.debug "created ${d.displayName} with id $dni"
d.refresh()
} else {
@@ -352,15 +322,16 @@ def addBulbs() {
} else {
//backwards compatable
newHueBulb = bulbs.find { (app.id + "/" + it.id) == dni }
d = addChildBulb(dni, "Extended Color Light", newHueBulb?.value?.name, newHueBulb?.value?.hub)
d = addChildDevice("smartthings", "Hue Bulb", dni, newHueBulb?.hub, ["label":newHueBulb?.name])
d.refresh()
}
} else {
log.debug "found ${d.displayName} with id $dni already exists, type: '$d.typeName'"
if (bulbs instanceof java.util.Map) {
// Update device type if incorrect
def newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni }
upgradeDeviceType(d, newHueBulb?.value?.type)
if (newHueBulb?.value?.type?.equalsIgnoreCase("Dimmable light") && d.typeName == "Hue Bulb") {
d.setDeviceType("Hue Lux Bulb")
}
}
}
}
@@ -502,7 +473,7 @@ def locationHandler(evt) {
def bulbs = getHueBulbs()
log.debug "Adding bulbs to state!"
body.each { k,v ->
bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:parsedEvent.hub]
bulbs[k] = [id: k, name: v.name, type: v.type, hub:parsedEvent.hub]
}
}
}
@@ -686,53 +657,39 @@ def setColorTemperature(childDevice, huesettings) {
}
def setColor(childDevice, huesettings) {
log.debug "Executing 'setColor($huesettings)'"
def value = [:]
log.debug "Executing 'setColor($huesettings)'"
def hue = null
def sat = null
def xy = null
if (huesettings.hex != null) {
value.xy = getHextoXY(huesettings.hex)
} else {
if (huesettings.hue != null)
value.hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
if (huesettings.saturation != null)
value.sat = Math.min(Math.round(huesettings.saturation * 255 / 100), 255)
if (huesettings.hex) {
xy = getHextoXY(huesettings.hex)
} else if (huesettings.hue && huesettings.saturation) {
hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
sat = Math.min(Math.round(huesettings.saturation * 255 / 100), 255)
}
// Default behavior is to turn light on
value.on = true
def alert = huesettings.alert ? huesettings.alert : "none"
def transition = huesettings.transition ? huesettings.transition : 4
if (huesettings.level != null) {
if (huesettings.level <= 0)
value.on = false
else if (huesettings.level == 1)
value.bri = 1
else
value.bri = Math.min(Math.round(huesettings.level * 255 / 100), 255)
}
value.alert = huesettings.alert ? huesettings.alert : "none"
value.transition = huesettings.transition ? huesettings.transition : 4
def value = [xy: xy, sat: sat, hue: hue, alert: alert, transitiontime: transition, on: true]
// Make sure to turn off light if requested
if (huesettings.switch == "off")
value.on = false
if (huesettings.level != null) {
if (huesettings.level == 1) value.bri = 1 else value.bri = Math.min(Math.round(huesettings.level * 255 / 100), 255)
value.on = value.bri > 0
}
log.debug "sending command $value"
put("lights/${getId(childDevice)}/state", value)
return "Color set to $value"
log.debug "sending command $value"
put("lights/${getId(childDevice)}/state", value)
}
def nextLevel(childDevice) {
def level = device.latestValue("level") as Integer ?: 0
if (level < 100) {
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
} else {
level = 25
}
setLevel(childDevice,level)
def level = device.latestValue("level") as Integer ?: 0
if (level < 100) {
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
}
else {
level = 25
}
setLevel(childDevice,level)
}
private getId(childDevice) {
@@ -831,14 +788,16 @@ private getHextoXY(String colorStr) {
// Make green more vivid
if (normalizedToOne[1] > 0.04045) {
green = (float) Math.pow((normalizedToOne[1] + 0.055) / (1.0 + 0.055), 2.4);
green = (float) Math.pow((normalizedToOne[1] + 0.055)
/ (1.0 + 0.055), 2.4);
} else {
green = (float) (normalizedToOne[1] / 12.92);
}
// Make blue more vivid
if (normalizedToOne[2] > 0.04045) {
blue = (float) Math.pow((normalizedToOne[2] + 0.055) / (1.0 + 0.055), 2.4);
blue = (float) Math.pow((normalizedToOne[2] + 0.055)
/ (1.0 + 0.055), 2.4);
} else {
blue = (float) (normalizedToOne[2] / 12.92);
}
@@ -847,8 +806,8 @@ private getHextoXY(String colorStr) {
float Y = (float) (red * 0.234327 + green * 0.743075 + blue * 0.022598);
float Z = (float) (red * 0.0000000 + green * 0.053077 + blue * 1.035763);
float x = (X != 0 ? X / (X + Y + Z) : 0);
float y = (Y != 0 ? Y / (X + Y + Z) : 0);
float x = X / (X + Y + Z);
float y = Y / (X + Y + Z);
double[] xy = new double[2];
xy[0] = x;
@@ -865,7 +824,7 @@ def convertBulbListToMap() {
if (state.bulbs instanceof java.util.List) {
def map = [:]
state.bulbs.unique {it.id}.each { bulb ->
map << ["${bulb.id}":["id":bulb.id, "name":bulb.name, "type": bulb.type, "modelid": bulb.modelid, "hub":bulb.hub]]
map << ["${bulb.id}":["id":bulb.id, "name":bulb.name, "hub":bulb.hub]]
}
state.bulbs = map
}

View File

@@ -23,9 +23,9 @@
'''Minimum time between messages (optional, defaults to every message)'''.ko=메시지 전송 간격 설정
'''If outside the US please make sure to enter the proper country code'''.ko=미국 이외 국가에 거주한다면 국가 코드와 함께 입력하여 주세요.
'''Water Sensor Wet'''.ko=누수가 감지되었을 때
'''{{ triggerEvent.linkText }} has arrived at the {{ location.name }}'''.ko={{ location.name }}에 {{ triggerEvent.linkText }} 귀가
'''{{ triggerEvent.linkText }} has arrived at {{ location.name }}'''.ko={{ location.name }}에 {{ triggerEvent.linkText }} 귀가
'''{{ triggerEvent.linkText }} has left the {{ location.name }}'''.ko={{ location.name }}에서 {{ triggerEvent.linkText }} 외출
'''{{ triggerEvent.linkText }} has left {{ location.name }}'''.ko={{ location.name }}에서 {{ triggerEvent.linkText }} 외출
'''{{ triggerEvent.linkText }} has arrived at the {{ location.name }}'''.ko={{ triggerEvent.linkText }}님이 {{ location.name }}에 도착했습니다
'''{{ triggerEvent.linkText }} has arrived at {{ location.name }}'''.ko={{ triggerEvent.linkText }}님이 {{ location.name }}에 도착했습니다
'''{{ triggerEvent.linkText }} has left the {{ location.name }}'''.ko={{ triggerEvent.linkText }}님이 {{ location.name }}을(를) 떠났습니다
'''{{ triggerEvent.linkText }} has left {{ location.name }}'''.ko={{ triggerEvent.linkText }}님이 {{ location.name }}을(를) 떠났습니다
'''Assign a name'''.ko=이름 설정
'''Choose Modes'''.ko=상태 선택

View File

@@ -1,107 +0,0 @@
/**
* Device Tile Controller
*
* 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.
*
*/
definition(
name: "Device Tile Controller",
namespace: "smartthings/tile-ux",
author: "SmartThings",
description: "A controller SmartApp to install virtual devices into your location in order to simulate various native Device Tiles.",
category: "SmartThings Internal",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
singleInstance: true)
preferences {
// landing page
page(name: "defaultPage")
}
def defaultPage() {
dynamicPage(name: "defaultPage", install: true, uninstall: true) {
section {
paragraph "Select on Unselect the devices that you want to install"
}
section(title: "Multi Attribute Tile Types") {
input(type: "bool", name: "genericDeviceTile", title: "generic", description: "A device that showcases the various use of generic multi-attribute-tiles.", defaultValue: "false")
input(type: "bool", name: "lightingDeviceTile", title: "lighting", description: "A device that showcases the various use of lighting multi-attribute-tiles.", defaultValue: "false")
input(type: "bool", name: "thermostatDeviceTile", title: "thermostat", description: "A device that showcases the various use of thermostat multi-attribute-tiles.", defaultValue: "true")
input(type: "bool", name: "mediaPlayerDeviceTile", title: "media player", description: "A device that showcases the various use of mediaPlayer multi-attribute-tiles.", defaultValue: "false")
input(type: "bool", name: "videoPlayerDeviceTile", title: "video player", description: "A device that showcases the various use of videoPlayer multi-attribute-tiles.", defaultValue: "false")
}
section(title: "Device Tile Types") {
input(type: "bool", name: "standardDeviceTile", title: "standard device tiles", description: "A device that showcases the various use of standard device tiles.", defaultValue: "false")
input(type: "bool", name: "valueDeviceTile", title: "value device tiles", description: "A device that showcases the various use of value device tiles.", defaultValue: "false")
input(type: "bool", name: "presenceDeviceTile", title: "presence device tiles", description: "A device that showcases the various use of color control device tile.", defaultValue: "false")
}
section(title: "Other Tile Types") {
input(type: "bool", name: "carouselDeviceTile", title: "image carousel", description: "A device that showcases the various use of carousel device tile.", defaultValue: "false")
input(type: "bool", name: "sliderDeviceTile", title: "slider", description: "A device that showcases the various use of slider device tile.", defaultValue: "false")
input(type: "bool", name: "colorWheelDeviceTile", title: "color wheel", description: "A device that showcases the various use of color wheel device tile.", defaultValue: "false")
}
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
}
def uninstalled() {
getChildDevices().each {
deleteChildDevice(it.deviceNetworkId)
}
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initializeDevices()
}
def initializeDevices() {
settings.each { key, value ->
log.debug "$key : $value"
def existingDevice = getChildDevices().find { it.name == key }
log.debug "$existingDevice"
if (existingDevice && !value) {
deleteChildDevice(existingDevice.deviceNetworkId)
} else if (!existingDevice && value) {
String dni = UUID.randomUUID()
log.debug "$dni"
addChildDevice(app.namespace, key, dni, null, [
label: labelMap()[key] ?: key,
completedSetup: true
])
}
}
}
// Map the name of the Device to a proper Label
def labelMap() {
[
genericDeviceTile: "Tile Multiattribute Generic",
lightingDeviceTile: "Tile Multiattribute Lighting",
thermostatDeviceTile: "Tile Multiattribute Thermostat",
mediaPlayerDeviceTile: "Tile Multiattribute Media Player",
videoPlayerDeviceTile: "Tile Multiattribute Video Player",
standardDeviceTile: "Tile Device Standard",
valueDeviceTile: "Tile Device Value",
presenceDeviceTile: "Tile Device Presence",
carouselDeviceTile: "Tile Device Carousel",
sliderDeviceTile: "Tile Device Slider",
colorWheelDeviceTile: "Tile Device Color Wheel"
]
}

View File

@@ -40,7 +40,6 @@ preferences {
page name:"pageSetup"
page name:"Setup"
page name:"Settings"
page name: "timeIntervalInput"
}
@@ -186,8 +185,7 @@ def Settings() {
}
}
def timeIntervalInput() {
dynamicPage(name: "timeIntervalInput") {
page(name: "timeIntervalInput", title: "Only during a certain time", refreshAfterSelection:true) {
section {
input "startTimeType", "enum", title: "Starting at", options: [["time": "A specific time"], ["sunrise": "Sunrise"], ["sunset": "Sunset"]], defaultValue: "time", submitOnChange: true
if (startTimeType in ["sunrise","sunset"]) {
@@ -206,10 +204,9 @@ def timeIntervalInput() {
input "ending", "time", title: "End time", required: false
}
}
}
}
def installed() {
initialize()
}