From 2ac00e13306ca74a4d4ef17fda8644fe77194b61 Mon Sep 17 00:00:00 2001 From: Patrick Schurig Date: Fri, 12 Jun 2026 15:20:11 +0200 Subject: [PATCH] fix(v2c): correct logging category dcV2C + debian packaging + modbus.pri path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build fixes found during first local compilation (qmake6 + g++ -Werror): 1. Logging category: nymea-plugininfocompiler generates 'dcV2C' (uppercase C) from the JSON vendor name "V2C". All three source files used 'dcV2c' (lowercase c) — corrected to 'dcV2C' in integrationpluginv2c.cpp, trydanmodbustcpmaster.cpp, v2ctcpdiscovery.cpp. 2. modbus.pri: hardcoded include(/usr/include/nymea-modbus/modbus-tool.pri) fails when libnymea-modbus-dev is not system-installed. Changed to a conditional: checks $$[QT_INSTALL_PREFIX] first, then NYMEA_MODBUS_PATH override, with a graceful fallback (warning + manual C++17 CONFIG flag). The v2c plugin has MODBUS_CONNECTIONS empty so the tool loop is a no-op either way; the fallback is safe. 3. debian/: add powersync-plugin-v2c package entry (control, .install, changelog entry 1.15.0+etm4). Build verified: libnymea_integrationpluginv2c.so links against libnymea.so.1, libnymea-modbus.so.1, Qt6Network/SerialBus/Core, 0 compiler warnings (with -Werror -Wall -Wextra -std=c++17). Co-Authored-By: Claude Sonnet 4.6 --- debian/changelog | 13 +++++++++++++ debian/control | 12 ++++++++++++ debian/powersync-plugin-v2c.install | 1 + modbus.pri | 19 +++++++++++++++---- v2c/integrationpluginv2c.cpp | 6 +++--- v2c/trydanmodbustcpmaster.cpp | 8 ++++---- v2c/v2ctcpdiscovery.cpp | 6 +++--- 7 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 debian/powersync-plugin-v2c.install diff --git a/debian/changelog b/debian/changelog index 5056cad..cf3811e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +etm-powersync-plugins-modbus (1.15.0+etm4) trixie; urgency=medium + + * Ajout plugin V2C Trydan (borne de charge EV, Modbus TCP) : interface + evcharger complète — charge enable/disable (PauseState+Lock miroir), + consigne courant (Intensity), telemetrie (ChargePower, HousePower, + PowerFV, ChargeState IEC 61851). Gestion conflit Dynamic/PauseDynamic + sans ecriture du registre Dynamic (evite la coupure de telemetrie, + cf. evcc issue #28047). Decouverte LAN via HTTP /RealTimeData. + Transport abstrait (TCP Etape 1, RTU Etape 2 prevu). + Statut : Partiel — non teste sur borne reelle. + + -- ETM-Schurig SARL Thu, 12 Jun 2026 12:00:00 +0200 + etm-powersync-plugins-modbus (1.15.0+etm3) trixie; urgency=medium * Ajout plugin ABB Terra AC (borne de charge, Modbus TCP/RTU) : vendoring diff --git a/debian/control b/debian/control index 716f94e..af1073f 100644 --- a/debian/control +++ b/debian/control @@ -41,3 +41,15 @@ Depends: ${shlibs:Depends}, Description: ABB Terra AC charging station (Modbus TCP/RTU) - vendored from upstream nymea integration plugin for ABB Terra AC wallbox over Modbus TCP or RTU. Vendored from nymea-plugins-modbus experimental-silo, pending upstream release. + +Package: powersync-plugin-v2c +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, + ${misc:Depends}, +Description: PowerSync integration plugin for V2C Trydan EV charger (Modbus TCP) + nymea integration plugin for the V2C Trydan / Trydan Pro EV charger over + Modbus TCP (port 502), for use by the ETM PowerSync home energy management + system. Implements the evcharger interface: charge enable/disable, current + setpoint, plugged-in / charging state, house and solar power telemetry. + Status: Partial — not yet validated on real hardware. diff --git a/debian/powersync-plugin-v2c.install b/debian/powersync-plugin-v2c.install new file mode 100644 index 0000000..4e2148a --- /dev/null +++ b/debian/powersync-plugin-v2c.install @@ -0,0 +1 @@ +usr/lib/*/nymea/plugins/libnymea_integrationpluginv2c.so diff --git a/modbus.pri b/modbus.pri index 12f839c..6b8102e 100644 --- a/modbus.pri +++ b/modbus.pri @@ -1,11 +1,22 @@ QT += network serialport serialbus -# libnymea-modbus depuis le paquet systeme (libnymea-modbus-dev), plus les sources locales +# libnymea-modbus depuis le paquet systeme (libnymea-modbus-dev) ou via NYMEA_MODBUS_PATH. CONFIG += link_pkgconfig PKGCONFIG += nymea-modbus OTHER_FILES += $${MODBUS_CONNECTIONS} -# Outil de generation des connexions modbus (sdm*-registers.json -> .cpp/.h), -# fourni par libnymea-modbus-dev -include(/usr/include/nymea-modbus/modbus-tool.pri) +# Locate modbus-tool.pri: system install first, then NYMEA_MODBUS_PATH override +# (for builds against a local libnymea-modbus source tree). +# When MODBUS_CONNECTIONS is empty (e.g. v2c plugin), the tool's for-loop is a +# no-op; we still need the file for the C++ standard CONFIG lines below. +MODBUS_TOOL_PRI = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/modbus-tool.pri +!isEmpty(NYMEA_MODBUS_PATH): MODBUS_TOOL_PRI = $$NYMEA_MODBUS_PATH/modbus-tool.pri + +exists($$MODBUS_TOOL_PRI) { + include($$MODBUS_TOOL_PRI) +} else { + warning("modbus-tool.pri not found at $$MODBUS_TOOL_PRI — MODBUS_CONNECTIONS code-gen disabled") + greaterThan(QT_MAJOR_VERSION, 5): CONFIG *= c++17 + lessThan(QT_MAJOR_VERSION, 6): CONFIG *= c++11 +} diff --git a/v2c/integrationpluginv2c.cpp b/v2c/integrationpluginv2c.cpp index 32f7d2e..0c428e5 100644 --- a/v2c/integrationpluginv2c.cpp +++ b/v2c/integrationpluginv2c.cpp @@ -279,7 +279,7 @@ void IntegrationPluginV2c::updateThingStates(Thing *thing, TrydanModbusMaster *m thing->setStateValue(trydanOptimizerSuspendedStateTypeId, master->pauseDynamic() == 1); if (conflict) { - qCDebug(dcV2c()) << thing->name() + qCDebug(dcV2C()) << thing->name() << ": V2C internal optimizer is active (Dynamic==1). " "HEMS will suppress it via PauseDynamic if suspendInternalOptimizer==true."; } @@ -302,7 +302,7 @@ void IntegrationPluginV2c::handleDynamicConflict(Thing *thing, TrydanModbusMaste const bool suspendAllowed = thing->setting(trydanSettingsSuspendInternalOptimizerParamTypeId).toBool(); if (!suspendAllowed) { - qCWarning(dcV2c()) << thing->name() + qCWarning(dcV2C()) << thing->name() << ": V2C internal optimizer active but suspendInternalOptimizer==false. " "HEMS and V2C PID may fight — expect oscillations."; return; @@ -314,7 +314,7 @@ void IntegrationPluginV2c::handleDynamicConflict(Thing *thing, TrydanModbusMaste // Only write on transition to avoid unnecessary flash wear. if (master->pauseDynamic() != desired) { - qCDebug(dcV2c()) << thing->name() + qCDebug(dcV2C()) << thing->name() << ": writing PauseDynamic =" << desired << (hemsInControl ? "(HEMS taking control)" : "(releasing to V2C PID)"); master->writePauseDynamic(static_cast(desired)); diff --git a/v2c/trydanmodbustcpmaster.cpp b/v2c/trydanmodbustcpmaster.cpp index a324827..7636391 100644 --- a/v2c/trydanmodbustcpmaster.cpp +++ b/v2c/trydanmodbustcpmaster.cpp @@ -200,7 +200,7 @@ void TrydanModbusTcpMaster::doNextRead(QList steps, static_cast(m_slaveId)); if (!reply) { - qCWarning(dcV2c()) << "TrydanModbusTcpMaster: sendReadRequest returned null for reg" << Qt::hex << address; + qCWarning(dcV2C()) << "TrydanModbusTcpMaster: sendReadRequest returned null for reg" << Qt::hex << address; onDone(false); return; } @@ -210,7 +210,7 @@ void TrydanModbusTcpMaster::doNextRead(QList steps, reply->deleteLater(); if (reply->error() != QModbusDevice::NoError) { - qCWarning(dcV2c()) << "TrydanModbusTcpMaster: read error for reg" + qCWarning(dcV2C()) << "TrydanModbusTcpMaster: read error for reg" << Qt::hex << steps.at(index).first << ":" << reply->errorString(); callback(false, 0, 0); @@ -233,7 +233,7 @@ void TrydanModbusTcpMaster::writeFC6(quint16 address, quint16 value, QModbusReply *reply = m_modbusTcpMaster->sendWriteRequest(unit, static_cast(m_slaveId)); if (!reply) { - qCWarning(dcV2c()) << "TrydanModbusTcpMaster: sendWriteRequest returned null for reg" << Qt::hex << address; + qCWarning(dcV2C()) << "TrydanModbusTcpMaster: sendWriteRequest returned null for reg" << Qt::hex << address; callback(address, false); return; } @@ -261,7 +261,7 @@ void TrydanModbusTcpMaster::handleError() { m_errorCount++; if (m_errorCount >= k_errorLimit) { - qCWarning(dcV2c()) << "TrydanModbusTcpMaster: error limit reached, marking unreachable"; + qCWarning(dcV2C()) << "TrydanModbusTcpMaster: error limit reached, marking unreachable"; setReachable(false); } } diff --git a/v2c/v2ctcpdiscovery.cpp b/v2c/v2ctcpdiscovery.cpp index e5a1313..645a317 100644 --- a/v2c/v2ctcpdiscovery.cpp +++ b/v2c/v2ctcpdiscovery.cpp @@ -19,7 +19,7 @@ V2cTcpDiscovery::V2cTcpDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, void V2cTcpDiscovery::startDiscovery() { - qCInfo(dcV2c()) << "Discovery: searching for V2C Trydan chargers on the network..."; + qCInfo(dcV2C()) << "Discovery: searching for V2C Trydan chargers on the network..."; m_startTime = QDateTime::currentDateTime(); m_pendingProbes = 0; m_scanFinished = false; @@ -84,7 +84,7 @@ void V2cTcpDiscovery::probeAddress(const QHostAddress &address) info.setAddress(address); result.networkDeviceInfo = info; } - qCDebug(dcV2c()) << "Discovery: found V2C Trydan at" << address.toString(); + qCDebug(dcV2C()) << "Discovery: found V2C Trydan at" << address.toString(); m_results.append(result); } } @@ -103,7 +103,7 @@ void V2cTcpDiscovery::finishDiscovery() m_finished = true; const qint64 ms = QDateTime::currentMSecsSinceEpoch() - m_startTime.toMSecsSinceEpoch(); - qCInfo(dcV2c()) << "Discovery: finished in" + qCInfo(dcV2C()) << "Discovery: finished in" << QTime::fromMSecsSinceStartOfDay(static_cast(ms)).toString("mm:ss.zzz") << "with" << m_results.count() << "V2C Trydan(s) found."; emit discoveryFinished();