Need Help: Trying To Record Event Times And Text Those At Later Time

Developers:

I am a total newbie and have been trying to mash up bits and pieces from available apps to create what I’m trying to do. I haven’t been able to get it to work and wanted to see if some of the more experienced developers could give me some guidance.

Here’s want I’m trying to do:

  1. Select a motion sensor
  2. Select a phone number to text to
  3. Select a start time of day to monitor the “active” state of the motion sensor
  4. Select an end time of day to stop monitoring the “active” state of the motion sensor
  5. Select a time of day to send a text with the times during the window defined by 3 and 4 above when motion occurred.

I want to log the times of day within the start-end time window when motion is detected. I have teenagers in the house and it seems like I wake up to find then up and wandering around when they ought to be sleeping. I’d like to record those times and then get a text message at say 9:00AM which lists the times when the motion sensor was active. If it is a quiet night and the set the start time at midnight and the end time at 6:00AM, I would expect I should see not logs of in the text message of the motion sensor being active.

In the code I tried to write (shown below) I assumed there would be no more than 6 instances of the motion sensor going active. There’s probably a much more elegant way to make an array where I wouldn’t be limited by a number but that is way beyond my coding skills. Also, I tried to but a 300 second delay after the motion sensor goes active so I wouldn’t log essentially the same roving teenager event.

Again any points or portions or the entirety are very welcome.

Thanks,
GilS

/**
 *  TimesMovingAtNight
 *
 *  Author: gil.schmitt.public@gmail.com
 *  Date: 2013-09-02
 */
preferences {
	section("Motion Sensor") {
		input "motion1", "capability.motionSensor", title: "Pick your Motion Sensor"
	}
    section("Text me at..."){
		input "phone1", "phone", title: "Phone number?"
	}
	section("Time In Bed"){
		input "startTime", "time", title: "Start Time"
		input "endTime", "time", title: "End Time"
	}
    section("Time To Send Report Text"){
    	input "textTime", "time", title: "Text Time"
}

def installed() {
	subscribe(motion1, "motion.active", motionActiveHandler)
}

def updated() {
	unsubscribe()
	subscribe(motion1, "motion.active", motionActiveHandler)
}

// inTimeWindow sets the period of time from startTime to stopTime where the app is to record the time that motion1 is active.
// If the current time is outside of this window, the app does nothing
def inTimeWindow()
{
	def result
	def now = now()
	if(now > startTime && now < endTime){
		return true
	}
	else{
		return false
	}
	result
}

// It is expected that during the inTimeWindow period there will be no more that 6 times that motion1 goes active.
// This module defines each of these events as movement1Time, movement2Time, etc..
// The module check first if the current time is in the inTimeWindow and then progressively the movement#Time that are null value.
// This was successive movement#Time variables are written to and the ones already written are not written over

def motionActiveHandler(evt) 
{
    def movement1Time
    def movement2Time
    def movement3Time
    def movement4Time
    def movement5Time
    def movement6Time
    if(inTimeWindow() == true && movement1Time == null)
    {
    	movement1Time = now()
        runIn(300, motionActiveHandler())
    }
    if(inTimeWindow() == true && movement1Time != null && movement2Time == null)
    {
    	movement2Time = now()
        runIn(300, motionActiveHandler())
    }
    if(inTimeWindow() == true && movement1Time != null && movement2Time != null && movement3Time == null)
    {
    	movement3Time = now()
        runIn(300, motionActiveHandler())
    }
    if(inTimeWindow() == true && movement1Time != null && movement2Time != null && movement3Time != null && movement4Time == null)
    {
    	movement4Time = now()
        runIn(300, motionActiveHandler())
    }
    if(inTimeWindow() == true && movement1Time != null && movement2Time != null && movement3Time != null && movement4Time != null && movement5Time == null)
    {
    	movement5Time = now()
        runIn(300, motionActiveHandler())
    }
    if(inTimeWindow() == true && movement1Time != null && movement2Time != null && movement3Time != null && movement4Time != null && movement5Time != null && movement6Time == null)
    {
    	movement6Time = now()
    }
    
}
	
// When the current time is equivalent to the text time set in the preferences section, an SMS text message is sent with the times of movement1Time,
// movement2Time, ...
    
    
    if(now() == textTime)
    {
    	sendSms(phone1, "${movement1Time} ${movement2Time} ${movement3Time} ${movement4Time} ${movement5Time} ${movement6Time}")
    }
}

First problem I see is this:

