From 09dd698cf60a5caa0b6166dd0acd84caa5517c79 Mon Sep 17 00:00:00 2001 From: Patrick Schurig Date: Mon, 1 Jun 2026 09:09:22 +0200 Subject: [PATCH] abbterra: restaure pilotage (cpp+json upstream) + registers.json sans readSchedule vide (compat generateur 1.15) --- abbterra/abbterra-registers.json | 193 +++--------------------- abbterra/integrationpluginabbterra.cpp | 120 ++++++++++++++- abbterra/integrationpluginabbterra.json | 16 +- 3 files changed, 153 insertions(+), 176 deletions(-) diff --git a/abbterra/abbterra-registers.json b/abbterra/abbterra-registers.json index 597f15a..b693960 100644 --- a/abbterra/abbterra-registers.json +++ b/abbterra/abbterra-registers.json @@ -12,184 +12,35 @@ "id": "deviceInfo", "readSchedule": "init", "registers": [ - { - "id": "serialNumber", - "address": 16384, - "size": 4, - "type": "uint64", - "registerType": "holdingRegister", - "description": "Product serial number", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "firmwareVersionRaw", - "address": 16388, - "size": 2, - "type": "uint32", - "registerType": "holdingRegister", - "description": "Firmware version", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "userSettableMaxCurrent", - "address": 16390, - "size": 2, - "type": "uint32", - "unit": "mA", - "registerType": "holdingRegister", - "description": "Maximum user settable charging current", - "defaultValue": "32000", - "access": "RO" - } + { "id": "serialNumber", "address": 16384, "size": 4, "type": "uint64", "registerType": "holdingRegister", "description": "Product serial number", "defaultValue": "0", "access": "RO" }, + { "id": "firmwareVersionRaw", "address": 16388, "size": 2, "type": "uint32", "registerType": "holdingRegister", "description": "Firmware version", "defaultValue": "0", "access": "RO" }, + { "id": "userSettableMaxCurrent", "address": 16390, "size": 2, "type": "uint32", "unit": "mA", "registerType": "holdingRegister", "description": "Maximum user settable charging current", "defaultValue": "32000", "access": "RO" } ] }, { "id": "status", "readSchedule": "update", "registers": [ - { - "id": "errorCode", - "address": 16392, - "size": 2, - "type": "uint32", - "registerType": "holdingRegister", - "description": "Last error code", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "socketLockState", - "address": 16394, - "size": 2, - "type": "uint32", - "registerType": "holdingRegister", - "description": "Socket and cable lock state", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "chargingStateRaw", - "address": 16396, - "size": 2, - "type": "uint32", - "registerType": "holdingRegister", - "description": "Charging state", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "chargingCurrentLimit", - "address": 16398, - "size": 2, - "type": "uint32", - "unit": "mA", - "registerType": "holdingRegister", - "description": "Current charging current limit", - "defaultValue": "6000", - "access": "RO" - }, - { - "id": "currentL1", - "address": 16400, - "size": 2, - "type": "uint32", - "unit": "mA", - "registerType": "holdingRegister", - "description": "Current L1", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "currentL2", - "address": 16402, - "size": 2, - "type": "uint32", - "unit": "mA", - "registerType": "holdingRegister", - "description": "Current L2", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "currentL3", - "address": 16404, - "size": 2, - "type": "uint32", - "unit": "mA", - "registerType": "holdingRegister", - "description": "Current L3", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "voltageL1", - "address": 16406, - "size": 2, - "type": "uint32", - "unit": "0.1V", - "registerType": "holdingRegister", - "description": "Voltage L1", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "voltageL2", - "address": 16408, - "size": 2, - "type": "uint32", - "unit": "0.1V", - "registerType": "holdingRegister", - "description": "Voltage L2", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "voltageL3", - "address": 16410, - "size": 2, - "type": "uint32", - "unit": "0.1V", - "registerType": "holdingRegister", - "description": "Voltage L3", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "activePower", - "address": 16412, - "size": 2, - "type": "uint32", - "unit": "W", - "registerType": "holdingRegister", - "description": "Measured active power", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "sessionEnergy", - "address": 16414, - "size": 2, - "type": "uint32", - "unit": "Wh", - "registerType": "holdingRegister", - "description": "Delivered energy of the current session", - "defaultValue": "0", - "access": "RO" - }, - { - "id": "communicationTimeoutReadback", - "address": 16416, - "size": 1, - "type": "uint16", - "unit": "s", - "registerType": "holdingRegister", - "description": "Communication timeout", - "defaultValue": "60", - "access": "RO" - } + { "id": "errorCode", "address": 16392, "size": 2, "type": "uint32", "registerType": "holdingRegister", "description": "Last error code", "defaultValue": "0", "access": "RO" }, + { "id": "socketLockState", "address": 16394, "size": 2, "type": "uint32", "registerType": "holdingRegister", "description": "Socket and cable lock state", "defaultValue": "0", "access": "RO" }, + { "id": "chargingStateRaw", "address": 16396, "size": 2, "type": "uint32", "registerType": "holdingRegister", "description": "Charging state", "defaultValue": "0", "access": "RO" }, + { "id": "chargingCurrentLimit", "address": 16398, "size": 2, "type": "uint32", "unit": "mA", "registerType": "holdingRegister", "description": "Current charging current limit", "defaultValue": "6000", "access": "RO" }, + { "id": "currentL1", "address": 16400, "size": 2, "type": "uint32", "unit": "mA", "registerType": "holdingRegister", "description": "Current L1", "defaultValue": "0", "access": "RO" }, + { "id": "currentL2", "address": 16402, "size": 2, "type": "uint32", "unit": "mA", "registerType": "holdingRegister", "description": "Current L2", "defaultValue": "0", "access": "RO" }, + { "id": "currentL3", "address": 16404, "size": 2, "type": "uint32", "unit": "mA", "registerType": "holdingRegister", "description": "Current L3", "defaultValue": "0", "access": "RO" }, + { "id": "voltageL1", "address": 16406, "size": 2, "type": "uint32", "unit": "0.1V", "registerType": "holdingRegister", "description": "Voltage L1", "defaultValue": "0", "access": "RO" }, + { "id": "voltageL2", "address": 16408, "size": 2, "type": "uint32", "unit": "0.1V", "registerType": "holdingRegister", "description": "Voltage L2", "defaultValue": "0", "access": "RO" }, + { "id": "voltageL3", "address": 16410, "size": 2, "type": "uint32", "unit": "0.1V", "registerType": "holdingRegister", "description": "Voltage L3", "defaultValue": "0", "access": "RO" }, + { "id": "activePower", "address": 16412, "size": 2, "type": "uint32", "unit": "W", "registerType": "holdingRegister", "description": "Measured active power", "defaultValue": "0", "access": "RO" }, + { "id": "sessionEnergy", "address": 16414, "size": 2, "type": "uint32", "unit": "Wh", "registerType": "holdingRegister", "description": "Delivered energy of the current session", "defaultValue": "0", "access": "RO" }, + { "id": "communicationTimeoutReadback", "address": 16416, "size": 1, "type": "uint16", "unit": "s", "registerType": "holdingRegister", "description": "Communication timeout", "defaultValue": "60", "access": "RO" } ] } + ], + "registers": [ + { "id": "chargingCurrentLimitCommand", "address": 16640, "size": 2, "type": "uint32", "unit": "mA", "registerType": "holdingRegister", "description": "Set charging current limit", "defaultValue": "6000", "access": "WO" }, + { "id": "socketLockCommand", "address": 16642, "size": 1, "type": "uint16", "registerType": "holdingRegister", "description": "Socket lock control", "defaultValue": "0", "access": "WO" }, + { "id": "startStopChargingSession", "address": 16645, "size": 1, "type": "uint16", "registerType": "holdingRegister", "description": "Start or stop charging session", "defaultValue": "0", "access": "WO" }, + { "id": "communicationTimeoutCommand", "address": 16646, "size": 1, "type": "uint16", "unit": "s", "registerType": "holdingRegister", "description": "Set communication timeout", "defaultValue": "60", "access": "WO" } ] } diff --git a/abbterra/integrationpluginabbterra.cpp b/abbterra/integrationpluginabbterra.cpp index 9c6a351..762181a 100644 --- a/abbterra/integrationpluginabbterra.cpp +++ b/abbterra/integrationpluginabbterra.cpp @@ -133,7 +133,93 @@ void IntegrationPluginAbbterra::thingRemoved(Thing *thing) void IntegrationPluginAbbterra::executeAction(ThingActionInfo *info) { - // Read-only mode: WO registers removed for compatibility with libnymea-modbus 1.15 + 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; + } + } + info->finish(Thing::ThingErrorUnsupportedFeature); } @@ -194,6 +280,7 @@ 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) { @@ -221,6 +308,11 @@ 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) @@ -264,6 +356,7 @@ 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) { @@ -291,8 +384,33 @@ 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.json b/abbterra/integrationpluginabbterra.json index c08aa71..392c218 100644 --- a/abbterra/integrationpluginabbterra.json +++ b/abbterra/integrationpluginabbterra.json @@ -107,19 +107,23 @@ "id": "207e2074-0147-4617-9a8b-3f326dcd6a0b", "name": "power", "displayName": "Charging enabled", + "displayNameAction": "Set charging enabled", "type": "bool", - "defaultValue": true + "defaultValue": true, + "writable": 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 + "defaultValue": 6, + "writable": true }, { "id": "0764bce9-fd26-4da8-8d92-f6a5ce73e81e", @@ -290,19 +294,23 @@ "id": "e35fd4fa-bf5a-45a1-8a39-f0d3d9efa4c6", "name": "power", "displayName": "Charging enabled", + "displayNameAction": "Set charging enabled", "type": "bool", - "defaultValue": true + "defaultValue": true, + "writable": 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 + "defaultValue": 6, + "writable": true }, { "id": "cd1add95-18d9-46b5-a3d5-f0f29d5160c9",