Skip to content

Conversation

AndreasBoehm
Copy link
Member

@AndreasBoehm AndreasBoehm commented Oct 5, 2025

Fixes #2271

This pull request updates the logic for applying power reduction in both the smart buffer inverter and solar inverter classes. The main improvement is that reductions are now calculated using the lower of the current output or the current limit as the baseline, ensuring output never exceeds configured limits after reduction.

Power reduction logic improvements:

  • In both PowerLimiterSmartBufferInverter::applyReduction and PowerLimiterSolarInverter::applyReduction, the baseline for reduction is now set to the lower of the current output or the current limit, preventing output from exceeding the allowed limit after a reduction. [1] [2]
  • Introduced a local variable currentLimitWatts in both methods for clarity and to avoid repeated function calls. [1] [2]

@AndreasBoehm AndreasBoehm requested a review from Copilot October 5, 2025 15:52
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes a power reduction calculation issue in Dynamic Power Limiter (DPL) where the system needs to reduce power based on the current limit rather than the actual output when AC output exceeds the set limit.

  • Introduces baseline calculation logic to use the current limit when output exceeds it
  • Applies the same fix to both solar inverter and smart buffer inverter implementations
  • Ensures power reduction calculations work correctly when inverters are operating above their configured limits

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/PowerLimiterSolarInverter.cpp Adds baseline calculation using current limit when AC output exceeds limit
src/PowerLimiterSmartBufferInverter.cpp Applies same baseline calculation fix and refactors variable usage

Copy link

github-actions bot commented Oct 5, 2025

Build Artifacts

Firmware built from this pull request's code:

Notice

  • These artifacts are ZIP files containing the factory update binary as well as the OTA update binary.
    Extract the binaries from the ZIP files first. Do not use the ZIP files themselves to perform an update.
  • These links point to artifacts of the latest successful build run.
  • The linked artifacts were built from ad7118d.

@AndreasBoehm
Copy link
Member Author

@lmcmike Probier bitte mal wie die Test-Version aus dem Kommentar bei dir läuft. Wenn ich mich nicht Irre sollte dein Problem damit erledigt sein.

#2272 (comment)

@lmcmike
Copy link

lmcmike commented Oct 5, 2025

@AndreasBoehm Danke, habe die Test-Version gedownloaded und werde sie ausprobieren sobald sich hier bei mir mal wieder die Sonne zeigt. Ich berichte anschließend.

@lmcmike
Copy link

lmcmike commented Oct 8, 2025

@AndreasBoehm
Heute konnte ich die Test-FW endlich einmal wenn auch relativ kurz im Betrieb beobachten.
Leider ist das Problem mit dieser Version nicht behoben.
Screenshot_20251008-140752_Firefox

@AndreasBoehm
Copy link
Member Author

Ich brauche ein Log der Situation bitte.

@lmcmike
Copy link

lmcmike commented Oct 9, 2025

Wenn ich den entsprechenden Augenblick erwische mache ich natürlich ein Log.

@lmcmike
Copy link

lmcmike commented Oct 10, 2025

So anbei ein Log. Ich hoffe dass ich den richtigen Moment erwischt habe.

opendtu-log-2025-10-10_17-24-47.txt

@AndreasBoehm
Copy link
Member Author

Im Log sieht alles gut aus, ist aber auch eine reguläre Situation und nicht wie du sie Ursprünglich beschrieben hast.

Aktuelles Limit 121 W
Output 117 W
Power Meter 72 W
-> neues Limit 185 W

[17:24:44.798] D (422716716) dynamicPowerLimiter: [Controller] targeting 5 W, base load is 120 W, power meter reads 72.6 W (valid)
[17:24:44.798] D (422716716) dynamicPowerLimiter: [Controller] requesting 185 W from 1 smart-buffer-powered inverter currently producing 117 W (diff 68 W, hysteresis 10 W)
[17:24:45.175] V (422716718) dynamicPowerLimiter: [Inverter 116182803895]     lower/current/upper limit: 30/121/1000 W, output capability: 1200 W
...
[17:24:45.693] I (422716719) dynamicPowerLimiter: [Inverter 116182803895] sending limit of 15.4 % (185 W respectively), max output is 1200 W

@AndreasBoehm
Copy link
Member Author

