mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-22 13:20:53 +00:00
Compare commits
1 Commits
MSA-1312-1
...
MSA-1306-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45a43c140e |
294
devicetypes/smartthings/-.src/-.groovy
Normal file
294
devicetypes/smartthings/-.src/-.groovy
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2015 SmartThings
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
metadata {
|
||||||
|
definition (name: "재부재 센서", namespace: "smartthings", author: "김성훈") {
|
||||||
|
capability "Tone"
|
||||||
|
capability "Actuator"
|
||||||
|
capability "Signal Strength"
|
||||||
|
capability "Presence Sensor"
|
||||||
|
capability "Sensor"
|
||||||
|
capability "Battery"
|
||||||
|
|
||||||
|
fingerprint profileId: "FC01", deviceId: "019A"
|
||||||
|
fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000,0003", outClusters: "0003"
|
||||||
|
fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000", outClusters: "0006"
|
||||||
|
}
|
||||||
|
|
||||||
|
simulator {
|
||||||
|
status "present": "presence: 1"
|
||||||
|
status "not present": "presence: 0"
|
||||||
|
status "battery": "battery: 27, batteryDivisor: 0A, rssi: 100, lqi: 64"
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
section {
|
||||||
|
image(name: 'educationalcontent', multiple: true, images: [
|
||||||
|
"http://cdn.device-gse.smartthings.com/Arrival/Arrival1.jpg",
|
||||||
|
"http://cdn.device-gse.smartthings.com/Arrival/Arrival2.jpg"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tiles {
|
||||||
|
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
||||||
|
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
|
||||||
|
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ebeef2"
|
||||||
|
}
|
||||||
|
standardTile("beep", "device.beep", decoration: "flat") {
|
||||||
|
state "beep", label:'', action:"tone.beep", icon:"st.secondary.beep", backgroundColor:"#ffffff"
|
||||||
|
}
|
||||||
|
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) {
|
||||||
|
state "battery", label:'${currentValue}% battery', unit:""/*, backgroundColors:[
|
||||||
|
[value: 5, color: "#BC2323"],
|
||||||
|
[value: 10, color: "#D04E00"],
|
||||||
|
[value: 15, color: "#F1D801"],
|
||||||
|
[value: 16, color: "#FFFFFF"]
|
||||||
|
]*/
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
valueTile("lqi", "device.lqi", decoration: "flat", inactiveLabel: false) {
|
||||||
|
state "lqi", label:'${currentValue}% signal', unit:""
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
main "presence"
|
||||||
|
details(["presence", "beep", "battery"/*, "lqi"*/])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def beep() {
|
||||||
|
/*
|
||||||
|
You can make the speaker turn on for 0.5-second beeps by sending some CLI commands:
|
||||||
|
|
||||||
|
Command: send raw, wait 7, send raw, wait 7, send raw
|
||||||
|
Future: new packet type "st.beep"
|
||||||
|
|
||||||
|
raw 0xFC05 {15 0A 11 00 00 15 01}
|
||||||
|
send 0x2F7F 2 2
|
||||||
|
|
||||||
|
where "0xABCD" is the node ID of the Smart Tag, everything else above is a constant. Except
|
||||||
|
the "15 01" at the end of the first raw command, that sets the speaker's period (reciprocal
|
||||||
|
of frequency). You can play with this value up or down to experiment with loudness as the
|
||||||
|
loudness will be strongly dependent upon frequency and the enclosure that it's in. Note that
|
||||||
|
"15 01" represents the hex number 0x0115 so a lower frequency is "16 01" (longer period) and
|
||||||
|
a higher frequency is "14 01" (shorter period). Note that since the tag only checks its parent
|
||||||
|
for messages every 5 seconds (while at rest) or every 3 seconds (while in motion) it will take
|
||||||
|
up to this long from the time you send the message to the time you hear a sound.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[
|
||||||
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 7000",
|
||||||
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 7000",
|
||||||
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 7000",
|
||||||
|
"raw 0xFC05 {15 0A 11 00 00 15 01}",
|
||||||
|
"delay 7000",
|
||||||
|
"raw 0xFC05 {15 0A 11 00 00 15 01}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
def parse(String description) {
|
||||||
|
def results
|
||||||
|
if (isBatteryMessage(description)) {
|
||||||
|
results = parseBatteryMessage(description)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
results = parsePresenceMessage(description)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug "Parse returned $results.descriptionText"
|
||||||
|
results
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map parsePresenceMessage(String description) {
|
||||||
|
def name = parseName(description)
|
||||||
|
def value = parseValue(description)
|
||||||
|
def linkText = getLinkText(device)
|
||||||
|
def descriptionText = parseDescriptionText(linkText, value, description)
|
||||||
|
def handlerName = getState(value)
|
||||||
|
def isStateChange = isStateChange(device, name, value)
|
||||||
|
|
||||||
|
def results = [
|
||||||
|
name: name,
|
||||||
|
value: value,
|
||||||
|
unit: null,
|
||||||
|
linkText: linkText,
|
||||||
|
descriptionText: descriptionText,
|
||||||
|
handlerName: handlerName,
|
||||||
|
isStateChange: isStateChange,
|
||||||
|
displayed: displayed(description, isStateChange)
|
||||||
|
]
|
||||||
|
|
||||||
|
results
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseName(String description) {
|
||||||
|
if (description?.startsWith("presence: ")) {
|
||||||
|
return "presence"
|
||||||
|
}
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseValue(String description) {
|
||||||
|
if (description?.startsWith("presence: "))
|
||||||
|
{
|
||||||
|
if (description?.endsWith("1"))
|
||||||
|
{
|
||||||
|
return "present"
|
||||||
|
}
|
||||||
|
else if (description?.endsWith("0"))
|
||||||
|
{
|
||||||
|
return "not present"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
description
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseDescriptionText(String linkText, String value, String description) {
|
||||||
|
switch(value) {
|
||||||
|
case "present": return "$linkText has arrived"
|
||||||
|
case "not present": return "$linkText has left"
|
||||||
|
default: return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getState(String value) {
|
||||||
|
def state = value
|
||||||
|
if (value == "present") {
|
||||||
|
state = "arrived"
|
||||||
|
}
|
||||||
|
else if (value == "not present") {
|
||||||
|
state = "left"
|
||||||
|
}
|
||||||
|
|
||||||
|
state
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean isBatteryMessage(String description) {
|
||||||
|
// "raw:36EF1C, dni:36EF, battery:1B, rssi:, lqi:"
|
||||||
|
description ==~ /.*battery:.*rssi:.*lqi:.*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private List parseBatteryMessage(String description) {
|
||||||
|
def results = []
|
||||||
|
def parts = description.split(',')
|
||||||
|
parts.each { part ->
|
||||||
|
part = part.trim()
|
||||||
|
if (part.startsWith('battery:')) {
|
||||||
|
def batteryResult = getBatteryResult(part, description)
|
||||||
|
if (batteryResult) {
|
||||||
|
results << batteryResult
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (part.startsWith('rssi:')) {
|
||||||
|
def rssiResult = getRssiResult(part, description)
|
||||||
|
if (rssiResult) {
|
||||||
|
results << rssiResult
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (part.startsWith('lqi:')) {
|
||||||
|
def lqiResult = getLqiResult(part, description)
|
||||||
|
if (lqiResult) {
|
||||||
|
results << lqiResult
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
results
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
def unit = "%"
|
||||||
|
def linkText = getLinkText(device)
|
||||||
|
def descriptionText = "$linkText battery was ${value}${unit}"
|
||||||
|
def isStateChange = isStateChange(device, name, value)
|
||||||
|
|
||||||
|
[
|
||||||
|
name: name,
|
||||||
|
value: value,
|
||||||
|
unit: unit,
|
||||||
|
linkText: linkText,
|
||||||
|
descriptionText: descriptionText,
|
||||||
|
handlerName: name,
|
||||||
|
isStateChange: isStateChange,
|
||||||
|
//displayed: displayed(description, isStateChange)
|
||||||
|
displayed: false
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRssiResult(part, description) {
|
||||||
|
def name = "rssi"
|
||||||
|
def parts = part.split(":")
|
||||||
|
if (parts.size() != 2) return null
|
||||||
|
|
||||||
|
def valueString = parts[1].trim()
|
||||||
|
def valueInt = Integer.parseInt(valueString, 16)
|
||||||
|
def value = (valueInt - 128).toString()
|
||||||
|
def linkText = getLinkText(device)
|
||||||
|
def descriptionText = "$linkText was $value dBm"
|
||||||
|
def isStateChange = isStateChange(device, name, value)
|
||||||
|
|
||||||
|
[
|
||||||
|
name: name,
|
||||||
|
value: value,
|
||||||
|
unit: "dBm",
|
||||||
|
linkText: linkText,
|
||||||
|
descriptionText: descriptionText,
|
||||||
|
handlerName: null,
|
||||||
|
isStateChange: isStateChange,
|
||||||
|
//displayed: displayed(description, isStateChange)
|
||||||
|
displayed: false
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use LQI (Link Quality Indicator) as a measure of signal strength. The values
|
||||||
|
* are 0 to 255 (0x00 to 0xFF) and higher values represent higher signal
|
||||||
|
* strength. Return as a percentage of 255.
|
||||||
|
*
|
||||||
|
* Note: To make the signal strength indicator more accurate, we could combine
|
||||||
|
* LQI with RSSI.
|
||||||
|
*/
|
||||||
|
private getLqiResult(part, description) {
|
||||||
|
def name = "lqi"
|
||||||
|
def parts = part.split(":")
|
||||||
|
if (parts.size() != 2) return null
|
||||||
|
|
||||||
|
def valueString = parts[1].trim()
|
||||||
|
def valueInt = Integer.parseInt(valueString, 16)
|
||||||
|
def percentageOf = 255
|
||||||
|
def value = Math.round((valueInt / percentageOf * 100)).toString()
|
||||||
|
def unit = "%"
|
||||||
|
def linkText = getLinkText(device)
|
||||||
|
def descriptionText = "$linkText Signal (LQI) was ${value}${unit}"
|
||||||
|
def isStateChange = isStateChange(device, name, value)
|
||||||
|
|
||||||
|
[
|
||||||
|
name: name,
|
||||||
|
value: value,
|
||||||
|
unit: unit,
|
||||||
|
linkText: linkText,
|
||||||
|
descriptionText: descriptionText,
|
||||||
|
handlerName: null,
|
||||||
|
isStateChange: isStateChange,
|
||||||
|
//displayed: displayed(description, isStateChange)
|
||||||
|
displayed: false
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,316 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright 2015 SmartThings
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
* Speaker Control
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
|
||||||
*
|
|
||||||
* Date: 2013-12-10
|
|
||||||
*/
|
|
||||||
definition(
|
|
||||||
name: "스피커 컨트롤",
|
|
||||||
namespace: "smartthings",
|
|
||||||
author: "jung`s",
|
|
||||||
description: "Play or pause your Speaker when certain actions take place in your home.",
|
|
||||||
category: "SmartThings Labs",
|
|
||||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/sonos.png",
|
|
||||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/sonos@2x.png"
|
|
||||||
)
|
|
||||||
|
|
||||||
preferences {
|
|
||||||
page(name: "mainPage", title: "Control your Speaker when something happens", install: true, uninstall: true)
|
|
||||||
page(name: "timeIntervalInput", title: "Only during a certain time") {
|
|
||||||
section {
|
|
||||||
input "starting", "time", title: "Starting", required: false
|
|
||||||
input "ending", "time", title: "Ending", required: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def mainPage() {
|
|
||||||
dynamicPage(name: "mainPage") {
|
|
||||||
def anythingSet = anythingSet()
|
|
||||||
if (anythingSet) {
|
|
||||||
section("When..."){
|
|
||||||
ifSet "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
|
|
||||||
ifSet "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
|
|
||||||
ifSet "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
|
|
||||||
ifSet "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
|
|
||||||
ifSet "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
|
|
||||||
ifSet "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
|
|
||||||
ifSet "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
|
|
||||||
ifSet "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
|
|
||||||
ifSet "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
|
|
||||||
ifSet "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
|
|
||||||
ifSet "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
|
|
||||||
ifSet "triggerModes", "mode", title: "System Changes Mode", required: false, multiple: true
|
|
||||||
ifSet "timeOfDay", "time", title: "At a Scheduled Time", required: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
section(anythingSet ? "Select additional triggers" : "When...", hideable: anythingSet, hidden: true){
|
|
||||||
ifUnset "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
|
|
||||||
ifUnset "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
|
|
||||||
ifUnset "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
|
|
||||||
ifUnset "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
|
|
||||||
ifUnset "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
|
|
||||||
ifUnset "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
|
|
||||||
ifUnset "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
|
|
||||||
ifUnset "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
|
|
||||||
ifUnset "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
|
|
||||||
ifUnset "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
|
|
||||||
ifUnset "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
|
|
||||||
ifUnset "triggerModes", "mode", title: "System Changes Mode", required: false, multiple: true
|
|
||||||
ifUnset "timeOfDay", "time", title: "At a Scheduled Time", required: false
|
|
||||||
}
|
|
||||||
section("Perform this action"){
|
|
||||||
input "actionType", "enum", title: "Action?", required: true, defaultValue: "play", options: [
|
|
||||||
"Play",
|
|
||||||
"Stop Playing",
|
|
||||||
"Toggle Play/Pause",
|
|
||||||
"Skip to Next Track",
|
|
||||||
"Play Previous Track"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
section {
|
|
||||||
input "sonos", "capability.musicPlayer", title: "Speaker music player", required: true
|
|
||||||
}
|
|
||||||
section("More options", hideable: true, hidden: true) {
|
|
||||||
input "volume", "number", title: "Set the volume volume", description: "0-100%", required: false
|
|
||||||
input "frequency", "decimal", title: "Minimum time between actions (defaults to every event)", description: "Minutes", required: false
|
|
||||||
href "timeIntervalInput", title: "Only during a certain time", description: timeLabel ?: "Tap to set", state: timeLabel ? "complete" : "incomplete"
|
|
||||||
input "days", "enum", title: "Only on certain days of the week", multiple: true, required: false,
|
|
||||||
options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
|
|
||||||
if (settings.modes) {
|
|
||||||
input "modes", "mode", title: "Only when mode is", multiple: true, required: false
|
|
||||||
}
|
|
||||||
input "oncePerDay", "bool", title: "Only once per day", required: false, defaultValue: false
|
|
||||||
}
|
|
||||||
section([mobileOnly:true]) {
|
|
||||||
label title: "Assign a name", required: false
|
|
||||||
mode title: "Set for specific mode(s)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private anythingSet() {
|
|
||||||
for (name in ["motion","contact","contactClosed","acceleration","mySwitch","mySwitchOff","arrivalPresence","departurePresence","smoke","water","button1","triggerModes","timeOfDay"]) {
|
|
||||||
if (settings[name]) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private ifUnset(Map options, String name, String capability) {
|
|
||||||
if (!settings[name]) {
|
|
||||||
input(options, name, capability)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ifSet(Map options, String name, String capability) {
|
|
||||||
if (settings[name]) {
|
|
||||||
input(options, name, capability)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def installed() {
|
|
||||||
log.debug "Installed with settings: ${settings}"
|
|
||||||
subscribeToEvents()
|
|
||||||
}
|
|
||||||
|
|
||||||
def updated() {
|
|
||||||
log.debug "Updated with settings: ${settings}"
|
|
||||||
unsubscribe()
|
|
||||||
unschedule()
|
|
||||||
subscribeToEvents()
|
|
||||||
}
|
|
||||||
|
|
||||||
def subscribeToEvents() {
|
|
||||||
log.trace "subscribeToEvents()"
|
|
||||||
subscribe(app, appTouchHandler)
|
|
||||||
subscribe(contact, "contact.open", eventHandler)
|
|
||||||
subscribe(contactClosed, "contact.closed", eventHandler)
|
|
||||||
subscribe(acceleration, "acceleration.active", eventHandler)
|
|
||||||
subscribe(motion, "motion.active", eventHandler)
|
|
||||||
subscribe(mySwitch, "switch.on", eventHandler)
|
|
||||||
subscribe(mySwitchOff, "switch.off", eventHandler)
|
|
||||||
subscribe(arrivalPresence, "presence.present", eventHandler)
|
|
||||||
subscribe(departurePresence, "presence.not present", eventHandler)
|
|
||||||
subscribe(smoke, "smoke.detected", eventHandler)
|
|
||||||
subscribe(smoke, "smoke.tested", eventHandler)
|
|
||||||
subscribe(smoke, "carbonMonoxide.detected", eventHandler)
|
|
||||||
subscribe(water, "water.wet", eventHandler)
|
|
||||||
subscribe(button1, "button.pushed", eventHandler)
|
|
||||||
|
|
||||||
if (triggerModes) {
|
|
||||||
subscribe(location, modeChangeHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeOfDay) {
|
|
||||||
schedule(timeOfDay, scheduledTimeHandler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def eventHandler(evt) {
|
|
||||||
if (allOk) {
|
|
||||||
def lastTime = state[frequencyKey(evt)]
|
|
||||||
if (oncePerDayOk(lastTime)) {
|
|
||||||
if (frequency) {
|
|
||||||
if (lastTime == null || now() - lastTime >= frequency * 60000) {
|
|
||||||
takeAction(evt)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.debug "Not taking action because $frequency minutes have not elapsed since last action"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
takeAction(evt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.debug "Not taking action because it was already taken today"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def modeChangeHandler(evt) {
|
|
||||||
log.trace "modeChangeHandler $evt.name: $evt.value ($triggerModes)"
|
|
||||||
if (evt.value in triggerModes) {
|
|
||||||
eventHandler(evt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def scheduledTimeHandler() {
|
|
||||||
eventHandler(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
def appTouchHandler(evt) {
|
|
||||||
takeAction(evt)
|
|
||||||
}
|
|
||||||
|
|
||||||
private takeAction(evt) {
|
|
||||||
log.debug "takeAction($actionType)"
|
|
||||||
def options = [:]
|
|
||||||
if (volume) {
|
|
||||||
sonos.setLevel(volume as Integer)
|
|
||||||
options.delay = 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (actionType) {
|
|
||||||
case "Play":
|
|
||||||
options ? sonos.on(options) : sonos.on()
|
|
||||||
break
|
|
||||||
case "Stop Playing":
|
|
||||||
options ? sonos.off(options) : sonos.off()
|
|
||||||
break
|
|
||||||
case "Toggle Play/Pause":
|
|
||||||
def currentStatus = sonos.currentValue("status")
|
|
||||||
if (currentStatus == "playing") {
|
|
||||||
options ? sonos.pause(options) : sonos.pause()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
options ? sonos.play(options) : sonos.play()
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case "Skip to Next Track":
|
|
||||||
options ? sonos.nextTrack(options) : sonos.nextTrack()
|
|
||||||
break
|
|
||||||
case "Play Previous Track":
|
|
||||||
options ? sonos.previousTrack(options) : sonos.previousTrack()
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
log.error "Action type '$actionType' not defined"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frequency) {
|
|
||||||
state.lastActionTimeStamp = now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private frequencyKey(evt) {
|
|
||||||
//evt.deviceId ?: evt.value
|
|
||||||
"lastActionTimeStamp"
|
|
||||||
}
|
|
||||||
|
|
||||||
private dayString(Date date) {
|
|
||||||
def df = new java.text.SimpleDateFormat("yyyy-MM-dd")
|
|
||||||
if (location.timeZone) {
|
|
||||||
df.setTimeZone(location.timeZone)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
|
|
||||||
}
|
|
||||||
df.format(date)
|
|
||||||
}
|
|
||||||
|
|
||||||
private oncePerDayOk(Long lastTime) {
|
|
||||||
def result = true
|
|
||||||
if (oncePerDay) {
|
|
||||||
result = lastTime ? dayString(new Date()) != dayString(new Date(lastTime)) : true
|
|
||||||
log.trace "oncePerDayOk = $result"
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO - centralize somehow
|
|
||||||
private getAllOk() {
|
|
||||||
modeOk && daysOk && timeOk
|
|
||||||
}
|
|
||||||
|
|
||||||
private getModeOk() {
|
|
||||||
def result = !modes || modes.contains(location.mode)
|
|
||||||
log.trace "modeOk = $result"
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
private getDaysOk() {
|
|
||||||
def result = true
|
|
||||||
if (days) {
|
|
||||||
def df = new java.text.SimpleDateFormat("EEEE")
|
|
||||||
if (location.timeZone) {
|
|
||||||
df.setTimeZone(location.timeZone)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
|
|
||||||
}
|
|
||||||
def day = df.format(new Date())
|
|
||||||
result = days.contains(day)
|
|
||||||
}
|
|
||||||
log.trace "daysOk = $result"
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
private getTimeOk() {
|
|
||||||
def result = true
|
|
||||||
if (starting && ending) {
|
|
||||||
def currTime = now()
|
|
||||||
def start = timeToday(starting, location?.timeZone).time
|
|
||||||
def stop = timeToday(ending, location?.timeZone).time
|
|
||||||
result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
|
|
||||||
}
|
|
||||||
log.trace "timeOk = $result"
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
private hhmm(time, fmt = "h:mm a")
|
|
||||||
{
|
|
||||||
def t = timeToday(time, location.timeZone)
|
|
||||||
def f = new java.text.SimpleDateFormat(fmt)
|
|
||||||
f.setTimeZone(location.timeZone ?: timeZone(time))
|
|
||||||
f.format(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
private timeIntervalLabel()
|
|
||||||
{
|
|
||||||
(starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
|
|
||||||
}
|
|
||||||
// TODO - End Centralize
|
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2015 SmartThings
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
* Turn It On For 5 Minutes
|
||||||
|
* Turn on a switch when a contact sensor opens and then turn it back off 5 minutes later.
|
||||||
|
*
|
||||||
|
* Author: SmartThings
|
||||||
|
*/
|
||||||
|
definition(
|
||||||
|
name: "Turn It On For 1 Minutes",
|
||||||
|
namespace: "smartthings",
|
||||||
|
author: "mr.kim",
|
||||||
|
description: "When a SmartSense Multi is opened, a switch will be turned on, and then turned off after 5 minutes.",
|
||||||
|
category: "Safety & Security",
|
||||||
|
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Meta/light_contact-outlet.png",
|
||||||
|
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Meta/light_contact-outlet@2x.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
section("When it opens..."){
|
||||||
|
input "contact1", "capability.contactSensor"
|
||||||
|
}
|
||||||
|
section("Turn on a switch for 5 minutes..."){
|
||||||
|
input "switch1", "capability.switch"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
log.debug "Installed with settings: ${settings}"
|
||||||
|
subscribe(contact1, "contact.open", contactOpenHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated(settings) {
|
||||||
|
log.debug "Updated with settings: ${settings}"
|
||||||
|
unsubscribe()
|
||||||
|
subscribe(contact1, "contact.open", contactOpenHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
def contactOpenHandler(evt) {
|
||||||
|
switch1.on()
|
||||||
|
def fiveMinuteDelay = 60 * 1
|
||||||
|
runIn(fiveMinuteDelay, turnOffSwitch)
|
||||||
|
}
|
||||||
|
|
||||||
|
def turnOffSwitch() {
|
||||||
|
switch1.off()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user