Repository navigation
Commit 8b67d5e
* feat(octopus): log a per-car IOG dispatch timeline diagnostic (#4516 Stage 1)
Issue #4516: a future daytime IOG dispatch slot is still Octopus's own
provisional/revisable plan, but Predbat currently treats it the same as a
confirmed one. Before building any gating/replan logic on a specific
confirmation signal, first observe real dispatch lifecycles - two signals
investigated for this (intelligent_charge_cap_hours, then the
intelligent_dispatching binary_sensor's default mode) both looked promising
and both turned out unreliable on inspection.
Adds build_dispatch_timeline() (octopus.py): a small render helper producing
a fixed-width, one-character-per-30-min-block status string ('.' nothing,
'P' planned, 'S' started, 'C' completed) across a -4h..+24h window around
now. Logged once per car per 30-minute boundary from fetch_sensor_data_cars()
- purely observational, not merged into octopus_slots or used for any
rate/plan decision. Stacking consecutive lines in a monospace log viewer
reveals dispatch lifecycle as diagonal stripes: a specific dispatch drifts
one column per line as now advances, so a rescinded slot shows as a stripe
that stops before reaching the 'now' column.
Also reads started_dispatches/startedDispatches from the octopus_intelligent_slot
entity for the first time - present on the entity (confirmed against the
actual Octopus Energy HA integration source) but not previously read anywhere
in Predbat.
8 new unit tests for the render helper (empty/planned/started/completed
rendering, confirmed-status priority ordering, out-of-window slots,
multi-block spans). Sanity-checked against a real captured debug.yaml's
octopus_slots data - handles real-world irregularities (negative
charge_in_kwh, non-standard location values) without crashing.
Stage 2 (the actual confirmed-slot gating + immediate-replan trigger) is
deferred until dispatch timelines have been observed for a while.
* feat(octopus): mark in the dispatch timeline where Predbat plans to charge
The Stage 1 timeline shows a dispatch's lifecycle (planned -> started -> completed)
but not whether Predbat depended on it. A slot that disappears having never been
planned against costs nothing; one Predbat committed an import to is a plan that
will not happen. Those look identical in a P/S/C render.
Lowercase the letter where Predbat's plan charges in that block, so 'p' is a
provisional slot being relied on and 'P' one that is not. Read as stripes, a run of
'p' that stops before reaching the now column is exactly the case worth finding:
Predbat planned around a slot and lost it.
This runs in fetch, before the planner, so the windows are the previous cycle's plan
- one 5-minute cycle stale against 30-minute blocks. Deliberate: what Predbat
believed while the slot was still live is the more useful record, and the error is
well inside a block.
Windows with a zero charge limit are not treated as charging.
Still purely observational - no rate or plan decision reads this.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(octopus): decode dispatch-timeline slot boundaries without the metadata reject
Copilot review on #4948: decode_octopus_slot()'s "remove empty slots" check
rejects a slot with no kWh, source or location as empty. A real
started_dispatches entry from the HA Octopus Energy integration carries only
start/end - no metadata at all - so build_dispatch_timeline()'s mark() call
decoded every real started dispatch as empty and 'S' could never render for
real data. The existing tests all use a _slot() helper that adds
source/location, which masked this.
The timeline only needs start/end; it never reads the kWh/source/location
this rejection is guarding. Added decode_octopus_slot(boundaries_only=True),
returning right after the start/end decode and before the metadata handling,
and pointed build_dispatch_timeline() at it. Every other caller is
unaffected - the parameter defaults False.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat(octopus): log the dispatch timeline on change, not just the 30-min heartbeat
PR #4948 review: a heartbeat every 30 minutes alone can miss a provisional
slot that appears, influences Predbat's plan, and disappears again entirely
within one half-hour window - exactly the "stripe that never reaches now"
pattern this diagnostic exists to catch, invisible regardless of how little
time it had to affect SoC. The underlying dispatch lists were already being
re-read every 5-minute cycle; only the log line itself was gated to the
30-minute boundary.
Added dispatch_timeline_should_log(), called every cycle: the 30-minute
heartbeat still always logs unmarked, and a change from the last logged
timeline for that car now also logs immediately, marked with a trailing
' *' so the two kinds of line can be told apart (or grepped separately).
The marker is a suffix, appended after build_dispatch_timeline()'s
fixed-width string rather than before it, so heartbeat and change-triggered
lines keep stacking column-for-column in a monospace viewer - the whole
point of the render is that consecutive lines line up into diagonal
stripes, and a prefix of differing length between the two line kinds would
break that.
5 new tests for the logging decision itself (heartbeat, no-change,
change, no-repeat, independent per-car state), confirmed to fail with an
AttributeError against the pre-change code.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent 64a58d6 commit 8b67d5e
5 files changed
Lines changed: 369 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1402 | 1402 | | |
1403 | 1403 | | |
1404 | 1404 | | |
| 1405 | + | |
1405 | 1406 | | |
1406 | 1407 | | |
1407 | 1408 | | |
| |||
1415 | 1416 | | |
1416 | 1417 | | |
1417 | 1418 | | |
| 1419 | + | |
| 1420 | + | |
| 1421 | + | |
| 1422 | + | |
| 1423 | + | |
1418 | 1424 | | |
1419 | 1425 | | |
1420 | 1426 | | |
1421 | 1427 | | |
| 1428 | + | |
| 1429 | + | |
| 1430 | + | |
| 1431 | + | |
| 1432 | + | |
| 1433 | + | |
| 1434 | + | |
1422 | 1435 | | |
1423 | 1436 | | |
1424 | 1437 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2910 | 2910 | | |
2911 | 2911 | | |
2912 | 2912 | | |
2913 | | - | |
| 2913 | + | |
2914 | 2914 | | |
2915 | 2915 | | |
| 2916 | + | |
| 2917 | + | |
| 2918 | + | |
| 2919 | + | |
| 2920 | + | |
2916 | 2921 | | |
2917 | 2922 | | |
2918 | 2923 | | |
| |||
2936 | 2941 | | |
2937 | 2942 | | |
2938 | 2943 | | |
| 2944 | + | |
| 2945 | + | |
| 2946 | + | |
2939 | 2947 | | |
2940 | 2948 | | |
2941 | 2949 | | |
| |||
3021 | 3029 | | |
3022 | 3030 | | |
3023 | 3031 | | |
| 3032 | + | |
| 3033 | + | |
| 3034 | + | |
| 3035 | + | |
| 3036 | + | |
| 3037 | + | |
| 3038 | + | |
| 3039 | + | |
| 3040 | + | |
| 3041 | + | |
| 3042 | + | |
| 3043 | + | |
| 3044 | + | |
| 3045 | + | |
| 3046 | + | |
| 3047 | + | |
| 3048 | + | |
| 3049 | + | |
| 3050 | + | |
| 3051 | + | |
| 3052 | + | |
| 3053 | + | |
| 3054 | + | |
| 3055 | + | |
| 3056 | + | |
| 3057 | + | |
| 3058 | + | |
| 3059 | + | |
| 3060 | + | |
| 3061 | + | |
| 3062 | + | |
| 3063 | + | |
| 3064 | + | |
| 3065 | + | |
| 3066 | + | |
| 3067 | + | |
| 3068 | + | |
| 3069 | + | |
| 3070 | + | |
| 3071 | + | |
| 3072 | + | |
| 3073 | + | |
| 3074 | + | |
| 3075 | + | |
| 3076 | + | |
| 3077 | + | |
| 3078 | + | |
| 3079 | + | |
| 3080 | + | |
| 3081 | + | |
| 3082 | + | |
| 3083 | + | |
| 3084 | + | |
| 3085 | + | |
| 3086 | + | |
| 3087 | + | |
| 3088 | + | |
| 3089 | + | |
| 3090 | + | |
| 3091 | + | |
| 3092 | + | |
| 3093 | + | |
| 3094 | + | |
| 3095 | + | |
| 3096 | + | |
| 3097 | + | |
| 3098 | + | |
| 3099 | + | |
| 3100 | + | |
| 3101 | + | |
| 3102 | + | |
| 3103 | + | |
| 3104 | + | |
| 3105 | + | |
| 3106 | + | |
| 3107 | + | |
| 3108 | + | |
| 3109 | + | |
| 3110 | + | |
| 3111 | + | |
| 3112 | + | |
| 3113 | + | |
| 3114 | + | |
| 3115 | + | |
| 3116 | + | |
| 3117 | + | |
| 3118 | + | |
| 3119 | + | |
| 3120 | + | |
| 3121 | + | |
| 3122 | + | |
| 3123 | + | |
3024 | 3124 | | |
3025 | 3125 | | |
3026 | 3126 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
497 | 497 | | |
498 | 498 | | |
499 | 499 | | |
| 500 | + | |
500 | 501 | | |
501 | 502 | | |
502 | 503 | | |
| |||
0 commit comments