Skip to content

Subaru: handle transient API failures returning empty payloads#29036

Draft
ummon-v wants to merge 4 commits intoevcc-io:masterfrom
ummon-v:fix-subaru-api-transient-err
Draft

Subaru: handle transient API failures returning empty payloads#29036
ummon-v wants to merge 4 commits intoevcc-io:masterfrom
ummon-v:fix-subaru-api-transient-err

Conversation

@ummon-v
Copy link
Copy Markdown
Contributor

@ummon-v ummon-v commented Apr 12, 2026

Subaru Connected Services API occasionally returns empty payloads on transient failures. Without validation, these responses surface as 0% SoC / 0 km range, causing evcc to act on bad data (e.g. starting unwanted charging sessions).

Implementation

  • Wrap Subaru API status calls with caching (util.Cached) to avoid redundant requests and to retain last known good values
  • Detect transient API failures where the response payload is empty (missing range unit) and signal api.ErrMustRetry instead of propagating invalid data
  • Prevents 0% SoC from being reported during transient outages, which could incorrectly trigger minSoC charging

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • ValueInKilometers currently truncates the converted float to int64; consider using rounding (e.g. via math.Round) to avoid systematically under-reporting range after unit conversion.
  • status() only checks for an empty Unit string to detect transient empty payloads; if the API can return other sentinel values (e.g. zero range with a non-empty unit) for failures, it may be worth broadening the validation so invalid data is consistently mapped to api.ErrMustRetry.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- ValueInKilometers currently truncates the converted float to int64; consider using rounding (e.g. via math.Round) to avoid systematically under-reporting range after unit conversion.
- status() only checks for an empty Unit string to detect transient empty payloads; if the API can return other sentinel values (e.g. zero range with a non-empty unit) for failures, it may be worth broadening the validation so invalid data is consistently mapped to api.ErrMustRetry.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

return res, err
}
if res.Payload.EvRangeWithAc.Unit == "" ||
res.Payload.BatteryLevel == 0 && res.Payload.EvRangeWithAc.Value == 0 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this won't help as it does not clear the cache. The right thing to do would be not storing the invalid value in the first place.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% sure but it should be addressed with last push so zero can still be returned on a bad call, but it's never returned without the error, and the cache won't sit on it retrying immediately.

Do you think this is a good solution?

@andig andig marked this pull request as draft April 12, 2026 08:37
@andig andig added the vehicles Specific vehicle support label Apr 12, 2026
return impl
}

func (v *Provider) status() (Status, error) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove. why wrap a wrapper?

func (v *Provider) Range() (int64, error) {
res, err := v.status()
return int64(res.Payload.EvRangeWithAc.Value), err
if err != nil {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why change this? please don't make arbitrary unrelated changes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vehicles Specific vehicle support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants