Trouble adding acceleration sensor to Smart Security


(Micah Kordsmeier) #1

I want my siren to go off if vibration is detected on a back window. So I’m trying to edit the Smart Security app so that it includes the acceleration capability of the SmartSense multi sensor. It seems straightforward enough, but when I test it, the acceleration sensor won’t turn on the siren. Here is the code. Basically, every time the program references a contact sensor, I added a section for the acceleration sensor below it.

Can anyone help me? My house has been burglarized twice in the past month and I’m desperate to get all my security up and running. Thank you!

/**
 *  Smart Security
 *
 *  Author: SmartThings
 *  Date: 2013-03-07
 */
definition(
    name: "Smart Security",
    namespace: "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",
    category: "Safety & Security",
    iconUrl: "https://s3.amazonaws.com/smartapp-icons/SafetyAndSecurity/App-IsItSafe.png",
    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/SafetyAndSecurity/App-IsItSafe@2x.png"
)

preferences {
    section("Sensors detecting an intruder") {
        input "intrusionMotions", "capability.motionSensor", title: "Motion Sensors", multiple: true, required: false
        input "intrusionContacts", "capability.contactSensor", title: "Contact Sensors", multiple: true, required: false
        input "intrusionAcceleration", "capability.accelerationSensor", title: "Vibration Sensors", multiple: true, required: false
    }
    section("Sensors detecting residents") {
        input "residentMotions", "capability.motionSensor", title: "Motion Sensors", multiple: true, required: false
    }
    section("Alarm settings and actions") {
        input "alarms", "capability.alarm", title: "Which Alarm(s)", multiple: true, required: false
        input "silent", "text", title: "Silent alarm only (Yes/No)"
        input "seconds", "number", title: "Delay in seconds before siren sounds"
        input "lights", "capability.switch", title: "Flash these lights (optional)", multiple: true, required: false
        input "newMode", "mode", title: "Change to this mode (optional)", required: false
    }
    section("Notify others (optional)") {
        input "textMessage", "text", title: "Send this message", multiple: false, required: false
        input "phone", "text", title: "To this phone", multiple: false, required: false
    }
    section("Arm system when residents quiet for (default 3 minutes)") {
        input "residentsQuietThreshold", "number", title: "Time in minutes", required: false
    }
}

def installed() {
    log.debug "INSTALLED"
    subscribeToEvents()
    state.alarmActive = null
}

def updated() {
    log.debug "UPDATED"
    unsubscribe()
    subscribeToEvents()
    unschedule()
    state.alarmActive = null
    state.residentsAreUp = null
    state.lastIntruderMotion = null
    alarms?.off()
}

private subscribeToEvents()
{
    subscribe intrusionMotions, "motion", intruderMotion
    subscribe residentMotions, "motion", residentMotion
    subscribe intrusionContacts, "contact", contact
        subscribe intrustionAcceleration, "vibration", intruderAcceleration
    subscribe alarms, "alarm", alarm
    subscribe(app, appTouch)
}

private residentsHaveBeenQuiet()
{
    def threshold = ((residentsQuietThreshold != null && residentsQuietThreshold != "") ? residentsQuietThreshold : 3) * 60 * 1000
    def result = true
    def t0 = new Date(now() - threshold)
    for (sensor in residentMotions) {
        def recentStates = sensor.statesSince("motion", t0)
        if (recentStates.find{it.value == "active"}) {
            result = false
            break
        }
    }
    log.debug "residentsHaveBeenQuiet: $result"
    result
}

private intruderMotionInactive()
{
    def result = true
    for (sensor in intrusionMotions) {
        if (sensor.currentMotion == "active") {
            result = false
            break
        }
    }
    result
}

private isResidentMotionSensor(evt)
{
    residentMotions?.find{it.id == evt.deviceId} != null
}

def appTouch(evt)
{
    alarms?.off()
    state.alarmActive = false
}

// Here to handle old subscriptions
def motion(evt)
{
    if (isResidentMotionSensor(evt)) {
        log.debug "resident motion, $evt.name: $evt.value"
        residentMotion(evt)
    }
    else {
        log.debug "intruder motion, $evt.name: $evt.value"
        intruderMotion(evt)
    }
}

def intruderMotion(evt)
{
    if (evt.value == "active") {
        log.debug "motion by potential intruder, residentsAreUp: $state.residentsAreUp"
        if (!state.residentsAreUp) {
            log.trace "checking if residents have been quiet"
            if (residentsHaveBeenQuiet()) {
                log.trace "calling startAlarmSequence"
                startAlarmSequence()
            }
            else {
                log.trace "calling disarmIntrusionDetection"
                disarmIntrusionDetection()
            }
        }
    }
    state.lastIntruderMotion = now()
}

def residentMotion(evt)
{
    // Don't think we need this any more
    //if (evt.value == "inactive") {
    //    if (state.residentsAreUp) {
    //        startReArmSequence()
    //    }
    //}
}

