sunrise sunset working, not the cleanest solution but it works

This commit is contained in:
Sam Lewis
2022-10-24 23:03:04 -04:00
parent a2d3b46335
commit 66e179c568
4 changed files with 61 additions and 28 deletions

28
app.go
View File

@@ -36,7 +36,7 @@ type TimeString string
NewApp establishes the websocket connection and returns an object NewApp establishes the websocket connection and returns an object
you can use to register schedules and listeners. you can use to register schedules and listeners.
*/ */
func NewApp(connString string) app { func NewApp(connString string) *app {
token := os.Getenv("HA_AUTH_TOKEN") token := os.Getenv("HA_AUTH_TOKEN")
conn, ctx, ctxCancel := ws.SetupConnection(connString, token) conn, ctx, ctxCancel := ws.SetupConnection(connString, token)
@@ -45,7 +45,7 @@ func NewApp(connString string) app {
service := NewService(conn, ctx, httpClient) service := NewService(conn, ctx, httpClient)
state := newState(httpClient) state := newState(httpClient)
return app{ return &app{
conn: conn, conn: conn,
ctx: ctx, ctx: ctx,
ctxCancel: ctxCancel, ctxCancel: ctxCancel,
@@ -65,6 +65,12 @@ func (a *app) Cleanup() {
} }
func (a *app) RegisterSchedule(s schedule) { func (a *app) RegisterSchedule(s schedule) {
// realStartTime already set for sunset/sunrise
if s.isSunrise || s.isSunset {
a.schedules.Insert(s, float64(s.realStartTime.Unix()))
return
}
if s.frequency == 0 { if s.frequency == 0 {
log.Fatalln("A schedule must call either Daily() or Every() when built.") log.Fatalln("A schedule must call either Daily() or Every() when built.")
} }
@@ -106,21 +112,7 @@ func (a *app) RegisterEventListener(evl eventListener) {
} }
} }
// Sunrise take an optional string that is passed to time.ParseDuration. func getSunriseSunset(a *app, sunrise bool, offset []TimeString) carbon.Carbon {
// Examples include "-1.5h", "30m", etc. See https://pkg.go.dev/time#ParseDuration
// for full list.
func (a *app) Sunrise(offset ...TimeString) string {
return getSunriseSunset(a, true, offset)
}
// Sunset take an optional string that is passed to time.ParseDuration.
// Examples include "-1.5h", "30m", etc. See https://pkg.go.dev/time#ParseDuration
// for full list.
func (a *app) Sunset(offset ...TimeString) string {
return getSunriseSunset(a, false, offset)
}
func getSunriseSunset(a *app, sunrise bool, offset []TimeString) string {
printString := "Sunset" printString := "Sunset"
attrKey := "next_setting" attrKey := "next_setting"
if sunrise { if sunrise {
@@ -150,7 +142,7 @@ func getSunriseSunset(a *app, sunrise bool, offset []TimeString) string {
nextSetOrRise = nextSetOrRise.AddMinutes(int(t.Minutes())) nextSetOrRise = nextSetOrRise.AddMinutes(int(t.Minutes()))
} }
return carbon2TimeString(nextSetOrRise) return nextSetOrRise
} }
func carbon2TimeString(c carbon.Carbon) string { func carbon2TimeString(c carbon.Carbon) string {

View File

@@ -1,8 +1,5 @@
package gomeassistant package gomeassistant
// TODO: impl eventListener. could probably create generic listener struct for
// code reuse between eventListener and eventListener
import ( import (
"encoding/json" "encoding/json"
"log" "log"

View File

@@ -25,6 +25,13 @@ func main() {
At("23:00"). At("23:00").
Build() Build()
_30minsBeforeSunrise := ga.
ScheduleBuilder().
Call(sunriseSched).
Daily().
Sunrise(app, "-30m").
Build()
zwaveEventListener := ga. zwaveEventListener := ga.
EventListenerBuilder(). EventListenerBuilder().
EventTypes("zwave_js_value_notification"). EventTypes("zwave_js_value_notification").
@@ -33,6 +40,7 @@ func main() {
app.RegisterEntityListener(pantryDoor) app.RegisterEntityListener(pantryDoor)
app.RegisterSchedule(_11pmSched) app.RegisterSchedule(_11pmSched)
app.RegisterSchedule(_30minsBeforeSunrise)
app.RegisterEventListener(zwaveEventListener) app.RegisterEventListener(zwaveEventListener)
app.Start() app.Start()
@@ -72,3 +80,8 @@ func lightsOut(service *ga.Service, state *ga.State) {
service.Light.TurnOff("light.main_lights") service.Light.TurnOff("light.main_lights")
} }
} }
func sunriseSched(service *ga.Service, state *ga.State) {
service.Light.TurnOn("light.living_room_lamps")
service.Light.TurnOff("light.christmas_lights")
}

View File

@@ -33,6 +33,10 @@ type schedule struct {
*/ */
offset time.Duration offset time.Duration
realStartTime time.Time realStartTime time.Time
isSunrise bool
isSunset bool
sunOffset TimeString
} }
func (s schedule) Hash() string { func (s schedule) Hash() string {
@@ -107,6 +111,24 @@ func (sb scheduleBuilderDaily) At(s string) scheduleBuilderEnd {
return scheduleBuilderEnd(sb) return scheduleBuilderEnd(sb)
} }
// Sunrise takes an app pointer and an optional duration string that is passed to time.ParseDuration.
// Examples include "-1.5h", "30m", etc. See https://pkg.go.dev/time#ParseDuration
// for full list.
func (sb scheduleBuilderDaily) Sunrise(a *app, offset ...TimeString) scheduleBuilderEnd {
sb.schedule.realStartTime = getSunriseSunset(a, true, offset).Carbon2Time()
sb.schedule.isSunrise = true
return scheduleBuilderEnd(sb)
}
// Sunset takes an app pointer and an optional duration string that is passed to time.ParseDuration.
// Examples include "-1.5h", "30m", etc. See https://pkg.go.dev/time#ParseDuration
// for full list.
func (sb scheduleBuilderDaily) Sunset(a *app, offset ...TimeString) scheduleBuilderEnd {
sb.schedule.realStartTime = getSunriseSunset(a, false, offset).Carbon2Time()
sb.schedule.isSunset = true
return scheduleBuilderEnd(sb)
}
func (sb scheduleBuilderCall) Every(s TimeString) scheduleBuilderCustom { func (sb scheduleBuilderCall) Every(s TimeString) scheduleBuilderCustom {
d, err := time.ParseDuration(string(s)) d, err := time.ParseDuration(string(s))
if err != nil { if err != nil {
@@ -145,7 +167,7 @@ func runSchedules(a *app) {
for { for {
sched := popSchedule(a) sched := popSchedule(a)
// log.Default().Println(sched.realStartTime) log.Default().Println(sched.realStartTime)
// run callback for all schedules before now in case they overlap // run callback for all schedules before now in case they overlap
for sched.realStartTime.Before(time.Now()) { for sched.realStartTime.Before(time.Now()) {
@@ -167,11 +189,20 @@ func popSchedule(a *app) schedule {
} }
func requeueSchedule(a *app, s schedule) { func requeueSchedule(a *app, s schedule) {
// TODO: figure out how to handle sunset/sunrise in here. Maybe just if s.isSunrise || s.isSunset {
// add sunrise bool and sunset bool to Schedule, might have to change nextSunTime := getSunriseSunset(a, s.isSunrise, []TimeString{s.sunOffset})
// API to be .Call().Sunset("1h") instead of .Call().At(ga.Sunset("1h"))
// then that function could easily set the flag. Kinda ruins the english // this is true when there is a negative offset, so schedule runs before sunset/sunrise and
// language sentence structure but maybe simplest way to get it working // HA still shows today's sunset as next sunset. Just add 24h as a default handler
s.realStartTime = s.realStartTime.Add(s.frequency) // since we can't get tomorrow's sunset from HA at this point.
if nextSunTime.IsToday() {
nextSunTime = nextSunTime.AddHours(24)
}
s.realStartTime = nextSunTime.Carbon2Time()
} else {
s.realStartTime = s.realStartTime.Add(s.frequency)
}
a.schedules.Insert(s, float64(s.realStartTime.Unix())) a.schedules.Insert(s, float64(s.realStartTime.Unix()))
} }