diff --git a/README.md b/README.md index 6d337c0..34aae96 100644 --- a/README.md +++ b/README.md @@ -78,10 +78,10 @@ sunset := ga.NewDailySchedule().Call(myFunc).Sunset().Build() Daily schedules have other functions to change the behavior. -| Function | Info | -| ------------------------------------ | ----------------------------------------------------------------------------------- | -| ExceptionDay(time.Time) | A one time exception on the given date. Time is ignored, applies to whole day. | -| ExceptionRange(time.Time, time.Time) | A one time exception between the two date/times. Both date and time are considered. | +| Function | Info | +| ----------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| ExceptionDates(t time.Time, ...time.Time) | Skip the schedule on the given date(s). Functions like a blocklist. Cannot be combined with OnlyOnDates. | +| OnlyOnDates(t time.Time, ...time.Time) | Run only on the given date(s). Functions like an allowlist. Cannot be combined with ExceptionDates. | #### Schedule Callback function @@ -106,18 +106,18 @@ etl := ga.NewEntityListener().EntityIds("binary_sensor.front_door").Call(myFunc) Entity listeners have other functions to change the behavior. -| Function | Info | -| ------------------------------------ | ------------------------------------------------------------------------------------------------- | -| ToState("on") | Function only called if new state matches argument. | -| FromState("on") | Function only called if old state matches argument. | -| Throttle("30s") | Minimum time between function calls. | -| Duration("30s") | Requires ToState(). Sets how long the entity should be in the state before running your function. | -| OnlyAfter("03:00") | Only run your function after a specified time of day. | -| OnlyBefore("03:00") | Only run your function before a specified time of day. | -| OnlyBetween("03:00", "14:00") | Only run your function between two specified times of day. | -| ExceptionDay(time.Time) | A one time exception on the given date. Time is ignored, applies to whole day. | -| ExceptionRange(time.Time, time.Time) | A one time exception between the two date/times. Both date and time are considered. | -| RunOnStartup() | Run your callback once during App.Start() | +| Function | Info | +| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| ToState("on") | Function only called if new state matches argument. | +| FromState("on") | Function only called if old state matches argument. | +| Throttle("30s") | Minimum time between function calls. | +| Duration("30s") | Requires ToState(). Sets how long the entity must be in the state before running your function. | +| OnlyAfter("03:00") | Only run your function after a specified time of day. | +| OnlyBefore("03:00") | Only run your function before a specified time of day. | +| OnlyBetween("03:00", "14:00") | Only run your function between two specified times of day. | +| ExceptionDates(time.Time, ...time.Time) | A one time exception on the given date. Time is ignored, applies to whole day. Functions like a "blocklist". | +| ExceptionRange(time.Time, time.Time) | A one time exception between the two date/times. Both date and time are considered. Functions like a "blocklist". | +| RunOnStartup() | Run your callback during `App.Start()`. | #### Entity Listener Callback function @@ -143,14 +143,14 @@ evl := ga.NewEntityListener().EntityIds("binary_sensor.front_door").Call(myFunc) Event listeners have other functions to change the behavior. -| Function | Info | -| ------------------------------------ | ----------------------------------------------------------------------------------- | -| Throttle("30s") | Minimum time between function calls. | -| OnlyAfter("03:00") | Only run your function after a specified time of day. | -| OnlyBefore("03:00") | Only run your function before a specified time of day. | -| OnlyBetween("03:00", "14:00") | Only run your function between two specified times of day. | -| ExceptionDay(time.Time) | A one time exception on the given date. Time is ignored, applies to whole day. | -| ExceptionRange(time.Time, time.Time) | A one time exception between the two date/times. Both date and time are considered. | +| Function | Info | +| --------------------------------------- | ----------------------------------------------------------------------------------- | +| Throttle("30s") | Minimum time between function calls. | +| OnlyAfter("03:00") | Only run your function after a specified time of day. | +| OnlyBefore("03:00") | Only run your function before a specified time of day. | +| OnlyBetween("03:00", "14:00") | Only run your function between two specified times of day. | +| ExceptionDates(time.Time, ...time.Time) | A one time exception on the given date. Time is ignored, applies to whole day. | +| ExceptionRange(time.Time, time.Time) | A one time exception between the two date/times. Both date and time are considered. | #### Event Listener Callback function @@ -179,12 +179,12 @@ interval = ga.NewInterval().Call(myFunc).Every("5m").StartingAt("10:00").EndingA Intervals have other functions to change the behavior. -| Function | Info | -| ------------------------------------ | ----------------------------------------------------------------------------------- | -| StartingAt(TimeString) | What time the interval begins to run each day. | -| EndingAt(TimeString) | What time the interval stops running each day. | -| ExceptionDay(time.Time) | A one time exception on the given date. Time is ignored, applies to whole day. | -| ExceptionRange(time.Time, time.Time) | A one time exception between the two date/times. Both date and time are considered. | +| Function | Info | +| --------------------------------------- | ----------------------------------------------------------------------------------- | +| StartingAt(TimeString) | What time the interval begins to run each day. | +| EndingAt(TimeString) | What time the interval stops running each day. | +| ExceptionDates(time.Time, ...time.Time) | A one time exception on the given date. Time is ignored, applies to whole day. | +| ExceptionRange(time.Time, time.Time) | A one time exception between the two date/times. Both date and time are considered. | #### Interval Callback function diff --git a/entitylistener.go b/entitylistener.go index 8918253..d1592b8 100644 --- a/entitylistener.go +++ b/entitylistener.go @@ -22,7 +22,7 @@ type EntityListener struct { delay time.Duration delayTimer *time.Timer - exceptionDays []time.Time + exceptionDates []time.Time exceptionRanges []timeRange runOnStartup bool @@ -133,8 +133,8 @@ func (b elBuilder3) Throttle(s DurationString) elBuilder3 { return b } -func (b elBuilder3) ExceptionDay(t time.Time) elBuilder3 { - b.entityListener.exceptionDays = append(b.entityListener.exceptionDays, t) +func (b elBuilder3) ExceptionDates(t time.Time, tl ...time.Time) elBuilder3 { + b.entityListener.exceptionDates = append(tl, t) return b } @@ -189,7 +189,7 @@ func callEntityListeners(app *App, msgBytes []byte) { if c := checkThrottle(l.throttle, l.lastRan); c.fail { continue } - if c := checkExceptionDays(l.exceptionDays); c.fail { + if c := checkExceptionDates(l.exceptionDates); c.fail { continue } if c := checkExceptionRanges(l.exceptionRanges); c.fail { diff --git a/eventListener.go b/eventListener.go index ecb0cea..afda335 100644 --- a/eventListener.go +++ b/eventListener.go @@ -17,7 +17,7 @@ type EventListener struct { throttle time.Duration lastRan carbon.Carbon - exceptionDays []time.Time + exceptionDates []time.Time exceptionRanges []timeRange } @@ -80,8 +80,8 @@ func (b eventListenerBuilder3) Throttle(s DurationString) eventListenerBuilder3 return b } -func (b eventListenerBuilder3) ExceptionDay(t time.Time) eventListenerBuilder3 { - b.eventListener.exceptionDays = append(b.eventListener.exceptionDays, t) +func (b eventListenerBuilder3) ExceptionDates(t time.Time, tl ...time.Time) eventListenerBuilder3 { + b.eventListener.exceptionDates = append(tl, t) return b } @@ -118,7 +118,7 @@ func callEventListeners(app *App, msg ws.ChanMsg) { if c := checkThrottle(l.throttle, l.lastRan); c.fail { continue } - if c := checkExceptionDays(l.exceptionDays); c.fail { + if c := checkExceptionDates(l.exceptionDates); c.fail { continue } if c := checkExceptionRanges(l.exceptionRanges); c.fail { diff --git a/interval.go b/interval.go index 14dcde8..44b26d2 100644 --- a/interval.go +++ b/interval.go @@ -16,12 +16,12 @@ type Interval struct { endTime TimeString nextRunTime time.Time - exceptionDays []time.Time + exceptionDates []time.Time exceptionRanges []timeRange } func (i Interval) Hash() string { - return fmt.Sprint(i.startTime, i.endTime, i.frequency, i.callback, i.exceptionDays, i.exceptionRanges) + return fmt.Sprint(i.startTime, i.endTime, i.frequency, i.callback, i.exceptionDates, i.exceptionRanges) } // Call @@ -34,7 +34,7 @@ type intervalBuilderCall struct { interval Interval } -// Offset, ExceptionDay, ExceptionRange +// Offset, ExceptionDates, ExceptionRange type intervalBuilderEnd struct { interval Interval } @@ -93,8 +93,8 @@ func (sb intervalBuilderEnd) EndingAt(s TimeString) intervalBuilderEnd { return sb } -func (sb intervalBuilderEnd) ExceptionDay(t time.Time) intervalBuilderEnd { - sb.interval.exceptionDays = append(sb.interval.exceptionDays, t) +func (sb intervalBuilderEnd) ExceptionDates(t time.Time, tl ...time.Time) intervalBuilderEnd { + sb.interval.exceptionDates = append(tl, t) return sb } @@ -137,7 +137,7 @@ func (i Interval) maybeRunCallback(a *App) { if c := checkStartEndTime(i.endTime /* isStart = */, false); c.fail { return } - if c := checkExceptionDays(i.exceptionDays); c.fail { + if c := checkExceptionDates(i.exceptionDates); c.fail { return } if c := checkExceptionRanges(i.exceptionRanges); c.fail { diff --git a/listeners.go b/listeners.go index c7dbd1e..c56305b 100644 --- a/listeners.go +++ b/listeners.go @@ -62,7 +62,7 @@ func checkThrottle(throttle time.Duration, lastRan carbon.Carbon) conditionCheck return cc } -func checkExceptionDays(eList []time.Time) conditionCheck { +func checkExceptionDates(eList []time.Time) conditionCheck { cc := conditionCheck{fail: false} for _, e := range eList { y1, m1, d1 := e.Date() @@ -87,6 +87,23 @@ func checkExceptionRanges(eList []timeRange) conditionCheck { return cc } +func checkAllowlistDates(eList []time.Time) conditionCheck { + if len(eList) == 0 { + return conditionCheck{fail: false} + } + + cc := conditionCheck{fail: true} + for _, e := range eList { + y1, m1, d1 := e.Date() + y2, m2, d2 := time.Now().Date() + if y1 == y2 && m1 == m2 && d1 == d2 { + cc.fail = false + break + } + } + return cc +} + func checkStartEndTime(s TimeString, isStart bool) conditionCheck { cc := conditionCheck{fail: false} // pass immediately if default diff --git a/schedule.go b/schedule.go index 393732b..6b47b26 100644 --- a/schedule.go +++ b/schedule.go @@ -23,8 +23,8 @@ type DailySchedule struct { isSunset bool sunOffset DurationString - exceptionDays []time.Time - exceptionRanges []timeRange + exceptionDates []time.Time + allowlistDates []time.Time } func (s DailySchedule) Hash() string { @@ -93,13 +93,13 @@ func (sb scheduleBuilderCall) Sunset(offset ...DurationString) scheduleBuilderEn return scheduleBuilderEnd(sb) } -func (sb scheduleBuilderEnd) ExceptionDay(t time.Time) scheduleBuilderEnd { - sb.schedule.exceptionDays = append(sb.schedule.exceptionDays, t) +func (sb scheduleBuilderEnd) ExceptionDates(t time.Time, tl ...time.Time) scheduleBuilderEnd { + sb.schedule.exceptionDates = append(tl, t) return sb } -func (sb scheduleBuilderEnd) ExceptionRange(start, end time.Time) scheduleBuilderEnd { - sb.schedule.exceptionRanges = append(sb.schedule.exceptionRanges, timeRange{start, end}) +func (sb scheduleBuilderEnd) OnlyOnDates(t time.Time, tl ...time.Time) scheduleBuilderEnd { + sb.schedule.allowlistDates = append(tl, t) return sb } @@ -132,10 +132,10 @@ func runSchedules(a *App) { } func (s DailySchedule) maybeRunCallback(a *App) { - if c := checkExceptionDays(s.exceptionDays); c.fail { + if c := checkExceptionDates(s.exceptionDates); c.fail { return } - if c := checkExceptionRanges(s.exceptionRanges); c.fail { + if c := checkAllowlistDates(s.allowlistDates); c.fail { return } go s.callback(a.service, a.state)