Repository navigation
Charge Manager tests in divert_sim, and a downloadable replay package - #1351
Draft
jeremypoulter wants to merge 6 commits into
Draft
jeremypoulter wants to merge 6 commits into
jeremypoulter wants to merge 6 commits into
Conversation
The simulator now builds the firmware's Scheduler, Limit, TempThrottleTask and RfidTask into every peer, so Charge Manager rules, session limits, temperature protection and RFID gating execute the real firmware code. - Scheduler takes its divert/shaper/RFID/limit collaborators by reference instead of reaching for the globals, so each peer can own one. MQTT publishing and the SNTP time-change hook are compiled out under DIVERT_SIM, where the scheduler reads simulated wall-clock time. - rfid.cpp drops two unused includes (mqtt.h, input.h). - The RAPI shim reports a protocol 5 controller with vflags (EV connected, charging) and the simulated EVSE temperature on $GP. - Scenarios gain a schedule (scenario-wide or per peer), a temperature input, rfid_reader/report_soc peer options and rfid, temperature, soc, claim, release, limit and schedule events. - CSV output adds pilot_a, temperature_c, limit, rfid_auth and schedule_event per peer. - Scenario runs use a private EpoxyFS/EEPROM directory, so parallel runs no longer share persisted state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XEyVzUHFzxthd54TWTGA1r
charge_manager.py configures a simulated station the way the Charge Manager screen does (always-on features as config, scheduled rules compiled with a port of the GUI's rulesToTimers) and parses the claim columns into an arbitration oracle. test_charge_manager.py covers each feature on its own: default state and station current, session limits (energy, time, SoC), eco divert, grid shaping, RFID, OCPP (as the claims OcppTask makes), temperature protection, every scheduled rule action, rule current and limit, midnight wrap, day filters, rules without a stop, manual override, and live rule edits and deletes. test_charge_manager_combinations.py runs all 417 combinations the Charge Manager allows through one scripted day and checks claim arbitration and each feature's contract on every row. Breaking RFID gating or the divert timer priority in the firmware fails 244 of these tests. Two known gaps are strict xfails: - a scheduled OCPP rule is a plain charge window (SchedulerFeature::OCPP is a placeholder); - a timed Disable rule never ends, because rulesToTimers writes its stop as another 'disabled' timer. Simulator fidelity fixes found along the way: - the RAPI shim holds the station current ($GC cmaxamps, $SC M), so max_current_soft caps the pilot; - live_pwr_add_ev models a whole-site meter that also sees the EV, taking the EV's share from the firmware's own ammeter reading; - a session_wh column exposes the firmware's session energy; - run_scenario_doc runs an in-memory scenario. Five charge_manager_* showcase scenarios are generated for the viewer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XEyVzUHFzxthd54TWTGA1r
…n divert_sim The firmware now keeps a replay recording: every 10 s the solar, grid and site power, voltage, temperature, plug state, EVSE state, pilot, current and target, plus every claim, limit, boost, RFID, schedule and config change. GET /debug/replay (?download=1 to save) returns it with the configuration and schedule. The recorder is passive (it polls public getters) and allocates ~12 KB once at boot; ENABLE_REPLAY_RECORDER, REPLAY_SAMPLES, REPLAY_SAMPLE_INTERVAL_MS and REPLAY_EVENTS size it. - replay_redact.cpp: the package configuration is an allowlist of behaviour settings, as for crash reports; stored RFID tags become numbered placeholders. - The response is buffered in one heap block, so the package is sized to the largest free block and keeps the newest samples and events that fit, reporting how many it left out. - divert_sim/replay.py converts a package into a scenario (config, schedule, measured inputs, plug and EV-pause events, card taps, user limits and boosts, and the recorded claims of clients the simulator does not run), runs it, and reports where the simulation differs from the device. - A real capture from the native build against the emulator replays at 100% charging-state agreement (divert_sim/test_replay.py). - Native unit tests (test/test_replay_format) cover the ring, sample encoding, claim diffing and redaction; tests/integration/test_replay.py covers the endpoint. - api.yml, the feature map, troubleshooting.md and the divert_sim README document it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XEyVzUHFzxthd54TWTGA1r
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…into claude/relaxed-ramanujan-tij76b
Contributor
Contributor
Contributor
Integration Tests 1 files 1 suites 7m 5s ⏱️ Results for commit e5cad20. ♻️ This comment has been updated with latest results. |
Contributor
Flash usage
Builds at or above 95% of their app partition are flagged |
The ArduinoMongoose v7 migration (#1155) dropped the $ anchor from every route; under v7 "/debug/replay$" only matches that literal path, so the merge left the replay endpoint answering 404 and the integration tests failing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XEyVzUHFzxthd54TWTGA1r
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.
Two related additions:
Charge Manager in the simulator
Each simulated charge point now runs the firmware's
Scheduler,Limit,TempThrottleTaskandRfidTask(fed by a simulated card reader). These sit alongside divert, the shaper, manual override and boost, which it already ran. Scheduled rules, session limits, temperature protection and RFID gating therefore execute real firmware code.Firmware changes needed for this (small):
Schedulertakes its divert, shaper, RFID and limit collaborators by reference instead of using the globals (main.cpp:Scheduler scheduler(evse, divert, shaper, rfid, limit)). That lets each simulated peer own one.DIVERT_SIM. In the sim, the scheduler reads simulated time.rfid.cppdrops two unused includes.Simulator changes:
$GP, and the station current ($GCcmaxamps,$SC M).schedule;temperatureinput;rfid_reader,ev.report_socandlive_pwr_add_ev;rfid,temperature,soc,limit,schedule,claimandrelease.claim/releasecover sources the sim doesn't run, such as OCPP, MQTT and evcc.pilot_a,temperature_c,limit,rfid_auth,schedule_eventandsession_wh.Tests:
charge_manager.pyconfigures the station the way the Charge Manager screen does. Scheduled rules go through a port of the GUI'srulesToTimers. It also provides an oracle that checks each row against the winning claims.test_charge_manager.py(31 tests) covers each feature on its own: station defaults, every always-on feature, temperature protection, every scheduled rule action, rule current/limit, midnight wrap, day filters, manual override, and editing or deleting a live rule.test_charge_manager_combinations.pyruns all 417 combinations the Charge Manager allows through one scripted day. On every row it checks claim arbitration and each feature's contract. Breaking RFID gating or the divert timer priority in the firmware makes 244 of them fail.Gaps found, kept as strict
xfails:rulesToTimers(gui-nightshift) writes its stop as anotherdisabledtimer.SchedulerFeature::OCPPis a placeholder.Replay package
The recorder is passive: it polls public getters about once a second and drives nothing.
The rings take about 12 KB of heap, allocated at boot. Build flags size them:
ENABLE_REPLAY_RECORDER,REPLAY_SAMPLES,REPLAY_SAMPLE_INTERVAL_MSandREPLAY_EVENTS.Download:
GET /debug/replayreturns the package (add?download=1to save it as a file).replay_redact.cpp), the same approach as crash reports. Stored RFID tags become numbered placeholders.Replay:
divert_sim/replay.py package.jsonturns a package into a scenario. The scenario carries:The tool runs that scenario and reports where the simulated charger differs from the real one.
Docs:
api.yml, the feature map,troubleshooting.mdand the divert_sim README are updated.Testing
native_test: all doctest suites pass, including the newtest_replay_format(12 cases: ring, encoding, claim diff, redaction).native_simulator,native_openevseandopenevse_wifi_v1all build. Onopenevse_wifi_v1, flash is 91.0% and static RAM 25.6%.divert_sim/data/replay/native_eco_manual_override.jsonand replayed bytest_replay.py.tests/integration/test_replay.pypassed (6/6) against that native + emulator pair, using a local stand-in fixture. I could not run it through the docker harness here, so CI will be its first run there.Not in this PR
/debug/replay?download=1works as a direct link.🤖 Generated with Claude Code
https://claude.ai/code/session_01XEyVzUHFzxthd54TWTGA1r
Generated by Claude Code