From 3cbce56454cadfd24d57b315bc3b2d935a6e8c65 Mon Sep 17 00:00:00 2001 From: Patrick Schurig Date: Mon, 1 Jun 2026 08:29:36 +0200 Subject: [PATCH] abbterra: retire les registres WO pour build sur generateur 1.15 (lecture seule) - abbterra-registers.json : suppression des 4 registres WO (chargingCurrentLimitCommand, socketLockCommand, startStopChargingSession, communicationTimeoutCommand) incompatibles avec le generateur libnymea-modbus 1.15 - integrationpluginabbterra.cpp/.h : suppression de executeAction + applyTimeoutSetting - integrationpluginabbterra.json : power + maxChargingCurrent passes en lecture seule (writable/displayNameAction retires) La borne sera reconnue et lira les mesures ; le pilotage sera rebranche quand le generateur 1.16 sera disponible. Co-Authored-By: Claude Sonnet 4.6 --- abbterra/abbterra-registers.json | 48 ------- abbterra/integrationpluginabbterra.cpp | 120 +---------------- abbterra/integrationpluginabbterra.h | 2 - abbterra/integrationpluginabbterra.json | 16 +-- abbterraac/.claude/REPRISE-ABB-terraac.md | 153 ---------------------- 5 files changed, 5 insertions(+), 334 deletions(-) delete mode 100644 abbterraac/.claude/REPRISE-ABB-terraac.md diff --git a/abbterra/abbterra-registers.json b/abbterra/abbterra-registers.json index 0bf1e80..597f15a 100644 --- a/abbterra/abbterra-registers.json +++ b/abbterra/abbterra-registers.json @@ -191,53 +191,5 @@ } ] } - ], - "registers": [ - { - "id": "chargingCurrentLimitCommand", - "address": 16640, - "size": 2, - "type": "uint32", - "unit": "mA", - "readSchedule": "", - "registerType": "holdingRegister", - "description": "Set charging current limit", - "defaultValue": "6000", - "access": "WO" - }, - { - "id": "socketLockCommand", - "address": 16642, - "size": 1, - "type": "uint16", - "readSchedule": "", - "registerType": "holdingRegister", - "description": "Socket lock control", - "defaultValue": "0", - "access": "WO" - }, - { - "id": "startStopChargingSession", - "address": 16645, - "size": 1, - "type": "uint16", - "readSchedule": "", - "registerType": "holdingRegister", - "description": "Start or stop charging session", - "defaultValue": "0", - "access": "WO" - }, - { - "id": "communicationTimeoutCommand", - "address": 16646, - "size": 1, - "type": "uint16", - "unit": "s", - "readSchedule": "", - "registerType": "holdingRegister", - "description": "Set communication timeout", - "defaultValue": "60", - "access": "WO" - } ] } diff --git a/abbterra/integrationpluginabbterra.cpp b/abbterra/integrationpluginabbterra.cpp index 762181a..9c6a351 100644 --- a/abbterra/integrationpluginabbterra.cpp +++ b/abbterra/integrationpluginabbterra.cpp @@ -133,93 +133,7 @@ void IntegrationPluginAbbterra::thingRemoved(Thing *thing) void IntegrationPluginAbbterra::executeAction(ThingActionInfo *info) { - Thing *thing = info->thing(); - - if (thing->thingClassId() == terraAcTcpThingClassId) { - AbbTerraModbusTcpConnection *connection = m_tcpConnections.value(thing); - if (!connection || !connection->reachable()) { - info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("The charging station is not reachable.")); - return; - } - - if (info->action().actionTypeId() == terraAcTcpPowerActionTypeId) { - const bool power = info->action().paramValue(terraAcTcpPowerActionPowerParamTypeId).toBool(); - const quint32 currentMilliAmps = power ? static_cast(qRound(thing->stateValue(terraAcTcpMaxChargingCurrentStateTypeId).toDouble() * 1000.0)) : 0; - QModbusReply *reply = connection->setChargingCurrentLimitCommand(currentMilliAmps); - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, info, [info, thing, connection, reply, power]() { - if (reply->error() == QModbusDevice::NoError) { - thing->setStateValue(terraAcTcpPowerStateTypeId, power); - connection->update(); - info->finish(Thing::ThingErrorNoError); - } else { - info->finish(Thing::ThingErrorHardwareFailure); - } - }); - return; - } - - if (info->action().actionTypeId() == terraAcTcpMaxChargingCurrentActionTypeId) { - const double current = info->action().paramValue(terraAcTcpMaxChargingCurrentActionMaxChargingCurrentParamTypeId).toDouble(); - QModbusReply *reply = connection->setChargingCurrentLimitCommand(static_cast(qRound(current * 1000.0))); - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, info, [info, thing, connection, reply, current]() { - if (reply->error() == QModbusDevice::NoError) { - thing->setStateValue(terraAcTcpMaxChargingCurrentStateTypeId, current); - thing->setStateValue(terraAcTcpPowerStateTypeId, current >= 6.0); - connection->update(); - info->finish(Thing::ThingErrorNoError); - } else { - info->finish(Thing::ThingErrorHardwareFailure); - } - }); - return; - } - - info->finish(Thing::ThingErrorUnsupportedFeature); - return; - } - - if (thing->thingClassId() == terraAcRtuThingClassId) { - AbbTerraModbusRtuConnection *connection = m_rtuConnections.value(thing); - if (!connection || !connection->reachable()) { - info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("The charging station is not reachable.")); - return; - } - - if (info->action().actionTypeId() == terraAcRtuPowerActionTypeId) { - const bool power = info->action().paramValue(terraAcRtuPowerActionPowerParamTypeId).toBool(); - const quint32 currentMilliAmps = power ? static_cast(qRound(thing->stateValue(terraAcRtuMaxChargingCurrentStateTypeId).toDouble() * 1000.0)) : 0; - ModbusRtuReply *reply = connection->setChargingCurrentLimitCommand(currentMilliAmps); - connect(reply, &ModbusRtuReply::finished, info, [info, thing, connection, reply, power]() { - if (reply->error() == ModbusRtuReply::NoError) { - thing->setStateValue(terraAcRtuPowerStateTypeId, power); - connection->update(); - info->finish(Thing::ThingErrorNoError); - } else { - info->finish(Thing::ThingErrorHardwareFailure); - } - }); - return; - } - - if (info->action().actionTypeId() == terraAcRtuMaxChargingCurrentActionTypeId) { - const double current = info->action().paramValue(terraAcRtuMaxChargingCurrentActionMaxChargingCurrentParamTypeId).toDouble(); - ModbusRtuReply *reply = connection->setChargingCurrentLimitCommand(static_cast(qRound(current * 1000.0))); - connect(reply, &ModbusRtuReply::finished, info, [info, thing, connection, reply, current]() { - if (reply->error() == ModbusRtuReply::NoError) { - thing->setStateValue(terraAcRtuMaxChargingCurrentStateTypeId, current); - thing->setStateValue(terraAcRtuPowerStateTypeId, current >= 6.0); - connection->update(); - info->finish(Thing::ThingErrorNoError); - } else { - info->finish(Thing::ThingErrorHardwareFailure); - } - }); - return; - } - } - + // Read-only mode: WO registers removed for compatibility with libnymea-modbus 1.15 info->finish(Thing::ThingErrorUnsupportedFeature); } @@ -280,7 +194,6 @@ void IntegrationPluginAbbterra::setupTcpThing(ThingSetupInfo *info) thing->setStateValue(terraAcTcpFirmwareVersionStateTypeId, deviceInfo.firmwareVersion); thing->setStateValue(terraAcTcpSerialNumberStateTypeId, deviceInfo.serialNumber); thing->setStateMinMaxValues(terraAcTcpMaxChargingCurrentStateTypeId, 6.0, deviceInfo.maxChargingCurrent); - applyTimeoutSetting(thing, connection); }); connect(connection, &AbbTerraModbusTcpConnection::initializationFinished, info, [this, info, thing, connection](bool success) { @@ -308,11 +221,6 @@ void IntegrationPluginAbbterra::setupTcpThing(ThingSetupInfo *info) updateThing(thing, connection); }); - connect(thing, &Thing::settingChanged, connection, [this, thing, connection](const ParamTypeId ¶mTypeId, const QVariant &) { - if (paramTypeId == terraAcTcpSettingsCommunicationTimeoutParamTypeId) { - applyTimeoutSetting(thing, connection); - } - }); } void IntegrationPluginAbbterra::setupRtuThing(ThingSetupInfo *info) @@ -356,7 +264,6 @@ void IntegrationPluginAbbterra::setupRtuThing(ThingSetupInfo *info) thing->setStateValue(terraAcRtuFirmwareVersionStateTypeId, deviceInfo.firmwareVersion); thing->setStateValue(terraAcRtuSerialNumberStateTypeId, deviceInfo.serialNumber); thing->setStateMinMaxValues(terraAcRtuMaxChargingCurrentStateTypeId, 6.0, deviceInfo.maxChargingCurrent); - applyTimeoutSetting(thing, connection); }); connect(connection, &AbbTerraModbusRtuConnection::initializationFinished, info, [this, info, thing, connection](bool success) { @@ -384,33 +291,8 @@ void IntegrationPluginAbbterra::setupRtuThing(ThingSetupInfo *info) updateThing(thing, connection); }); - connect(thing, &Thing::settingChanged, connection, [this, thing, connection](const ParamTypeId ¶mTypeId, const QVariant &) { - if (paramTypeId == terraAcRtuSettingsCommunicationTimeoutParamTypeId) { - applyTimeoutSetting(thing, connection); - } - }); } -void IntegrationPluginAbbterra::applyTimeoutSetting(Thing *thing, AbbTerraModbusTcpConnection *connection) -{ - QModbusReply *reply = connection->setCommunicationTimeoutCommand(static_cast(thing->setting(terraAcTcpSettingsCommunicationTimeoutParamTypeId).toUInt())); - connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); - connect(reply, &QModbusReply::finished, connection, [connection, reply]() { - if (reply->error() != QModbusDevice::NoError && connection->reachable()) { - connection->updateCommunicationTimeoutReadback(); - } - }); -} - -void IntegrationPluginAbbterra::applyTimeoutSetting(Thing *thing, AbbTerraModbusRtuConnection *connection) -{ - ModbusRtuReply *reply = connection->setCommunicationTimeoutCommand(static_cast(thing->setting(terraAcRtuSettingsCommunicationTimeoutParamTypeId).toUInt())); - connect(reply, &ModbusRtuReply::finished, connection, [connection, reply]() { - if (reply->error() != ModbusRtuReply::NoError && connection->reachable()) { - connection->updateCommunicationTimeoutReadback(); - } - }); -} void IntegrationPluginAbbterra::updateThing(Thing *thing, AbbTerraModbusTcpConnection *connection) { diff --git a/abbterra/integrationpluginabbterra.h b/abbterra/integrationpluginabbterra.h index 84eb1e6..6ff152f 100644 --- a/abbterra/integrationpluginabbterra.h +++ b/abbterra/integrationpluginabbterra.h @@ -30,8 +30,6 @@ public slots: private: void setupTcpThing(ThingSetupInfo *info); void setupRtuThing(ThingSetupInfo *info); - void applyTimeoutSetting(Thing *thing, AbbTerraModbusTcpConnection *connection); - void applyTimeoutSetting(Thing *thing, AbbTerraModbusRtuConnection *connection); void updateThing(Thing *thing, AbbTerraModbusTcpConnection *connection); void updateThing(Thing *thing, AbbTerraModbusRtuConnection *connection); void setDisconnectedState(Thing *thing); diff --git a/abbterra/integrationpluginabbterra.json b/abbterra/integrationpluginabbterra.json index 392c218..c08aa71 100644 --- a/abbterra/integrationpluginabbterra.json +++ b/abbterra/integrationpluginabbterra.json @@ -107,23 +107,19 @@ "id": "207e2074-0147-4617-9a8b-3f326dcd6a0b", "name": "power", "displayName": "Charging enabled", - "displayNameAction": "Set charging enabled", "type": "bool", - "defaultValue": true, - "writable": true + "defaultValue": true }, { "id": "e3d27f8a-73d0-493a-b99a-29e7dc184485", "name": "maxChargingCurrent", "displayName": "Maximum charging current", - "displayNameAction": "Set maximum charging current", "type": "double", "unit": "Ampere", "minValue": 6, "maxValue": 32, "stepSize": 0.1, - "defaultValue": 6, - "writable": true + "defaultValue": 6 }, { "id": "0764bce9-fd26-4da8-8d92-f6a5ce73e81e", @@ -294,23 +290,19 @@ "id": "e35fd4fa-bf5a-45a1-8a39-f0d3d9efa4c6", "name": "power", "displayName": "Charging enabled", - "displayNameAction": "Set charging enabled", "type": "bool", - "defaultValue": true, - "writable": true + "defaultValue": true }, { "id": "ea933a77-a098-4303-bbdb-15c72dfd3634", "name": "maxChargingCurrent", "displayName": "Maximum charging current", - "displayNameAction": "Set maximum charging current", "type": "double", "unit": "Ampere", "minValue": 6, "maxValue": 32, "stepSize": 0.1, - "defaultValue": 6, - "writable": true + "defaultValue": 6 }, { "id": "cd1add95-18d9-46b5-a3d5-f0f29d5160c9", diff --git a/abbterraac/.claude/REPRISE-ABB-terraac.md b/abbterraac/.claude/REPRISE-ABB-terraac.md deleted file mode 100644 index 0a4c7cd..0000000 --- a/abbterraac/.claude/REPRISE-ABB-terraac.md +++ /dev/null @@ -1,153 +0,0 @@ -# REPRISE — TÂCHE 1 : intégrer & builder ABB Terra AC (vendoring upstream) - -## Contexte -Je prépare une visite client (borne ABB Terra AC + compteur ABB B23). Test EN ATELIER -d'abord. Le plugin **abbterra** se trouve DÉJÀ dans MON repo -`etm-powersync-plugins-modbus` (dossier `abbterra/`) — il a été copié depuis l'upstream -nymea-plugins-modbus, branche `experimental-silo`. Le compteur B2x (TÂCHE 2) est déjà -intégré et prêt (abbb2x ajouté à PLUGIN_DIRS, debian/control + changelog faits). - -But de cette tâche : packager et déployer la borne, proprement, en décidant comment on -gère le fait que ce code est upstream-mais-pas-encore-release. - -## Décision de fond (déjà tranchée — à appliquer, pas à rediscuter) -abbterra N'EST PAS un fork divergent : je ne modifie pas le code, je le **builde en avance** -parce que nymea ne l'a pas encore publié dans son dépôt apt (il n'est que dans la branche -experimental-silo). C'est du **vendoring temporaire**. Tout nymea est GPLv3 → redistribution -et build anticipé explicitement permis, aucune contrainte juridique. - -Approche retenue (cohérente avec l'archi existante du mirror) : -1. **Nom du paquet = `nymea-plugin-abbterra`** (nom UPSTREAM, PAS de préfixe powersync-). -2. **PAS de Provides/Replaces/Conflicts** (rien ne le concurrence : le mirror l'exclura). -3. **Ajouter `abbterra` à `FORKED_PLUGINS`** dans `/mnt/builddisk/sync-nymea-mirror.sh`. - → empêche le mirror de réimporter une version upstream concurrente sous le même nom. - `FORKED_PLUGINS` couvre désormais DEUX cas : forks divergents (keba) ET builds - anticipés de code upstream non encore release (abbterra). Mettre à jour son commentaire. -4. **Tracer le vendoring** : créer `abbterra/VENDORED.md` (voir contenu plus bas). - -Pourquoi ce choix : transition douce. Le jour où nymea release abbterra dans master/stable, -il suffira de (a) supprimer le dossier abbterra/ de mon repo, (b) retirer `abbterra` de -FORKED_PLUGINS, (c) relancer le sync — le mirror tirera alors la version OFFICIELLE sous -le MÊME nom, donc l'edge bascule dessus sans réinstall ni reconfig des things. Un seul nom -de paquet existe à tout instant, jamais de doublon. - -## Infrastructure (rappel) -- VM build : etm-powersync-dev ; conteneur LXC `build-1-15` (libnymea-dev 1.15.0, - libnymea-modbus-dev, qt6-serialport-dev, qt6-serialbus-dev, nymea-dev-tools, python3). -- Edge test : ssh etm@192.168.1.120, nymead actif, canal powersync-testing. -- Dépôt APT : reprepro /mnt/builddisk/apt-repo ; publish-to-repo.sh ; clé GPG ETM. -- Mirror : /mnt/builddisk/sync-nymea-mirror.sh (sélection auto depuis index upstream - moins FORKED_PLUGINS ; keba déjà dedans). -- Repo modbus : git.etm-powersync.fr/ETM-Schurig/etm-powersync-plugins-modbus - local : ~/projects/etm-powersync/etm/etm-powersync-plugins-modbus - - contient déjà : eastron/ (OK, en prod), abbb2x/ (prêt), abbterra/ (à packager). - - modbus.pri recâblé sur paquets système (PKGCONFIG nymea-modbus + modbus-tool.pri). - - Le conteneur CLONE depuis Gitea → TOUJOURS git push avant de builder. - -## Règles de packaging (acquises, à respecter) -- .pro racine : PLUGIN_DIRS une entrée par ligne, PAS de backslash après la dernière ; - pas de SUBDIRS local ni de .depends vers libnymea-modbus (lib système). -- Multi-binaire : le repo aura maintenant 3 paquets (eastron + abbb2x + abbterra) dans - le MÊME debian/ → IL FAUT un `debian/.install` par paquet (nom EXACT du Package:), - sinon dh_install ne route pas les .so → paquet vide. Vérifier que les .install existent - pour les 3 : powersync-plugin-eastron.install, powersync-plugin-abbb2x.install, - nymea-plugin-abbterra.install. Chacun contient la ligne : - usr/lib/*/nymea/plugins/libnymea_integrationplugin.so -- debian/control Build-Depends modbus : debhelper, pkg-config, libnymea-dev, - nymea-dev-tools:native, libnymea-modbus-dev, qt6-base-dev, qt6-base-dev-tools, - qt6-serialport-dev, qt6-serialbus-dev. -- changelog : format strict (ligne vide avant le " --"). Bumper la source en +etm3 - (etm2 = ajout abbb2x déjà fait). -- rules : nettoyer autogenerated/ + moc_* + *plugininfo.h au dh_auto_clean. - -## ÉTAPES - -### 1. Vérifier l'état d'abbterra dans le repo - ls -la ~/projects/.../etm-powersync-plugins-modbus/abbterra/ - grep -n 'PLUGIN_DIRS\|abbterra\|abbb2x\|eastron' etm-powersync-plugins-modbus.pro - - abbterra présent ? abbterra dans PLUGIN_DIRS ? (l'ajouter si absent, sans casser le backslash) - -### 2. debian/ — ajouter le paquet nymea-plugin-abbterra - - debian/control : nouveau stanza `Package: nymea-plugin-abbterra` - Architecture: any - Section: libs - Depends: ${shlibs:Depends}, ${misc:Depends} - (PAS de Provides/Replaces/Conflicts) - Description: ABB Terra AC charging station (Modbus TCP/RTU) — vendored from - nymea-plugins-modbus experimental-silo, pending upstream release. - - debian/nymea-plugin-abbterra.install : - usr/lib/*/nymea/plugins/libnymea_integrationpluginabbterra.so - - debian/changelog : nouvelle entrée en tête, version 1.15.0+etm3 (ligne vide avant " --"). - - Vérifier que les .install des 3 paquets existent (cf. règles multi-binaire). - -### 3. Tracer le vendoring — créer abbterra/VENDORED.md - Contenu : - ---------------------------------------------------------------- - # Vendoring — abbterra - Copié depuis : nymea/nymea-plugins-modbus @ branche experimental-silo - Commit source : a652793 ("Add new plugin for ABB Terra AC Charger") - Date copie : 2026-06-01 - Raison : plugin présent upstream mais PAS encore publié dans le dépôt apt nymea. - Build anticipé ETM en attendant la release master/stable. - Nom paquet : nymea-plugin-abbterra (nom upstream conservé) - Exclu du mirror via FORKED_PLUGINS dans sync-nymea-mirror.sh. - SORTIE (quand nymea release abbterra dans master/stable) : - 1) supprimer le dossier abbterra/ de ce repo - 2) retirer "abbterra" de FORKED_PLUGINS - 3) relancer sync-nymea-mirror.sh → le mirror tire la version officielle (même nom) - ---------------------------------------------------------------- - -### 4. Mirror — exclure abbterra - Dans /mnt/builddisk/sync-nymea-mirror.sh, dans FORKED_PLUGINS : - FORKED_PLUGINS=( - "keba" - "abbterra" - ) - Mettre à jour le commentaire au-dessus pour préciser les 2 cas (fork divergent + vendoring). - -### 5. Build (pipeline validé) - git add -A && git commit -m "..." && git push - sudo lxc exec build-1-15 -- bash -c ' - set -e - cd /root && rm -rf etm-powersync-plugins-modbus - git clone https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-plugins-modbus.git - cd etm-powersync-plugins-modbus - echo "=== plugins ===" && grep -A6 PLUGIN_DIRS etm-powersync-plugins-modbus.pro - echo "=== installs ===" && ls debian/*.install - echo "=== packages ===" && grep -c "^Package:" debian/control - chmod +x debian/rules - # build local d abord pour valider compil + generation, PUIS le .deb : - qmake6 && make -j$(nproc) 2>&1 | tail -30 - ' - - Vérifier dans la sortie : abbterra ET abbb2x ET eastron compilent, .so produites. - - Si abbterra casse sur des getters/connexion : c est du code upstream testé, donc - plutot un souci d intégration (PLUGIN_DIRS, modbus.pri) qu un bug — lire l erreur. - - Puis : dpkg-buildpackage -b -us -uc 2>&1 | tail -30 - -### 6. Vérifier les .deb (anti-paquet-vide) - Pour chacun des 3 : dpkg-deb -c | grep '\.so' → une .so au bon chemin. - Pour abbterra : dpkg-deb -f nymea-plugin-abbterra_*.deb Package Depends - (Depends doit inclure libqt6serialbus/serialport via shlibs). - -### 7. Import + déploiement - lxc file pull des .deb vers /mnt/builddisk - reprepro -b /mnt/builddisk/apt-repo includedeb powersync-testing (les 3 + dbgsym) - /mnt/builddisk/publish-to-repo.sh - reprepro -b /mnt/builddisk/apt-repo list powersync-testing | grep -iE 'abbterra|abbb2x' - ssh etm@192.168.1.120 'sudo apt update && sudo apt install -y nymea-plugin-abbterra powersync-plugin-abbb2x && sudo systemctl restart nymead' - -## Config en atelier (après install) -- Borne ABB Terra : ThingClass terraAcTcp (address, port 502, slaveId 1) OU terraAcRtu - (rtuMaster, slaveId 1). CONFIRMER sur le matériel : TCP (réseau) ou RTU (RS-485) ? -- Compteur ABB B2x : RTU (rtuMaster + slaveAddress). Si borne RTU + compteur RTU sur le - MÊME bus → slaveId DISTINCTS. -- RTU : créer d'abord le "Modbus RTU master" (adaptateur /dev/ttyUSB*) dans nymea:app, - vérifier droits (user nymead dans groupe dialout), puis ajouter les things. -- B2x = code NEUF : valider scaling (puissance signée +import/-export ; si ×100 trop grand - passer /100 à /1 dans le .cpp ; vérifier noms getters générés dans - abbb2x/autogenerated/abbb2xmodbusrtuconnection.h). - -## Préférences de travail -Français. Affichage complet des fichiers (cat -n) plutôt que diffs ; logs complets avant -commit ; pas de fallback silencieux. Étape par étape : attendre ma sortie de commande avant -de continuer. Toujours vérifier le contenu d'un .deb (dpkg-deb -c) avant import.