Nur noch. mal zum Verständnis: Die Anpassung kann nicht verhindern das die Situation eintritt das dein WR mehr produziert als das geforderte Limit. Was die Anpassung macht ist diese Situation beim nächsten DPL Regellauf feststellen und das neue Limit auf eine andere Art zu berechnen um das Problem auszugleichen.

Protokollierst du Limit und Ausgangsleistung irgendwo? Home Assistant? Dann könntest du dort mal schauen ob das Problem nun weniger häufig auftritt bzw schnell wieder ausgeregelt wird.

@lmcmike
Copy link

lmcmike commented Oct 10, 2025

Hab ich doch nicht den richtigen Augeblick erwischt 👎
Am Wochenende bin ich wieder zu Hause dann kann ich die Regelung genauer beobachten und noch ein Log machen.
Jetzt zwischen Tür und Angel ist das gerade etwas schwierig.
Ich berichte !!

@AndreasBoehm
Copy link
Member Author

@coderabbitai review

Copy link

coderabbitai bot commented Oct 12, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

coderabbitai bot commented Oct 12, 2025

Walkthrough

Introduces baseline-aware reduction in applyReduction for SmartBuffer and Solar inverters. Baseline equals min(currentOutputAcWatts, currentLimitWatts). Reduction and output updates use baseline instead of raw output. Standby path now returns min(reduction, currentOutputAcWatts). No public interfaces changed.

Changes

Cohort / File(s) Summary
Smart-buffer inverter baseline reduction
src/PowerLimiterSmartBufferInverter.cpp
Added currentLimitWatts and baseline=min(currentOutputAcWatts, currentLimitWatts). Applied reduction against (baseline - LowerPowerLimit). Updated setAcOutput to baseline-reduction. Standby path returns min(reduction, currentOutputAcWatts). Swapped std::min args for lower bound.
Solar inverter baseline reduction
src/PowerLimiterSolarInverter.cpp
Introduced baseline=min(currentOutputAcWatts, currentLimitWatts). Reduction computed from (baseline - LowerPowerLimit). Control flow updated to use baseline with clarifying comments.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Controller
  participant INV as Inverter
  participant PL as applyReduction()

  C->>INV: Request limit update
  INV->>PL: applyReduction(currentOutputAcWatts, currentLimitWatts, LowerPowerLimit)
  note over PL: Compute baseline = min(currentOutputAcWatts, currentLimitWatts)

  alt Standby allowed and triggered
    PL-->>INV: return min(reduction, currentOutputAcWatts)
    note right of INV: Skip further adjustments
  else Reduction path
    PL->>PL: reduction <= (baseline - LowerPowerLimit)
    PL->>INV: setAcOutput(baseline - reduction)
    INV-->>C: Limit applied using baseline
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A watt-wise rabbit, ears attuned to breeze,
Nibbles baselines down beneath the trees.
“Limit first, then trim,” the bunny sings—
No more runaway inverter wings.
With gentle paws, it reins the sun,
So targets met, the grid stays won. 🌞🐇⚡️

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues Check ✅ Passed The code changes implement the core objective from issue #2271 by computing the reduction baseline as the minimum of the inverter’s current output and the configured limit so that output above the limit can be properly reduced, and the introduced currentLimitWatts variable improves clarity without altering public interfaces.
Out of Scope Changes Check ✅ Passed All modifications are confined to the applyReduction methods of the smart‐buffer and solar inverter classes and directly implement the linked issue’s requirements, with no unrelated features or signature changes introduced.
Description Check ✅ Passed The pull request description directly summarizes the specific changes made to the power reduction logic, namely the introduction of a baseline based on the lower of current output or current limit and the addition of currentLimitWatts for clarity, which aligns with the diff summaries for both inverter classes.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch andreasboehm/fix/dpl-decrease-ac-higher

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/PowerLimiterSmartBufferInverter.cpp (1)

74-82: Baseline logic mirrors SolarInverter implementation.

The baseline selection and reduction application correctly handle the case when output exceeds the limit, consistent with the fix in PowerLimiterSolarInverter.cpp.

Optional: Consider extracting baseline logic into a shared helper.

The baseline calculation (lines 76-79 here and lines 115-119 in PowerLimiterSolarInverter.cpp) is duplicated across both files. If these classes share a common base or if this pattern is used elsewhere, extracting it into a helper method could reduce duplication:

uint16_t getBaselineForReduction(uint16_t currentOutputAcWatts, uint16_t currentLimitWatts) {
    // when the output is higher than the limit, we must use the limit as the baseline
    return (currentOutputAcWatts > currentLimitWatts) ? currentLimitWatts : currentOutputAcWatts;
}

This is a minor refinement and can be deferred if you prefer to keep the logic explicit in each class.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af39f5a and 9157257.

📒 Files selected for processing (2)
  • src/PowerLimiterSmartBufferInverter.cpp (2 hunks)
  • src/PowerLimiterSolarInverter.cpp (1 hunks)
🔇 Additional comments (3)
src/PowerLimiterSolarInverter.cpp (2)

112-119: LGTM! Baseline logic correctly addresses the issue.

The baseline selection properly handles the case when currentOutputAcWatts > currentLimitWatts by using the limit as the baseline. This ensures that when the inverter is producing more than the configured limit, the reduction is calculated from the limit rather than the actual output, preventing the DPL from inadvertently requesting a higher limit.

The local variable currentLimitWatts also eliminates redundant getCurrentLimitWatts() calls, improving both clarity and efficiency.


120-122: Reduction calculation correctly uses baseline.

The updated condition (baseline - _config.LowerPowerLimit) >= reduction and subsequent setAcOutput(baseline - reduction) properly apply the reduction against the baseline, ensuring consistent behavior whether the output is above or below the limit.

src/PowerLimiterSmartBufferInverter.cpp (1)

63-65: Guard condition correctly uses both limit and output.

The updated low calculation using std::min(currentLimitWatts, currentOutputAcWatts) properly checks whether either the limit or the output is at or below the lower power limit, ensuring the inverter cannot be reduced below that threshold.

The local currentLimitWatts variable also avoids repeated function calls.

Comment on lines +74 to 83
uint16_t baseline = currentOutputAcWatts;

// when the output is higher than the limit, we must use the limit as the baseline
if (currentOutputAcWatts > currentLimitWatts) {
baseline = currentLimitWatts;
}