def contact(evt)
{
    if (evt.value == "open") {
        // TODO - check for residents being up?
        if (!state.residentsAreUp) {
            if (residentsHaveBeenQuiet()) {
                startAlarmSequence()
            }
            else {
                disarmIntrusionDetection()
            }
        }
    }
}

def intruderAcceleration(evt)
{
    if (evt.value == "active") {
    // TODO - check for residents being up?
        if (!state.residentsAreUp) {
            if (residentsHaveBeenQuiet()) {
                startAlarmSequence()
            }
            else {
                disarmIntrusionDetection()
            }
        }
    }
}

def alarm(evt)
{
    log.debug "$evt.name: $evt.value"
    if (evt.value == "off") {
        alarms?.off()
        state.alarmActive = false
    }
}

private disarmIntrusionDetection()
{
    log.debug "residents are up, disarming intrusion detection"
    state.residentsAreUp = true
    scheduleReArmCheck()
}

private scheduleReArmCheck()
{
    def cron = "0 * * * * ?"
    schedule(cron, "checkForReArm")
    log.debug "Starting re-arm check, cron: $cron"
}

def checkForReArm()
{
    def threshold = ((residentsQuietThreshold != null && residentsQuietThreshold != "") ? residentsQuietThreshold : 3) * 60 * 1000
    log.debug "checkForReArm: threshold is $threshold"
    // check last intruder motion
    def lastIntruderMotion = state.lastIntruderMotion
    log.debug "checkForReArm: lastIntruderMotion=$lastIntruderMotion"
    if (lastIntruderMotion != null)
    {
        log.debug "checkForReArm, time since last intruder motion: ${now() - lastIntruderMotion}"
        if (now() - lastIntruderMotion > threshold) {
            log.debug "re-arming intrusion detection"
            state.residentsAreUp = false
            unschedule()
        }
    }
    else {
        log.warn "checkForReArm: lastIntruderMotion was null, unable to check for re-arming intrusion detection"
    }    
}

private startAlarmSequence()
{
    if (state.alarmActive) {
        log.debug "alarm already active"
    }
    else {
        state.alarmActive = true
        log.debug "starting alarm sequence"
        sendPush("Potential intruder detected!")

        if (newMode) {
            setLocationMode(newMode)
        }

        if (silentAlarm()) {
            log.debug "Silent alarm only"
            alarms?.strobe()
            if (phone) {
                sendSms(phone, textMessage ?: "Potential intruder detected")
            }
        }
        else {
            def delayTime = seconds
            if (delayTime) {
                alarms?.strobe()
                runIn(delayTime, "soundSiren")
                log.debug "Sounding siren in $delayTime seconds"
            }
            else {
                soundSiren()
            }
        }

        if (lights) {
            flashLights(Math.min((seconds/2) as Integer, 10))
        }
    }
}

def soundSiren()
{
    if (state.alarmActive) {
        log.debug "Sounding siren"
        if (phone) {
            sendSms(phone, textMessage ?: "Potential intruder detected")
        }
        alarms?.both()
        if (lights) {
            log.debug "continue flashing lights"
            continueFlashing()
        }
    }
    else {
        log.debug "alarm activation aborted"
    }
    unschedule("soundSiren") // Temporary work-around to scheduling bug
}

def continueFlashing()
{
    unschedule()
    if (state.alarmActive) {
        flashLights(10)
        schedule(util.cronExpression(now() + 10000), "continueFlashing")
    }
}

private flashLights(numFlashes) {
    def onFor = 1000
    def offFor = 1000

    log.debug "FLASHING $numFlashes times"
    def delay = 1L
    numFlashes.times {
        log.trace "Switch on after  $delay msec"
        lights?.on(delay: delay)
        delay += onFor
        log.trace "Switch off after $delay msec"
        lights?.off(delay: delay)
        delay += offFor
    }
}

private silentAlarm()
{
    silent?.toLowerCase() in ["yes","true","y"]
}

(Micah Kordsmeier) #2

Sorry about the messy code above - I tried just pasting it in and that obviously didn’t work…


(Ben Edwards) #3

Fixed code formatting but didn’t answer your question.


(Greg) #4

I had a similar issue where smart security wouldn’t trigger the siren from a motion event. I switched to “Smart Alarm” and it works well.


(Matt Nohr) #5

You actually need to subscribe to acceleration, not vibration. Try this:

subscribe intrustionAcceleration, "acceleration", intruderAcceleration

You can see the list of capabilities here: https://graph.api.smartthings.com/ide/doc/capabilities


(Micah Kordsmeier) #6

Oh thank you! I saw also had a typo in there. I think it’s working now. By the way, is there a reason the acceleration sensor isn’t supported by default on more apps such as this one?


#7

I love using the acceleration sensors on my doors. I have lights turn on and get a notification if someone kicks or bangs on the door.


(Cesare Pagani) #8

Hi Micah,
would you mind to post the full working code for this app? Thanks


(Sean) #9

@greg, are you saying you got acceleration to alert using SmartAlarm? I thought Geko said it hasn’t been added yet to his app.


(Greg) #10

No, sorry 1234567890


(James W) #11

Did anyone get the final code?