def result
def now = now()
if(now > startTime && now < endTime){
return true
}

So, let’s say you did 11:00pm as start time and 6:00am as end time. Then motion is seen at 1:00am.

Your conditional say: If 1:00am is greater than 11:00pm AND 1:00am is less than 6:00am, then return true. It doesn’t really matter which times you put here to test it, it’ll never return true because it’s impossible to be greater than your start time AND less than your end time if you’re doing it over midnight. You could solve this by only setting the time from 12:01am to 6:00am, but this probably limits the program too much.

Instead we’re going to change the conditional a little bit:

if(now > endTime && now < startTime){
     }
     else {
     return true
     }

Using my example above, we’re asking is now (1:00am) greater than the endTime (6:00am) and less than startTime (11:00pm)? Of course it isn’t. So the conditional fails and we run the ELSE instructions: we “return true.”

Lets say that motion is detected at 3 in the afternoon now. What happens? Well, is now (3pm) greater than the end time (6:00am)? Yes! And is now (3pm) less than the startTime (11pm)? Yes! So the conditional is met and we do… nothing!

Potential second problem:

if(now() == textTime)
{
sendSms(phone1, “${movement1Time} ${movement2Time} ${movement3Time} ${movement4Time} ${movement5Time} ${movement6Time}”)
}
}

I don’t know if this will work. There’s nothing really calling this procedure to or a way for this conditional to now when or if it should fire.

I think what you want to do instead is schedule this event to run at 9:00am (or whatever time you plug into the program). That’s going to take a little more doing. The schedule command is pretty easy. Just write this up as a def instead of an if:

def sendText()
{
sendSms(phone1, “${movement1Time} ${movement2Time} ${movement3Time} ${movement4Time} ${movement5Time} ${movement6Time}”)
}
}

And then to schedule it the command would be:

schedule("0 0 9 * * ?", sendTxt)

This command schedules the procedure sendTxt to run at 0 seconds, 0 minutes, 9 hours (ie, 9:00:00am). The * * ? means running: Every Day of the month, Every Month of the year, Any day of the week.

Now, the tricky part is scheduling for a time the person entered when setting up the program. That I don’t know how to do because when you ask for a time the program doesn’t grab 9:00. Instead you get a long string like including your timezone, date, times, extra. You want to strip out just the hours and minutes entered. I’m not sure how to do this.

Potential third problem:

def motionActiveHandler(evt)
{
def movement1Time
def movement2Time
def movement3Time
def movement4Time
def movement5Time
def movement6Time
if(inTimeWindow() == true && movement1Time == null)
{
movement1Time = now()
runIn(300, motionActiveHandler())
}
if(inTimeWindow() == true && movement1Time != null && movement2Time == null)
...

I’m not sure how the definition of the variables (movement#Time) works here. It may be that when this is defined it sets the variable value as null. If it does, this obviously isn’t good because everytime this procedure is called (which happens when there is movement) any data in those variables is getting overwritten.

What I would do is setup the variables in a different procedure:

def resetTimes() {
     def state.time1 = null
     def state.time2 = null
     ....
     def state.time6 = null
}

Now, run this procedure in both the install and update parts:
resetTimes()

This also solves another problem you were going to run into: After this runs for the first night, those variables all have values so when it runs the next time, none will show as null value and no new times will be entered, they’ll all have old times so you’ll keep getting text every morning even if there was no activity last night. But now that we have the reset procedure written, it’s a simple thing to add that same command into the procedure we’re running to send the text:

def sendText()
{
sendSms(phone1, “${movement1Time} ${movement2Time} ${movement3Time} ${movement4Time} ${movement5Time} ${movement6Time}”)
resetTime()
}

Now after you get your text message, the times recorded through the night are reset and we’re ready for the next night.

Potential 4th problem:

I think you’re text messages are going to be huge. As I mentioned above when calling time I think you get a very big string of data, not such hours and minutes and seconds. I believe it has time zones, daylight saves status, etc. involved. Given that text messages are limited to 160 characters, I’m not sure what happens if you try to send more than that. I don’t know if SmartThings will just send more than one text or if you only get the first 160 characters and then rest is lost.

With the new IFTTT for smartthings channel your can log activity to a spreadsheet as it happens. I think this fits your desires better. And you can make really cool charts or graphs showing the statistics of that activity.

I’m tracking the pantry door right now. Lol

Twack

Thanks for the guidance. I’ll work on the code and in the mean time I’ve set up on IFTTT to log the motion sensor. Thanks ChrisB and Twack.