Repository navigation
feat(teslemetry): enable teslemetry_tbc_control by default - #5188
Merged
springfall2008 merged 3 commits intoSep 24, 2026
Merged
Conversation
Graduate the Time-Based Control trial setting (added in PR #4976 for GH#4892) to default-on: an apps.yaml that never sets teslemetry_tbc_control now gets the signal tariff and autonomous mode, so Tesla's Opticaster runs the charge at full rate. An explicit teslemetry_tbc_control: False keeps the real-rate tariff and reserve-driven charging. The registry default and initialize()'s own default are flipped together so a direct construction (the CLI test run) takes the same path as production. Template and docs now describe the setting as on by default with an opt-out. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The registry-to-constructor default wiring is not directly covered by the test, and the related lifecycle docstring needs correction.
Review effort: Lite
Findings: None
What changed in this PR
Enables Teslemetry Time-Based Control by default while retaining an explicit opt-out.
Changes:
- Updates registry and initialization defaults to
True. - Documents the new default and opt-out configuration.
- Updates tests for default-on and explicit-off behavior.
| File | Summary |
|---|---|
templates/teslemetry.yaml |
Adds a commented opt-out configuration. |
docs/inverter-setup.md |
Documents default-on behavior, opt-out guidance, and limitations. |
docs/components.md |
Updates component defaults and tariff behavior. |
apps/predbat/tests/test_teslemetry.py |
Updates default and opt-out tests. A moderate issue remains: the test does not exercise Components.initialize() default resolution; a docstring lifecycle reference also needs correction. |
apps/predbat/teslemetry.py |
Aligns direct initialization with the new default. |
apps/predbat/components.py |
Enables TBC by default in the component registry. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
springfall2008
commented
Sep 21, 2026
springfall2008
commented
Sep 21, 2026
springfall2008
commented
Sep 21, 2026
springfall2008
commented
Sep 21, 2026
springfall2008
commented
Sep 21, 2026
springfall2008
commented
Sep 21, 2026
springfall2008
commented
Sep 21, 2026
…ontrol-default-on-5186
…gnostics Addresses review feedback on #5188: - components.py: a registry default is now applied when apps.yaml has the key present but empty. A YAML null reached get_arg as None, and its bool branch only coerces strings - unlike the int/float branches it has no None fallback - so "on by default" silently did not apply, with nothing logged. - teslemetry.py: DEFAULT_TBC_CONTROL is now a single class constant, read by initialize() and by both getattr(self, "tbc_control", ...) fallbacks, which still encoded the old False and so would have selected the non-default path. - teslemetry.py: the diagnostic CLI takes --tbc-control/--no-tbc-control and names the control path in its mode banner, so a --control run cannot silently flip the Powerwall to the signal tariff and autonomous mode. - teslemetry.py: the 81-99 reserve-band diagnostic is now Warn rather than Info, since that band is reachable by a plausible set_reserve_min on the default path. - docs/inverter-setup.md: "on by default" is scoped to within the beta component, which resolves the contradiction with the beta warning above it. Tests: a Components-level test pins the resolution end-to-end (absent / null / explicit False), and a teslemetry test pins the fallback and the registry-to- constant agreement. Both fail without their fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
springfall2008
deleted the
feat/teslemetry-tbc-control-default-on-5186
branch
September 24, 2026 07:56
This was referenced Sep 24, 2026
springfall2008
pushed a commit
that referenced
this pull request
Sep 26, 2026
Resolve debug-journal conflicts with #5223's fold of the same merge batch: - Solis: keep this PR's #5189 detail and write-skip/test notes, then main's GH#5152 window-scoped hold lever - GE Cloud: main's #5109 wording plus the once-per-episode ems_slot_warned warning and its log text - Teslemetry: this PR's #5188 default-flip consequences plus main's GH#5157 forced re-assert - Manual rates: fold both rows into one (#5173 fix, surviving :59:59 boundary-minute and offset traps, test lesson) - Kraken, Sunsynk, Octopus, Car charging from main; Axle, GivTCP, Compare and the three new rows from this PR Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
CossieRob
pushed a commit
to CossieRob/batpred
that referenced
this pull request
Sep 26, 2026
…pringfall2008#5103/springfall2008#5186/springfall2008#5053-adjacent entries Folded (13 entries from the 15-candidate slice, all re-verified against origin/main 130596b): - Load ML row (GH#5075, PR springfall2008#5112 open draft): is_valid() can report active for a never-trained model; training_timestamp is None is not a sound never-trained test (legacy saved models); train() stamps at the end of every curriculum pass, so an abort leaves fresh stamps that suppress the ml_max_model_age_hours retrain. Normalisation-statistics skew stays suspected. - Octopus row: GH#5144 overlapping DIRECT/NON_DIRECT_DEBIT rows, minute_data last-row-wins and the period-to-period flip - fixed in PR springfall2008#5145 (filter_payment_method, keeps nulls). - Car charging row: GH#5146/GH#5151 the two different Hold-for-car gates (execute.py live block vs prediction.py plan gate), deliberate export-window exemption test-codified (discharge_car_full_bat2), read-only users never see the status sensor's annotation. - Sunsynk/DEYE row: PR springfall2008#5150 control_active persistence + upgrade-cache inference; the in-code press every cycle comment is wrong (both press sites change-gated, post-restart re-commit is is_hm_format-only); GH#5156 TOU padding truncation fixed in tou_schedule.py _padding_segments. - Solis row: GH#5152 the hold lever is the window-scoped timed current (standing battery_discharge_current never driven); PR springfall2008#5189 adds the rated-current cap (GH#5187). - Predheat row: GH#5153 no Fahrenheit conversion in get_weather_data + the optional heating_energy age bug pinning minute_data_age to 0. - Teslemetry row: GH#5157 forced re-assert implemented (FORCED_ASSERT_SECONDS = 2h, dedupe bypassed, tariff excluded); tbc_control default on since PR springfall2008#5188. - Keep section: GH#5162 manual_soc floor penalty is import-rate-weighted, so inert inside 0p windows; the manual_soc_max ceiling is export-rate-weighted; manual_charge lookalike trap. - New Kraken row: GH#5166/PR springfall2008#5167 EDF 400-on-day/night vs Octopus 200-empty; KRAKEN_REST_RATES_UNAVAILABLE_STATUSES; the (None, None) tuple contract and the failures_total double-count, both fixed in the merged PR and kept as mechanisms. - New Manual rates row: GH#5168 day_of_week stamped across the whole rate horizon, fixed in PR springfall2008#5173; end ':59:59' final-minute trap and the metric_future_rate_offset test pin kept. Dropped: 5169-5053-cache-now-on-main (already covered by the redaction entry and the GH#5063 premise bullet; its lock-lazy-init nugget is recorded as a fact of the merged PR springfall2008#5171 mixin). Corrected by the merge scan: GH#5103 fixed in PR springfall2008#5109 (hourly settings refresh + the new check_ems_inverter_slots warning); teslemetry_tbc_control default on (PR springfall2008#5188); the log-redaction cache moved into the LogRedaction mixin (log_secrets.py, PR springfall2008#5171). Co-Authored-By: Claude Code <noreply@anthropic.com>
CossieRob
pushed a commit
to CossieRob/batpred
that referenced
this pull request
Sep 26, 2026
…s); correct entries overtaken by the springfall2008#5109/springfall2008#5173/springfall2008#5185/springfall2008#5188/springfall2008#5189 merge batch Co-Authored-By: Claude Code <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is an automated draft PR generated from issue #5186 — a maintainer should review it before merging.
Fixes #5186
Summary
Makes
teslemetry_tbc_controlon by default. Before this it was an opt-in trial setting, added in PR #4976 for GH#4892. Ifapps.yamldoesn't set the key, the Teslemetry component now pushes the signal tariff (0p over the charge window, 50p import elsewhere, 100p over the export window) and puts the Powerwall in autonomous mode, so Tesla's Opticaster charges at full rate. Settingteslemetry_tbc_control: Falseexplicitly still gives the real-rate tariff and reserve-driven charging.apps/predbat/components.py: registry default fortbc_controlchanged fromFalsetoTrue. This is the functional change:Components.start()resolves an unset key to this value (components.py:806).apps/predbat/teslemetry.py:initialize()'s owntbc_controldefault also changed toTrue, and the docstring updated. Production always passes the registry value, so this doesn't change production behaviour. It keeps a direct construction on the same path as production; the__main__CLI test run builds the class without passingtbc_control.templates/teslemetry.yaml: the commented#teslemetry_tbc_control: Truehint is replaced with a commented opt-out,#teslemetry_tbc_control: False.docs/components.mdanddocs/inverter-setup.md: the defaults table, the "Important notes" tariff bullets and the Teslemetry setup section now describe the setting as on by default, with an opt-out. The setup section's example YAML previously had an uncommentedteslemetry_tbc_control: False, so anyone copying it would have stayed opted out. That line is now a commented opt-out.Testing
./run_pre_commit(fromcoverage/): every hook passed, andrun_all --quickpassed (4 slow tests skipped). I ran it before and after the self-review edits.tools/triage_test.sh teslemetry: fails without the fix and passes with it. With onlycomponents.pyandteslemetry.pystashed, the newtest_teslemetry_tbc_control_defaults_on_via_the_registryfails atassert api.tbc_control is True. With the fix restored, the module passes.tools/triage_test.sh components: passes (9/9).Test changes in
apps/predbat/tests/test_teslemetry.py:test_teslemetry_tbc_control_defaults_on_via_the_registry. Takes the registry default, passes it throughinitialize(), and checks the TBC path is selected (autonomous mode inside a charge window). It also checks that a bareinitialize()agrees with the registry default.test_teslemetry_tbc_control_defaults_off_and_uses_the_real_rate_tariffis nowtest_teslemetry_tbc_control_off_uses_the_real_rate_tariff, and it setstbc_control = Falseexplicitly. It now tests the opt-out rather than a default.test_teslemetry_initialize_sets_tbc_control_from_component_argnow also asserts thatinitialize(tbc_control=False)is honoured.test_teslemetry_component_registry_confignow pins the registry default asTrue.Notes
run()(teslemetry.py:508) is gated on read-only mode but not onteslemetry_automatic. So after upgrading, every non-read-only Teslemetry user who hasn't set the key moves to the signal tariff and autonomous mode on their first cycle. That includes users who don't haveteslemetry_automatic: True. The triage comment said only automatic users would be affected; that isn't quite right. Two visible changes: the Tesla app will show the 0/50/100p signal tariff instead of the user's real rates, and Predbat's charge and export targets become advisory. Probably worth a line in the release notes.docs/inverter-setup.mdnow applies to anyone on the default: withset_reserve_minanywhere in 81-99, grid charging stays disabled in every state, and the only explanation is a one-off log line. This PR doesn't change that behaviour. It's a judgement for the maintainer whether that needs a louder diagnostic before the setting defaults on.getattr(self, "tbc_control", False)fallbacks inevaluate_scheduleandsync_tariff(teslemetry.py:592/:1414) still default toFalse. They can't be reached in production, becauseinitialize()always sets the attribute, so I kept this change scoped.MockTeslemetryAPIstill setstbc_control = False, so the roughly 100 existing tests written against the real-rate path keep testing it. A comment on the mock says why, and the TBC tests opt in explicitly.impactonTeslemetryAPI.initializeis LOW with no static callers; the registry constructs the class dynamically.COMPONENT_LISTis a data constant that GitNexus can't resolve as a target, so I found its readers by search: the registry resolver (components.py:806), the web component-config view (web.py:5483, which only displays the default), and the tests.detect_changes: LOW risk, 0 affected execution flows.tools/debug-journal.mdinformed this change: it describes the TBC path and the 81-99% rounding.🤖 Generated with Claude Code