Skip to content

feat(ocpp-cp): honor v201 TriggerMessage(LogStatusNotification) by re-reporting the latest log-upload status (M7) - #587

Open
duyhuynh-vn wants to merge 2 commits into
mainfrom
claude/inspiring-ramanujan-23nqpy
Open

duyhuynh-vn wants to merge 2 commits into
mainfrom
claude/inspiring-ramanujan-23nqpy

Conversation

@duyhuynh-vn

Copy link
Copy Markdown
Collaborator

Summary

Honors TriggerMessage(requestedMessage = LogStatusNotification) on the OCPP 2.0.1 CP simulator by re-reporting the station's latest log-upload status as one schema-valid LogStatusNotification — advancing M7 (OCPP 2.0.1). The direct log-upload twin of #583 (FirmwareStatusNotification).

Closes #584

Real use case

A support engineer is diagnosing a charge point that uploaded its diagnostics log hours ago via GetLog. The station reported progress asynchronously at the time, but the CSMS operator wasn't watching and the notifications have scrolled off. Rather than kicking off a fresh (slow, bandwidth-heavy) upload, the operator sends TriggerMessage(LogStatusNotification) and the station immediately re-reports where that last upload landed — Uploaded (with the correlating requestId), or a terminal UploadFailure if it never made it — so the operator knows whether the log is already sitting at the remote location before acting. Before this change the 2.0.1 simulator answered that trigger with NotImplemented, so a CSMS conformance suite exercising the log-status re-report had no station-side counterpart.

What changed

  • crates/ocpp-cp/src/v201_log_upload.rs — new V201LogStatusReport { status, request_id } (default { Idle, None }) retained in V201LogUploadStore alongside the in-flight requestId. record_reported captures every emitted status; last_reported returns the snapshot. Deliberately not cleared when the in-flight slot is, so a settled Uploaded / terminal failure stays reportable.
  • crates/ocpp-cp/src/v201_command.rs — LogStatusNotification reclassified NotImplemented → Accepted in v201_trigger_message_status; new v201_log_status_report(status, Option<i32>) re-report builder (the async v201_log_status_notification now delegates to it) that omits requestId for an Idle snapshot (schema has no null for it).
  • crates/ocpp-cp/src/lib.rs — send_v201_log_status records the status before sending (so the CP's notion of upload progress advances even if a progress CALL fails to transmit); new trigger_v201_log_status_notification re-reports the snapshot as a pure, side-effect-free CALL on the command-consumer task (off the inbound-CALL path — no receive-loop re-entrancy), wired into send_v201_triggered_message.

Trust boundary / failure modes: the trigger is CSMS-originated over the WebSocket; the re-report starts no upload and leaves the in-flight store untouched. requestId is stored opaquely (never parsed/indexed), so no wire value can panic. A send failure is logged, not propagated.

What was ported

Ports ocpp.v201.call.LogStatusNotification (whose request_id: Optional[int] we mirror), gated by MessageTriggerEnumType.log_status_notification and reporting UploadLogStatusEnumType (ocpp/v201/enums.py). Follows the pattern established by #583 (#586). The 2.0.1 analog of the 1.6J TriggerMessage(DiagnosticsStatusNotification) re-report.

Test plan

cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo test --workspace — all green (ocpp-cp lib: 1002 passed; integration: 51 passed). Added:

  • Store: new store reports { Idle, None }; record_reported tracks latest (status, requestId); the terminal survives the in-flight clear; extreme requestIds don't panic.
  • Builder: Idle re-report omits requestId on the wire (absent, not null); a Some re-report carries it; both, plus every lifecycle status, are schema-valid against the bundled 2.0.1 FINAL LogStatusNotification schema.
  • Policy: v201_trigger_message_status(LogStatusNotification) == Accepted; producible/unsupported counts updated (7 Accepted / 4 NotImplemented); totality test still passes.
  • Handler (mock CSMS): trigger with no prior upload → Accepted then LogStatusNotification(Idle), no requestId; with a recorded status → re-reports it + requestId and leaves the in-flight slot untouched.
  • Wired: a real run_v201_log_upload leaves Uploaded (happy path) / UploadFailure (fault-injected) as the re-reportable status.
  • Updated the central_system_boot integration test to use PublishFirmwareStatusNotification as its NotImplemented example (LogStatusNotification is now Accepted).

Acceptance criteria

  • TriggerMessage(LogStatusNotification) is Accepted and originates one schema-valid LogStatusNotification with the latest status.
  • Latest status (+ requestId) tracked across the upload lifecycle; never-ran reports Idle, requestId omitted.
  • Pure snapshot — no upload started, in-flight store unchanged; no regression to the async GetLog → LogStatusNotification flow or 1.6J.
  • cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo test --workspace all green.

Known gaps / notes


🤖 Generated with Claude Code

https://claude.ai/code/session_0176cR1foeU8uwtbWZQDdsPZ


Generated by Claude Code

…-reporting the latest log-upload status (M7)

A CSMS asking `TriggerMessage(requestedMessage = LogStatusNotification)` on
the OCPP 2.0.1 CP simulator now gets the station's current log-upload status
re-reported as one schema-valid `LogStatusNotification` — the direct
log-upload twin of #583 (FirmwareStatusNotification) and the 2.0.1 analog of
the 1.6J TriggerMessage(DiagnosticsStatusNotification) re-report. Previously
the trigger was classified NotImplemented despite the simulator modeling
GetLog uploads.

- V201LogUploadStore: retain the latest V201LogStatusReport { status,
  request_id } (default { Idle, None }) alongside the in-flight requestId,
  recorded at the single send_v201_log_status choke point and deliberately not
  cleared with the in-flight slot, so a settled Uploaded / terminal failure
  stays reportable.
- v201_command: reclassify LogStatusNotification NotImplemented -> Accepted;
  add v201_log_status_report(status, Option<i32>) re-report builder (the async
  v201_log_status_notification now delegates to it) that omits requestId for an
  Idle snapshot.
- lib: send_v201_log_status records the status before sending; new
  trigger_v201_log_status_notification re-reports the snapshot as a pure,
  side-effect-free CALL on the command-consumer task, wired into
  send_v201_triggered_message.

Ports ocpp.v201.call.LogStatusNotification (request_id: Optional[int]).
Pure snapshot: starts no upload, leaves the in-flight store untouched, off the
inbound-CALL path. 1.6J unaffected.

Closes #584.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0176cR1foeU8uwtbWZQDdsPZ
…atus_notification

The bare [`trigger_v201_firmware_status_notification`] link in the new
trigger_v201_log_status_notification doc comment did not resolve (a method
needs a qualified path), failing the `--deny warnings` Documentation CI job.
Qualify it with `Self::` so rustdoc resolves it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0176cR1foeU8uwtbWZQDdsPZ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants