refactor: PowerSync complete architecture strangler (Phases 0–7) - #41
refactor: PowerSync complete architecture strangler (Phases 0–7)#41Artic0din wants to merge 9 commits into
Conversation
Move price and energy DataUpdateCoordinator classes out of the monolithic coordinator.py into pricing/coordinators.py and energy/coordinators.py, with shared helpers in pricing/_shared.py. Keep coordinator.py as a compatibility re-export so existing imports continue to work. Co-authored-by: Artic0din <Artic0din@users.noreply.github.com>
Move all 63 HTTP view classes into custom_components/power_sync/api_http/ (powerwall, energy_brands, tariff, automations, ev, network, optimization) and re-export them from __init__.py so registration call sites stay unchanged. Co-authored-by: Artic0din <Artic0din@users.noreply.github.com>
Move PowerSyncConfigFlow/OptionsFlow and helpers into a modular config_flow_pkg with a thin config_flow.py facade for HA discovery. Add portal mixin stub, nested-schema migrate helper, and provider/ battery package placeholders for the next extraction phase. Co-authored-by: Artic0din <Artic0din@users.noreply.github.com>
Wire LoadpointArbiter through ev/ chargers+bridge+ownership re-exports and attach it when EVChargingModeCoordinator is stored. Extract bootstrap.lifecycle attach_runtime for EntryRuntime dual-write, and split const into const_pkg with a stable re-export facade. Co-authored-by: Artic0din <Artic0din@users.noreply.github.com>
Split OptimizationCoordinator and BatteryOptimizer into focused mixin modules (overlays, tariff windows, price forecast, reserve policy, action executor, LP/greedy/schedule emit). Route optimizer hardware commands through BatteryPort, deprecate ScheduleExecutor.execute_action, and extend stub const coverage for the new import surface. Co-authored-by: Artic0din <Artic0din@users.noreply.github.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_221d3260-293c-4329-a2a9-c5e7ca5bd228) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_84ca946c-b407-44ea-ac77-a19e24a828a5) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 506213a84b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| isinstance(slot_start, datetime) | ||
| and isinstance(slot_end, datetime) |
There was a problem hiding this comment.
Import datetime before using boundary deferral
When a periodic optimizer poll wants to start a forced action mid-slot after a cached non-forced boundary action, this branch evaluates isinstance(..., datetime), but the extracted mixin only imports timedelta. In that scenario _execute_optimizer_action raises NameError instead of deferring or executing the action, so the optimizer cycle fails until the next trigger. Import datetime here as it was available in the original coordinator module.
Useful? React with 👍 / 👎.
| bag[RUNTIME_KEY] = runtime | ||
| domain_data = hass.data.setdefault(domain, {}) | ||
| domain_data[entry.entry_id] = bag | ||
| domain_data.setdefault("_runtimes", {})[entry.entry_id] = runtime |
There was a problem hiding this comment.
Remove runtime registry entries on unload
Storing _runtimes under hass.data[DOMAIN] makes the domain dict non-empty even after async_unload_entry pops the last config entry; the unload path then skips its if not hass.data[DOMAIN] service cleanup and the _runtimes map keeps EntryRuntime objects holding the unloaded hass/entry references. This affects any last-entry unload/reload path, so the registry should either live outside the entry-domain bag or be pruned when the entry unloads.
Useful? React with 👍 / 👎.
|
|
||
| from homeassistant.core import HomeAssistant | ||
| from homeassistant.exceptions import ConfigEntryAuthFailed |
There was a problem hiding this comment.
Re-export UpdateFailed from the coordinator facade
For callers that still catch power_sync.coordinator.UpdateFailed or use from ...coordinator import UpdateFailed, this compatibility facade now raises AttributeError/ImportError even though _fetch_with_retry still raises that HA exception from pricing._shared. The facade promises existing imports from this module keep working, so it should import and expose UpdateFailed alongside ConfigEntryAuthFailed.
Useful? React with 👍 / 👎.
* chore(workflow): adopt GitHub-native task tracking Replace Linear-first agent guidance with GitHub Issues and the shared Development Project. Keep pull requests and CI authoritative for implementation. * fix(docs): remove stray workflow marker
…oud setup) (#52) Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* ci(github): install Repo Assist Install the current upstream Copilot workflow, compiled lock file, and agentic-workflow tooling. Use GitHub-native issues, pull requests, and persistent repository memory. * fix(github): satisfy workflow security gates Disable checkout credential persistence and document the generated workflow exceptions required by repository linting. * fix(github): address Repo Assist review findings Authenticate scheduled checks, remove the undefined merge driver, align the Copilot setup action, and clarify generated configuration. * fix(github): use keyless Copilot authentication Use the per-run GitHub token for Copilot inference, keep capacity skips green, and align active task guidance with GitHub Issues. * fix(github): harden Repo Assist pull requests Use trusted labels for automation capacity and branch updates, produce conventional pull request titles, and guarantee three distinct tasks. * fix(github): align Repo Assist maintenance markers Match generated pull request titles and labels, disclose automated status messages, and avoid an undefined merge driver. * fix(github): complete Repo Assist output policy Allow required changelog updates and narrowly permit closing labeled Repo Assist summary issues. * fix(github): serialize Repo Assist runs Prevent overlapping repository runs and suppress noisy no-op and failure issues while preserving visible workflow failures. * fix(github): expose workflow upgrade tools Allow cloud agents to run the fix and upgrade routes advertised by the installed Agentic Workflows skill.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f2f4d3d137
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| from custom_components.power_sync.control import ( | ||
| BatteryPort, | ||
| ServiceBatteryPort, | ||
| apply_restore_success_gate, | ||
| ) |
There was a problem hiding this comment.
Keep architecture tests off the package initializer
In the normal repo test environment, Home Assistant is not installed and tests are expected to stub it; importing custom_components.power_sync.control first executes custom_components/power_sync/__init__.py, which imports homeassistant.* before any stub is installed. The new architecture tests therefore fail during collection instead of testing the leaf contracts; use the existing power_sync package-stub pattern or load the leaf modules directly.
AGENTS.md reference: AGENTS.md:L18-L20
Useful? React with 👍 / 👎.
| from ..const import ( | ||
| CONF_CHIP_MODE_ENABLED, |
There was a problem hiding this comment.
Avoid import-time optional tariff constants
With the existing optimizer fixtures that stub power_sync.const narrowly, importing power_sync.optimization.coordinator now fails before tests run because this new mixin imports chip/demand constants unconditionally at module import time; tests/test_optimization_price_source.py errors on CONF_CHIP_MODE_ENABLED even for unrelated price-source cases. Keep these constants as local imports inside the tariff helpers or update the shared stubs so focused optimizer tests can still import the coordinator.
Useful? React with 👍 / 👎.
| @@ -16,10 +16,14 @@ | |||
| """ | |||
| from __future__ import annotations | |||
There was a problem hiding this comment.
Preserve the LP solver monkeypatch seam
After the solver split, battery_optimizer.py no longer exposes _solve_lp_highs, but the existing focused optimizer test still monkeypatches power_sync.optimization.battery_optimizer._solve_lp_highs and now raises AttributeError before it can verify the HiGHS time-limit path. Either keep this compatibility seam wired through the facade or update the focused test to patch the new solver module explicitly.
AGENTS.md reference: AGENTS.md:L20-L20
Useful? React with 👍 / 👎.
Summary
Implements the PowerSync complete architecture refactor as a strangler-fig rewrite with controlled migration.
What landed
EntryRuntimedual-write,BatteryPort+ restore contract, brand capability matrix, optimizer commands routed throughBatteryPortHomeAssistantViewclasses moved toapi_http/coordinator.pyfacade overpricing/+energy/withPriceProvider/EnergyTelemetryoverlays,tariff_windows,price_forecast,reserve_policy,action_executor) and solver split (lp_solver,greedy_solver,schedule_emit); deprecated deadScheduleExecutor.execute_actionpathLoadpointArbiter, charger adapter stubs, ownership re-export, planner attach hookconfig_flow.pythin facade overconfig_flow_pkg/+ portal mixin + migration helperbootstrap/lifecycle.attach_runtime,const.pyre-export facade overconst_pkg/tests/architecture/contract suiteVerification
pytest tests/architecture/ tests/test_greedy_priority_export.py tests/test_run_optimization_atomicity.py tests/test_battery_controller_wrapper.py tests/test_optimizer_restore_retry.py tests/test_spread_export_charge_preservation.py→ 45 passedFollow-ups (intentional strangler remainder)
__init__.pyintobatteries/config_flow_pkg/__init__.pysetup closures intobootstrap/