Skip to content

Commit

Permalink
lock info and overwrite mode
Browse files Browse the repository at this point in the history
  • Loading branch information
ethayer committed Jan 8, 2017
1 parent e79da20 commit 2ab41f7
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,6 @@ private allCodesDeleted() {
}

def reportAllCodes(state) {
log.debug 'report..'
def map = [ name: "reportAllCodes", data: [:], displayed: false, isStateChange: false, type: "physical" ]
state.each { entry ->
//iterate through all the state entries and add them to the event data to be handled by application event handlers
Expand Down
150 changes: 142 additions & 8 deletions smartapps/ethayer/lock-manager.src/lock-manager.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ definition(
namespace: 'ethayer',
author: 'Erik Thayer',
description: 'Manage locks and users',
category: 'My Apps',
category: 'Safety & Security',
iconUrl: 'https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png',
iconX2Url: 'https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png',
iconX3Url: 'https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png'
Expand All @@ -13,18 +13,75 @@ import groovy.json.JsonBuilder

preferences {
page(name: 'mainPage', title: 'Users', install: true, uninstall: true,submitOnChange: true)
page(name: "lockInfoPage")
page(name: "infoRefreshPage")
}

def mainPage() {
dynamicPage(name: 'mainPage', install: true, uninstall: true, submitOnChange: true) {
section('Create') {
app(name: 'lockUsers', appName: "Lock User", namespace: "ethayer", title: "New User", multiple: true)
}
section('Which Locks?') {
section('Locks') {
if (locks) {
def i = 0
locks.each { lock->
i++
href(name: "toLockInfoPage${i}", page: "lockInfoPage", params: [id: lock.id], required: false, title: lock.displayName )
}
}
}
section('Global Settings') {
input 'locks', 'capability.lockCodes', title: 'Select Locks', required: true, multiple: true, submitOnChange: true
input(name: "overwriteMode", title: "Overwrite?", type: "bool", required: true, defaultValue: true, description: 'Overwrite mode automatically deletes codes not in the users list')
href(name: "toInfoRefreshPage", page: "infoRefreshPage", title: "Refresh Lock Data", description: 'Tap to refresh')
}
}
}

def infoRefreshPage() {
dynamicPage(name:"infoRefreshPage", title:"Lock Info") {
section() {
doPoll()
paragraph "Lock info refreshing soon."
href(name: "toMainPage", page: "mainPage", title: "Back")
}
}
}

def lockInfoPage(params) {
dynamicPage(name:"lockInfoPage", title:"Lock Info") {
def lock = getLock(params)
if (lock) {
section("${lock.displayName}") {
if (state."lock${lock.id}".codes != null) {
def i = 0
def setCode = ''
def child
def usage
def para
state."lock${lock.id}".codes.each { code->
i++
child = findAssignedChildApp(lock, i)
setCode = state."lock${lock.id}".codes."slot${i}"
para = "Slot ${i}\nCode: ${setCode}"
if (child) {
para = para + child.getLockUserInfo(lock)
}
paragraph para

}
} else {
paragraph "No Lock data received yet. Requires custom device driver. Will be populated on next poll event."
doPoll()
}
}
} else {
section() {
paragraph "Error: Can't find lock!"
}
}
}
}

def installed() {
Expand All @@ -39,18 +96,36 @@ def updated() {
}

def initialize() {
// nothing needed here, since the child apps will handle preferences/subscriptions
// this just logs some messages for demo/information purposes
def children = getChildApps()

initalizeLockData()
setAccess()
subscribe(locks, "reportAllCodes", pollCodeReport, [filterEvents:false])
log.debug "there are ${children.size()} lock users"
}

log.debug "there are ${children.size()} child smartapps"
childApps.each {child ->
log.debug "child app: ${child.label}"
def initalizeLockData() {
locks.each { lock->
if (state."lock${lock.id}" == null) {
state."lock${lock.id}" = [:]
}
}
}

def getLock(params) {
def id = ''
// Assign params to id. Sometimes parameters are double nested.
if (params.id) {
id = params.id
} else if (params.params){
id = params.params.id
} else if (state.lastLock) {
id = state.lastLock
}
state.lastLock = id
return locks.find{it.id == id}
}

def availableSlots(selectedSlot) {
def options = []
(1..30).each { slot->
Expand Down Expand Up @@ -86,12 +161,48 @@ def pollCodeReport(evt) {
needPoll = true
}
}
if (needPoll) {
def unmangedCodesNotReady = false
if (overwriteMode) {
unmangedCodesNotReady = removeUnmanagedCodes(evt)
}
if (needPoll || unmangedCodesNotReady) {
log.debug 'asking for poll!'
runIn(20, doPoll)
}
}

def removeUnmanagedCodes(evt) {
def codeData = new JsonSlurper().parseText(evt.data)
def lock = locks.find{it.id == evt.deviceId}
def array = []
def codes = [:]
def codeSlots = 30
if (codeData.codes) {
codeSlots = codeData.codes
}

(1..codeSlots).each { slot ->
def child = findAssignedChildApp(lock, slot)
if (!child) {
def currentCode = codeData."code${slot}"
// there is no app associated
if (currentCode != '') {
// Code is set, We should be disabled.
array << ["code${slot}", '']
}
}
}
def json = new groovy.json.JsonBuilder(array).toString()
if (json != '[]') {
//Lock has codes we don't want
lock.updateCodes(json)
return true
} else {
//Lock is clean
return false
}
}

// def doErrorPoll() {
// def needPoll = false
// def children = getChildApps()
Expand Down Expand Up @@ -130,3 +241,26 @@ def setAccess() {
def doPoll() {
locks.poll()
}

def populateDiscovery(codeData, lock) {
def codes = [:]
def codeSlots = 30
if (codeData.codes) {
codeSlots = codeData.codes
}
(1..codeSlots).each { slot->
codes."slot${slot}" = codeData."code${slot}"
}
state."lock${lock.id}".codes = codes
}

def findAssignedChildApp(lock, slot) {
def children = getChildApps()
def childApp = false
children.each { child ->
if (child.userSlot?.toInteger() == slot) {
childApp = child
}
}
return childApp
}
17 changes: 14 additions & 3 deletions smartapps/ethayer/lock-user.src/lock-user.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ definition (
namespace: 'ethayer',
author: 'Erik Thayer',
description: 'App to manager users. This is a child app.',
category: 'My Apps',
category: 'Safety & Security',

// the parent option allows you to specify the parent app in the form <namespace>/<app name>
parent: 'ethayer:Lock Manager',
iconUrl: 'https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png',
iconX2Url: 'https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png',
Expand Down Expand Up @@ -440,7 +439,6 @@ def isValidCode() {
if (userCode?.isNumber()) {
return true
} else {
log.debug 'Not a number!'
return false
}
}
Expand Down Expand Up @@ -686,6 +684,8 @@ def pollCodeReport(evt) {
def active = isActive(lock.id)
def currentCode = codeData."code${userSlot}"
def array = []

parent.populateDiscovery(codeData, lock)
setKnownCode(currentCode, lock)

if (active) {
Expand Down Expand Up @@ -812,3 +812,14 @@ def sendMessage(msg) {
}
}
}

def getLockUserInfo(lock) {
def para = "\n${app.label}"
def usage = state."lock${lock.id}".usage
para += " // Usage: ${usage}"
if (!state."lock${lock.id}".enabled) {
def reason = state."lock${lock.id}".disabledReason
para += "\n ${reason}"
}
return para
}

0 comments on commit 2ab41f7

Please sign in to comment.