mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-22 13:20:53 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55081dd486 | ||
|
|
90dee51255 | ||
|
|
7b7fdd43cd | ||
|
|
9059718818 | ||
|
|
8ae9b06022 | ||
|
|
71fc8e7f5f |
@@ -66,9 +66,20 @@ metadata {
|
|||||||
import physicalgraph.zwave.commands.doorlockv1.*
|
import physicalgraph.zwave.commands.doorlockv1.*
|
||||||
import physicalgraph.zwave.commands.usercodev1.*
|
import physicalgraph.zwave.commands.usercodev1.*
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
try {
|
||||||
|
if (!state.init) {
|
||||||
|
state.init = true
|
||||||
|
response(secureSequence([zwave.doorLockV1.doorLockOperationGet(), zwave.batteryV1.batteryGet()]))
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log.warn "updated() threw $e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
def result = null
|
def result = null
|
||||||
if (description.startsWith("Err")) {
|
if (description.startsWith("Err 106")) {
|
||||||
if (state.sec) {
|
if (state.sec) {
|
||||||
result = createEvent(descriptionText:description, displayed:false)
|
result = createEvent(descriptionText:description, displayed:false)
|
||||||
} else {
|
} else {
|
||||||
@@ -80,6 +91,8 @@ def parse(String description) {
|
|||||||
displayed: true,
|
displayed: true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else if (description == "updated") {
|
||||||
|
return null
|
||||||
} else {
|
} else {
|
||||||
def cmd = zwave.parse(description, [ 0x98: 1, 0x72: 2, 0x85: 2, 0x86: 1 ])
|
def cmd = zwave.parse(description, [ 0x98: 1, 0x72: 2, 0x85: 2, 0x86: 1 ])
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
@@ -286,7 +299,7 @@ def zwaveEvent(physicalgraph.zwave.commands.alarmv2.AlarmReport cmd) {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 167:
|
case 167:
|
||||||
if (!state.lastbatt || (new Date().time) - state.lastbatt > 12*60*60*1000) {
|
if (!state.lastbatt || now() - state.lastbatt > 12*60*60*1000) {
|
||||||
map = [ descriptionText: "$device.displayName: battery low", isStateChange: true ]
|
map = [ descriptionText: "$device.displayName: battery low", isStateChange: true ]
|
||||||
result << response(secure(zwave.batteryV1.batteryGet()))
|
result << response(secure(zwave.batteryV1.batteryGet()))
|
||||||
} else {
|
} else {
|
||||||
@@ -431,7 +444,7 @@ def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
|||||||
} else {
|
} else {
|
||||||
map.value = cmd.batteryLevel
|
map.value = cmd.batteryLevel
|
||||||
}
|
}
|
||||||
state.lastbatt = new Date().time
|
state.lastbatt = now()
|
||||||
createEvent(map)
|
createEvent(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,15 +512,14 @@ def refresh() {
|
|||||||
cmds << "delay 4200"
|
cmds << "delay 4200"
|
||||||
cmds << zwave.associationV1.associationGet(groupingIdentifier:2).format() // old Schlage locks use group 2 and don't secure the Association CC
|
cmds << zwave.associationV1.associationGet(groupingIdentifier:2).format() // old Schlage locks use group 2 and don't secure the Association CC
|
||||||
cmds << secure(zwave.associationV1.associationGet(groupingIdentifier:1))
|
cmds << secure(zwave.associationV1.associationGet(groupingIdentifier:1))
|
||||||
state.associationQuery = new Date().time
|
state.associationQuery = now()
|
||||||
} else if (new Date().time - state.associationQuery.toLong() > 9000) {
|
} else if (secondsPast(state.associationQuery, 9)) {
|
||||||
log.debug "setting association"
|
|
||||||
cmds << "delay 6000"
|
cmds << "delay 6000"
|
||||||
cmds << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId).format()
|
cmds << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId).format()
|
||||||
cmds << secure(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId))
|
cmds << secure(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId))
|
||||||
cmds << zwave.associationV1.associationGet(groupingIdentifier:2).format()
|
cmds << zwave.associationV1.associationGet(groupingIdentifier:2).format()
|
||||||
cmds << secure(zwave.associationV1.associationGet(groupingIdentifier:1))
|
cmds << secure(zwave.associationV1.associationGet(groupingIdentifier:1))
|
||||||
state.associationQuery = new Date().time
|
state.associationQuery = now()
|
||||||
}
|
}
|
||||||
log.debug "refresh sending ${cmds.inspect()}"
|
log.debug "refresh sending ${cmds.inspect()}"
|
||||||
cmds
|
cmds
|
||||||
@@ -515,55 +527,22 @@ def refresh() {
|
|||||||
|
|
||||||
def poll() {
|
def poll() {
|
||||||
def cmds = []
|
def cmds = []
|
||||||
if (state.assoc != zwaveHubNodeId && secondsPast(state.associationQuery, 19 * 60)) {
|
// Only check lock state if it changed recently or we haven't had an update in an hour
|
||||||
log.debug "setting association"
|
def latest = device.currentState("lock")?.date?.time
|
||||||
cmds << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:zwaveHubNodeId).format()
|
if (!latest || !secondsPast(latest, 6 * 60) || secondsPast(state.lastPoll, 55 * 60)) {
|
||||||
cmds << secure(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId))
|
cmds << secure(zwave.doorLockV1.doorLockOperationGet())
|
||||||
cmds << zwave.associationV1.associationGet(groupingIdentifier:2).format()
|
state.lastPoll = now()
|
||||||
cmds << "delay 6000"
|
} else if (!state.lastbatt || now() - state.lastbatt > 53*60*60*1000) {
|
||||||
cmds << secure(zwave.associationV1.associationGet(groupingIdentifier:1))
|
cmds << secure(zwave.batteryV1.batteryGet())
|
||||||
cmds << "delay 6000"
|
state.lastbatt = now() //inside-214
|
||||||
state.associationQuery = new Date().time
|
|
||||||
} else {
|
|
||||||
// Only check lock state if it changed recently or we haven't had an update in an hour
|
|
||||||
def latest = device.currentState("lock")?.date?.time
|
|
||||||
if (!latest || !secondsPast(latest, 6 * 60) || secondsPast(state.lastPoll, 55 * 60)) {
|
|
||||||
cmds << secure(zwave.doorLockV1.doorLockOperationGet())
|
|
||||||
state.lastPoll = (new Date()).time
|
|
||||||
} else if (!state.MSR) {
|
|
||||||
cmds << zwave.manufacturerSpecificV1.manufacturerSpecificGet().format()
|
|
||||||
} else if (!state.fw) {
|
|
||||||
cmds << zwave.versionV1.versionGet().format()
|
|
||||||
} else if (!state.codes) {
|
|
||||||
state.pollCode = 1
|
|
||||||
cmds << secure(zwave.userCodeV1.usersNumberGet())
|
|
||||||
} else if (state.pollCode && state.pollCode <= state.codes) {
|
|
||||||
cmds << requestCode(state.pollCode)
|
|
||||||
} else if (!state.lastbatt || (new Date().time) - state.lastbatt > 53*60*60*1000) {
|
|
||||||
cmds << secure(zwave.batteryV1.batteryGet())
|
|
||||||
} else if (!state.enc) {
|
|
||||||
encryptCodes()
|
|
||||||
state.enc = 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
log.debug "poll is sending ${cmds.inspect()}"
|
if (cmds) {
|
||||||
device.activity()
|
log.debug "poll is sending ${cmds.inspect()}"
|
||||||
cmds ?: null
|
cmds
|
||||||
}
|
} else {
|
||||||
|
// workaround to keep polling from stopping due to lack of activity
|
||||||
private def encryptCodes() {
|
sendEvent(descriptionText: "skipping poll", isStateChange: true, displayed: false)
|
||||||
def keys = new ArrayList(state.keySet().findAll { it.startsWith("code") })
|
null
|
||||||
keys.each { key ->
|
|
||||||
def match = (key =~ /^code(\d+)$/)
|
|
||||||
if (match) try {
|
|
||||||
def keynum = match[0][1].toInteger()
|
|
||||||
if (keynum > 30 && !state[key]) {
|
|
||||||
state.remove(key)
|
|
||||||
} else if (state[key] && !state[key].startsWith("~")) {
|
|
||||||
log.debug "encrypting $key: ${state[key].inspect()}"
|
|
||||||
state[key] = encrypt(state[key])
|
|
||||||
}
|
|
||||||
} catch (java.lang.NumberFormatException e) { }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,7 +651,7 @@ private Boolean secondsPast(timestamp, seconds) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (new Date().time - timestamp) > (seconds * 1000)
|
return (now() - timestamp) > (seconds * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
private allCodesDeleted() {
|
private allCodesDeleted() {
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* Light Up The Night
|
||||||
|
*
|
||||||
|
* Copyright 2015 Brian Warner
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
definition(
|
||||||
|
name: "Light Up The Night",
|
||||||
|
namespace: "brianwarner",
|
||||||
|
author: "Brian Warner",
|
||||||
|
description: "Turn on certain lights when a door opens at night, and turn them off a certain time after the last door closes. Great for garage doors and driveway lights.",
|
||||||
|
category: "Convenience",
|
||||||
|
iconUrl: "http://cdn.device-icons.smartthings.com/Lighting/light9-icn.png",
|
||||||
|
iconX2Url: "http://cdn.device-icons.smartthings.com/Lighting/light9-icn@2x.png",
|
||||||
|
iconX3Url: "http://cdn.device-icons.smartthings.com/Lighting/light9-icn@3x.png")
|
||||||
|
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
|
||||||
|
section() {
|
||||||
|
input "contactsensors", "capability.contactSensor", multiple: true, title: "When these doors open:"
|
||||||
|
}
|
||||||
|
|
||||||
|
section() {
|
||||||
|
input "lights", "capability.switch", required: true, multiple: true, title: "Turn on these lights:"
|
||||||
|
}
|
||||||
|
|
||||||
|
section() {
|
||||||
|
input "timer", "number", required: true, title: "Keep them on until all doors are closed for this many minutes:", range: "0..240"
|
||||||
|
}
|
||||||
|
|
||||||
|
section() {
|
||||||
|
input "sunriseoffset", "number", required: true, title: "Start turning on the lights this many minutes before sunset:", range: "0..360"
|
||||||
|
}
|
||||||
|
|
||||||
|
section() {
|
||||||
|
input "sunsetoffset", "number", required: true, title: "Stop turning on the lights this many minutes after sunrise:", range: "0..360"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
log.debug "Installed with settings: ${settings}"
|
||||||
|
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
log.debug "Updated with settings: ${settings}"
|
||||||
|
|
||||||
|
unsubscribe()
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
|
subscribe(garagedoors, "door.open", doorOpenHandler)
|
||||||
|
subscribe(garagedoors, "door.closed", doorClosedHandler)
|
||||||
|
subscribe(contactsensors, "contact.open", doorOpenHandler)
|
||||||
|
subscribe(contactsensors, "contact.closed", doorClosedHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
def doorOpenHandler(evt) {
|
||||||
|
// log.debug "Door opened."
|
||||||
|
def now = new Date()
|
||||||
|
def sunTime = getSunriseAndSunset(sunriseOffset: "00:$sunriseoffset", sunsetOffset: "-00:$sunsetoffset")
|
||||||
|
|
||||||
|
if (now > sunTime.sunset || now < sunTime.sunrise) {
|
||||||
|
// log.debug "Turning lights on."
|
||||||
|
lights.on()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def doorClosedHandler(evt) {
|
||||||
|
// log.debug "A door closed."
|
||||||
|
runIn(60 * timer, checkClosed)
|
||||||
|
}
|
||||||
|
|
||||||
|
def checkClosed() {
|
||||||
|
// log.debug "Checking to ensure all doors are still closed."
|
||||||
|
|
||||||
|
def contactSensorState = contactsensors.currentState("contact")
|
||||||
|
def anyContactSensorsOpen = contactSensorState.value.findAll {it == "open"}
|
||||||
|
|
||||||
|
if (!anyContactSensorsOpen) {
|
||||||
|
def elapsed = now() - contactSensorState.date.time.max()
|
||||||
|
def timeout = 1000 * 60 * timer
|
||||||
|
|
||||||
|
if (elapsed >= timeout) {
|
||||||
|
// log.debug "Doors have stayed closed. Turning off the lights."
|
||||||
|
lights.off()
|
||||||
|
} else {
|
||||||
|
// log.debug "Doors were opened. Wait a little longer."
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// log.debug "It appears a door is still open."
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -246,6 +246,9 @@ def toggle(devices) {
|
|||||||
else if (devices*.currentValue('lock').contains('locked')) {
|
else if (devices*.currentValue('lock').contains('locked')) {
|
||||||
devices.unlock()
|
devices.unlock()
|
||||||
}
|
}
|
||||||
|
else if (devices*.currentValue('lock').contains('unlocked')) {
|
||||||
|
devices.lock()
|
||||||
|
}
|
||||||
else if (devices*.currentValue('alarm').contains('off')) {
|
else if (devices*.currentValue('alarm').contains('off')) {
|
||||||
devices.siren()
|
devices.siren()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,168 +0,0 @@
|
|||||||
/**
|
|
||||||
* Auto Lock
|
|
||||||
*
|
|
||||||
* Copyright 2015 Vikash Varma
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Automatically generated. Make future change here.
|
|
||||||
definition(
|
|
||||||
name: "Auto Lock",
|
|
||||||
namespace: "varma",
|
|
||||||
author: "Vikash Varma",
|
|
||||||
description: "Manage authorized users and send notification when lock is unlocked. Automatically lock it based on elapsed time or no motion detected near the lock",
|
|
||||||
category: "Safety & Security",
|
|
||||||
iconUrl: "http://ecx.images-amazon.com/images/I/51lIeDU229L._SL1500_.jpg",
|
|
||||||
iconX2Url: "http://ecx.images-amazon.com/images/I/51lIeDU229L._SL1500_.jpg",
|
|
||||||
oauth: true
|
|
||||||
)
|
|
||||||
import groovy.json.JsonSlurper
|
|
||||||
|
|
||||||
preferences {
|
|
||||||
page (name: "mainPage", title: "Automatically locks a deadbolt or lever lock using motion sensor or time elapsed", nextPage: "page2", uninstall: true) {
|
|
||||||
section {
|
|
||||||
input "lockDevice", "capability.lock", title:"Which Lock?"
|
|
||||||
input "lockOpt", "enum", title: "Preference", metadata: [values: ["Motion", "Time"]], multiple:false
|
|
||||||
input "maxusers", "number", title: "Maximum authorized users", required:true
|
|
||||||
input "pushNotify", "boolean" , title:"Send push notification when unlocked", default: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
page (name: "page2", nextPage: "adduser", title: "Automatically locks a deadbolt or lever lock using motion sensor or time elapsed", install: true, uninstall: true)
|
|
||||||
}
|
|
||||||
def page2() {
|
|
||||||
dynamicPage(name: "page2") {
|
|
||||||
section("Set $lockOpt Preference") {
|
|
||||||
if (lockOpt == "Motion" ) {
|
|
||||||
input "motion1", "capability.motionSensor", title:"Lock door after no motion"
|
|
||||||
} else {
|
|
||||||
input "minutesLater", "number", title: "Lock door after how many minutes?"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; i <= settings.maxusers; i++) {
|
|
||||||
section("Add User #${i}") {
|
|
||||||
input "user${i}", "string", title: "Username", required:true
|
|
||||||
input "code${i}", "password", title: "Code", required:true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def installed() {
|
|
||||||
log.debug "Installed with settings: ${settings}"
|
|
||||||
initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
def updated() {
|
|
||||||
log.debug "Updated with settings: ${settings}"
|
|
||||||
unsubscribe()
|
|
||||||
initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
def initialize() {
|
|
||||||
state.lockStatus = 1 // 0 = locked; 1 = unlocked
|
|
||||||
subscribe(lockDevice, "lock.locked", lockEvent)
|
|
||||||
if (lockOpt == 'Time') {
|
|
||||||
subscribe(lockDevice, "lock.unlocked", unlockEvent)
|
|
||||||
} else {
|
|
||||||
subscribe(motion1, "motion", motionHandler)
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteLockCode()
|
|
||||||
state.maxusers = 0
|
|
||||||
for (int i=0; i< settings.maxusers; i++) {
|
|
||||||
runIn(i*180, setLockCode, [overwrite: false])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def setLockCode() {
|
|
||||||
log.trace "setLockCode start: state.maxuser=$state.maxusers"
|
|
||||||
if (state.maxusers < settings.maxusers ) {
|
|
||||||
state.maxusers = state.maxusers + 1
|
|
||||||
def lockCode = settings."code${state.maxusers}"
|
|
||||||
lockCode = lockCode +""
|
|
||||||
def msg = "$lockDevice added user $state.maxusers, code: $lockCode"
|
|
||||||
log.info msg
|
|
||||||
lockDevice.setCode(state.maxusers, lockCode)
|
|
||||||
} else {
|
|
||||||
log.debug "end scheduling,state.maxuser=$state.maxusers, settings.maxusers=$settings.maxusers"
|
|
||||||
}
|
|
||||||
log.trace "setLockCode end: state.maxuser=$state.maxusers"
|
|
||||||
}
|
|
||||||
|
|
||||||
def unlockEvent(evt) {
|
|
||||||
log.debug "Lock ${lockDevice} was: ${evt.value}"
|
|
||||||
state.lockStatus = 1
|
|
||||||
def delay = minutesLater * 60
|
|
||||||
log.debug "Locking $lockDevice.displayName in ${minutesLater} minutes"
|
|
||||||
runIn(delay, lockDoor)
|
|
||||||
|
|
||||||
def data = []
|
|
||||||
def unlockmsg = ""
|
|
||||||
if (evt.data != null) {
|
|
||||||
data = new JsonSlurper().parseText(evt.data)
|
|
||||||
if (data.usedCode <= settings.maxusers) {
|
|
||||||
def u = settings."user${data.usedCode}"
|
|
||||||
unlockmsg = "$lockDevice was unlocked by $u"
|
|
||||||
} else {
|
|
||||||
unlockmsg = "$lockDevice was unlocked by unknown user"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unlockmsg = "$lockDevice was unlocked by app"
|
|
||||||
|
|
||||||
}
|
|
||||||
log.debug "pushNotify=$pushNotify | unlockmsg=$unlockmsg"
|
|
||||||
if (pushNotify) {
|
|
||||||
sendPush(unlockmsg);
|
|
||||||
} else {
|
|
||||||
log.debug "noPush"
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def lockEvent(evt) {
|
|
||||||
state.lockStatus = 0
|
|
||||||
log.debug "$lockDevice.displayName is locked"
|
|
||||||
unschedule( lockDoor )
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def motionHandler(evt) {
|
|
||||||
if (evt.value == "inactive") {
|
|
||||||
lockDoor(evt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def lockDoor(evt) {
|
|
||||||
if ( state.lockStatus ) {
|
|
||||||
sendPush("$app.name is locking $lockDevice.displayName")
|
|
||||||
lockDevice.lock()
|
|
||||||
state.lockStatus = 0
|
|
||||||
} else {
|
|
||||||
log.debug "$lolockDeviceck1.displayName already locked"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def deleteLockCode() {
|
|
||||||
log.debug "in deleteLockCode"
|
|
||||||
for (int i = settings.maxusers + 1 ; i <= state.maxusers; i++) {
|
|
||||||
lockDevice.deleteCode(i)
|
|
||||||
log.debug "Deleting code $i"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def checkCodeSetup() {
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user