Initial commit

This commit is contained in:
bflorian
2015-08-04 15:49:03 -07:00
commit 6ad3c4fd7a
322 changed files with 67201 additions and 0 deletions

View 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)
}

View File

@@ -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.")
}
}

View File

@@ -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()
}
}

View 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)
}

View 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
}

View 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.")
}
}

View File

@@ -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)
}