diff --git a/charger/daheimladen.go b/charger/daheimladen.go index c2f31e146..4146c9d15 100644 --- a/charger/daheimladen.go +++ b/charger/daheimladen.go @@ -22,8 +22,8 @@ type DaheimLaden struct { idTag string token string transactionID int32 - statusG func() (daheimladen.GetLatestStatus, error) - meterG func() (daheimladen.GetLatestMeterValueResponse, error) + statusCache provider.Cacheable[daheimladen.GetLatestStatus] + meterCache provider.Cacheable[daheimladen.GetLatestMeterValueResponse] cache time.Duration } @@ -67,29 +67,30 @@ func NewDaheimLaden(token, stationID string, cache time.Duration) (*DaheimLaden, Base: c.Client.Transport, } - c.reset() + c.statusCache = provider.ResettableCached(func() (daheimladen.GetLatestStatus, error) { + var res daheimladen.GetLatestStatus + err := c.GetJSON(fmt.Sprintf("%s/cs/%s/status", daheimladen.BASE_URL, c.stationID), &res) + return res, err + }, c.cache) + + c.meterCache = provider.ResettableCached(func() (daheimladen.GetLatestMeterValueResponse, error) { + var res daheimladen.GetLatestMeterValueResponse + err := c.GetJSON(fmt.Sprintf("%s/cs/%s/metervalue", daheimladen.BASE_URL, c.stationID), &res) + return res, err + }, c.cache) return c, nil } // reset cache func (c *DaheimLaden) reset() { - c.statusG = provider.Cached(func() (daheimladen.GetLatestStatus, error) { - var res daheimladen.GetLatestStatus - err := c.GetJSON(fmt.Sprintf("%s/cs/%s/status", daheimladen.BASE_URL, c.stationID), &res) - return res, err - }, c.cache) - - c.meterG = provider.Cached(func() (daheimladen.GetLatestMeterValueResponse, error) { - var res daheimladen.GetLatestMeterValueResponse - err := c.GetJSON(fmt.Sprintf("%s/cs/%s/metervalue", daheimladen.BASE_URL, c.stationID), &res) - return res, err - }, c.cache) + c.statusCache.Reset() + c.meterCache.Reset() } // Status implements the api.Charger interface func (c *DaheimLaden) Status() (api.ChargeStatus, error) { - res, err := c.statusG() + res, err := c.statusCache.Get() if err != nil { return api.StatusNone, err } @@ -111,7 +112,7 @@ func (c *DaheimLaden) Status() (api.ChargeStatus, error) { // Enabled implements the api.Charger interface func (c *DaheimLaden) Enabled() (bool, error) { - res, err := c.statusG() + res, err := c.statusCache.Get() return res.Status == string(daheimladen.CHARGING), err } @@ -192,7 +193,7 @@ var _ api.Meter = (*DaheimLaden)(nil) // CurrentPower implements the api.Meter interface func (c *DaheimLaden) CurrentPower() (float64, error) { - res, err := c.meterG() + res, err := c.meterCache.Get() return float64(res.ActivePowerImport * 1e3), err } @@ -200,7 +201,7 @@ var _ api.MeterEnergy = (*DaheimLaden)(nil) // TotalEnergy implements the api.MeterMeterEnergy interface func (c *DaheimLaden) TotalEnergy() (float64, error) { - res, err := c.meterG() + res, err := c.meterCache.Get() return float64(res.EnergyActiveImportRegister), err } @@ -208,6 +209,6 @@ var _ api.PhaseCurrents = (*DaheimLaden)(nil) // Currents implements the api.PhaseCurrents interface func (c *DaheimLaden) Currents() (float64, float64, float64, error) { - res, err := c.meterG() + res, err := c.meterCache.Get() return float64(res.CurrentImportPhaseL1), float64(res.CurrentImportPhaseL2), float64(res.CurrentImportPhaseL3), err } diff --git a/charger/mystrom.go b/charger/mystrom.go index b1a8603ac..44439b0ef 100644 --- a/charger/mystrom.go +++ b/charger/mystrom.go @@ -21,8 +21,8 @@ func init() { type MyStrom struct { conn *mystrom.Connection *switchSocket - cache time.Duration - reportG func() (mystrom.Report, error) + cache time.Duration + reportCache provider.Cacheable[mystrom.Report] } // NewMyStromFromConfig creates a myStrom charger from generic config @@ -45,21 +45,21 @@ func NewMyStromFromConfig(other map[string]interface{}) (api.Charger, error) { } c.switchSocket = NewSwitchSocket(c.Enabled, c.conn.CurrentPower, cc.StandbyPower) - c.reportG = provider.Cached(c.conn.Report, c.cache) + c.reportCache = provider.ResettableCached(c.conn.Report, c.cache) return c, nil } // Enabled implements the api.Charger interface func (c *MyStrom) Enabled() (bool, error) { - res, err := c.reportG() + res, err := c.reportCache.Get() return res.Relay, err } // Enable implements the api.Charger interface func (c *MyStrom) Enable(enable bool) error { // reset cache - c.reportG = provider.Cached(c.conn.Report, c.cache) + c.reportCache.Reset() onoff := map[bool]int{false: 0, true: 1} return c.conn.Request(fmt.Sprintf("relay?state=%d", onoff[enable])) diff --git a/charger/smaevcharger.go b/charger/smaevcharger.go index 698a70b39..50d6f58f2 100644 --- a/charger/smaevcharger.go +++ b/charger/smaevcharger.go @@ -37,12 +37,12 @@ import ( // smaevchager charger implementation type Smaevcharger struct { *request.Helper - log *util.Logger - uri string // 192.168.XXX.XXX - cache time.Duration - oldstate float64 - measurementG func() ([]smaevcharger.Measurements, error) - parameterG func() ([]smaevcharger.Parameters, error) + log *util.Logger + uri string // 192.168.XXX.XXX + cache time.Duration + oldstate float64 + measurementCache provider.Cacheable[[]smaevcharger.Measurements] + parameterCache provider.Cacheable[[]smaevcharger.Parameters] } func init() { @@ -95,7 +95,8 @@ func NewSmaevcharger(uri, user, password string, cache time.Duration) (api.Charg } // setup cached values - wb.reset() + wb.measurementCache = provider.ResettableCached(wb._measurementData, wb.cache) + wb.parameterCache = provider.ResettableCached(wb._parameterData, wb.cache) ts, err := smaevcharger.TokenSource(log, wb.uri, user, password) if err != nil { @@ -267,8 +268,8 @@ func (wb *Smaevcharger) Currents() (float64, float64, float64, error) { // reset cache func (wb *Smaevcharger) reset() { - wb.measurementG = provider.Cached(wb._measurementData, wb.cache) - wb.parameterG = provider.Cached(wb._parameterData, wb.cache) + wb.measurementCache.Reset() + wb.parameterCache.Reset() } func (wb *Smaevcharger) _measurementData() ([]smaevcharger.Measurements, error) { @@ -298,7 +299,7 @@ func (wb *Smaevcharger) _parameterData() ([]smaevcharger.Parameters, error) { } func (wb *Smaevcharger) getMeasurement(id string) (float64, error) { - res, err := wb.measurementG() + res, err := wb.measurementCache.Get() if err != nil { return 0, err } @@ -313,7 +314,7 @@ func (wb *Smaevcharger) getMeasurement(id string) (float64, error) { } func (wb *Smaevcharger) getParameter(id string) (string, error) { - res, err := wb.parameterG() + res, err := wb.parameterCache.Get() if err != nil { return "", err } diff --git a/charger/zaptec.go b/charger/zaptec.go index c6853f0e2..868b7d381 100644 --- a/charger/zaptec.go +++ b/charger/zaptec.go @@ -41,11 +41,11 @@ import ( // Zaptec charger implementation type Zaptec struct { *request.Helper - log *util.Logger - statusG func() (zaptec.StateResponse, error) - id string - priority bool - cache time.Duration + log *util.Logger + statusCache provider.Cacheable[zaptec.StateResponse] + id string + priority bool + cache time.Duration } func init() { @@ -91,7 +91,14 @@ func NewZaptec(user, password, id string, priority bool, cache time.Duration) (a } // setup cached values - c.reset() + c.statusCache = provider.ResettableCached(func() (zaptec.StateResponse, error) { + var res zaptec.StateResponse + + uri := fmt.Sprintf("%s/api/chargers/%s/state", zaptec.ApiURL, c.id) + err := c.GetJSON(uri, &res) + + return res, err + }, c.cache) data := url.Values{ "grant_type": {"password"}, @@ -118,17 +125,6 @@ func NewZaptec(user, password, id string, priority bool, cache time.Duration) (a return c, err } -func (c *Zaptec) reset() { - c.statusG = provider.Cached(func() (zaptec.StateResponse, error) { - var res zaptec.StateResponse - - uri := fmt.Sprintf("%s/api/chargers/%s/state", zaptec.ApiURL, c.id) - err := c.GetJSON(uri, &res) - - return res, err - }, c.cache) -} - func (c *Zaptec) chargers() ([]string, error) { var res zaptec.ChargersResponse @@ -145,7 +141,7 @@ func (c *Zaptec) chargers() ([]string, error) { // Status implements the api.Charger interface func (c *Zaptec) Status() (api.ChargeStatus, error) { - res, err := c.statusG() + res, err := c.statusCache.Get() if err != nil { return api.StatusA, err } @@ -167,7 +163,7 @@ func (c *Zaptec) Status() (api.ChargeStatus, error) { // Enabled implements the api.Charger interface func (c *Zaptec) Enabled() (bool, error) { - res, err := c.statusG() + res, err := c.statusCache.Get() return res.ObservationByID(zaptec.IsEnabled).Bool() && !res.ObservationByID(zaptec.FinalStopActive).Bool(), err } @@ -183,7 +179,7 @@ func (c *Zaptec) Enable(enable bool) error { req, err := request.New(http.MethodPost, uri, nil, request.JSONEncoding) if err == nil { _, err = c.DoBody(req) - c.reset() + c.statusCache.Reset() } return err @@ -195,7 +191,7 @@ func (c *Zaptec) chargerUpdate(data zaptec.Update) error { req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding) if err == nil { _, err = c.DoBody(req) - c.reset() + c.statusCache.Reset() } return err @@ -207,7 +203,7 @@ func (c *Zaptec) sessionPriority(session string, data zaptec.SessionPriority) er req, err := request.New(http.MethodPost, uri, request.MarshalJSON(data), request.JSONEncoding) if err == nil { _, err = c.DoBody(req) - c.reset() + c.statusCache.Reset() } return err @@ -227,7 +223,7 @@ var _ api.Meter = (*Zaptec)(nil) // CurrentPower implements the api.Meter interface func (c *Zaptec) CurrentPower() (float64, error) { - res, err := c.statusG() + res, err := c.statusCache.Get() if err != nil { return 0, err } @@ -239,7 +235,7 @@ var _ api.ChargeRater = (*Zaptec)(nil) // ChargedEnergy implements the api.ChargeRater interface func (c *Zaptec) ChargedEnergy() (float64, error) { - res, err := c.statusG() + res, err := c.statusCache.Get() if err != nil { return 0, err } @@ -251,7 +247,7 @@ var _ api.PhaseCurrents = (*Zaptec)(nil) // Currents implements the api.PhaseCurrents interface func (c *Zaptec) Currents() (float64, float64, float64, error) { - res, err := c.statusG() + res, err := c.statusCache.Get() if err != nil { return 0, 0, 0, err } @@ -270,7 +266,7 @@ var _ api.PhaseSwitcher = (*Zaptec)(nil) // Phases1p3p implements the api.ChargePhases interface func (c *Zaptec) Phases1p3p(phases int) error { - res, err := c.statusG() + res, err := c.statusCache.Get() if err == nil { data := zaptec.Update{ @@ -299,7 +295,7 @@ var _ api.Diagnosis = (*Zaptec)(nil) // Diagnosis implements the api.ChargePhases interface func (c *Zaptec) Diagnose() { - res, _ := c.statusG() + res, _ := c.statusCache.Get() // sort for printing sort.Slice(res, func(i, j int) bool { diff --git a/provider/cache.go b/provider/cache.go index 1b041a3e8..bcfaffcef 100644 --- a/provider/cache.go +++ b/provider/cache.go @@ -36,7 +36,6 @@ type cached[T any] struct { // Cached wraps a getter with a cache func Cached[T any](g func() (T, error), cache time.Duration) func() (T, error) { c := ResettableCached(g, cache) - _ = bus.Subscribe(reset, c.Reset) return c.Get } @@ -51,11 +50,13 @@ var _ Cacheable[int64] = (*cached[int64])(nil) // ResettableCached wraps a getter with a cache. It returns a `Cacheable`. // Instead of the cached getter, the `Get()` and `Reset()` methods are exposed. func ResettableCached[T any](g func() (T, error), cache time.Duration) *cached[T] { - return &cached[T]{ + c := &cached[T]{ clock: clock.New(), cache: cache, g: g, } + _ = bus.Subscribe(reset, c.Reset) + return c } func (c *cached[T]) Get() (T, error) {