mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-25 13:04:10 +00:00
Initial commit
This commit is contained in:
88
smartapps/imbrianj/door-knocker.src/door-knocker.groovy
Normal file
88
smartapps/imbrianj/door-knocker.src/door-knocker.groovy
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Door Knocker
|
||||
*
|
||||
* Author: brian@bevey.org
|
||||
* Date: 9/10/13
|
||||
*
|
||||
* Let me know when someone knocks on the door, but ignore
|
||||
* when someone is opening the door.
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "Door Knocker",
|
||||
namespace: "imbrianj",
|
||||
author: "brian@bevey.org",
|
||||
description: "Alert if door is knocked, but not opened.",
|
||||
category: "Convenience",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
|
||||
)
|
||||
|
||||
preferences {
|
||||
section("When Someone Knocks?") {
|
||||
input name: "knockSensor", type: "capability.accelerationSensor", title: "Where?"
|
||||
}
|
||||
|
||||
section("But not when they open this door?") {
|
||||
input name: "openSensor", type: "capability.contactSensor", title: "Where?"
|
||||
}
|
||||
|
||||
section("Knock Delay (defaults to 5s)?") {
|
||||
input name: "knockDelay", type: "number", title: "How Long?", required: false
|
||||
}
|
||||
|
||||
section("Notifications") {
|
||||
input "sendPushMessage", "enum", title: "Send a push notification?", metadata: [values: ["Yes", "No"]], required: false
|
||||
input "phone", "phone", title: "Send a Text Message?", required: false
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
init()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
unsubscribe()
|
||||
init()
|
||||
}
|
||||
|
||||
def init() {
|
||||
state.lastClosed = 0
|
||||
subscribe(knockSensor, "acceleration.active", handleEvent)
|
||||
subscribe(openSensor, "contact.closed", doorClosed)
|
||||
}
|
||||
|
||||
def doorClosed(evt) {
|
||||
state.lastClosed = now()
|
||||
}
|
||||
|
||||
def doorKnock() {
|
||||
if((openSensor.latestValue("contact") == "closed") &&
|
||||
(now() - (60 * 1000) > state.lastClosed)) {
|
||||
log.debug("${knockSensor.label ?: knockSensor.name} detected a knock.")
|
||||
send("${knockSensor.label ?: knockSensor.name} detected a knock.")
|
||||
}
|
||||
|
||||
else {
|
||||
log.debug("${knockSensor.label ?: knockSensor.name} knocked, but looks like it was just someone opening the door.")
|
||||
}
|
||||
}
|
||||
|
||||
def handleEvent(evt) {
|
||||
def delay = knockDelay ?: 5
|
||||
runIn(delay, "doorKnock")
|
||||
}
|
||||
|
||||
private send(msg) {
|
||||
if(sendPushMessage != "No") {
|
||||
log.debug("Sending push message")
|
||||
sendPush(msg)
|
||||
}
|
||||
|
||||
if(phone) {
|
||||
log.debug("Sending text message")
|
||||
sendSms(phone, msg)
|
||||
}
|
||||
|
||||
log.debug(msg)
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Forgiving Security
|
||||
*
|
||||
* Author: brian@bevey.org
|
||||
* Date: 10/25/13
|
||||
*
|
||||
* Arm a simple security system based on mode. Has a grace period to allow an
|
||||
* ever present lag in presence detection.
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "Forgiving Security",
|
||||
namespace: "imbrianj",
|
||||
author: "brian@bevey.org",
|
||||
description: "Alerts you if something happens while you're away. Has a settable grace period to compensate for presence sensors that may take a few seconds to be noticed.",
|
||||
category: "Safety & Security",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
|
||||
)
|
||||
|
||||
preferences {
|
||||
section("Things to secure?") {
|
||||
input "contacts", "capability.contactSensor", title: "Contact Sensors", multiple: true, required: false
|
||||
input "motions", "capability.motionSensor", title: "Motion Sensors", multiple: true, required: false
|
||||
}
|
||||
|
||||
section("Alarms to go off?") {
|
||||
input "alarms", "capability.alarm", title: "Which Alarms?", multiple: true, required: false
|
||||
input "lights", "capability.switch", title: "Turn on which lights?", multiple: true, required: false
|
||||
}
|
||||
|
||||
section("Delay for presence lag?") {
|
||||
input name: "presenceDelay", type: "number", title: "Seconds (defaults to 15s)", required: false
|
||||
}
|
||||
|
||||
section("Notifications?") {
|
||||
input "sendPushMessage", "enum", title: "Send a push notification?", metadata: [values: ["Yes", "No"]], required: false
|
||||
input "phone", "phone", title: "Send a Text Message?", required: false
|
||||
}
|
||||
|
||||
section("Message interval?") {
|
||||
input name: "messageDelay", type: "number", title: "Minutes (default to every message)", required: false
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
init()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
unsubscribe()
|
||||
init()
|
||||
}
|
||||
|
||||
def init() {
|
||||
state.lastTrigger = now()
|
||||
state.deviceTriggers = []
|
||||
subscribe(contacts, "contact.open", triggerAlarm)
|
||||
subscribe(motions, "motion.active", triggerAlarm)
|
||||
}
|
||||
|
||||
def triggerAlarm(evt) {
|
||||
def presenceDelay = presenceDelay ?: 15
|
||||
|
||||
if(now() - (presenceDelay * 1000) > state.lastTrigger) {
|
||||
log.warn("Stale event - ignoring")
|
||||
|
||||
state.deviceTriggers = []
|
||||
}
|
||||
|
||||
state.deviceTriggers.add(evt.displayName)
|
||||
state.triggerMode = location.mode
|
||||
state.lastTrigger = now()
|
||||
|
||||
log.info(evt.displayName + " triggered an alarm. Waiting for presence lag.")
|
||||
runIn(presenceDelay, "fireAlarm")
|
||||
}
|
||||
|
||||
def fireAlarm() {
|
||||
if(state.deviceTriggers.size() > 0) {
|
||||
def devices = state.deviceTriggers.unique().join(", ")
|
||||
|
||||
if(location.mode == state.triggerMode) {
|
||||
log.info(devices + " alarm triggered and mode hasn't changed.")
|
||||
send(devices + " alarm has been triggered!")
|
||||
lights?.on()
|
||||
alarms?.both()
|
||||
}
|
||||
|
||||
else {
|
||||
log.info(devices + " alarm triggered, but it looks like you were just coming home. Ignoring.")
|
||||
}
|
||||
}
|
||||
|
||||
state.deviceTriggers = []
|
||||
}
|
||||
|
||||
private send(msg) {
|
||||
def delay = (messageDelay != null && messageDelay != "") ? messageDelay * 60 * 1000 : 0
|
||||
|
||||
if(now() - delay > state.lastMessage) {
|
||||
state.lastMessage = now()
|
||||
if(sendPushMessage == "Yes") {
|
||||
log.debug("Sending push message.")
|
||||
sendPush(msg)
|
||||
}
|
||||
|
||||
if(phone) {
|
||||
log.debug("Sending text message.")
|
||||
sendSms(phone, msg)
|
||||
}
|
||||
|
||||
log.debug(msg)
|
||||
}
|
||||
|
||||
else {
|
||||
log.info("Have a message to send, but user requested to not get it.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Hall Light: Welcome Home
|
||||
*
|
||||
* Author: brian@bevey.org
|
||||
* Date: 9/25/13
|
||||
*
|
||||
* Turn on the hall light if someone comes home (presence) and the door opens.
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "Hall Light: Welcome Home",
|
||||
namespace: "imbrianj",
|
||||
author: "brian@bevey.org",
|
||||
description: "Turn on the hall light if someone comes home (presence) and the door opens.",
|
||||
category: "Convenience",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
|
||||
)
|
||||
|
||||
preferences {
|
||||
section("People to watch for?") {
|
||||
input "people", "capability.presenceSensor", multiple: true
|
||||
}
|
||||
|
||||
section("Front Door?") {
|
||||
input "sensors", "capability.contactSensor", multiple: true
|
||||
}
|
||||
|
||||
section("Hall Light?") {
|
||||
input "lights", "capability.switch", title: "Switch Turned On", multilple: true
|
||||
}
|
||||
|
||||
section("Presence Delay (defaults to 30s)?") {
|
||||
input name: "presenceDelay", type: "number", title: "How Long?", required: false
|
||||
}
|
||||
|
||||
section("Door Contact Delay (defaults to 10s)?") {
|
||||
input name: "contactDelay", type: "number", title: "How Long?", required: false
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
init()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
unsubscribe()
|
||||
init()
|
||||
}
|
||||
|
||||
def init() {
|
||||
state.lastClosed = now()
|
||||
subscribe(people, "presence.present", presence)
|
||||
subscribe(sensors, "contact.open", doorOpened)
|
||||
}
|
||||
|
||||
def presence(evt) {
|
||||
def delay = contactDelay ?: 10
|
||||
|
||||
state.lastPresence = now()
|
||||
|
||||
if(now() - (delay * 1000) < state.lastContact) {
|
||||
log.info('Presence was delayed, but you probably still want the light on.')
|
||||
lights?.on()
|
||||
}
|
||||
}
|
||||
|
||||
def doorOpened(evt) {
|
||||
def delay = presenceDelay ?: 30
|
||||
|
||||
state.lastContact = now()
|
||||
|
||||
if(now() - (delay * 1000) < state.lastPresence) {
|
||||
log.info('Welcome home! Let me get that light for you.')
|
||||
lights?.on()
|
||||
}
|
||||
}
|
||||
164
smartapps/imbrianj/nobody-home.src/nobody-home.groovy
Normal file
164
smartapps/imbrianj/nobody-home.src/nobody-home.groovy
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* Nobody Home
|
||||
*
|
||||
* Author: brian@bevey.org
|
||||
* Date: 12/19/14
|
||||
*
|
||||
* Monitors a set of presence detectors and triggers a mode change when everyone has left.
|
||||
* When everyone has left, sets mode to a new defined mode.
|
||||
* When at least one person returns home, set the mode back to a new defined mode.
|
||||
* When someone is home - or upon entering the home, their mode may change dependent on sunrise / sunset.
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "Nobody Home",
|
||||
namespace: "imbrianj",
|
||||
author: "brian@bevey.org",
|
||||
description: "When everyone leaves, change mode. If at least one person home, switch mode based on sun position.",
|
||||
category: "Mode Magic",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
|
||||
)
|
||||
|
||||
preferences {
|
||||
section("When all of these people leave home") {
|
||||
input "people", "capability.presenceSensor", multiple: true
|
||||
}
|
||||
|
||||
section("Change to this mode to...") {
|
||||
input "newAwayMode", "mode", title: "Everyone is away"
|
||||
input "newSunsetMode", "mode", title: "At least one person home and nightfall"
|
||||
input "newSunriseMode", "mode", title: "At least one person home and sunrise"
|
||||
}
|
||||
|
||||
section("Away threshold (defaults to 10 min)") {
|
||||
input "awayThreshold", "decimal", title: "Number of minutes", required: false
|
||||
}
|
||||
|
||||
section("Notifications") {
|
||||
input "sendPushMessage", "enum", title: "Send a push notification?", metadata:[values:["Yes","No"]], required:false
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
init()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
unsubscribe()
|
||||
init()
|
||||
}
|
||||
|
||||
def init() {
|
||||
subscribe(people, "presence", presence)
|
||||
subscribe(location, "sunrise", setSunrise)
|
||||
subscribe(location, "sunset", setSunset)
|
||||
|
||||
state.sunMode = location.mode
|
||||
}
|
||||
|
||||
def setSunrise(evt) {
|
||||
changeSunMode(newSunriseMode)
|
||||
}
|
||||
|
||||
def setSunset(evt) {
|
||||
changeSunMode(newSunsetMode)
|
||||
}
|
||||
|
||||
def changeSunMode(newMode) {
|
||||
state.sunMode = newMode
|
||||
|
||||
if(everyoneIsAway() && (location.mode == newAwayMode)) {
|
||||
log.debug("Mode is away, not evaluating")
|
||||
}
|
||||
|
||||
else if(location.mode != newMode) {
|
||||
def message = "${app.label} changed your mode to '${newMode}'"
|
||||
send(message)
|
||||
setLocationMode(newMode)
|
||||
}
|
||||
|
||||
else {
|
||||
log.debug("Mode is the same, not evaluating")
|
||||
}
|
||||
}
|
||||
|
||||
def presence(evt) {
|
||||
if(evt.value == "not present") {
|
||||
log.debug("Checking if everyone is away")
|
||||
|
||||
if(everyoneIsAway()) {
|
||||
log.info("Starting ${newAwayMode} sequence")
|
||||
def delay = (awayThreshold != null && awayThreshold != "") ? awayThreshold * 60 : 10 * 60
|
||||
runIn(delay, "setAway")
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if(location.mode != state.sunMode) {
|
||||
log.debug("Checking if anyone is home")
|
||||
|
||||
if(anyoneIsHome()) {
|
||||
log.info("Starting ${state.sunMode} sequence")
|
||||
|
||||
changeSunMode(state.sunMode)
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
log.debug("Mode is the same, not evaluating")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def setAway() {
|
||||
if(everyoneIsAway()) {
|
||||
if(location.mode != newAwayMode) {
|
||||
def message = "${app.label} changed your mode to '${newAwayMode}' because everyone left home"
|
||||
log.info(message)
|
||||
send(message)
|
||||
setLocationMode(newAwayMode)
|
||||
}
|
||||
|
||||
else {
|
||||
log.debug("Mode is the same, not evaluating")
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
log.info("Somebody returned home before we set to '${newAwayMode}'")
|
||||
}
|
||||
}
|
||||
|
||||
private everyoneIsAway() {
|
||||
def result = true
|
||||
|
||||
if(people.findAll { it?.currentPresence == "present" }) {
|
||||
result = false
|
||||
}
|
||||
|
||||
log.debug("everyoneIsAway: ${result}")
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private anyoneIsHome() {
|
||||
def result = false
|
||||
|
||||
if(people.findAll { it?.currentPresence == "present" }) {
|
||||
result = true
|
||||
}
|
||||
|
||||
log.debug("anyoneIsHome: ${result}")
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private send(msg) {
|
||||
if(sendPushMessage != "No") {
|
||||
log.debug("Sending push message")
|
||||
sendPush(msg)
|
||||
}
|
||||
|
||||
log.debug(msg)
|
||||
}
|
||||
134
smartapps/imbrianj/ready-for-rain.src/ready-for-rain.groovy
Normal file
134
smartapps/imbrianj/ready-for-rain.src/ready-for-rain.groovy
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Ready for Rain
|
||||
*
|
||||
* Author: brian@bevey.org
|
||||
* Date: 9/10/13
|
||||
*
|
||||
* Warn if doors or windows are open when inclement weather is approaching.
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "Ready For Rain",
|
||||
namespace: "imbrianj",
|
||||
author: "brian@bevey.org",
|
||||
description: "Warn if doors or windows are open when inclement weather is approaching.",
|
||||
category: "Convenience",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
|
||||
)
|
||||
|
||||
preferences {
|
||||
section("Zip code?") {
|
||||
input "zipcode", "text", title: "Zipcode?"
|
||||
}
|
||||
|
||||
section("Things to check?") {
|
||||
input "sensors", "capability.contactSensor", multiple: true
|
||||
}
|
||||
|
||||
section("Notifications?") {
|
||||
input "sendPushMessage", "enum", title: "Send a push notification?", metadata: [values: ["Yes", "No"]], required: false
|
||||
input "phone", "phone", title: "Send a Text Message?", required: false
|
||||
}
|
||||
|
||||
section("Message interval?") {
|
||||
input name: "messageDelay", type: "number", title: "Minutes (default to every message)", required: false
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
init()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
unsubscribe()
|
||||
unschedule()
|
||||
init()
|
||||
}
|
||||
|
||||
def init() {
|
||||
state.lastMessage = 0
|
||||
state.lastCheck = ["time": 0, "result": false]
|
||||
schedule("0 0,30 * * * ?", scheduleCheck) // Check at top and half-past of every hour
|
||||
subscribe(sensors, "contact.open", scheduleCheck)
|
||||
}
|
||||
|
||||
def scheduleCheck(evt) {
|
||||
def open = sensors.findAll { it?.latestValue("contact") == "open" }
|
||||
def plural = open.size() > 1 ? "are" : "is"
|
||||
|
||||
// Only need to poll if we haven't checked in a while - and if something is left open.
|
||||
if((now() - (30 * 60 * 1000) > state.lastCheck["time"]) && open) {
|
||||
log.info("Something's open - let's check the weather.")
|
||||
def response = getWeatherFeature("forecast", zipcode)
|
||||
def weather = isStormy(response)
|
||||
|
||||
if(weather) {
|
||||
send("${open.join(', ')} ${plural} open and ${weather} coming.")
|
||||
}
|
||||
}
|
||||
|
||||
else if(((now() - (30 * 60 * 1000) <= state.lastCheck["time"]) && state.lastCheck["result"]) && open) {
|
||||
log.info("We have fresh weather data, no need to poll.")
|
||||
send("${open.join(', ')} ${plural} open and ${state.lastCheck["result"]} coming.")
|
||||
}
|
||||
|
||||
else {
|
||||
log.info("Everything looks closed, no reason to check weather.")
|
||||
}
|
||||
}
|
||||
|
||||
private send(msg) {
|
||||
def delay = (messageDelay != null && messageDelay != "") ? messageDelay * 60 * 1000 : 0
|
||||
|
||||
if(now() - delay > state.lastMessage) {
|
||||
state.lastMessage = now()
|
||||
if(sendPushMessage == "Yes") {
|
||||
log.debug("Sending push message.")
|
||||
sendPush(msg)
|
||||
}
|
||||
|
||||
if(phone) {
|
||||
log.debug("Sending text message.")
|
||||
sendSms(phone, msg)
|
||||
}
|
||||
|
||||
log.debug(msg)
|
||||
}
|
||||
|
||||
else {
|
||||
log.info("Have a message to send, but user requested to not get it.")
|
||||
}
|
||||
}
|
||||
|
||||
private isStormy(json) {
|
||||
def types = ["rain", "snow", "showers", "sprinkles", "precipitation"]
|
||||
def forecast = json?.forecast?.txt_forecast?.forecastday?.first()
|
||||
def result = false
|
||||
|
||||
if(forecast) {
|
||||
def text = forecast?.fcttext?.toLowerCase()
|
||||
|
||||
log.debug(text)
|
||||
|
||||
if(text) {
|
||||
for (int i = 0; i < types.size() && !result; i++) {
|
||||
if(text.contains(types[i])) {
|
||||
result = types[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
log.warn("Got forecast, couldn't parse.")
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
log.warn("Did not get a forecast: ${json}")
|
||||
}
|
||||
|
||||
state.lastCheck = ["time": now(), "result": result]
|
||||
|
||||
return result
|
||||
}
|
||||
131
smartapps/imbrianj/safe-watch.src/safe-watch.groovy
Normal file
131
smartapps/imbrianj/safe-watch.src/safe-watch.groovy
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Safe Watch
|
||||
*
|
||||
* Author: brian@bevey.org
|
||||
* Date: 2013-11-17
|
||||
*
|
||||
* Watch a series of sensors for any anomalies for securing a safe or room.
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "Safe Watch",
|
||||
namespace: "imbrianj",
|
||||
author: "brian@bevey.org",
|
||||
description: "Watch a series of sensors for any anomalies for securing a safe.",
|
||||
category: "Safety & Security",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
|
||||
)
|
||||
|
||||
preferences {
|
||||
section("Things to secure?") {
|
||||
input "contact", "capability.contactSensor", title: "Contact Sensor", required: false
|
||||
input "motion", "capability.motionSensor", title: "Motion Sensor", required: false
|
||||
input "knock", "capability.accelerationSensor", title: "Knock Sensor", required: false
|
||||
input "axis", "capability.threeAxis", title: "Three-Axis Sensor", required: false
|
||||
}
|
||||
|
||||
section("Temperature monitor?") {
|
||||
input "temp", "capability.temperatureMeasurement", title: "Temp Sensor", required: false
|
||||
input "maxTemp", "number", title: "Max Temp?", required: false
|
||||
input "minTemp", "number", title: "Min Temp?", required: false
|
||||
}
|
||||
|
||||
section("When which people are away?") {
|
||||
input "people", "capability.presenceSensor", multiple: true
|
||||
}
|
||||
|
||||
section("Notifications?") {
|
||||
input "sendPushMessage", "enum", title: "Send a push notification?", metadata: [values: ["Yes", "No"]], required: false
|
||||
input "phone", "phone", title: "Send a Text Message?", required: false
|
||||
}
|
||||
|
||||
section("Message interval?") {
|
||||
input name: "messageDelay", type: "number", title: "Minutes (default to every message)", required: false
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
init()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
unsubscribe()
|
||||
init()
|
||||
}
|
||||
|
||||
def init() {
|
||||
subscribe(contact, "contact.open", triggerContact)
|
||||
subscribe(motion, "motion.active", triggerMotion)
|
||||
subscribe(knock, "acceleration.active", triggerKnock)
|
||||
subscribe(temp, "temperature", triggerTemp)
|
||||
subscribe(axis, "threeAxis", triggerAxis)
|
||||
}
|
||||
|
||||
def triggerContact(evt) {
|
||||
if(everyoneIsAway()) {
|
||||
send("Safe Watch: ${contact.label ?: contact.name} was opened!")
|
||||
}
|
||||
}
|
||||
|
||||
def triggerMotion(evt) {
|
||||
if(everyoneIsAway()) {
|
||||
send("Safe Watch: ${motion.label ?: motion.name} sensed motion!")
|
||||
}
|
||||
}
|
||||
|
||||
def triggerKnock(evt) {
|
||||
if(everyoneIsAway()) {
|
||||
send("Safe Watch: ${knock.label ?: knock.name} was knocked!")
|
||||
}
|
||||
}
|
||||
|
||||
def triggerTemp(evt) {
|
||||
def temperature = evt.doubleValue
|
||||
|
||||
if((maxTemp && maxTemp < temperature) ||
|
||||
(minTemp && minTemp > temperature)) {
|
||||
send("Safe Watch: ${temp.label ?: temp.name} is ${temperature}")
|
||||
}
|
||||
}
|
||||
|
||||
def triggerAxis(evt) {
|
||||
if(everyoneIsAway()) {
|
||||
send("Safe Watch: ${axis.label ?: axis.name} was tilted!")
|
||||
}
|
||||
}
|
||||
|
||||
private everyoneIsAway() {
|
||||
def result = true
|
||||
|
||||
if(people.findAll { it?.currentPresence == "present" }) {
|
||||
result = false
|
||||
}
|
||||
|
||||
log.debug("everyoneIsAway: ${result}")
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private send(msg) {
|
||||
def delay = (messageDelay != null && messageDelay != "") ? messageDelay * 60 * 1000 : 0
|
||||
|
||||
if(now() - delay > state.lastMessage) {
|
||||
state.lastMessage = now()
|
||||
if(sendPushMessage == "Yes") {
|
||||
log.debug("Sending push message.")
|
||||
sendPush(msg)
|
||||
}
|
||||
|
||||
if(phone) {
|
||||
log.debug("Sending text message.")
|
||||
sendSms(phone, msg)
|
||||
}
|
||||
|
||||
log.debug(msg)
|
||||
}
|
||||
|
||||
else {
|
||||
log.info("Have a message to send, but user requested to not get it.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Thermostat Window Check
|
||||
*
|
||||
* Author: brian@bevey.org
|
||||
* Date: 9/13/13
|
||||
*
|
||||
* If your heating or cooling system come on, it gives you notice if there are
|
||||
* any windows or doors left open, preventing the system from working
|
||||
* optimally.
|
||||
*/
|
||||
|
||||
definition(
|
||||
name: "Thermostat Window Check",
|
||||
namespace: "imbrianj",
|
||||
author: "brian@bevey.org",
|
||||
description: "If your heating or cooling system come on, it gives you notice if there are any windows or doors left open, preventing the system from working optimally.",
|
||||
category: "Green Living",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience%402x.png"
|
||||
)
|
||||
|
||||
preferences {
|
||||
section("Things to check?") {
|
||||
input "sensors", "capability.contactSensor", multiple: true
|
||||
}
|
||||
|
||||
section("Thermostats to monitor") {
|
||||
input "thermostats", "capability.thermostat", multiple: true
|
||||
}
|
||||
|
||||
section("Notifications") {
|
||||
input "sendPushMessage", "enum", title: "Send a push notification?", metadata: [values: ["Yes", "No"]], required: false
|
||||
input "phone", "phone", title: "Send a Text Message?", required: false
|
||||
}
|
||||
|
||||
section("Turn thermostat off automatically?") {
|
||||
input "turnOffTherm", "enum", metadata: [values: ["Yes", "No"]], required: false
|
||||
}
|
||||
|
||||
section("Delay to wait before turning thermostat off (defaults to 1 minute)") {
|
||||
input "turnOffDelay", "decimal", title: "Number of minutes", required: false
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
subscribe(thermostats, "thermostatMode", thermoChange);
|
||||
subscribe(sensors, "contact.open", windowChange);
|
||||
}
|
||||
|
||||
def updated() {
|
||||
unsubscribe()
|
||||
subscribe(thermostats, "thermostatMode", thermoChange);
|
||||
subscribe(sensors, "contact.open", windowChange);
|
||||
}
|
||||
|
||||
def thermoChange(evt) {
|
||||
if(evt.value == "heat" ||
|
||||
evt.value == "cool") {
|
||||
def open = sensors.findAll { it?.latestValue("contact") == "open" }
|
||||
|
||||
if(open) {
|
||||
def plural = open.size() > 1 ? "are" : "is"
|
||||
send("${open.join(', ')} ${plural} still open and the thermostat just came on.")
|
||||
|
||||
thermoShutOffTrigger()
|
||||
}
|
||||
|
||||
else {
|
||||
log.info("Thermostat came on and nothing is open.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def windowChange(evt) {
|
||||
def heating = thermostats.findAll { it?.latestValue("thermostatMode") == "heat" }
|
||||
def cooling = thermostats.findAll { it?.latestValue("thermostatMode") == "cool" }
|
||||
|
||||
if(heating || cooling) {
|
||||
def open = sensors.findAll { it?.latestValue("contact") == "open" }
|
||||
def tempDirection = heating ? "heating" : "cooling"
|
||||
def plural = open.size() > 1 ? "were" : "was"
|
||||
send("${open.join(', ')} ${plural} opened and the thermostat is still ${tempDirection}.")
|
||||
|
||||
thermoShutOffTrigger()
|
||||
}
|
||||
}
|
||||
|
||||
def thermoShutOffTrigger() {
|
||||
if(turnOffTherm == "Yes") {
|
||||
log.info("Starting timer to turn off thermostat")
|
||||
def delay = (turnOffDelay != null && turnOffDelay != "") ? turnOffDelay * 60 : 60
|
||||
state.turnOffTime = now()
|
||||
|
||||
runIn(delay, "thermoShutOff")
|
||||
}
|
||||
}
|
||||
|
||||
def thermoShutOff() {
|
||||
def open = sensors.findAll { it?.latestValue("contact") == "open" }
|
||||
def tempDirection = heating ? "heating" : "cooling"
|
||||
def plural = open.size() > 1 ? "are" : "is"
|
||||
|
||||
log.info("Checking if we need to turn thermostats off")
|
||||
|
||||
if(open.size()) {
|
||||
send("Thermostats turned off: ${open.join(', ')} ${plural} open and thermostats ${tempDirection}.")
|
||||
log.info("Windows still open, turning thermostats off")
|
||||
thermostats?.off()
|
||||
}
|
||||
|
||||
else {
|
||||
log.info("Looks like everything is shut now - no need to turn off thermostats")
|
||||
}
|
||||
}
|
||||
|
||||
private send(msg) {
|
||||
if(sendPushMessage != "No") {
|
||||
log.debug("Sending push message")
|
||||
sendPush(msg)
|
||||
}
|
||||
|
||||
if(phone) {
|
||||
log.debug("Sending text message")
|
||||
sendSms(phone, msg)
|
||||
}
|
||||
|
||||
log.debug(msg)
|
||||
}
|
||||
Reference in New Issue
Block a user