Compare commits

..

3 Commits

Author SHA1 Message Date
임희진
8caff0f0fd MSA-930: test 2016-03-08 03:18:30 -06:00
임희진
4af884ad50 MSA-930: test 2016-03-08 03:18:28 -06:00
임희진
b98d795193 MSA-930: test 2016-03-08 03:18:24 -06:00
4 changed files with 481 additions and 539 deletions

View File

@@ -0,0 +1,35 @@
/**
* 에너지미터
*
* Copyright 2016 임희진
*
* 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: "에너지미터", author: "임희진") {
capability "Energy Meter"
}
simulator {
// TODO: define status and reply messages here
}
tiles {
// TODO: define your main and details tiles here
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
// TODO: handle 'energy' attribute
}

View File

@@ -1,93 +0,0 @@
/**
* TEST
*
* Copyright 2016 박춘영
*
* 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: "TEST", namespace: "스마트보안", author: "박춘영") {
capability "Button"
capability "Samsung TV"
}
simulator {
// TODO: define status and reply messages here
}
tiles {
// TODO: define your main and details tiles here
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
// TODO: handle 'button' attribute
// TODO: handle 'volume' attribute
// TODO: handle 'mute' attribute
// TODO: handle 'pictureMode' attribute
// TODO: handle 'soundMode' attribute
// TODO: handle 'switch' attribute
// TODO: handle 'messageButton' attribute
}
// handle commands
def volumeUp() {
log.debug "Executing 'volumeUp'"
// TODO: handle 'volumeUp' command
}
def volumeDown() {
log.debug "Executing 'volumeDown'"
// TODO: handle 'volumeDown' command
}
def setVolume() {
log.debug "Executing 'setVolume'"
// TODO: handle 'setVolume' command
}
def mute() {
log.debug "Executing 'mute'"
// TODO: handle 'mute' command
}
def unmute() {
log.debug "Executing 'unmute'"
// TODO: handle 'unmute' command
}
def setPictureMode() {
log.debug "Executing 'setPictureMode'"
// TODO: handle 'setPictureMode' command
}
def setSoundMode() {
log.debug "Executing 'setSoundMode'"
// TODO: handle 'setSoundMode' command
}
def on() {
log.debug "Executing 'on'"
// TODO: handle 'on' command
}
def off() {
log.debug "Executing 'off'"
// TODO: handle 'off' command
}
def showMessage() {
log.debug "Executing 'showMessage'"
// TODO: handle 'showMessage' command
}

View File

@@ -1,317 +1,317 @@
/** /**
* Copyright 2015 SmartThings * Copyright 2015 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at: * in compliance with the License. You may obtain a copy of the License at:
* *
* http://www.apache.org/licenses/LICENSE-2.0 * 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 * 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 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License. * for the specific language governing permissions and limitations under the License.
* *
* Smart Security * Smart Security
* *
* Author: SmartThings * Author: SmartThings
* Date: 2013-03-07 * Date: 2013-03-07
*/ */
definition( definition(
name: "Smart Security", name: "Smart Security",
namespace: "smartthings", namespace: "smartthings",
author: "SmartThings", author: "SmartThings",
description: "Alerts you when there are intruders but not when you just got up for a glass of water in the middle of the night", description: "Alerts you when there are intruders but not when you just got up for a glass of water in the middle of the night",
category: "Safety & Security", category: "Safety & Security",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/SafetyAndSecurity/App-IsItSafe.png", iconUrl: "https://s3.amazonaws.com/smartapp-icons/SafetyAndSecurity/App-IsItSafe.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/SafetyAndSecurity/App-IsItSafe@2x.png" iconX2Url: "https://s3.amazonaws.com/smartapp-icons/SafetyAndSecurity/App-IsItSafe@2x.png"
) )
preferences { preferences {
section("Sensors detecting an intruder") { section("Sensors detecting an intruder") {
input "intrusionMotions", "capability.motionSensor", title: "Motion Sensors", multiple: true, required: false input "intrusionMotions", "capability.motionSensor", title: "Motion Sensors", multiple: true, required: false
input "intrusionContacts", "capability.contactSensor", title: "Contact Sensors", multiple: true, required: false input "intrusionContacts", "capability.contactSensor", title: "Contact Sensors", multiple: true, required: false
} }
section("Sensors detecting residents") { section("Sensors detecting residents") {
input "residentMotions", "capability.motionSensor", title: "Motion Sensors", multiple: true, required: false input "residentMotions", "capability.motionSensor", title: "Motion Sensors", multiple: true, required: false
} }
section("Alarm settings and actions") { section("Alarm settings and actions") {
input "alarms", "capability.alarm", title: "Which Alarm(s)", multiple: true, required: false input "alarms", "capability.alarm", title: "Which Alarm(s)", multiple: true, required: false
input "silent", "enum", options: ["Yes","No"], title: "Silent alarm only (Yes/No)" input "silent", "enum", options: ["Yes","No"], title: "Silent alarm only (Yes/No)"
input "seconds", "number", title: "Delay in seconds before siren sounds" input "seconds", "number", title: "Delay in seconds before siren sounds"
input "lights", "capability.switch", title: "Flash these lights (optional)", multiple: true, required: false input "lights", "capability.switch", title: "Flash these lights (optional)", multiple: true, required: false
input "newMode", "mode", title: "Change to this mode (optional)", required: false input "newMode", "mode", title: "Change to this mode (optional)", required: false
} }
section("Notify others (optional)") { section("Notify others (optional)") {
input "textMessage", "text", title: "Send this message", multiple: false, required: false input "textMessage", "text", title: "Send this message", multiple: false, required: false
input("recipients", "contact", title: "Send notifications to") { input("recipients", "contact", title: "Send notifications to") {
input "phone", "phone", title: "To this phone", multiple: false, required: false input "phone", "phone", title: "To this phone", multiple: false, required: false
} }
} }
section("Arm system when residents quiet for (default 3 minutes)") { section("Arm system when residents quiet for (default 3 minutes)") {
input "residentsQuietThreshold", "number", title: "Time in minutes", required: false input "residentsQuietThreshold", "number", title: "Time in minutes", required: false
} }
} }
def installed() { def installed() {
log.debug "INSTALLED" log.debug "INSTALLED"
subscribeToEvents() subscribeToEvents()
state.alarmActive = null state.alarmActive = null
} }
def updated() { def updated() {
log.debug "UPDATED" log.debug "UPDATED"
unsubscribe() unsubscribe()
subscribeToEvents() subscribeToEvents()
unschedule() unschedule()
state.alarmActive = null state.alarmActive = null
state.residentsAreUp = null state.residentsAreUp = null
state.lastIntruderMotion = null state.lastIntruderMotion = null
alarms?.off() alarms?.off()
} }
private subscribeToEvents() private subscribeToEvents()
{ {
subscribe intrusionMotions, "motion", intruderMotion subscribe intrusionMotions, "motion", intruderMotion
subscribe residentMotions, "motion", residentMotion subscribe residentMotions, "motion", residentMotion
subscribe intrusionContacts, "contact", contact subscribe intrusionContacts, "contact", contact
subscribe alarms, "alarm", alarm subscribe alarms, "alarm", alarm
subscribe(app, appTouch) subscribe(app, appTouch)
} }
private residentsHaveBeenQuiet() private residentsHaveBeenQuiet()
{ {
def threshold = ((residentsQuietThreshold != null && residentsQuietThreshold != "") ? residentsQuietThreshold : 3) * 60 * 1000 def threshold = ((residentsQuietThreshold != null && residentsQuietThreshold != "") ? residentsQuietThreshold : 3) * 60 * 1000
def result = true def result = true
def t0 = new Date(now() - threshold) def t0 = new Date(now() - threshold)
for (sensor in residentMotions) { for (sensor in residentMotions) {
def recentStates = sensor.statesSince("motion", t0) def recentStates = sensor.statesSince("motion", t0)
if (recentStates.find{it.value == "active"}) { if (recentStates.find{it.value == "active"}) {
result = false result = false
break break
} }
} }
log.debug "residentsHaveBeenQuiet: $result" log.debug "residentsHaveBeenQuiet: $result"
result result
} }
private intruderMotionInactive() private intruderMotionInactive()
{ {
def result = true def result = true
for (sensor in intrusionMotions) { for (sensor in intrusionMotions) {
if (sensor.currentMotion == "active") { if (sensor.currentMotion == "active") {
result = false result = false
break break
} }
} }
result result
} }
private isResidentMotionSensor(evt) private isResidentMotionSensor(evt)
{ {
residentMotions?.find{it.id == evt.deviceId} != null residentMotions?.find{it.id == evt.deviceId} != null
} }
def appTouch(evt) def appTouch(evt)
{ {
alarms?.off() alarms?.off()
state.alarmActive = false state.alarmActive = false
} }
// Here to handle old subscriptions // Here to handle old subscriptions
def motion(evt) def motion(evt)
{ {
if (isResidentMotionSensor(evt)) { if (isResidentMotionSensor(evt)) {
log.debug "resident motion, $evt.name: $evt.value" log.debug "resident motion, $evt.name: $evt.value"
residentMotion(evt) residentMotion(evt)
} }
else { else {
log.debug "intruder motion, $evt.name: $evt.value" log.debug "intruder motion, $evt.name: $evt.value"
intruderMotion(evt) intruderMotion(evt)
} }
} }
def intruderMotion(evt) def intruderMotion(evt)
{ {
if (evt.value == "active") { if (evt.value == "active") {
log.debug "motion by potential intruder, residentsAreUp: $state.residentsAreUp" log.debug "motion by potential intruder, residentsAreUp: $state.residentsAreUp"
if (!state.residentsAreUp) { if (!state.residentsAreUp) {
log.trace "checking if residents have been quiet" log.trace "checking if residents have been quiet"
if (residentsHaveBeenQuiet()) { if (residentsHaveBeenQuiet()) {
log.trace "calling startAlarmSequence" log.trace "calling startAlarmSequence"
startAlarmSequence() startAlarmSequence()
} }
else { else {
log.trace "calling disarmIntrusionDetection" log.trace "calling disarmIntrusionDetection"
disarmIntrusionDetection() disarmIntrusionDetection()
} }
} }
} }
state.lastIntruderMotion = now() state.lastIntruderMotion = now()
} }
def residentMotion(evt) def residentMotion(evt)
{ {
// Don't think we need this any more // Don't think we need this any more
//if (evt.value == "inactive") { //if (evt.value == "inactive") {
// if (state.residentsAreUp) { // if (state.residentsAreUp) {
// startReArmSequence() // startReArmSequence()
// } // }
//} //}
} }
def contact(evt) def contact(evt)
{ {
if (evt.value == "open") { if (evt.value == "open") {
// TODO - check for residents being up? // TODO - check for residents being up?
if (!state.residentsAreUp) { if (!state.residentsAreUp) {
if (residentsHaveBeenQuiet()) { if (residentsHaveBeenQuiet()) {
startAlarmSequence() startAlarmSequence()
} }
else { else {
disarmIntrusionDetection() disarmIntrusionDetection()
} }
} }
} }
} }
def alarm(evt) def alarm(evt)
{ {
log.debug "$evt.name: $evt.value" log.debug "$evt.name: $evt.value"
if (evt.value == "off") { if (evt.value == "off") {
alarms?.off() alarms?.off()
state.alarmActive = false state.alarmActive = false
} }
} }
private disarmIntrusionDetection() private disarmIntrusionDetection()
{ {
log.debug "residents are up, disarming intrusion detection" log.debug "residents are up, disarming intrusion detection"
state.residentsAreUp = true state.residentsAreUp = true
scheduleReArmCheck() scheduleReArmCheck()
} }
private scheduleReArmCheck() private scheduleReArmCheck()
{ {
def cron = "0 * * * * ?" def cron = "0 * * * * ?"
schedule(cron, "checkForReArm") schedule(cron, "checkForReArm")
log.debug "Starting re-arm check, cron: $cron" log.debug "Starting re-arm check, cron: $cron"
} }
def checkForReArm() def checkForReArm()
{ {
def threshold = ((residentsQuietThreshold != null && residentsQuietThreshold != "") ? residentsQuietThreshold : 3) * 60 * 1000 def threshold = ((residentsQuietThreshold != null && residentsQuietThreshold != "") ? residentsQuietThreshold : 3) * 60 * 1000
log.debug "checkForReArm: threshold is $threshold" log.debug "checkForReArm: threshold is $threshold"
// check last intruder motion // check last intruder motion
def lastIntruderMotion = state.lastIntruderMotion def lastIntruderMotion = state.lastIntruderMotion
log.debug "checkForReArm: lastIntruderMotion=$lastIntruderMotion" log.debug "checkForReArm: lastIntruderMotion=$lastIntruderMotion"
if (lastIntruderMotion != null) if (lastIntruderMotion != null)
{ {
log.debug "checkForReArm, time since last intruder motion: ${now() - lastIntruderMotion}" log.debug "checkForReArm, time since last intruder motion: ${now() - lastIntruderMotion}"
if (now() - lastIntruderMotion > threshold) { if (now() - lastIntruderMotion > threshold) {
log.debug "re-arming intrusion detection" log.debug "re-arming intrusion detection"
state.residentsAreUp = false state.residentsAreUp = false
unschedule() unschedule()
} }
} }
else { else {
log.warn "checkForReArm: lastIntruderMotion was null, unable to check for re-arming intrusion detection" log.warn "checkForReArm: lastIntruderMotion was null, unable to check for re-arming intrusion detection"
} }
} }
private startAlarmSequence() private startAlarmSequence()
{ {
if (state.alarmActive) { if (state.alarmActive) {
log.debug "alarm already active" log.debug "alarm already active"
} }
else { else {
state.alarmActive = true state.alarmActive = true
log.debug "starting alarm sequence" log.debug "starting alarm sequence"
sendPush("Potential intruder detected!") sendPush("Potential intruder detected!")
if (newMode) { if (newMode) {
setLocationMode(newMode) setLocationMode(newMode)
} }
if (silentAlarm()) { if (silentAlarm()) {
log.debug "Silent alarm only" log.debug "Silent alarm only"
alarms?.strobe() alarms?.strobe()
if (location.contactBookEnabled) { if (location.contactBookEnabled) {
sendNotificationToContacts(textMessage ?: "Potential intruder detected", recipients) sendNotificationToContacts(textMessage ?: "Potential intruder detected", recipients)
} }
else { else {
if (phone) { if (phone) {
sendSms(phone, textMessage ?: "Potential intruder detected") sendSms(phone, textMessage ?: "Potential intruder detected")
} }
} }
} }
else { else {
def delayTime = seconds def delayTime = seconds
if (delayTime) { if (delayTime) {
alarms?.strobe() alarms?.strobe()
runIn(delayTime, "soundSiren") runIn(delayTime, "soundSiren")
log.debug "Sounding siren in $delayTime seconds" log.debug "Sounding siren in $delayTime seconds"
} }
else { else {
soundSiren() soundSiren()
} }
} }
if (lights) { if (lights) {
flashLights(Math.min((seconds/2) as Integer, 10)) flashLights(Math.min((seconds/2) as Integer, 10))
} }
} }
} }
def soundSiren() def soundSiren()
{ {
if (state.alarmActive) { if (state.alarmActive) {
log.debug "Sounding siren" log.debug "Sounding siren"
if (location.contactBookEnabled) { if (location.contactBookEnabled) {
sendNotificationToContacts(textMessage ?: "Potential intruder detected", recipients) sendNotificationToContacts(textMessage ?: "Potential intruder detected", recipients)
} }
else { else {
if (phone) { if (phone) {
sendSms(phone, textMessage ?: "Potential intruder detected") sendSms(phone, textMessage ?: "Potential intruder detected")
} }
} }
alarms?.both() alarms?.both()
if (lights) { if (lights) {
log.debug "continue flashing lights" log.debug "continue flashing lights"
continueFlashing() continueFlashing()
} }
} }
else { else {
log.debug "alarm activation aborted" log.debug "alarm activation aborted"
} }
unschedule("soundSiren") // Temporary work-around to scheduling bug unschedule("soundSiren") // Temporary work-around to scheduling bug
} }
def continueFlashing() def continueFlashing()
{ {
unschedule() unschedule()
if (state.alarmActive) { if (state.alarmActive) {
flashLights(10) flashLights(10)
schedule(util.cronExpression(now() + 10000), "continueFlashing") schedule(util.cronExpression(now() + 10000), "continueFlashing")
} }
} }
private flashLights(numFlashes) { private flashLights(numFlashes) {
def onFor = 1000 def onFor = 1000
def offFor = 1000 def offFor = 1000
log.debug "FLASHING $numFlashes times" log.debug "FLASHING $numFlashes times"
def delay = 1L def delay = 1L
numFlashes.times { numFlashes.times {
log.trace "Switch on after $delay msec" log.trace "Switch on after $delay msec"
lights?.on(delay: delay) lights?.on(delay: delay)
delay += onFor delay += onFor
log.trace "Switch off after $delay msec" log.trace "Switch off after $delay msec"
lights?.off(delay: delay) lights?.off(delay: delay)
delay += offFor delay += offFor
} }
} }
private silentAlarm() private silentAlarm()
{ {
silent?.toLowerCase() in ["yes","true","y"] silent?.toLowerCase() in ["yes","true","y"]
} }

