Skip to content

Add an option to send Session Current Limit as a TxDefaultProfile (#2158) - #2183

Merged
drc38 merged 1 commit into
lbbrhzn:mainfrom
KingHavok:fix/2158-txdefault-session-limit
Oct 5, 2026
Merged

drc38 merged 1 commit into
lbbrhzn:mainfrom
KingHavok:fix/2158-txdefault-session-limit

Conversation

@KingHavok

@KingHavok KingHavok commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #2158.

Some chargers refuse both the station ChargePointMaxProfile and a transaction-bound TxProfile, but accept a TxDefaultProfile on the connector and apply it to the running transaction (Timxon A0, ABB Terra AC, Morek MEV11 in #2158). Before #2131 the station slider reached them through its TxDefaultProfile fallback; since 0.12.0 nothing does.

What it does

A new per-charger option, Send Session Current Limit as a default profile (session_limit_default_profile, off by default), changes only how Session Current Limit works:

  • The slider sends one Relative TxDefaultProfile with no transaction id: on the connector on 1.6, on the connector's EVSE on 2.0.1. Profile id 2000+n, one stack level below the reported maximum (at least 1, and 0 when the charger reports 0). On 1.6 that is the profile the ocpp.set_charge_rate action already writes for its TxDefaultProfile leg, and the shape 0.11.4 sent, which the capture in Timxon A0 (OCPP 1.6J): Maximum Current broken since 0.12.0 — ChargePointMaxProfile NotSupported, absolute schedule gets no response #2158 shows these chargers apply.
  • The slider is available whenever the charger is connected with SmartCharging, with or without a transaction. On 2.0.1 it also waits until the charger has reported which EVSE the connector is on, so a profile that outlives the request is never sent to a guessed EVSE.
  • Its value is the last limit the charger accepted. It is kept across transactions and restored after a restart, since the charger keeps the profile. Only accepted values are saved, and only ones this mode set.

Maximum Current and the default per-transaction behaviour are unchanged. A cancelled slider request now reverts the display in both modes rather than leaving the in-flight value on show.

Configuration and rollback

  • No migration. The option is stored in the charger record only while it is on, so a charger that never enables it stays loadable by older releases.
  • Charger and central settings are now built from the keys their dataclass knows, so releases from this one on can add settings without breaking a rollback to it.
  • A charger with the option on still fails to load on 0.12.x and earlier, which do not know the key. The docs say to turn the option off before installing an older release.

Limits (documented)

  • The profile stays on the charger after the option is turned off; raise the slider to the maximum first. On 1.6 ocpp.clear_profile also removes it; on 2.0.1 that action clears only ChargingStationMaxProfile.
  • On a 2.0.1 charger with two connectors on one EVSE, both sliders target that EVSE with different ids at the same stack level, which K01.FR.06 forbids, so the second connector's limit is likely to be rejected.

Testing

Summary by CodeRabbit

  • New Features
    • Added an optional setting to send the Session Current Limit as a default profile, so it can be adjusted without an active charging session.
    • The setting is available for OCPP 1.6 and 2.0.1 chargers and preserves the last confirmed value across restarts.
  • Bug Fixes
    • Failed or cancelled limit changes no longer replace the last confirmed value.
  • Documentation
    • Added guidance on enabling the option, profile behavior, and compatibility considerations.

…brhzn#2158)

Some chargers (Timxon A0, ABB Terra AC, Morek MEV11 on OCPP 1.6) refuse
both the station ChargePointMaxProfile and a transaction-bound TxProfile,
but accept a TxDefaultProfile on the connector and apply it to the
running transaction. Before lbbrhzn#2131 the station slider reached them through
its TxDefaultProfile fallback; since 0.12.0 nothing does.

A per-charger option, session_limit_default_profile (off by default),
makes Session Current Limit send a Relative TxDefaultProfile instead: on
the connector on 1.6, on the connector's EVSE on 2.0.1. It uses profile
id 2000+n and one stack level below the reported maximum (at least 1, and
0 for a maximum of 0), which on 1.6 is the profile the set_charge_rate
action writes for its TxDefaultProfile leg.

With the option on, the slider needs no transaction. It is available
whenever the charger is up with SmartCharging and, on 2.0.1, has reported
which EVSE the connector is on; nothing is sent to a guessed EVSE. Its
value is the last limit the charger accepted, kept across transactions
and restored after a restart, saving only accepted values and only those
this mode set. A cancelled request reverts the display, in both modes.

The option is stored only while it is on and needs no migration, so a
charger that never enables it stays loadable by older releases. Settings
are now built from the keys their dataclass knows, so later releases can
add settings without breaking a rollback to this one.

The station slider and the transaction-bound mode are unchanged.
@KingHavok
KingHavok deployed to continuous-integration October 4, 2026 06:57 — with GitHub Actions Active
@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 98b28875-8e9a-4c66-b864-6f65987a5f79
📥 Commits

Reviewing files that changed from the base of the PR and between a33616a and 94f96a0.

📒 Files selected for processing (16)
  • custom_components/ocpp/api.py
  • custom_components/ocpp/chargepoint.py
  • custom_components/ocpp/config_flow.py
  • custom_components/ocpp/const.py
  • custom_components/ocpp/number.py
  • custom_components/ocpp/ocppv16.py
  • custom_components/ocpp/ocppv201.py
  • custom_components/ocpp/translations/en.json
  • custom_components/ocpp/translations/i-default.json
  • docs/Charge_automation.md
  • tests/test_api_paths.py
  • tests/test_config_flow.py
  • tests/test_flat_maximum_current.py
  • tests/test_options_flow.py
  • tests/test_set_charge_rate_v16.py
  • tests/test_v201_set_charge_rate_return.py

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.


📝 Walkthrough

Walkthrough

Adds an optional default-profile mode for session current limits. The mode sends connector-scoped TxDefaultProfile requests without an active transaction on OCPP 1.6 and 2.0.1. The number entity stores accepted values and restores them only when the saved profile purpose matches.

Changes

Session default current limit

Layer / File(s) Summary
Configure and load the setting
custom_components/ocpp/const.py, custom_components/ocpp/config_flow.py, custom_components/ocpp/api.py, custom_components/ocpp/translations/*, tests/test_config_flow.py, tests/test_options_flow.py, tests/test_api_paths.py
Adds the setting to setup and options forms. False or omitted values are removed from stored settings. Settings loading ignores keys not declared by the settings dataclass.
Build and dispatch default profiles
custom_components/ocpp/chargepoint.py, custom_components/ocpp/api.py, custom_components/ocpp/ocppv16.py, custom_components/ocpp/ocppv201.py, tests/test_api_paths.py, tests/test_set_charge_rate_v16.py, tests/test_v201_set_charge_rate_return.py
Adds API availability and setter methods, shared handling for profile requests, and protocol-specific request builders. The v2.0.1 path checks that the connector-to-EVSE mapping is known.
Select and persist the number entity
custom_components/ocpp/number.py, tests/test_flat_maximum_current.py, docs/Charge_automation.md
Selects the default-profile number entity when enabled. The entity sends limits without an active transaction and restores only saved TxDefaultProfile values. Documentation describes profile behavior and cleanup.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant SessionDefaultLimitNumber
  participant CentralSystem
  participant ChargePoint
  participant OCPPCharger
  SessionDefaultLimitNumber->>CentralSystem: Set connector session limit
  CentralSystem->>ChargePoint: Dispatch default limit
  ChargePoint->>OCPPCharger: Send SetChargingProfile with TxDefaultProfile
  OCPPCharger-->>ChargePoint: Return response status
  ChargePoint-->>SessionDefaultLimitNumber: Return result or error
Loading

Suggested reviewers: alexisml

Merge Risk: 🔵 Low · up to 94f96

This adds an optional session-limit mode that is off by default, so existing behavior is unchanged. It has not been tested on real chargers, so users who enable it should confirm their charger accepts the profile.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 94f96

The change is opt-in and remains scoped to the selected charger. However, a request with an uncertain outcome can leave a persistent charger limit different from the value displayed and restored. Disabling the option does not remove that limit, and connectors sharing an EVSE cannot be controlled independently through this mode.

Retained concerns

  • Medium · reliability · inferred: If a charger applies a default-profile write but its acknowledgement is lost or the caller is cancelled, the entity returns to its previous confirmed value without reconciling remote state. That previous value can then be saved and restored while the different charger profile remains active across transactions. Timeout drift predates this PR, but its new persistence weakens failure containment for current-limit control.
Security review details

Security Blast Radius

  • observed — The inspected setter resolves the selected charger to an active ChargePoint instance and sends through that instance. The remote write addresses a connector on OCPP 1.6 or an EVSE on OCPP 2.0.1, where multiple connectors may share the affected scope.

Trust Boundaries and Controls

  • observed — Availability checks require an online charger, SmartCharging support and a known target. The setter independently checks charger lookup and target knowledge, but does not repeat online or SmartCharging checks. This lookup-and-delegate pattern also exists in the transaction-bound setter; it does not by itself establish a newly exposed authorization bypass.

Resilience and Maintainability Implications

  • inferred — Serialization and acknowledged-only storage protect ordinary updates, but neither proves remote rollback after an uncertain outcome. Unlike the previous transaction-bound profile, the new profile has no transaction-end cleanup boundary, so control-state disagreement can affect later sessions.

Hardening Proposals

  • proposed — Represent post-transmission timeout or cancellation as an uncertain remote outcome rather than a confirmed rollback. Where charger capabilities permit, reconcile that outcome or perform an explicit acknowledged replacement before treating the restored value as the active limit. Keep this recovery distinct from broad profile clearing, which can remove unrelated controls.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Issue #2158 asks for an optional TxDefaultProfile fallback for the station-wide Maximum Current slider. This PR selects a new TxDefaultProfile mode only for the Session Current Limit entity. The Maxim… Add an opt-in TxDefaultProfile fallback to the station-wide Maximum Current slider for the affected OCPP 1.6 chargers, while preserving its existing behavior when the option is off.
Docstring Coverage ⚠️ Warning Docstring coverage is 72.37% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 76 functions across 13 files. (3 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The configuration, compatibility handling, translations, documentation, and tests support the new session-limit profile mode and its rollback constraints. The cancellation display fix also protects th…
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding an option to send the Session Current Limit as a TxDefaultProfile.
Full details: Linked Issues check

Explanation

Issue #2158 asks for an optional TxDefaultProfile fallback for the station-wide Maximum Current slider. This PR selects a new TxDefaultProfile mode only for the Session Current Limit entity. The Maximum Current path remains unchanged: tests/test_flat_maximum_current.py verifies it sends only ChargePointMaxProfile and does not fall back after refusal. Thus the requested station-slider behavior remains unmet.

Full details: Docstring Coverage

Explanation

Docstring coverage is 72.37% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 76 functions across 13 files. (3 skipped: 3 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Oct 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.35%. Comparing base (a33616a) to head (94f96a0).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2183      +/-   ##
==========================================
+ Coverage   97.30%   97.35%   +0.05%     
==========================================
  Files          12       12              
  Lines        4265     4354      +89     
==========================================
+ Hits         4150     4239      +89     
  Misses        115      115              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@alcrow68

alcrow68 commented Oct 5, 2026

Copy link
Copy Markdown

Tested on Timxon EAW-A007S (A0 platform), firmware A0-V2.2.4, OCPP 1.6J,
single phase 32 A, one connector.

Session Current Limit with the option on: works. The slider is accepted
with no error. Confirmed end to end — Current Offered follows the slider,
and the house meter shows the actual draw changing accordingly (4 kW,
then 7.6 kW).

Across a restart: set to 16 A, restarted Home Assistant with the car
charging. The slider came back at 16 A and the charger was still offering
16 A. The transaction survived the reconnection.

Only tested with a car connected so far — I'll check the no-transaction
case later today and report back.

Maximum Current: unchanged, still ChargePointMaxProfile: NotSupported,
as expected since this PR does not touch it.

One note for other testers: before this test I reset the charger's own
settings through the vendor app — cleared the hourly schedule and the
off-peak charging option — then pointed it back at Home Assistant.
Vendor-installed TxDefaultProfiles persist on this hardware and would
otherwise compete with the integration's.

@drc38
drc38 merged commit e6a95c5 into lbbrhzn:main Oct 5, 2026
9 checks passed
@alcrow68

alcrow68 commented Oct 5, 2026

Copy link
Copy Markdown

Follow-up: tested with no car connected — Session Current Limit accepted
at 17 A then 32 A, no error. Connector Available, Charge Control off.
All three cases from the test plan now covered on this charger.

This branch was successfully deployed

1 active deployment
continuous-integration — 94f96a0c Deployed Oct 4, 2026 by KingHavok via Run tests #3726
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.

Timxon A0 (OCPP 1.6J): Maximum Current broken since 0.12.0 — ChargePointMaxProfile NotSupported, absolute schedule gets no response

3 participants