Sunset and Sunrise¶
SmartApps often need to take some action at or around the local sunrise or sunset time. The SmartThings cloud provides access to this type of rich data, and even generates events for the location (if the geofence is set). We can also get access to sunrise and sunset times using a ZIP code.
Sunrise and Sunset Events¶
Using the sunrise and sunset events is the preferred (and simpler) way to take some action at (or around) sunrise or sunset. It is required that the location has set up a geofence.
Taking action at sunrise or sunset
If you wish to have certain actions take place at sunrise or sunset, you can use the sunrise and sunset events. These events will be fired at (gasp!) sunrise and sunset times for the user’s location.
You can subscribe to the events by passing in the location (automatically injected into every SmartApp), the event (“sunrise” or “sunset”), and your handler method:
def installed() {
subscribe(location, "sunset", sunsetHandler)
subscribe(location, "sunrise", sunriseHandler)
}
def sunsetHandler(evt) {
log.debug "Sun has set!"
...
}
def sunriseHandler(evt) {
log.debug "Sun has risen!"
...
}
Taking action before or after sunrise/sunset times
If you want to take some action a certain amount of time before or after sunset or sunrise, you can use the “sunriseTime” and “sunsetTime” events. These events are fired every day around the time of sunset or sunrise, and their value is the next sunrise or sunset. You can use this information to calculate an offset so that some action happens a certain amount of time before or after sunrise or sunset.
To use, you can subscribe to the events by passing the location, the event (“sunriseTime” or “sunsetTime”), and the handler method.
Consider the following example that turns on lights a specified number of minutes before sunset for the user’s location:
preferences {
section("Lights") {
input "switches", "capability.switch", title: "Which lights to turn on?"
input "offset", "number", title: "Turn on this many minutes before sunset"
}
}
def installed() {
initialize()
}
def updated() {
unsubscribe()
initialize()
}
def initialize() {
subscribe(location, "sunsetTime", sunsetTimeHandler)
//schedule it to run today too
scheduleTurnOn(location.currentValue("sunsetTime"))
}
def sunsetTimeHandler(evt) {
//when I find out the sunset time, schedule the lights to turn on with an offset
scheduleTurnOn(evt.value)
}
def scheduleTurnOn(sunsetString) {
//get the Date value for the string
def sunsetTime = Date.parse("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", sunsetString)
//calculate the offset
def timeBeforeSunset = new Date(sunsetTime.time - (offset * 60 * 1000))
log.debug "Scheduling for: $timeBeforeSunset (sunset is $sunsetTime)"
//schedule this to run one time
runOnce(timeBeforeSunset, turnOn)
}
def turnOn() {
log.debug "turning on lights"
switches.on()
}
Because the sunriseTime
and sunsetTime
events are fired every day for the next sunrise/sunset event, we use runOnce
to schedule one execution. Sunrise and sunset times change, so the next time the events are fired, we will create another scheduled execution using the runOnce
method for that time.
We want it to run today too, so we use the sunsetTime value of the user’s location to schedule the lights to turn on today.
Note
If a user changes their location’s geofence, it could change the sunrise and sunset times. You can listen for position change events and reschedule accordingly: subscribe(location, "position", locationPositionChangeHandler)
Looking up Sunrise or Sunset Directly¶
SmartApps can use the provided getSunriseAndSunset
methods to get the sunrise and sunset time. You can pass in a ZIP code, which can be useful if the user has not set a geofence for their location.
getSunriseAndSunset(Map options)
The supported options are:
- zipCode
- Optional. The ZIP code to get the sunrise and sunset data for. Defaults to the user’s location if not provided.
- sunsetOffset
- Optional. A string in the format of “HH:MM” to specify how long or after sunset to return. Use the “-” symbol to indicate time should be before sunset (“-00:30” for 30 minutes prior to sunset)
- sunriseOffset
- Optional. A string in the format of “HH:MM” to specify how long or after sunrise to return. Use the “-” symbol to indicate time should be before sunrise (“-00:30” for 30 minutes prior to sunrise)
- date
- Optional. If you want to find the sunrise or sunset time for a date other than today, you can specify a Date object.
The return value is a map in the following form:
[sunrise: Date, sunset: Date]
def initialize() {
def noParams = getSunriseAndSunset()
def beverlyHills = getSunriseAndSunset(zipCode: "90210")
def thirtyMinsBeforeSunset = getSunriseAndSunset(sunsetOffset: "-00:30")
log.debug "sunrise with no parameters: ${noParams.sunrise}"
log.debug "sunset with no parameters: ${noParams.sunset}"
log.debug "sunrise and sunset in 90210: $beverlyHills"
log.debug "thirty minutes before sunset at current location: ${thirtyMinsBeforeSunset.sunset}"
}
Polling for Sunrise/Sunset¶
You may have seen some SmartApp code that runs a task sometime after midnight (usually in a method called “astroCheck”) and calls a third party weather API to get the sunrise/sunset times. This is strongly discouraged now; it is much more efficient to use location events as they do not rely on third party services.
Examples¶
You can refer to these example SmartApps in the IDE to see how sunrise and sunset can be used:
- Smart Nightlight
- Sunrise/Sunset
You can also refer to the following examples in Github: