Skip to content

Isolate aiohttp session and storage per config entry (multi-account support) - #4

Merged
willbeeching merged 1 commit into
mainfrom
fix/multi-account-support
Apr 20, 2026
Merged

Isolate aiohttp session and storage per config entry (multi-account support)#4
willbeeching merged 1 commit into
mainfrom
fix/multi-account-support

Conversation

@willbeeching

Copy link
Copy Markdown
Owner

Summary

  • Give each coordinator its own aiohttp.ClientSession with a dedicated CookieJar so two BoilerJuice accounts can't overwrite each other's login cookies (root cause reported in Support for multiple instances? #3).
  • Key persisted consumption data by config entry_id instead of tank id, with a migration path from existing tank-id and "default" keys so nobody loses history on upgrade. The shared "default" bucket is left in place to avoid a race between two entries migrating from it.
  • Resolve service targets properly: reset_consumption and set_consumption now accept optional device_id/entry_id (plus the normal HA target selector) and only hit the matching coordinator(s). When nothing is selected the old "apply to all" behaviour is preserved for backwards compatibility.
  • Close the private session on async_unload_entry and on config-flow validation, so failed logins don't leak a connection.
  • Small clean-ups found along the way:
    • Remove a stray reset_consumption registration in sensor.py that had no schema and closed over a single coordinator, shadowing the real service.
    • async_unload_services now also removes set_consumption.
  • Bump manifest.json to 1.2.0.

Related to #3 (leaving the issue open for discussion with the reporter).

Test plan

  • black --check custom_components/boilerjuice/
  • isort --check-only custom_components/boilerjuice/
  • flake8 custom_components/boilerjuice/ --select=E9,F63,F7,F82 (strict CI checks)
  • Smoke-tested _resolve_target_coordinators with stubbed HA internals: no-target, entry_id, single/multi device_id, and unknown-target error paths.
  • Smoke-tested storage load/save with stubbed Store: legacy tank-id keys migrate into per-entry keys, shared "default" bucket is preserved when multiple entries might still need it, and the no-entry validation path falls back safely.
  • Install on a live HA with two BoilerJuice accounts and confirm both refresh independently.
  • Run boilerjuice.reset_consumption targeted at a single device and confirm the other account is untouched.

Multiple BoilerJuice accounts were overwriting each other because the
coordinator used Home Assistant's shared aiohttp session (and therefore a
shared cookie jar), and the consumption store fell back to a single
"default" bucket when no tank id was configured. Each coordinator now
owns a private ClientSession with its own CookieJar, and consumption
data is keyed by config entry id with a migration path from legacy
tank-id keys.

Also:
- Close the private session on entry unload and after config-flow
  validation so temporary coordinators don't leak connections.
- Add optional device_id/entry_id target selectors to the
  reset_consumption and set_consumption services so they no longer fan
  out to every configured account.
- Remove a stray reset_consumption registration in sensor.py that
  shadowed the properly-schemaed service with a single-coordinator one,
  and make async_unload_services drop set_consumption too.
@cursor

cursor Bot commented Apr 20, 2026

Copy link
Copy Markdown

You have used all of your free Bugbot PR reviews.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@willbeeching
willbeeching merged commit 0f56ea7 into main Apr 20, 2026
2 of 3 checks passed
@willbeeching
willbeeching deleted the fix/multi-account-support branch April 20, 2026 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant