mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-23 13:14:11 +00:00
Compare commits
1 Commits
MSA-1306-2
...
MSA-1312-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c673e7ad7 |
@@ -1,294 +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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
]
|
|
||||||
}
|
|
||||||
316
smartapps/smartthings/-.src/-.groovy
Normal file
316
smartapps/smartthings/-.src/-.groovy
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
/**
|
||||||
|
* 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
|
||||||
@@ -1,56 +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.
|
|
||||||
*
|
|
||||||
* 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