From 36330ac2ccbc3b17b53d9d64f4505fe92990c541 Mon Sep 17 00:00:00 2001 From: TomF79 <93859783+TomF79@users.noreply.github.com> Date: Tue, 22 Apr 2025 13:50:26 +0200 Subject: [PATCH] Solcast: limit api calls by time of day (#20696) --- tariff/solcast.go | 20 ++++++++++---- tariff/types.go | 10 +++++++ tariff/types_test.go | 34 ++++++++++++++++++++++++ templates/definition/tariff/solcast.yaml | 10 +++++++ 4 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 tariff/types_test.go diff --git a/tariff/solcast.go b/tariff/solcast.go index 7042b7ee0..41e7ef8d4 100644 --- a/tariff/solcast.go +++ b/tariff/solcast.go @@ -18,9 +18,10 @@ import ( type Solcast struct { *request.Helper - log *util.Logger - site string - data *util.Monitor[api.Rates] + log *util.Logger + site string + fromTo FromTo + data *util.Monitor[api.Rates] } var _ api.Tariff = (*Solcast)(nil) @@ -34,6 +35,7 @@ func NewSolcastFromConfig(other map[string]interface{}) (api.Tariff, error) { Site string Token string Interval time.Duration + FromTo `mapstructure:",squash"` }{ Interval: 3 * time.Hour, } @@ -56,6 +58,7 @@ func NewSolcastFromConfig(other map[string]interface{}) (api.Tariff, error) { log: log, site: cc.Site, Helper: request.NewHelper(log), + fromTo: cc.FromTo, data: util.NewMonitor[api.Rates](2 * cc.Interval), } @@ -71,8 +74,16 @@ func NewSolcastFromConfig(other map[string]interface{}) (api.Tariff, error) { func (t *Solcast) run(interval time.Duration, done chan error) { var once sync.Once - // don't exceed 10 requests per 24h for ; true; <-time.Tick(interval) { + // ensure we don't run when not needed, but execute once at startup + select { + case <-t.data.Done(): + if !t.fromTo.IsActive(time.Now().Hour()) { + continue + } + default: + } + var res solcast.Forecasts if err := backoff.Retry(func() error { @@ -80,7 +91,6 @@ func (t *Solcast) run(interval time.Duration, done chan error) { return backoffPermanentError(t.GetJSON(uri, &res)) }, bo()); err != nil { once.Do(func() { done <- err }) - t.log.ERROR.Println(err) continue } diff --git a/tariff/types.go b/tariff/types.go index e9af1c699..4c7183ade 100644 --- a/tariff/types.go +++ b/tariff/types.go @@ -12,3 +12,13 @@ func (t Typed) Name() string { } return t.Type } + +type FromTo struct { + From, To int +} + +func (ft FromTo) IsActive(hour int) bool { + return ft.From == 0 && ft.To == 0 || + ft.From < ft.To && ft.From <= hour && hour <= ft.To || + ft.From > ft.To && (ft.From <= hour || hour <= ft.To) +} diff --git a/tariff/types_test.go b/tariff/types_test.go new file mode 100644 index 000000000..0ddb8ab6d --- /dev/null +++ b/tariff/types_test.go @@ -0,0 +1,34 @@ +package tariff + +import ( + "testing" + "time" + + "github.com/benbjohnson/clock" + "github.com/stretchr/testify/assert" +) + +func TestFromTo(t *testing.T) { + tc := []struct { + from, to, now int + active bool + }{ + {0, 0, 0, true}, + {1, 2, 1, true}, + {1, 2, 2, true}, + {1, 2, 0, false}, + {1, 2, 3, false}, + {22, 2, 21, false}, + {22, 2, 22, true}, + {22, 2, 2, true}, + {22, 2, 3, false}, + } + + for _, tc := range tc { + clock := clock.NewMock() + clock.Add(time.Duration(tc.now) * time.Hour) + + ft := FromTo{tc.from, tc.to} + assert.Equal(t, tc.active, ft.IsActive(tc.now), "expected %v") + } +} diff --git a/templates/definition/tariff/solcast.yaml b/templates/definition/tariff/solcast.yaml index f4468178c..7487d4c54 100644 --- a/templates/definition/tariff/solcast.yaml +++ b/templates/definition/tariff/solcast.yaml @@ -18,6 +18,16 @@ params: en: Solcast API Token de: Solcast API Token required: true + - name: from + help: + en: Start time of data retrieval, specified in full hours, e.g. "6" + de: Startzeit der Datenabrufe, Angabe in vollen Stunden, z.B "6" + advanced: true + - name: to + help: + en: End time of data retrieval, specified in full hours, e.g. "20" + de: Endzeit der Datenabrufe, Angabe in vollen Stunden, z.B "20" + advanced: true - name: interval default: 3h advanced: true