MCPcopy Create free account
hub / github.com/evcc-io/evcc / pvMaxCurrent

Method pvMaxCurrent

core/loadpoint.go:1531–1653  ·  view source on GitHub ↗

pvMaxCurrent calculates the maximum target current for PV mode

(mode api.ChargeMode, sitePower, batteryBoostPower float64, batteryBuffered, batteryStart bool)

Source from the content-addressed store, hash-verified

1529
1530// pvMaxCurrent calculates the maximum target current for PV mode
1531func (lp *Loadpoint) pvMaxCurrent(mode api.ChargeMode, sitePower, batteryBoostPower float64, batteryBuffered, batteryStart bool) float64 {
1532 // read only once to simplify testing
1533 minCurrent := lp.effectiveMinCurrent()
1534 maxCurrent := lp.effectiveMaxCurrent()
1535
1536 // push demand to drain battery
1537 sitePower -= lp.boostPower(batteryBoostPower)
1538
1539 // switch phases up/down
1540 var scaledTo int
1541 if lp.hasPhaseSwitching() && lp.phaseSwitchCompleted() {
1542 scaledTo = lp.pvScalePhases(sitePower, minCurrent, maxCurrent)
1543 }
1544
1545 // calculate target charge current from delta power and actual current
1546 activePhases := lp.ActivePhases()
1547 effectiveCurrent := lp.effectiveCurrent()
1548 if scaledTo == 3 {
1549 // if we did scale, adjust the effective current to the new phase count
1550 effectiveCurrent /= float64(lp.maxActivePhases())
1551 }
1552 if lp.chargerHasFeature(api.IntegratedDevice) {
1553 // for slow-acting heating devices, only take actually consumed power into account
1554 effectiveCurrent = powerToCurrent(lp.chargePower, activePhases)
1555 }
1556 deltaCurrent := powerToCurrent(-sitePower, activePhases)
1557 targetCurrent := max(effectiveCurrent+deltaCurrent, 0)
1558
1559 // in MinPV mode or under special conditions return at least minCurrent
1560 if battery := batteryStart || batteryBuffered && lp.charging(); (mode == api.ModeMinPV || battery) && targetCurrent < minCurrent {
1561 lp.log.DEBUG.Printf("pv charge current: min %.3gA > %.3gA (%.0fW @ %dp, battery: %t)", minCurrent, targetCurrent, sitePower, activePhases, battery)
1562 return minCurrent
1563 }
1564
1565 lp.log.DEBUG.Printf("pv charge current: %.3gA = %.3gA + %.3gA (%.0fW @ %dp)", targetCurrent, effectiveCurrent, deltaCurrent, sitePower, activePhases)
1566
1567 if mode == api.ModePV && lp.enabled && targetCurrent < minCurrent {
1568 projectedSitePower := sitePower
1569 if lp.hasPhaseSwitching() && !lp.phaseTimer.IsZero() {
1570 // calculate site power after a phase switch from activePhases phases -> 1 phase
1571 // notes: activePhases can be 1, 2 or 3 and phaseTimer can only be active if lp current is already at minCurrent
1572 projectedSitePower -= Voltage * minCurrent * float64(activePhases-1)
1573 }
1574 // kick off disable sequence, unless climater keep-alive is holding
1575 // charging at minCurrent — otherwise the "pausing soon" badge would
1576 // flash on/off forever while climater is active (issue #29834).
1577 if projectedSitePower >= lp.Disable.Threshold && !lp.vehicleClimateActive() {
1578 lp.log.DEBUG.Printf("projected site power %.0fW >= %.0fW disable threshold", projectedSitePower, lp.Disable.Threshold)
1579
1580 if lp.pvTimer.IsZero() {
1581 lp.log.DEBUG.Printf("pv disable timer start: %v", lp.GetDisableDelay())
1582 lp.pvTimer = lp.clock.Now()
1583 }
1584
1585 lp.publishTimer(pvTimer, lp.GetDisableDelay(), pvDisable)
1586
1587 elapsed := lp.clock.Since(lp.pvTimer)
1588 if elapsed >= lp.GetDisableDelay() {

Callers 4

UpdateMethod · 0.95
TestPVHysteresisFunction · 0.95

Calls 15

effectiveMinCurrentMethod · 0.95
effectiveMaxCurrentMethod · 0.95
boostPowerMethod · 0.95
hasPhaseSwitchingMethod · 0.95
phaseSwitchCompletedMethod · 0.95
pvScalePhasesMethod · 0.95
ActivePhasesMethod · 0.95
effectiveCurrentMethod · 0.95
maxActivePhasesMethod · 0.95
chargerHasFeatureMethod · 0.95
chargingMethod · 0.95
vehicleClimateActiveMethod · 0.95

Tested by 3

TestPVHysteresisFunction · 0.76