From 5df69d79f86b4f49f77894a8ac425794eb3e8a9f Mon Sep 17 00:00:00 2001 From: pakutz79 Date: Sun, 5 Apr 2026 07:09:38 +0200 Subject: [PATCH] fix: detect actual EV phase instead of hardcoding phase A - evcharger.cpp: phases() now calls meteredPhases() instead of returning PhaseNone - smartchargingmanager: add chargerPhaseKey() with 3-level fallback 1. meteredPhases() when charger is active 2. effectivePhases from last known state 3. fallback 'A' + warning (previous behavior) - Remove 4 FIXME comments on lines 394, 477, 517 --- energyplugin/evcharger.cpp | 12 +++++----- energyplugin/smartchargingmanager.cpp | 34 +++++++++++++++++++++------ energyplugin/smartchargingmanager.h | 1 + 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/energyplugin/evcharger.cpp b/energyplugin/evcharger.cpp index 5329e18..f5c0649 100644 --- a/energyplugin/evcharger.cpp +++ b/energyplugin/evcharger.cpp @@ -168,13 +168,13 @@ Electricity::Phases EvCharger::phases() const } } - // TODO: Can we figure out from the root meter on which phase we're attached? - // One idea would be to sign up on root meter changes. When chargingEnabled is set or unset, - // memorize root meter values and compare the next (or some more) cycles if a phase changed - // by a similar value as we'd expect - - // Until we have this detection, we must ask the user how many phases will be used while charging + // For single-phase chargers, detect the actual connected phase from per-phase metering + Electricity::Phases metered = meteredPhases(); + if (metered != Electricity::PhaseNone) { + return metered; + } + // Phase unknown — charger has no per-phase metering or is not currently charging return Electricity::PhaseNone; } diff --git a/energyplugin/smartchargingmanager.cpp b/energyplugin/smartchargingmanager.cpp index 20fccc4..14dbdb7 100644 --- a/energyplugin/smartchargingmanager.cpp +++ b/energyplugin/smartchargingmanager.cpp @@ -391,9 +391,9 @@ void SmartChargingManager::verifyOverloadProtection(const QDateTime ¤tDate if (evCharger->phaseCount() == 1) { - // FIXME: get the actual phase, not assume it is phase A in single phase charging - if (requiredThrottlePower.value("A") > 0) { - int throttleAmpere = qCeil(requiredThrottlePower.value("A") / 230); + const QString phase = chargerPhaseKey(evCharger); + if (requiredThrottlePower.value(phase) > 0) { + int throttleAmpere = qCeil(requiredThrottlePower.value(phase) / 230); int desiredFallbackAmpere = evCharger->maxChargingCurrent() - throttleAmpere; if (desiredFallbackAmpere < static_cast(m_processInfos[evCharger].minimalChargingCurrent)) { @@ -474,8 +474,7 @@ void SmartChargingManager::verifyOverloadProtectionRecovery(const QDateTime &cur bool restoreCharger = false; if (evCharger->phaseCount() == 1) { - // FIXME: get the actual phase, not assume it is phase A in single phase charging - if (availablePhasePower.value("A") >= requiredRestorePhasePower) { + if (availablePhasePower.value(chargerPhaseKey(evCharger)) >= requiredRestorePhasePower) { qCDebug(dcNymeaEnergy()) << "Overload protection: Enought power available to restore the original configuration" << manualMaxChargingCurrent(evCharger->id()) << "[A]"; restoreCharger = true; @@ -514,8 +513,7 @@ void SmartChargingManager::verifyOverloadProtectionRecovery(const QDateTime &cur bool restoreChargerPower = false; if (evCharger->phaseCount() == 1) { - // FIXME: get the actual phase, not assume it is phase A in single phase charging - if (availablePhasePower.value("A") >= requiredRestorePhasePower) { + if (availablePhasePower.value(chargerPhaseKey(evCharger)) >= requiredRestorePhasePower) { qCDebug(dcNymeaEnergy()) << "Overload protection: Enought power available to start charging using the minimal charging current of" << m_processInfos.value(evCharger).minimalChargingCurrent << "[A]"; restoreChargerPower = true; @@ -1770,6 +1768,28 @@ Electricity::Phases SmartChargingManager::getAscendingPhasesForCount(uint phaseC return phases; } +QString SmartChargingManager::chargerPhaseKey(EvCharger *evCharger) const +{ + // Use live metering first — reliable when charger is actively charging + Electricity::Phases metered = evCharger->meteredPhases(); + if (metered.testFlag(Electricity::PhaseA)) return QStringLiteral("A"); + if (metered.testFlag(Electricity::PhaseB)) return QStringLiteral("B"); + if (metered.testFlag(Electricity::PhaseC)) return QStringLiteral("C"); + + // Charger may be off — fall back to last known phase stored by prepareInformation() + if (m_processInfos.contains(evCharger)) { + Electricity::Phases known = m_processInfos.value(evCharger).effectivePhases; + if (known.testFlag(Electricity::PhaseA)) return QStringLiteral("A"); + if (known.testFlag(Electricity::PhaseB)) return QStringLiteral("B"); + if (known.testFlag(Electricity::PhaseC)) return QStringLiteral("C"); + } + + // Phase unknown — conservative fallback (unchanged previous behavior) + qCWarning(dcNymeaEnergy()) << "Cannot determine connected phase for" + << evCharger->name() << "— defaulting to phase A"; + return QStringLiteral("A"); +} + uint SmartChargingManager::getBestPhaseCount(EvCharger *evCharger, double surplusAmpere) { uint desiredPhaseCount = 1; diff --git a/energyplugin/smartchargingmanager.h b/energyplugin/smartchargingmanager.h index 833bcaa..1099c34 100644 --- a/energyplugin/smartchargingmanager.h +++ b/energyplugin/smartchargingmanager.h @@ -123,6 +123,7 @@ private: Electricity::Phases getAscendingPhasesForCount(uint phaseCount); uint getBestPhaseCount(EvCharger *evCharger, double surplusAmpere); + QString chargerPhaseKey(EvCharger *evCharger) const; EnergyManager *m_energyManager = nullptr; ThingManager *m_thingManager = nullptr;