99 "strings"
1010 "time"
1111
12+ "github.com/cenkalti/backoff/v4"
1213 "github.com/evcc-io/evcc/api"
1314 "github.com/evcc-io/evcc/meter/tibber"
1415 "github.com/evcc-io/evcc/util"
@@ -109,34 +110,32 @@ func NewTibberFromConfig(ctx context.Context, other map[string]interface{}) (api
109110 WithConnectionParams (map [string ]any {
110111 "token" : cc .Token ,
111112 }).
112- WithRetryTimeout (15 * time .Second ). // Retry 15 seconds (3 tries) , then exit to outer retry loop that has backoff
113- WithRetryDelay (5 * time .Second ).
113+ WithRetryTimeout (20 * time .Second ). // 2 tries, then exit to outer retry loop that has backoff
114+ WithRetryDelay (10 * time .Second ).
114115 WithWriteTimeout (request .Timeout ).
115116 WithReadTimeout (90 * time .Second ).
116117 WithLog (log .TRACE .Println ).
117118 OnConnected (func () {
118- log .INFO .Println ("Tibber pulse: websocket connected" )
119+ log .DEBUG .Println ("websocket connected" )
119120 }).
120121 OnDisconnected (func () {
121- log .WARN .Println ("Tibber pulse: websocket disconnected" )
122+ log .WARN .Println ("websocket disconnected" )
122123 }).
123124 OnSubscriptionComplete (func (_ graphql.Subscription ) {
124- log .WARN .Println ("Tibber pulse: websocket subscription completed by server" )
125+ log .DEBUG .Println ("websocket subscription completed by server" )
125126 }).
126127 OnError (func (sc * graphql.SubscriptionClient , err error ) error {
127- // Don't let Hasura go graphql client reconnect when authorization fails
128+ // Don't let graphql client reconnect when authorization fails
128129 if sc .IsUnauthorized (err ) {
129- log .ERROR .Printf ("Tibber pulse: Unauthorized: %v" , err )
130130 return err
131131 }
132132 // Don't let Hasura go graphql client reconnect when too many initialisation requests
133133 // Reconnection will be attempted in the loop later
134134 if sc .IsTooManyInitialisationRequests (err ) {
135- log .ERROR .Printf ("Tibber pulse: Too many initialisation requests: %v" , err )
136135 return err
137136 }
138137
139- log .ERROR .Printf ("Tibber pulse: error occurred: %v" , err )
138+ log .ERROR .Printf ("error occurred: %v" , err )
140139 return nil
141140 })
142141
@@ -162,7 +161,6 @@ func NewTibberFromConfig(ctx context.Context, other map[string]interface{}) (api
162161 }
163162 }()
164163
165- reconnectCount := 0
166164 go func () {
167165 // The pulse sometimes declines valid(!) subscription requests, and asks the client to disconnect.
168166 // Therefore we need to restart the client when exiting gracefully upon server request
@@ -173,47 +171,46 @@ func NewTibberFromConfig(ctx context.Context, other map[string]interface{}) (api
173171 // 2. This loop, which is triggered server when Hasura exits on error or gracefully
174172 // 3. evcc itself restarts if the client exits with an error
175173
176- // Exponential backoff parameters
177- baseDelay := 5 * time .Second
178- maxDelay := 5 * time .Hour
179- delay := baseDelay
174+ var reconnectCount int
175+
176+ bo := backoff .NewExponentialBackOff (
177+ backoff .WithInitialInterval (30 * time .Second ),
178+ backoff .WithMaxInterval (10 * time .Minute ),
179+ backoff .WithMaxElapsedTime (0 ),
180+ )
180181
181182 for {
182183 reconnectCount ++
183- log .INFO .Printf ("Tibber pulse: Hasura go graphql client connection attempt #%d" , reconnectCount )
184+ log .DEBUG .Printf ("graphql client connection attempt #%d" , reconnectCount )
184185
185186 startTime := time .Now ()
186187 err := client .Run ()
187188 duration := time .Since (startTime ).Round (time .Second )
189+
188190 if err != nil {
189- log .ERROR .Printf ("Tibber pulse: Hasura go graphql client exited with error at %s: %v" , duration , err )
191+ log .ERROR .Printf ("graphql client exited with error at %s: %v" , duration , err )
190192 // Do not retry if unauthorized
191193 if client .IsUnauthorized (err ) {
192- log .ERROR .Println ("Tibber pulse: Not retrying due to unauthorized error." )
194+ log .ERROR .Println ("Not retrying due to unauthorized error." )
193195 return
194196 }
195- // Exponential backoff: double the delay, up to maxDelay
196- delay *= 2
197- if delay > maxDelay {
198- delay = maxDelay
199- }
200197 } else {
201- log .INFO .Printf ("Tibber pulse: Hasura go graphql client exited gracefully at %s" , duration )
202- // Reset delay after successful connection
203- delay = baseDelay
198+ log .DEBUG .Printf ("graphql client exited gracefully at %s" , duration )
199+ bo .Reset ()
204200 }
205201
202+ delay := bo .NextBackOff ()
203+
206204 select {
207205 case <- time .After (delay ):
208- log .INFO .Printf ("Tibber pulse: Reconnection timer triggered after %s, attempting reconnect " , delay )
206+ log .DEBUG .Printf ("reconnecting after %v backoff delay " , delay )
209207 case <- ctx .Done ():
210- log .INFO .Println ("Tibber pulse: Context canceled, exit reconnection loop" )
211208 return
212209 }
213210 }
214211 }()
215212
216- log .INFO .Printf ("!! User-Agent set to %s" , getUserAgent ())
213+ log .DEBUG .Printf ("!! User-Agent set to %s" , getUserAgent ())
217214
218215 return t , nil
219216}
@@ -227,7 +224,7 @@ func (t *Tibber) subscribe(client *graphql.SubscriptionClient, homeID string, lo
227224 "homeId" : graphql .ID (homeID ),
228225 }, func (data []byte , err error ) error {
229226 if err != nil {
230- log .ERROR .Printf ("Tibber pulse: Error during subscription: %v" , err )
227+ log .ERROR .Printf ("Error during subscription: %v" , err )
231228 return err
232229 }
233230
@@ -236,7 +233,7 @@ func (t *Tibber) subscribe(client *graphql.SubscriptionClient, homeID string, lo
236233 }
237234
238235 if err := json .Unmarshal (data , & res ); err != nil {
239- log .ERROR .Printf ("Tibber pulse: Error unmarshaling data: %v" , err )
236+ log .ERROR .Printf ("Error unmarshaling data: %v" , err )
240237 return err
241238 }
242239
0 commit comments