Tibber: resubscribe on clean disconnect (#18643)

This commit is contained in:
Michael Heß 2025-02-14 17:24:49 +01:00 • committed by GitHub
parent 40170cc93c
commit 4f978242e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -20,7 +20,9 @@ func init() {
}
type Tibber struct {
data *util.Monitor[tibber.LiveMeasurement]
data *util.Monitor[tibber.LiveMeasurement]
homeID string
timeout time.Duration
}
func NewTibberFromConfig(ctx context.Context, other map[string]interface{}) (api.Meter, error) {
@ -67,7 +69,9 @@ func NewTibberFromConfig(ctx context.Context, other map[string]interface{}) (api
}
t := &Tibber{
data: util.NewMonitor[tibber.LiveMeasurement](cc.Timeout),
data: util.NewMonitor[tibber.LiveMeasurement](cc.Timeout),
homeID: cc.HomeID,
timeout: cc.Timeout,
}
// subscription client
@ -99,18 +103,8 @@ func NewTibberFromConfig(ctx context.Context, other map[string]interface{}) (api
return nil
})
done := make(chan error, 1)
go func(done chan error) {
done <- t.subscribe(client, cc.HomeID)
}(done)
select {
case err := <-done:
if err != nil {
return nil, err
}
case <-time.After(cc.Timeout):
return nil, api.ErrTimeout
if err := t.ensureSubscribed(client); err != nil {
return nil, err
}
go func() {
@ -121,11 +115,16 @@ func NewTibberFromConfig(ctx context.Context, other map[string]interface{}) (api
}()
go func() {
// The pulse sometimes declines valid(!) subscription requests, and asks the client to disconnect.
// Therefore we need to restart the client when exiting gracefully upon server request
// https://github.com/evcc-io/evcc/issues/17925#issuecomment-2621458890
for tick := time.Tick(10 * time.Second); ; {
if err := client.Run(); err != nil {
err := client.Run()
if err == nil {
// The pulse sometimes declines valid(!) subscription requests, and asks the client to disconnect.
// This invalidates the subscription, and therefore we resubscribe when exiting Run() gracefully
// upon server request.
// https://github.com/evcc-io/evcc/issues/17925#issuecomment-2621458890
err = t.ensureSubscribed(client)
}
if err != nil {
log.ERROR.Println(err)
}
@ -140,13 +139,27 @@ func NewTibberFromConfig(ctx context.Context, other map[string]interface{}) (api
return t, nil
}
func (t *Tibber) subscribe(client *graphql.SubscriptionClient, homeID string) error {
func (t *Tibber) ensureSubscribed(client *graphql.SubscriptionClient) error {
done := make(chan error, 1)
go func(done chan error) {
done <- t.subscribe(client)
}(done)
select {
case err := <-done:
return err
case <-time.After(t.timeout):
return api.ErrTimeout
}
}
func (t *Tibber) subscribe(client *graphql.SubscriptionClient) error {
var query struct {
tibber.LiveMeasurement `graphql:"liveMeasurement(homeId: $homeId)"`
}
_, err := client.Subscribe(&query, map[string]any{
"homeId": graphql.ID(homeID),
"homeId": graphql.ID(t.homeID),
}, func(data []byte, err error) error {
if err != nil {
return err