View File

@@ -1,129 +1,129 @@
/** /**
* Copyright 2015 SmartThings * Copyright 2015 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at: * in compliance with the License. You may obtain a copy of the License at:
* *
* http://www.apache.org/licenses/LICENSE-2.0 * 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 * 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 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License. * for the specific language governing permissions and limitations under the License.
* *
* Alfred Workflow * Alfred Workflow
* *
* Author: SmartThings * Author: SmartThings
*/ */
definition( definition(
name: "Alfred Workflow", name: "Alfred Workflow",
namespace: "vlaminck", namespace: "vlaminck",
author: "SmartThings", author: "SmartThings",
description: "This SmartApp allows you to interact with the things in your physical graph through Alfred.", description: "This SmartApp allows you to interact with the things in your physical graph through Alfred.",
category: "Convenience", category: "Convenience",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/alfred-app.png", iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/alfred-app.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/alfred-app@2x.png", iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/alfred-app@2x.png",
oauth: [displayName: "SmartThings Alfred Workflow", displayLink: ""] oauth: [displayName: "SmartThings Alfred Workflow", displayLink: ""]
) )
preferences { preferences {
section("Allow Alfred to Control These Things...") { section("Allow Alfred to Control These Things...") {
input "switches", "capability.switch", title: "Which Switches?", multiple: true, required: false input "switches", "capability.switch", title: "Which Switches?", multiple: true, required: false
input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false
} }
} }
mappings { mappings {
path("/switches") { path("/switches") {
action: [ action: [
GET: "listSwitches", GET: "listSwitches",
PUT: "updateSwitches" PUT: "updateSwitches"
] ]
} }
path("/switches/:id") { path("/switches/:id") {
action: [ action: [
GET: "showSwitch", GET: "showSwitch",
PUT: "updateSwitch" PUT: "updateSwitch"
] ]
} }
path("/locks") { path("/locks") {
action: [ action: [
GET: "listLocks", GET: "listLocks",
PUT: "updateLocks" PUT: "updateLocks"
] ]
} }
path("/locks/:id") { path("/locks/:id") {
action: [ action: [
GET: "showLock", GET: "showLock",
PUT: "updateLock" PUT: "updateLock"
] ]
} }
} }
def installed() {} def installed() {}
def updated() {} def updated() {}
def listSwitches() { def listSwitches() {
switches.collect { device(it,"switch") } switches.collect { device(it,"switch") }
} }
void updateSwitches() { void updateSwitches() {
updateAll(switches) updateAll(switches)
} }
def showSwitch() { def showSwitch() {
show(switches, "switch") show(switches, "switch")
} }
void updateSwitch() { void updateSwitch() {
update(switches) update(switches)
} }
def listLocks() { def listLocks() {
locks.collect { device(it, "lock") } locks.collect { device(it, "lock") }
} }
void updateLocks() { void updateLocks() {
updateAll(locks) updateAll(locks)
} }
def showLock() { def showLock() {
show(locks, "lock") show(locks, "lock")
} }
void updateLock() { void updateLock() {
update(locks) update(locks)
} }
private void updateAll(devices) { private void updateAll(devices) {
def command = request.JSON?.command def command = request.JSON?.command
if (command) { if (command) {
devices."$command"() devices."$command"()
} }
} }
private void update(devices) { private void update(devices) {
log.debug "update, request: ${request.JSON}, params: ${params}, devices: $devices.id" log.debug "update, request: ${request.JSON}, params: ${params}, devices: $devices.id"
def command = request.JSON?.command def command = request.JSON?.command
if (command) { if (command) {
def device = devices.find { it.id == params.id } def device = devices.find { it.id == params.id }
if (!device) { if (!device) {
httpError(404, "Device not found") httpError(404, "Device not found")
} else { } else {
device."$command"() device."$command"()
} }
} }
} }
private show(devices, name) { private show(devices, name) {
def device = devices.find { it.id == params.id } def device = devices.find { it.id == params.id }
if (!device) { if (!device) {
httpError(404, "Device not found") httpError(404, "Device not found")
} }
else { else {
def s = device.currentState(name) def s = device.currentState(name)
[id: device.id, label: device.displayName, name: device.displayName, state: s] [id: device.id, label: device.displayName, name: device.displayName, state: s]
} }
} }
private device(it, name) { private device(it, name) {
if (it) { if (it) {
def s = it.currentState(name) def s = it.currentState(name)
[id: it.id, label: it.displayName, name: it.displayName, state: s] [id: it.id, label: it.displayName, name: it.displayName, state: s]
} }
} }