Can't Get First App tutorial to work... real or simulated


(Mark) #1

Hi

I am not a programmmer, but have an incompatible SmartThing I would like to use but needs a device handler and an app, so I thought I would have look at doing it myself. I’m aware of programming principles, but it isn’t my day job.

I have been through the my First SmartApp tutorial and everything was working fine until I tried to add a timescale to an event. The event being turning a light off if no movement has been detected after x number of minutes.

When I run the simulator using an actual switch and motion sensor ( can’t get the virtual ones in the simulator to work at all) the light switches on as expected, but does not turn off.

The last entry in the log is:

3b440f54-2bf8-4259-aa16-ce635fc4f61d 15:25:01 GMT: debug Motion has not stayed inactive long enough since last check (59156 ms): doing nothing

This has been like this for 20 minutes now and I set the switch to turn off after 1 minute.

In the end I copied and pasted the case in full direct from the tutorial, and got the same result, so it wasn’t a typo error on my part.

Any help would be greatly appreciated. Full code below:

Thanks

Mark

/**
 *  Tutorial
 *
 *  Copyright 2016 Mark Haddock
 *
 *  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: "My First SmartApp",
        namespace: "mygithubusername",
        author: "Peter Gregory",
        description: "This is my first SmartApp. Woot!",
        category: "My Apps",
        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")

preferences {
    section("Turn on when motion detected:") {
            input "themotion", "capability.motionSensor", required: true, title: "Where?"
    }
    section("Turn off when there's been no movement for") {
            input "minutes", "number", required: true, title: "Minutes?"
    }
    section("Turn on this light") {
            input "theswitch", "capability.switch", required: true
    }
}

def installed() {
    initialize()
}

def updated() {
    unsubscribe()
    initialize()
}

def initialize() {
    subscribe(themotion, "motion.active", motionDetectedHandler)
    subscribe(themotion, "motion.inactive", motionStoppedHandler)
}

def motionDetectedHandler(evt) {
    log.debug "motionDetectedHandler called: $evt"
    theswitch.on()
}

def motionStoppedHandler(evt) {
    log.debug "motionStoppedHandler called: $evt"
    runIn(60 * minutes, checkMotion)
}

def checkMotion() {
    log.debug "In checkMotion scheduled method"

    def motionState = themotion.currentState("motion")

    if (motionState.value == "inactive") {
            // get the time elapsed between now and when the motion reported inactive
        def elapsed = now() - motionState.date.time

        // elapsed time is in milliseconds, so the threshold must be converted to milliseconds too
        def threshold = 1000 * 60 * minutes

            if (elapsed >= threshold) {
            log.debug "Motion has stayed inactive long enough since last check ($elapsed ms):  turning switch off"
            theswitch.off()
            } else {
            log.debug "Motion has not stayed inactive long enough since last check ($elapsed ms):  doing nothing"
        }
    } else {
            // Motion active; just log it and do nothing
            log.debug "Motion is active, do nothing and wait for inactive"
    }
}

(Patrick Stuart [@pstuart]) #2

What motion sensor? Also. What is the actual current state of the motion sensor? Sound like the motion sensor still reports active.


(Mark) #3

Hi

Thanks for the response. The motion sensor is a SmartTings one which cam with the hub. The switch is too.

Looking at the simulator, when motion is detected the sensor change colour to indicate motion. And the light comes on. When no motion is detected the sensor changes back to the no motion state. The log also states there is no motion.


(Patrick Stuart [@pstuart]) #4

So, here’s the issue with SmartThings… This code example should work, but runIn just isn’t accurate for firing exactly on time.

Nor does this code example start another schedule to check again.

so, around line 64 just after the log.debug about not staying inactive long enough add this:

runIn(60 * minutes, checkMotion)

this will reschedule a check of the motion sensor x minutes from now.

Or, just extend the checking period to be a few seconds after the timeout, to be like this on line 44

runIn(61 * minutes, checkMotion)

this way, it will check a few seconds after the time.

Essentially, its a good example for testing methods of repeating schedules and the accuracy of the scheduler in SmartThings.

There are a lot of ways to improve this code to be more accurate, another way would be to add some more seconds to the threshold calculation.

Tagging @jim to update the code to deal with this…