Code help: Problem with SmartApp & Sunset


(Toby Cth3) #1

Would anyone mind taking a look at my SmartApp I wrote? I’m having trouble with my if statement that looks at the current time and verifies its equal to or after sunset and before sunrise in my def presencelightshome() statement. Everything else is WAD, it’s just the checking if its past sunset when someone arrives home (presence) that isn’t working.

I keep getting this error: a9549c0c-8dfd-4afc-bc5a-39d444981ccd 4:40:47 PM: error Cannot get property ‘time’ on null object

/**

  • Light Control
  • Author: toby@cth3.com
  • Date: 1/2/14
  • Monitors a set of presence detectors and turns off a set of lights when everyone has left.
  • When at least one person returns home, turns on a set of lights if it’s after sunset.
  • Turns on a set of lights at sunset and turns off a set of lights at a specified time based on mode.
    */

preferences {
section(“Monitor presence for these people”) {
input “people”, “capability.presenceSensor”, multiple: true
}

section(“When someone arrives turn on these lights”) {
input “presencelightson”, “capability.switch”, multiple: true
}

section(“When everyone has left turn off these lights”) {
input “presencelightsoff”, “capability.switch”, multiple: true
}

section(“At sunset turn on these lights”) {
input “schedulelightson”, “capability.switch”, multiple: true
}

section(“Turn these lights off according to schedule”) {
input “schedulelightsoff”, “capability.switch”, multiple: true
input “schedulemodehome”, “mode”, title: "Home mode"
input “scheduletimehome”, “time”, title: "Home mode time"
input “schedulemodeaway”, “mode”, title: "Away mode"
input “scheuletimeaway”, “time”, title: “Away mode time”
}

section(“Zip code (for sunrise/sunset)”) {
input “zip”, “decimal”, required: false
}

section(“False alarm threshold (defaults to 10 min)”) {
input “falseAlarmThreshold”, “decimal”, title: “Number of minutes”, required: false
}

section(“Notifications”) {
input “sendPushMessage”, “enum”, title: “Send a push notification?”, metadata:[values:[“Yes”,“No”]], required:false
}
}

def installed() {
init()
}

def updated() {
unsubscribe()
init()
}

def init() {
subscribe(location)
subscribe(people, “presence”, presence)
schedule(scheduletimehome, schedulelightshome)
schedule(scheduletimeaway, schedulelightsaway)
checkSun();
}

def checkSun() {
def zip = settings.zip as String
def locale = getWeatherFeature(“geolookup”, zip)
def timezone = TimeZone.getTimeZone(locale.location.tz_long)
def weather = getWeatherFeature(“astronomy”, zip)

def sunrise = weather.moon_phase.sunrise.hour + “:” + weather.moon_phase.sunrise.minute
def sunset = weather.moon_phase.sunset.hour + “:” + weather.moon_phase.sunset.minute
def current = weather.moon_phase.current_time.hour + “:” + weather.moon_phase.current_time.minute

def sunsetTime = timeToday(sunset, timezone)
def sunriseTime = timeToday(sunrise, timezone)

log.info(“Sunset: ${sunset}”)
log.info(“Sunrise: ${sunrise}”)
log.info(“Current: ${current}”)

schedule(timeToday(sunset, timezone), schedulelightssunset)
schedule(timeTodayAfter(new Date(), “01:00”, timezone), checkSun)
}

def presence(evt) {
if(evt.value == “not present”) {
log.debug(“Checking if everyone is away”)
if(everyoneIsAway()) {
log.info(“Starting lights off sequence”)
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != “”) ? falseAlarmThreshold * 60 : 10 * 60
runIn(delay, “presencelightsaway”)
}
}
else {
if(anyoneIsHome()) {
log.info(“Checking if anyone is home”)
presencelightshome()
}
}
}

def presencelightshome() {
log.debug(“Checking if it’s dark out”)
if (now() >= sunsetTime.time || now() < sunriseTime.time) {
def message = "${app.label} turned on the lights because someone arrived home"
log.info(message)
send(message)
settings.presencelightson.on()
}
}

def presencelightsaway() {
if(everyoneIsAway()) {
def message = "${app.label} turned off the lights because everyone left home"
log.info(message)
send(message)
settings.presencelightsoff.off()
}
}

def schedulelightssunset() {
def message = "${app.label} turned on the lights because it is sunset"
log.info(message)
send(message)
settings.schedulelightson.on()
}

def schedulelightshome() {
if (location.mode==schedulemodehome) {
def message = "${app.label} turned off the lights because of schedule ${location.mode}"
log.info(message)
send(message)
settings.schedulelightsoff.off()
}
}

def schedulelightsaway() {
if (location.mode==schedulemodeaway) {
def message = "${app.label} turned off the lights because of schedule ${location.mode}"
log.info(message)
send(message)
settings.schedulelightsoff.off()
}
}

private everyoneIsAway() {
def result = true
if(people.findAll { it?.currentPresence == “present” }) {
result = false
}
log.debug(“everyoneIsAway: ${result}”)
return result
}

private anyoneIsHome() {
def result = false
if(people.findAll { it?.currentPresence == “present” }) {
result = true
}
log.debug(“anyoneIsHome: ${result}”)
return result
}

private send(msg) {
if(sendPushMessage != “No”) {
log.debug(“Sending push message”)
sendPush(msg)
}
log.debug(msg)
}


(SStozki) #2

A few folks already created a SmartAPP like this…



(Glenn Franxman) #3

I think the issue is that sunriseTime and sunsetTime are scoped to checkSun.


(Toby Cth3) #4

Any suggestions on the best way to fix it? I use the checkSun function to schedule turning on lights at sunset (and getting when sunset will be). A dirty way would be to put the same checkSun code in the presencelightshome function but that just seems messy to me.


(C Chen) #5

You can save sunsetTime and sunriseTime to ‘state’, i.e.

def checkSun() {
   ...
   state.sunsetTime = sunsetTime
   ...
}

def presencelightshome() {
   ...
   if (now() >= state.sunsetTime.time ... ) 
   ...
}

(C Chen) #6

Also, you may have to unschedule( checkSun ) before scheduling it again in checkSun. I think a schedule call doesn’t have any effect for already-scheduled or running functions. The log will show ‘scheduling…’ but the function won’t get run.


(Toby Cth3) #7

Thank you very much, I’ll give that a try!


(Toby Cth3) #8

Unfortunately that didn’t work:

dce9e392-b3fb-4c90-ba61-a0359d25f9f8 4:42:55 PM: error No such property: time for class: java.lang.String


(C Chen) #9

Perhaps all values are serialized to primitive types. Try this instead then

def checkSun() {
   ...
   state.sunsetTime = sunsetTime.getTime()
   ...
}

def presencelightshome() {
   ...
   if (now() >= state.sunsetTime ... ) 
   ...
}

(Toby Cth3) #10

Hi C.Chen,
Thank you for your help. I was able to get the code to work by doing the following:

 def sunriseTime = timeToday(sunrise, timezone)
  def sunsetTime = timeToday(sunset, timezone)
  
  state.sunriseTime = sunriseTime.time
  state.sunsetTime = sunsetTime.time

  if (now() >= state.sunsetTime || now() < state.sunriseTime)