Conversation
The JSON raw plan data was missing the rate adjust type that the legacy HTML plan used to show estimated/replicated rates (? symbols, italic). Both the built-in web UI and SaaS frontend consume the JSON plan but had no way to indicate which rates are confirmed vs estimated. Adds import_rate_adjust and export_rate_adjust fields to each JSON row, and updates the web UI renderer to display italic text with the appropriate symbol (matching output.py adjust_symbol behaviour). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. 🤖 Generated with Claude Code |
There was a problem hiding this comment.
Pull request overview
Adds rate-adjustment metadata to the JSON plan output so the built-in web UI (and external consumers) can display the same “rate source/adjustment” indicators that previously only existed in the legacy HTML plan.
Changes:
- Add
import_rate_adjust/export_rate_adjustfields to each JSON plan row (plan_html.attributes.raw.rows). - Update the built-in JSON plan renderer JS to display the corresponding symbol (matching
Output.adjust_symbol) and italicize adjusted/replicated rates.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| apps/predbat/output.py | Emits per-row rate-adjust “type” fields into the JSON raw plan output. |
| apps/predbat/web_helper.py | Renders the new adjust-type fields in the web UI plan table via symbol mapping + italics. |
| # Json row | ||
| json_row = {} | ||
| json_row["time"] = rate_start.strftime(TIME_FORMAT) | ||
| json_row["slot_minute"] = minute # aligned slot minute used by the override system | ||
| json_row["import_rate"] = rate_value_import | ||
| json_row["export_rate"] = rate_value_export | ||
| json_row["import_rate_adjust"] = self.rate_import_replicated.get(minute, None) | ||
| json_row["export_rate_adjust"] = self.rate_export_replicated.get(minute, None) |
There was a problem hiding this comment.
This PR changes the plan_html.attributes.raw JSON schema and the web UI renderer behavior, but there are no assertions in the existing tests that the generated raw_plan["rows"] include/propagate the new fields. Please add/update a unit test that calls publish_html_plan() and validates import_rate_adjust/export_rate_adjust are present and match the underlying rate_*_replicated values for at least one adjusted slot (e.g., copied/future/manual).
| json_row["import_rate_adjust"] = self.rate_import_replicated.get(minute, None) | ||
| json_row["export_rate_adjust"] = self.rate_export_replicated.get(minute, None) |
There was a problem hiding this comment.
Adding import_rate_adjust/export_rate_adjust to every row (often as null) increases the size of predbat.plan_html's raw attribute. Home Assistant warns and may drop recording when state attributes exceed 16KB; consider omitting these keys when no adjustment exists (or moving adjustment info into a more compact structure) to reduce attribute bloat.
| json_row["import_rate_adjust"] = self.rate_import_replicated.get(minute, None) | |
| json_row["export_rate_adjust"] = self.rate_export_replicated.get(minute, None) | |
| # Only include raw adjustment values when they actually exist to reduce attribute size | |
| import_rate_adjust = self.rate_import_replicated.get(minute) | |
| if import_rate_adjust is not None: | |
| json_row["import_rate_adjust"] = import_rate_adjust | |
| export_rate_adjust = self.rate_export_replicated.get(minute) | |
| if export_rate_adjust is not None: | |
| json_row["export_rate_adjust"] = export_rate_adjust |
| json_row["import_rate_adjust"] = self.rate_import_replicated.get(minute, None) | ||
| json_row["export_rate_adjust"] = self.rate_export_replicated.get(minute, None) |
There was a problem hiding this comment.
The new import_rate_adjust/export_rate_adjust fields are string “adjust types”, but the name is easy to confuse with the existing numeric *_rate_adjusted fields (especially for external consumers). Consider renaming to something explicit like import_rate_adjust_type / export_rate_adjust_type (and updating the renderer accordingly) to make the JSON schema self-describing.
| json_row["import_rate_adjust"] = self.rate_import_replicated.get(minute, None) | |
| json_row["export_rate_adjust"] = self.rate_export_replicated.get(minute, None) | |
| json_row["import_rate_adjust_type"] = self.rate_import_replicated.get(minute, None) | |
| json_row["export_rate_adjust_type"] = self.rate_export_replicated.get(minute, None) |
Summary
import_rate_adjustandexport_rate_adjustfields to each row in the JSON raw plan data (plan_html.attributes.raw)adjust_symbol()behaviour from the legacy HTML plan:?for copied,? ⚖for future rates,? ⅆfor offset,=for user-set,ȣfor manual,±for increment,$for saving sessionsThe JSON plan was missing this information — the legacy HTML plan showed it via
adjust_symbol()but the JSON rows only had the rate values. Both the built-in web UI and external consumers (SaaS frontend) now have access to the adjust type.Test plan
?symbol in the web UI plan tableplan_html.attributes.rawJSON rows containimport_rate_adjust/export_rate_adjustfields🤖 Generated with Claude Code