79 lines
2.4 KiB
Go
79 lines
2.4 KiB
Go
package eebus
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/cenkalti/backoff/v4"
|
|
eebusapi "github.com/enbility/eebus-go/api"
|
|
"github.com/enbility/spine-go/model"
|
|
"github.com/evcc-io/evcc/api"
|
|
"github.com/evcc-io/evcc/util"
|
|
)
|
|
|
|
func WrapError(err error) error {
|
|
if errors.Is(err, eebusapi.ErrDataNotAvailable) || errors.Is(err, eebusapi.ErrDataInvalid) {
|
|
return api.ErrNotAvailable
|
|
}
|
|
return err
|
|
}
|
|
|
|
// WriteTimeout bounds how long an awaited eebus write waits for its result.
|
|
const WriteTimeout = 10 * time.Second
|
|
|
|
// Await runs a control write and waits for the remote device's result, returning
|
|
// an error if the write is rejected or no result arrives within WriteTimeout.
|
|
func Await(write func(func(model.ResultDataType, model.MsgCounterType)) (*model.MsgCounterType, error)) error {
|
|
res := make(chan model.ResultDataType, 1)
|
|
|
|
if _, err := write(func(r model.ResultDataType, _ model.MsgCounterType) { res <- r }); err != nil {
|
|
return err
|
|
}
|
|
|
|
select {
|
|
case r := <-res:
|
|
if r.ErrorNumber != nil && *r.ErrorNumber != 0 {
|
|
err := fmt.Errorf("write rejected: %d", *r.ErrorNumber)
|
|
if r.Description != nil {
|
|
err = fmt.Errorf("%w (%s)", err, *r.Description)
|
|
}
|
|
return err
|
|
}
|
|
return nil
|
|
case <-time.After(WriteTimeout):
|
|
return errors.New("write result timeout")
|
|
}
|
|
}
|
|
|
|
// limitTimeout keeps the retries inside the 60s the spec grants the Energy Guard.
|
|
const limitTimeout = 50 * time.Second
|
|
|
|
// AssertLimit states the current limit to a newly available Controllable System
|
|
// ([LPC-913]/[LPP-913]). Blocks while retrying- the CS ignores writes that do not
|
|
// follow a heartbeat and may reject them while still in state "init". Retrying
|
|
// stops when ctx is cancelled, i.e. when the device is gone.
|
|
func AssertLimit(ctx context.Context, log *util.Logger, write func() error) {
|
|
bo := backoff.NewExponentialBackOff(backoff.WithMaxElapsedTime(limitTimeout))
|
|
if err := backoff.Retry(write, backoff.WithContext(bo, ctx)); err != nil && ctx.Err() == nil {
|
|
log.DEBUG.Printf("assert limit: %v", err)
|
|
}
|
|
}
|
|
|
|
func LogEntities(log *log.Logger, actor string, uc eebusapi.UseCaseInterface) {
|
|
ss := uc.RemoteEntitiesScenarios()
|
|
if len(ss) > 0 {
|
|
log.Printf("%s:", actor)
|
|
}
|
|
|
|
for _, s := range ss {
|
|
var desc string
|
|
if d := s.Entity.Description(); d != nil {
|
|
desc = string(*d)
|
|
}
|
|
|
|
log.Printf(" entity: %s scenarios: %v meta: %s (%s)", s.Entity.Address(), s.Scenarios, s.Entity.EntityType(), desc)
|
|
}
|
|
}
|