mirror of
https://github.com/Xevion/go-ha.git
synced 2025-12-10 12:07:24 -06:00
216 lines
5.0 KiB
Go
216 lines
5.0 KiB
Go
package gomeassistant
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"reflect"
|
|
"runtime"
|
|
"time"
|
|
)
|
|
|
|
type sunriseSunset struct {
|
|
base timeOfDay
|
|
addition timeOfDay
|
|
subtraction timeOfDay
|
|
}
|
|
|
|
func Sunrise() *sunriseSunset {
|
|
return &sunriseSunset{
|
|
base: TimeOfDay(0, 10000),
|
|
addition: TimeOfDay(0, 0),
|
|
subtraction: TimeOfDay(0, 0),
|
|
}
|
|
}
|
|
|
|
func Sunset() *sunriseSunset {
|
|
return &sunriseSunset{
|
|
base: TimeOfDay(0, 20000),
|
|
addition: TimeOfDay(0, 0),
|
|
subtraction: TimeOfDay(0, 0),
|
|
}
|
|
}
|
|
|
|
func (ss *sunriseSunset) Add(hm timeOfDay) *sunriseSunset {
|
|
ss.addition = hm
|
|
return ss
|
|
}
|
|
|
|
func (ss *sunriseSunset) Subtract(hm timeOfDay) *sunriseSunset {
|
|
ss.subtraction = hm
|
|
return ss
|
|
}
|
|
|
|
func (ss *sunriseSunset) Minutes() int {
|
|
return ss.base.minute +
|
|
(ss.addition.hour*60 + ss.addition.minute) -
|
|
(ss.subtraction.hour*60 + ss.subtraction.minute)
|
|
}
|
|
|
|
// timeOfDay is used to express a time of day
|
|
// but it shouldn't be used directly. Use
|
|
// TimeOfDay(), Sunset(), or Sunrise() to
|
|
// create one. Add() and Subtract() can be
|
|
// called on Sunset and Sunrise to offset
|
|
// the time, e.g. Sunset().Subtract(TimeOfDay(0, 30))
|
|
// would be 30 minutes before sunset.
|
|
type timeOfDay struct {
|
|
hour int
|
|
minute int
|
|
}
|
|
|
|
type timeOfDayInterface interface {
|
|
// Time represented as number of Minutes
|
|
// after midnight. E.g. 02:00 would be 120.
|
|
Minutes() int
|
|
}
|
|
|
|
func (hm timeOfDay) minutes() int {
|
|
return hm.hour*60 + hm.minute
|
|
}
|
|
|
|
func TimeOfDay(Hour, Minute int) timeOfDay {
|
|
return timeOfDay{Hour, Minute}
|
|
}
|
|
|
|
func (hm timeOfDay) String() string {
|
|
return fmt.Sprintf("%02d:%02d", hm.hour, hm.minute)
|
|
}
|
|
|
|
type scheduleCallback func(Service, State)
|
|
|
|
type schedule struct {
|
|
/*
|
|
frequency is a time.Duration representing how often you want to run your function.
|
|
|
|
Some examples:
|
|
time.Second * 5 // runs every 5 seconds at 00:00:00, 00:00:05, etc.
|
|
time.Hour * 12 // runs at offset, +12 hours, +24 hours, etc.
|
|
gomeassistant.Daily // runs at offset, +24 hours, +48 hours, etc. Daily is a const helper for time.Hour * 24
|
|
// Helpers include Daily, Hourly, Minutely
|
|
*/
|
|
frequency time.Duration
|
|
callback scheduleCallback
|
|
/*
|
|
offset is 4 character string representing hours and minutes
|
|
in a 24-hr format.
|
|
It is the base that your frequency will be added to.
|
|
Defaults to "0000" (which is probably fine for most cases).
|
|
|
|
Example: Run in the 3rd minute of every hour.
|
|
Schedule{
|
|
frequency: gomeassistant.Hourly // helper const for time.Hour
|
|
offset: "0003"
|
|
}
|
|
*/
|
|
offset timeOfDay
|
|
/*
|
|
This will be set rather than returning an error to avoid checking err for nil on every schedule :)
|
|
RegisterSchedule will exit if the error is set.
|
|
*/
|
|
err error
|
|
realStartTime time.Time
|
|
}
|
|
|
|
type scheduleBuilder struct {
|
|
schedule schedule
|
|
}
|
|
|
|
type scheduleBuilderCall struct {
|
|
schedule schedule
|
|
}
|
|
|
|
type scheduleBuilderDaily struct {
|
|
schedule schedule
|
|
}
|
|
|
|
type scheduleBuilderCustom struct {
|
|
schedule schedule
|
|
}
|
|
|
|
type scheduleBuilderEnd struct {
|
|
schedule schedule
|
|
}
|
|
|
|
func ScheduleBuilder() scheduleBuilder {
|
|
return scheduleBuilder{
|
|
schedule{
|
|
frequency: 0,
|
|
offset: timeOfDay{0, 0},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (s schedule) String() string {
|
|
return fmt.Sprintf("Run %q %s %s",
|
|
getFunctionName(s.callback),
|
|
frequencyToString(s.frequency),
|
|
s.offset,
|
|
)
|
|
}
|
|
|
|
func frequencyToString(d time.Duration) string {
|
|
if d.Hours() == 24 {
|
|
return "daily at"
|
|
}
|
|
return "every " + d.String() + " with offset"
|
|
}
|
|
|
|
func (sb scheduleBuilder) Call(callback scheduleCallback) scheduleBuilderCall {
|
|
sb.schedule.callback = callback
|
|
return scheduleBuilderCall(sb)
|
|
}
|
|
|
|
func (sb scheduleBuilderCall) Daily() scheduleBuilderDaily {
|
|
sb.schedule.frequency = time.Hour * 24
|
|
return scheduleBuilderDaily(sb)
|
|
}
|
|
|
|
func (sb scheduleBuilderDaily) At(t timeOfDayInterface) scheduleBuilderEnd {
|
|
sb.schedule.offset = convertTimeOfDayToActualOffset(t)
|
|
return scheduleBuilderEnd(sb)
|
|
}
|
|
|
|
func (sb scheduleBuilderCall) Every(duration time.Duration) scheduleBuilderCustom {
|
|
sb.schedule.frequency = duration
|
|
return scheduleBuilderCustom(sb)
|
|
}
|
|
|
|
func (sb scheduleBuilderCustom) Offset(t timeOfDay) scheduleBuilderEnd {
|
|
sb.schedule.offset = t
|
|
return scheduleBuilderEnd(sb)
|
|
}
|
|
|
|
func (sb scheduleBuilderCustom) Build() schedule {
|
|
return sb.schedule
|
|
}
|
|
|
|
func (sb scheduleBuilderEnd) Build() schedule {
|
|
return sb.schedule
|
|
}
|
|
|
|
func getFunctionName(i interface{}) string {
|
|
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
|
|
}
|
|
|
|
func convertTimeOfDayToActualOffset(t timeOfDayInterface) timeOfDay {
|
|
mins := t.Minutes()
|
|
if mins > 15000 {
|
|
// TODO: same as below but w/ sunset
|
|
// don't forget to subtract 20000 here
|
|
return TimeOfDay(0, 0)
|
|
} else if mins > 5000 {
|
|
// TODO: use httpClient to get state of sun.sun
|
|
// to get next sunrise time
|
|
// don't forget to subtract 10000 here to get +- from sunrise that user requested
|
|
|
|
// retrieve next sunrise time
|
|
|
|
// use carbon.Parse() to create time.Time of that time
|
|
|
|
// return Time() of that many hours and minutes to set offset from midnight
|
|
} else if mins >= 1440 {
|
|
log.Fatalln("Offset (set via At() or Offset()) cannot be more than 1 day (23h59m)")
|
|
}
|
|
return TimeOfDay(0, mins)
|
|
}
|