fix(v2c): la borne basse du courant lit RegMinIntensity, comme la haute
executeAction écrêtait le haut avec master->maxIntensity() mais le bas avec un littéral 6.0. Une borne déclarant un minimum de 8 A aurait donc reçu une consigne de 7 A écrite telle quelle : au-dessus du littéral, en dessous de ce que la borne honore. L'asymétrie datait de l'écriture initiale — la lecture du registre 0x0BD1 existait déjà, elle n'était simplement pas utilisée là. Les deux extrémités passent maintenant par courantMinimalEffectif() / courantMaximalEffectif(), qui retiennent la PLUS CONTRAIGNANTE des deux sources : la borne peut être plus exigeante que l'IEC 61851, jamais moins — une lecture aberrante à 0 ne doit pas ouvrir la voie à une consigne de 3 A. La borne haute est refermée sur la basse pour la même raison : RegMaxIntensity dépend de la version de firmware, et un intervalle inversé ferait échouer setStateMinMaxValues. Le même couple sert aux DEUX usages, et c'est le point : ce qui est publié comme min/max du state (lu par le curseur de l'app et par EvCharger::maxChargingCurrentMinValue() côté moteur) et ce qui est écrêté à l'écriture. Les faire diverger donnerait un curseur qui propose une valeur que l'action transforme en pause — une commande sans effet. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7863517bba
commit
d526a1eaae
15
debian/changelog
vendored
15
debian/changelog
vendored
@ -1,3 +1,18 @@
|
||||
etm-powersync-plugins-modbus (1.15.2+etm14) trixie; urgency=medium
|
||||
|
||||
* v2c: the lower current bound now reads RegMinIntensity, like the upper one.
|
||||
|
||||
executeAction clamped the top end with master->maxIntensity() but the bottom
|
||||
end with a literal 6.0, so a charger declaring an 8 A minimum would have been
|
||||
sent a 7 A setpoint written as-is. Both ends now go through
|
||||
courantMinimalEffectif() / courantMaximalEffectif(), which take the stricter
|
||||
of the charger's declared bound and the IEC 61851 floor -- a misread 0 must
|
||||
not open the way to a 3 A setpoint. The same pair feeds setStateMinMaxValues,
|
||||
so the app slider and the action agree; letting them diverge would offer a
|
||||
value the action turns into a pause.
|
||||
|
||||
-- Patrick Schurig <etm.schurig@gmail.com> Tue, 08 Sep 2026 11:09:26 +0200
|
||||
|
||||
etm-powersync-plugins-modbus (1.15.2+etm13) trixie; urgency=medium
|
||||
|
||||
* v2c: sessionEnergy is now BUILT by the plugin, not wired to a register.
|
||||
|
||||
@ -15,6 +15,39 @@
|
||||
#include <QDateTime>
|
||||
#include <QSettings>
|
||||
|
||||
namespace {
|
||||
|
||||
/*!
|
||||
* \brief Courant minimal admissible sur cette borne, en ampères.
|
||||
*
|
||||
* Le plus contraignant des deux : le minimum IEC 61851 (6 A, sous lequel un véhicule ne
|
||||
* doit pas se voir proposer de consigne) et celui que la borne DÉCLARE dans RegMinIntensity
|
||||
* (0x0BD1). La borne gagne quand elle est plus exigeante ; elle ne peut pas descendre sous
|
||||
* la norme — une lecture aberrante à 0 ne doit pas ouvrir la voie à une consigne de 3 A.
|
||||
*
|
||||
* Le même plancher sert à l'écriture (executeAction) et à ce qui est PUBLIÉ comme minimum
|
||||
* du state (setStateMinMaxValues). Les deux doivent coïncider : un curseur d'app qui
|
||||
* propose une valeur que l'action transforme en pause serait une commande sans effet.
|
||||
*/
|
||||
double courantMinimalEffectif(TrydanModbusMaster *master)
|
||||
{
|
||||
return qMax(6.0, static_cast<double>(master->minIntensity()));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Courant maximal admissible, jamais inférieur au minimal.
|
||||
*
|
||||
* RegMaxIntensity dépend de la version de firmware et pourrait, mal lu, passer sous le
|
||||
* plancher. Un intervalle inversé ferait échouer setStateMinMaxValues et rendrait
|
||||
* l'écrêtage incohérent ; on le referme plutôt sur un point.
|
||||
*/
|
||||
double courantMaximalEffectif(TrydanModbusMaster *master)
|
||||
{
|
||||
return qMax(courantMinimalEffectif(master), static_cast<double>(master->maxIntensity()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
IntegrationPluginV2c::IntegrationPluginV2c()
|
||||
{}
|
||||
|
||||
@ -129,8 +162,8 @@ void IntegrationPluginV2c::setupThing(ThingSetupInfo *info)
|
||||
thing->setStateValue(trydanConnectedStateTypeId, true);
|
||||
thing->setStateValue(trydanStatusMessageStateTypeId, QString());
|
||||
thing->setStateMinMaxValues(trydanMaxChargingCurrentStateTypeId,
|
||||
master->minIntensity(),
|
||||
master->maxIntensity());
|
||||
courantMinimalEffectif(master),
|
||||
courantMaximalEffectif(master));
|
||||
// Immediate first poll. For setup the info handler below also calls update();
|
||||
// the m_updating guard makes the second call a no-op.
|
||||
master->update();
|
||||
@ -258,15 +291,20 @@ void IntegrationPluginV2c::executeAction(ThingActionInfo *info)
|
||||
double current = info->action().paramValue(
|
||||
trydanMaxChargingCurrentActionMaxChargingCurrentParamTypeId).toDouble();
|
||||
|
||||
// Clamp to IEC 61851 minimum. Below 6 A → pause rather than send invalid setpoint.
|
||||
if (current < 6.0) {
|
||||
// Plancher : le minimum que la BORNE déclare (RegMinIntensity), jamais sous les 6 A
|
||||
// de l'IEC 61851 — cf. courantMinimalEffectif(). Sous ce plancher → pause, plutôt
|
||||
// qu'une consigne que la borne n'honorerait pas. La borne haute lisait déjà le
|
||||
// registre ; la borne basse était un littéral 6.0, donc une borne qui exigerait
|
||||
// 8 A aurait reçu une consigne de 7 A écrite telle quelle.
|
||||
const double minA = courantMinimalEffectif(master);
|
||||
if (current < minA) {
|
||||
master->writePauseState(1);
|
||||
master->writeLock(1);
|
||||
thing->setStateValue(trydanPowerStateTypeId, false);
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
return;
|
||||
}
|
||||
current = qMin(current, static_cast<double>(master->maxIntensity()));
|
||||
current = qMin(current, courantMaximalEffectif(master));
|
||||
|
||||
const quint16 amps = static_cast<quint16>(qRound(current));
|
||||
master->writeIntensity(amps);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user