if ((baseline - _config.LowerPowerLimit) >= reduction) {
setAcOutput(baseline - reduction);
return reduction;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Incorrect return value when output exceeds limit.

Same issue as in PowerLimiterSolarInverter::applyReduction: when currentOutputAcWatts > currentLimitWatts, line 83 returns reduction instead of the actual reduction in output.

The actual reduction in output is:

currentOutputAcWatts - (baseline - reduction)

This inconsistency with lines 88 and 92 (which correctly return actual reduction from currentOutputAcWatts) causes the DPL to receive incorrect reduction values and make suboptimal power distribution decisions.

Apply this diff to fix the return value:

     if ((baseline - _config.LowerPowerLimit) >= reduction) {
         setAcOutput(baseline - reduction);
-        return reduction;
+        return currentOutputAcWatts - (baseline - reduction);
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
uint16_t baseline = currentOutputAcWatts;
// when the output is higher than the limit, we must use the limit as the baseline
if (currentOutputAcWatts > currentLimitWatts) {
baseline = currentLimitWatts;
}
if ((baseline - _config.LowerPowerLimit) >= reduction) {
setAcOutput(baseline - reduction);
return reduction;
uint16_t baseline = currentOutputAcWatts;
// when the output is higher than the limit, we must use the limit as the baseline
if (currentOutputAcWatts > currentLimitWatts) {
baseline = currentLimitWatts;
}
if ((baseline - _config.LowerPowerLimit) >= reduction) {
setAcOutput(baseline - reduction);
return currentOutputAcWatts - (baseline - reduction);
}
🤖 Prompt for AI Agents
In src/PowerLimiterSmartBufferInverter.cpp around lines 74 to 83, the function
currently returns 'reduction' when currentOutputAcWatts > currentLimitWatts,
which is incorrect; update the return value to compute and return the actual
reduction applied relative to currentOutputAcWatts (i.e., currentOutputAcWatts -
(baseline - reduction)) after calling setAcOutput(baseline - reduction). Ensure
the baseline logic remains (baseline = currentLimitWatts when output exceeds
limit) and mirror the correct return behavior used on lines 88 and 92 so the
function reports the true delta applied to the output.

Comment on lines +112 to 122
uint16_t currentLimitWatts = getCurrentLimitWatts();
uint16_t baseline = currentOutputAcWatts;

if ((currentOutputAcWatts - _config.LowerPowerLimit) >= reduction) {
setAcOutput(currentOutputAcWatts - reduction);
// when the output is higher than the limit, we must use the limit as the baseline
if (currentOutputAcWatts > currentLimitWatts) {
baseline = currentLimitWatts;
}

if ((baseline - _config.LowerPowerLimit) >= reduction) {
setAcOutput(baseline - reduction);
return reduction;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Incorrect return value when output exceeds limit.

When currentOutputAcWatts > currentLimitWatts, the baseline is set to currentLimitWatts and reduction is applied to it. However, line 122 returns reduction instead of the actual reduction in output.

The actual reduction in output is:

currentOutputAcWatts - (baseline - reduction)

When baseline < currentOutputAcWatts, returning just reduction underreports the actual reduction to the caller (DPL), leading to incorrect power distribution decisions across inverters.

Compare with line 126 and the standby() method (line 134), which correctly return the actual reduction from currentOutputAcWatts.

Apply this diff to fix the return value:

     if ((baseline - _config.LowerPowerLimit) >= reduction) {
         setAcOutput(baseline - reduction);
-        return reduction;
+        return currentOutputAcWatts - (baseline - reduction);
     }
🤖 Prompt for AI Agents
In src/PowerLimiterSolarInverter.cpp around lines 112 to 122, the function
returns just `reduction` after calling setAcOutput(baseline - reduction), which
underreports the actual output reduction when baseline was clipped to
currentLimitWatts; change the return value to the actual reduction applied to
the inverter: compute and return currentOutputAcWatts - (baseline - reduction)
(keeping the setAcOutput call as-is) so callers receive the true delta in
output.

@lmcmike
Copy link

lmcmike commented Oct 12, 2025

Was bedeuten die Ausgaben von coderabbitai für meine Problemdarstellung?
Muss von eurer Seite dadurch etwas am Programmcode der Test-Version geändert werden?

@lmcmike
Copy link

lmcmike commented Oct 12, 2025

Hier noch einmal anbei ein Log, ich glaube jetzt im richtigen Moment gemacht.

opendtu-log-2025-10-12_17-17-19.txt

@AndreasBoehm
Copy link
Member Author

Was @coderabbitai da ausgespuckt hat hab ich mir noch nicht angeschaut.

Dein Log ist leider sehr kurz, mehrere Zyklen wären gut um zu sehen wie alles reagiert.
Das was enthalte ist sieht aber super aus, das neue Limit wird basierend auf dem aktuellen Limit, nicht auf dem aktuellen Output, berechnet.
✅ Problem gelöst, zumindest soweit man das mit dem sehr kurzen Log beurteilen kann.

Aktuelles Limit 182 W
Output 252 W
Power Meter -68 W
Diff - 71 W
-> neues Limit 108 W

[17:17:16.797] D (595069774) dynamicPowerLimiter: [Controller] targeting 5 W, base load is 120 W, power meter reads -68.7 W (valid)
[17:17:16.798] D (595069775) dynamicPowerLimiter: [Controller] requesting 178 W from 1 smart-buffer-powered inverter currently producing 252 W (diff -74 W, hysteresis 10 W)
[17:17:16.798] D (595069775) dynamicPowerLimiter: [Controller] will cover 108 W using 1 smart-buffer-powered inverter
...
[17:17:17.002] I (595069778) dynamicPowerLimiter: [Inverter 116182803895] sending limit of 9.0 % (108 W respectively), max output is 1200 W

Copy link

coderabbitai bot commented Oct 12, 2025

Tip

For best results, initiate chat on the files or code changes.

@AndreasBoehm: Vielen Dank für die Rückmeldung! Die Testergebnisse sehen vielversprechend aus. Wenn du meine Review anschauen möchtest und Fragen oder Anmerkungen hast, stehe ich gerne zur Verfügung. Die von mir identifizierten Punkte beziehen sich hauptsächlich auf Code-Qualität und Dokumentation, aber die Kernlogik der Änderung erscheint solide.

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.

[Bug] DPL berechnet falsches Limit wenn der WR mehr liefert als das gesetzte Limit

2 participants