nettoyage

This commit is contained in:
Patrick Schurig 2026-06-01 07:40:11 +02:00
parent d7cb358b05
commit 8742444b4d
14 changed files with 0 additions and 1971 deletions

View File

@ -1,19 +0,0 @@
# ABB Terra AC
This plugin integrates ABB Terra AC chargers via Modbus TCP and Modbus RTU.
Implemented features:
- network discovery for Modbus TCP chargers
- Modbus RTU discovery using nymea's managed RTU hardware resource
- connection state
- plugged-in and charging state detection
- charging enable/disable via current-limit control
- writable maximum charging current
- active power and session energy
- firmware version, serial number, and error code
- communication timeout setting
The register model is based on:
- `ABB_Terra_AC_Charger_ModbusCommunication_v1.7.pdf`

View File

@ -1,243 +0,0 @@
{
"className": "AbbTerra",
"protocol": "BOTH",
"endianness": "BigEndian",
"stringEndianness": "BigEndian",
"errorLimitUntilNotReachable": 3,
"checkReachableRegister": "serialNumber",
"queuedRequests": true,
"queuedRequestsDelay": 50,
"blocks": [
{
"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": "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"
}
]
}
],
"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"
}
]
}

View File

@ -1,20 +0,0 @@
include(../plugins.pri)
MODBUS_CONNECTIONS += abbterra-registers.json
MODBUS_TOOLS_CONFIG += VERBOSE
include(../modbus.pri)
TARGET = $$qtLibraryTarget(nymea_integrationpluginabbterra)
OTHER_FILES += abbterra-registers.json
SOURCES += \
abbterrartudiscovery.cpp \
abbterratcpdiscovery.cpp \
integrationpluginabbterra.cpp
HEADERS += \
abbterrartudiscovery.h \
abbterratcpdiscovery.h \
abbterrautils.h \
integrationpluginabbterra.h

View File

@ -1,76 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "abbterrartudiscovery.h"
#include "abbterrautils.h"
#include "extern-plugininfo.h"
AbbTerraRtuDiscovery::AbbTerraRtuDiscovery(ModbusRtuHardwareResource *modbusRtuResource, QObject *parent)
: QObject(parent),
m_modbusRtuResource(modbusRtuResource)
{
}
void AbbTerraRtuDiscovery::startDiscovery()
{
qCInfo(dcAbbTerra()) << "Discovery: Searching for ABB Terra AC chargers on Modbus RTU...";
m_candidateMasters.clear();
m_results.clear();
m_masterIndex = 0;
m_slaveId = 1;
foreach (ModbusRtuMaster *master, m_modbusRtuResource->modbusRtuMasters()) {
if (master->connected()) {
m_candidateMasters.append(master);
}
}
if (m_candidateMasters.isEmpty()) {
qCWarning(dcAbbTerra()) << "No connected Modbus RTU master available for ABB Terra AC discovery.";
emit discoveryFinished(false);
return;
}
scanNext();
}
QList<AbbTerraRtuDiscovery::Result> AbbTerraRtuDiscovery::results() const
{
return m_results;
}
void AbbTerraRtuDiscovery::scanNext()
{
if (m_masterIndex >= m_candidateMasters.count()) {
emit discoveryFinished(true);
return;
}
if (m_slaveId > 247) {
m_masterIndex++;
m_slaveId = 1;
scanNext();
return;
}
ModbusRtuMaster *master = m_candidateMasters.at(m_masterIndex);
const quint16 currentSlaveId = m_slaveId++;
ModbusRtuReply *reply = master->readHoldingRegister(currentSlaveId, 0x4000, 8);
connect(reply, &ModbusRtuReply::finished, this, [this, master, currentSlaveId, reply]() {
if (reply->error() == ModbusRtuReply::NoError) {
const AbbTerraUtils::DeviceInfo deviceInfo = AbbTerraUtils::deviceInfoFromRegisters(reply->result());
if (deviceInfo.valid) {
Result result;
result.modbusRtuMasterId = master->modbusUuid();
result.slaveId = currentSlaveId;
result.serialNumber = deviceInfo.serialNumber;
result.productName = deviceInfo.productName;
result.firmwareVersion = deviceInfo.firmwareVersion;
m_results.append(result);
}
}
scanNext();
});
}

View File

@ -1,41 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef ABBTERRARTUDISCOVERY_H
#define ABBTERRARTUDISCOVERY_H
#include <QObject>
#include <hardware/modbus/modbusrtuhardwareresource.h>
class AbbTerraRtuDiscovery : public QObject
{
Q_OBJECT
public:
struct Result {
QUuid modbusRtuMasterId;
quint16 slaveId;
QString serialNumber;
QString productName;
QString firmwareVersion;
};
explicit AbbTerraRtuDiscovery(ModbusRtuHardwareResource *modbusRtuResource, QObject *parent = nullptr);
void startDiscovery();
QList<Result> results() const;
signals:
void discoveryFinished(bool modbusRtuMasterAvailable);
private:
void scanNext();
private:
ModbusRtuHardwareResource *m_modbusRtuResource = nullptr;
QList<ModbusRtuMaster *> m_candidateMasters;
QList<Result> m_results;
int m_masterIndex = 0;
quint16 m_slaveId = 1;
};
#endif // ABBTERRARTUDISCOVERY_H

View File

@ -1,127 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "abbterratcpdiscovery.h"
#include "abbterrautils.h"
#include "extern-plugininfo.h"
#include <QTime>
#include <QTimer>
#include <utility>
AbbTerraTcpDiscovery::AbbTerraTcpDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, QObject *parent)
: QObject(parent),
m_networkDeviceDiscovery(networkDeviceDiscovery)
{
}
void AbbTerraTcpDiscovery::startDiscovery()
{
qCInfo(dcAbbTerra()) << "Discovery: Starting to search for ABB Terra AC chargers on the network...";
m_startDateTime = QDateTime::currentDateTime();
m_networkDeviceInfos.clear();
m_temporaryResults.clear();
m_results.clear();
NetworkDeviceDiscoveryReply *discoveryReply = m_networkDeviceDiscovery->discover();
connect(discoveryReply, &NetworkDeviceDiscoveryReply::hostAddressDiscovered, this, &AbbTerraTcpDiscovery::checkNetworkDevice);
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, discoveryReply, &NetworkDeviceDiscoveryReply::deleteLater);
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [this, discoveryReply]() {
m_networkDeviceInfos = discoveryReply->networkDeviceInfos();
QTimer::singleShot(3000, this, &AbbTerraTcpDiscovery::finishDiscovery);
});
}
QList<AbbTerraTcpDiscovery::Result> AbbTerraTcpDiscovery::results() const
{
return m_results;
}
void AbbTerraTcpDiscovery::checkNetworkDevice(const QHostAddress &address)
{
AbbTerraModbusTcpConnection *connection = new AbbTerraModbusTcpConnection(address, 502, 1, this);
m_connections.append(connection);
connect(connection, &AbbTerraModbusTcpConnection::reachableChanged, this, [this, connection](bool reachable) {
if (!reachable) {
cleanupConnection(connection);
return;
}
connection->initialize();
});
connect(connection, &AbbTerraModbusTcpConnection::initializationFinished, this, [this, connection, address](bool success) {
if (!success) {
cleanupConnection(connection);
return;
}
const AbbTerraUtils::DeviceInfo deviceInfo = AbbTerraUtils::deviceInfoFromValues(connection->serialNumber(),
connection->firmwareVersionRaw(),
connection->userSettableMaxCurrent());
if (deviceInfo.valid) {
Result result;
result.serialNumber = deviceInfo.serialNumber;
result.productName = deviceInfo.productName;
result.firmwareVersion = deviceInfo.firmwareVersion;
result.networkDeviceInfo = m_networkDeviceInfos.get(address);
if (result.networkDeviceInfo.address().isNull()) {
NetworkDeviceInfo info;
info.setAddress(address);
result.networkDeviceInfo = info;
}
m_temporaryResults.append(result);
}
cleanupConnection(connection);
});
connect(connection->modbusTcpMaster(), &ModbusTcpMaster::connectionErrorOccurred, this, [this, connection](QModbusDevice::Error error) {
if (error != QModbusDevice::NoError) {
cleanupConnection(connection);
}
});
connect(connection, &AbbTerraModbusTcpConnection::checkReachabilityFailed, this, [this, connection]() {
cleanupConnection(connection);
});
connection->connectDevice();
}
void AbbTerraTcpDiscovery::cleanupConnection(AbbTerraModbusTcpConnection *connection)
{
m_connections.removeAll(connection);
connection->disconnectDevice();
connection->deleteLater();
}
void AbbTerraTcpDiscovery::finishDiscovery()
{
foreach (const Result &result, m_temporaryResults) {
bool known = false;
foreach (const Result &existing, m_results) {
if (existing.serialNumber == result.serialNumber || existing.networkDeviceInfo.address() == result.networkDeviceInfo.address()) {
known = true;
break;
}
}
if (!known) {
qCDebug(dcAbbTerra()) << "Discovery: Found" << result.productName << result.networkDeviceInfo;
m_results.append(result);
}
}
const QList<AbbTerraModbusTcpConnection *> leftoverConnections = m_connections;
foreach (AbbTerraModbusTcpConnection *connection, leftoverConnections) {
cleanupConnection(connection);
}
const qint64 durationMilliSeconds = QDateTime::currentMSecsSinceEpoch() - m_startDateTime.toMSecsSinceEpoch();
qCInfo(dcAbbTerra()) << "Discovery: Finished ABB Terra AC network discovery in"
<< QTime::fromMSecsSinceStartOfDay(durationMilliSeconds).toString("mm:ss.zzz")
<< "with" << m_results.count() << "result(s).";
emit discoveryFinished();
}

View File

@ -1,46 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef ABBTERRATCPDISCOVERY_H
#define ABBTERRATCPDISCOVERY_H
#include <QObject>
#include <QDateTime>
#include <network/networkdevicediscovery.h>
#include "abbterramodbustcpconnection.h"
class AbbTerraTcpDiscovery : public QObject
{
Q_OBJECT
public:
struct Result {
NetworkDeviceInfo networkDeviceInfo;
QString serialNumber;
QString productName;
QString firmwareVersion;
};
explicit AbbTerraTcpDiscovery(NetworkDeviceDiscovery *networkDeviceDiscovery, QObject *parent = nullptr);
void startDiscovery();
QList<Result> results() const;
signals:
void discoveryFinished();
private:
void checkNetworkDevice(const QHostAddress &address);
void cleanupConnection(AbbTerraModbusTcpConnection *connection);
void finishDiscovery();
private:
NetworkDeviceDiscovery *m_networkDeviceDiscovery = nullptr;
QDateTime m_startDateTime;
NetworkDeviceInfos m_networkDeviceInfos;
QList<AbbTerraModbusTcpConnection *> m_connections;
QList<Result> m_results;
QList<Result> m_temporaryResults;
};
#endif // ABBTERRATCPDISCOVERY_H

View File

@ -1,145 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef ABBTERRAUTILS_H
#define ABBTERRAUTILS_H
#include <QString>
#include <QVector>
#include <modbusdatautils.h>
namespace AbbTerraUtils {
struct DeviceInfo {
bool valid = false;
QString serialNumber;
QString productName;
QString firmwareVersion;
double maxChargingCurrent = 32.0;
};
inline QString connectorTypeName(quint8 connectorType)
{
switch (connectorType) {
case 'G':
return QStringLiteral("Cable");
case 'P':
return QStringLiteral("Outlet");
case 'S':
return QStringLiteral("Socket");
case 'T':
return QStringLiteral("Socket");
default:
return QString();
}
}
inline int ratedPowerFromCode(quint8 ratedPowerCode)
{
switch (ratedPowerCode) {
case 7:
return 7;
case 11:
return 11;
case 22:
return 22;
default:
return -1;
}
}
inline DeviceInfo deviceInfoFromValues(quint64 serialNumberRaw, quint32 firmwareVersionRaw, quint32 maxCurrentRaw)
{
DeviceInfo deviceInfo;
const quint8 connectorType = static_cast<quint8>((serialNumberRaw >> 56) & 0xff);
const quint8 ratedPowerCode = static_cast<quint8>((serialNumberRaw >> 48) & 0xff);
const quint8 plantId = static_cast<quint8>((serialNumberRaw >> 40) & 0xff);
const quint8 productionWeek = static_cast<quint8>((serialNumberRaw >> 24) & 0xff);
const quint8 productionYear = static_cast<quint8>((serialNumberRaw >> 16) & 0xff);
const quint8 uniqueHigh = static_cast<quint8>((serialNumberRaw >> 8) & 0xff);
const quint8 uniqueLow = static_cast<quint8>(serialNumberRaw & 0xff);
const int ratedPower = ratedPowerFromCode(ratedPowerCode);
const QString connectorName = connectorTypeName(connectorType);
if (ratedPower <= 0 || connectorName.isEmpty() || productionWeek == 0 || productionWeek > 53) {
return deviceInfo;
}
deviceInfo.valid = true;
deviceInfo.serialNumber = QStringLiteral("TACW%1-%2-%3%4-%5%6%7")
.arg(ratedPower)
.arg(plantId)
.arg(productionWeek, 2, 10, QLatin1Char('0'))
.arg(productionYear, 2, 10, QLatin1Char('0'))
.arg(QChar(static_cast<char>(connectorType)))
.arg(uniqueHigh, 2, 10, QLatin1Char('0'))
.arg(uniqueLow, 2, 10, QLatin1Char('0'));
deviceInfo.productName = QStringLiteral("ABB Terra AC %1 kW %2").arg(ratedPower).arg(connectorName);
deviceInfo.firmwareVersion = QStringLiteral("%1.%2.%3")
.arg((firmwareVersionRaw >> 24) & 0xff)
.arg((firmwareVersionRaw >> 16) & 0xff)
.arg((firmwareVersionRaw >> 8) & 0xff);
if (maxCurrentRaw >= 6000 && maxCurrentRaw <= 32000) {
deviceInfo.maxChargingCurrent = maxCurrentRaw / 1000.0;
}
return deviceInfo;
}
inline DeviceInfo deviceInfoFromRegisters(const QVector<quint16> &registers)
{
if (registers.count() < 8) {
return DeviceInfo();
}
return deviceInfoFromValues(
ModbusDataUtils::convertToUInt64(registers.mid(0, 4), ModbusDataUtils::ByteOrderBigEndian),
ModbusDataUtils::convertToUInt32(registers.mid(4, 2), ModbusDataUtils::ByteOrderBigEndian),
ModbusDataUtils::convertToUInt32(registers.mid(6, 2), ModbusDataUtils::ByteOrderBigEndian)
);
}
inline quint8 chargingStateCode(quint32 chargingStateRaw)
{
return static_cast<quint8>((chargingStateRaw >> 8) & 0x7f);
}
inline bool chargingLimitedByCar(quint32 chargingStateRaw)
{
return ((chargingStateRaw >> 15) & 0x1) == 0x1;
}
inline bool isVehiclePluggedIn(quint32 chargingStateRaw, quint32 socketLockState)
{
const quint8 chargingState = chargingStateCode(chargingStateRaw);
if (chargingState >= 3 && chargingState <= 6) {
return true;
}
return socketLockState == 0x0101 || socketLockState == 0x0111;
}
inline bool isCharging(quint32 chargingStateRaw, quint32 activePower)
{
return chargingStateCode(chargingStateRaw) == 6 || activePower > 100;
}
inline uint phaseCount(quint32 voltageL1, quint32 voltageL2, quint32 voltageL3)
{
uint phases = 0;
if (voltageL1 > 1000) {
phases++;
}
if (voltageL2 > 1000) {
phases++;
}
if (voltageL3 > 1000) {
phases++;
}
return qMax(phases, 1u);
}
} // namespace AbbTerraUtils
#endif // ABBTERRAUTILS_H

View File

@ -1,483 +0,0 @@
#include "integrationpluginabbterra.h"
#include "abbterrartudiscovery.h"
#include "abbterratcpdiscovery.h"
#include "abbterrautils.h"
#include "integrations/thing.h"
#include "integrations/thingactioninfo.h"
#include "integrations/thingdescriptor.h"
#include "integrations/thingdiscoveryinfo.h"
#include "integrations/thingsetupinfo.h"
#include "plugininfo.h"
#include <QLoggingCategory>
#include <QtMath>
#include <utility>
#include <hardwaremanager.h>
#include <hardware/modbus/modbusrtuhardwareresource.h>
#include <network/networkdevicediscovery.h>
IntegrationPluginAbbterra::IntegrationPluginAbbterra()
{
}
void IntegrationPluginAbbterra::discoverThings(ThingDiscoveryInfo *info)
{
if (info->thingClassId() == terraAcTcpThingClassId) {
AbbTerraTcpDiscovery *discovery = new AbbTerraTcpDiscovery(hardwareManager()->networkDeviceDiscovery(), info);
connect(discovery, &AbbTerraTcpDiscovery::discoveryFinished, info, [this, info, discovery]() {
foreach (const AbbTerraTcpDiscovery::Result &result, discovery->results()) {
ThingDescriptor descriptor(terraAcTcpThingClassId, result.productName, result.serialNumber);
ParamList params;
params.append(Param(terraAcTcpThingMacAddressParamTypeId, result.networkDeviceInfo.thingParamValueMacAddress()));
params.append(Param(terraAcTcpThingHostNameParamTypeId, result.networkDeviceInfo.thingParamValueHostName()));
params.append(Param(terraAcTcpThingAddressParamTypeId, result.networkDeviceInfo.thingParamValueAddress()));
params.append(Param(terraAcTcpThingPortParamTypeId, 502));
params.append(Param(terraAcTcpThingSlaveIdParamTypeId, 1));
descriptor.setParams(params);
if (Thing *existingThing = myThings().findByParams(params)) {
descriptor.setThingId(existingThing->id());
}
info->addThingDescriptor(descriptor);
}
info->finish(Thing::ThingErrorNoError);
});
discovery->startDiscovery();
return;
}
if (info->thingClassId() == terraAcRtuThingClassId) {
AbbTerraRtuDiscovery *discovery = new AbbTerraRtuDiscovery(hardwareManager()->modbusRtuResource(), info);
connect(discovery, &AbbTerraRtuDiscovery::discoveryFinished, info, [this, info, discovery](bool modbusRtuMasterAvailable) {
if (!modbusRtuMasterAvailable) {
info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("No connected Modbus RTU master available."));
return;
}
foreach (const AbbTerraRtuDiscovery::Result &result, discovery->results()) {
ThingDescriptor descriptor(terraAcRtuThingClassId, result.productName, QStringLiteral("Slave ID: %1").arg(result.slaveId));
ParamList params{
Param(terraAcRtuThingRtuMasterParamTypeId, result.modbusRtuMasterId),
Param(terraAcRtuThingSlaveIdParamTypeId, result.slaveId)
};
descriptor.setParams(params);
if (Thing *existingThing = myThings().findByParams(params)) {
descriptor.setThingId(existingThing->id());
}
info->addThingDescriptor(descriptor);
}
info->finish(Thing::ThingErrorNoError);
});
discovery->startDiscovery();
return;
}
info->finish(Thing::ThingErrorNoError);
}
void IntegrationPluginAbbterra::setupThing(ThingSetupInfo *info)
{
if (info->thing()->thingClassId() == terraAcTcpThingClassId) {
setupTcpThing(info);
return;
}
if (info->thing()->thingClassId() == terraAcRtuThingClassId) {
setupRtuThing(info);
return;
}
info->finish(Thing::ThingErrorUnsupportedFeature);
}
void IntegrationPluginAbbterra::postSetupThing(Thing *thing)
{
Q_UNUSED(thing)
if (m_pluginTimer) {
return;
}
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(30);
connect(m_pluginTimer, &PluginTimer::timeout, this, [this]() {
foreach (AbbTerraModbusTcpConnection *connection, m_tcpConnections) {
connection->update();
}
foreach (AbbTerraModbusRtuConnection *connection, m_rtuConnections) {
connection->update();
}
});
m_pluginTimer->start();
}
void IntegrationPluginAbbterra::thingRemoved(Thing *thing)
{
delete m_tcpConnections.take(thing);
delete m_rtuConnections.take(thing);
if (m_monitors.contains(thing)) {
hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
}
if (myThings().isEmpty() && m_pluginTimer) {
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
m_pluginTimer = nullptr;
}
}
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<quint32>(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<quint32>(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<quint32>(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<quint32>(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);
}
void IntegrationPluginAbbterra::setupTcpThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
if (m_tcpConnections.contains(thing)) {
m_tcpConnections.take(thing)->deleteLater();
}
NetworkDeviceMonitor *monitor = m_monitors.value(thing);
if (!monitor) {
monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(thing);
if (!monitor) {
info->finish(Thing::ThingErrorInvalidParameter);
return;
}
m_monitors.insert(thing, monitor);
}
const quint16 port = static_cast<quint16>(thing->paramValue(terraAcTcpThingPortParamTypeId).toUInt());
const quint16 slaveId = static_cast<quint16>(thing->paramValue(terraAcTcpThingSlaveIdParamTypeId).toUInt());
AbbTerraModbusTcpConnection *connection = new AbbTerraModbusTcpConnection(monitor->networkDeviceInfo().address(), port, slaveId, thing);
connect(info, &ThingSetupInfo::aborted, connection, &AbbTerraModbusTcpConnection::deleteLater);
connect(info, &ThingSetupInfo::aborted, monitor, [this, thing]() {
if (m_monitors.contains(thing)) {
hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
}
});
connect(monitor, &NetworkDeviceMonitor::networkDeviceInfoChanged, connection, [connection](const NetworkDeviceInfo &networkDeviceInfo) {
connection->modbusTcpMaster()->setHostAddress(networkDeviceInfo.address());
});
connect(connection, &AbbTerraModbusTcpConnection::reachableChanged, thing, [this, thing, connection](bool reachable) {
if (reachable) {
connection->initialize();
} else {
setDisconnectedState(thing);
}
});
connect(connection, &AbbTerraModbusTcpConnection::initializationFinished, thing, [this, thing, connection](bool success) {
if (!success) {
return;
}
const AbbTerraUtils::DeviceInfo deviceInfo = AbbTerraUtils::deviceInfoFromValues(connection->serialNumber(),
connection->firmwareVersionRaw(),
connection->userSettableMaxCurrent());
if (!deviceInfo.valid) {
return;
}
thing->setStateValue(terraAcTcpConnectedStateTypeId, true);
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) {
if (!success) {
connection->deleteLater();
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Could not initialize the communication with the charger."));
return;
}
const AbbTerraUtils::DeviceInfo deviceInfo = AbbTerraUtils::deviceInfoFromValues(connection->serialNumber(),
connection->firmwareVersionRaw(),
connection->userSettableMaxCurrent());
if (!deviceInfo.valid) {
connection->deleteLater();
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("The device does not match the ABB Terra AC Modbus register map."));
return;
}
m_tcpConnections.insert(thing, connection);
connection->update();
info->finish(Thing::ThingErrorNoError);
});
connect(connection, &AbbTerraModbusTcpConnection::updateFinished, thing, [this, thing, connection]() {
updateThing(thing, connection);
});
connect(thing, &Thing::settingChanged, connection, [this, thing, connection](const ParamTypeId &paramTypeId, const QVariant &) {
if (paramTypeId == terraAcTcpSettingsCommunicationTimeoutParamTypeId) {
applyTimeoutSetting(thing, connection);
}
});
}
void IntegrationPluginAbbterra::setupRtuThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
if (m_rtuConnections.contains(thing)) {
m_rtuConnections.take(thing)->deleteLater();
}
ModbusRtuMaster *master = hardwareManager()->modbusRtuResource()->getModbusRtuMaster(thing->paramValue(terraAcRtuThingRtuMasterParamTypeId).toUuid());
if (!master) {
info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("The Modbus RTU connection is not available."));
return;
}
const quint16 slaveId = static_cast<quint16>(thing->paramValue(terraAcRtuThingSlaveIdParamTypeId).toUInt());
AbbTerraModbusRtuConnection *connection = new AbbTerraModbusRtuConnection(master, slaveId, thing);
connect(connection, &AbbTerraModbusRtuConnection::reachableChanged, thing, [this, thing, connection](bool reachable) {
if (reachable) {
connection->initialize();
} else {
setDisconnectedState(thing);
}
});
connect(connection, &AbbTerraModbusRtuConnection::initializationFinished, thing, [this, thing, connection](bool success) {
if (!success) {
return;
}
const AbbTerraUtils::DeviceInfo deviceInfo = AbbTerraUtils::deviceInfoFromValues(connection->serialNumber(),
connection->firmwareVersionRaw(),
connection->userSettableMaxCurrent());
if (!deviceInfo.valid) {
return;
}
thing->setStateValue(terraAcRtuConnectedStateTypeId, true);
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) {
if (!success) {
connection->deleteLater();
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Could not initialize the communication with the charger."));
return;
}
const AbbTerraUtils::DeviceInfo deviceInfo = AbbTerraUtils::deviceInfoFromValues(connection->serialNumber(),
connection->firmwareVersionRaw(),
connection->userSettableMaxCurrent());
if (!deviceInfo.valid) {
connection->deleteLater();
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("The device does not match the ABB Terra AC Modbus register map."));
return;
}
m_rtuConnections.insert(thing, connection);
connection->update();
info->finish(Thing::ThingErrorNoError);
});
connect(connection, &AbbTerraModbusRtuConnection::updateFinished, thing, [this, thing, connection]() {
updateThing(thing, connection);
});
connect(thing, &Thing::settingChanged, connection, [this, thing, connection](const ParamTypeId &paramTypeId, const QVariant &) {
if (paramTypeId == terraAcRtuSettingsCommunicationTimeoutParamTypeId) {
applyTimeoutSetting(thing, connection);
}
});
}
void IntegrationPluginAbbterra::applyTimeoutSetting(Thing *thing, AbbTerraModbusTcpConnection *connection)
{
QModbusReply *reply = connection->setCommunicationTimeoutCommand(static_cast<quint16>(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<quint16>(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)
{
thing->setStateValue(terraAcTcpConnectedStateTypeId, connection->reachable());
thing->setStateValue(terraAcTcpPluggedInStateTypeId, AbbTerraUtils::isVehiclePluggedIn(connection->chargingStateRaw(), connection->socketLockState()));
thing->setStateValue(terraAcTcpChargingStateTypeId, AbbTerraUtils::isCharging(connection->chargingStateRaw(), connection->activePower()));
thing->setStateValue(terraAcTcpPowerStateTypeId, connection->chargingCurrentLimit() >= 6000);
thing->setStateValue(terraAcTcpMaxChargingCurrentStateTypeId, connection->chargingCurrentLimit() / 1000.0);
thing->setStateValue(terraAcTcpPhaseCountStateTypeId, AbbTerraUtils::phaseCount(connection->voltageL1(), connection->voltageL2(), connection->voltageL3()));
thing->setStateValue(terraAcTcpCurrentPowerStateTypeId, static_cast<double>(connection->activePower()));
thing->setStateValue("currentPhase1", connection->currentL1() / 1000.0);
thing->setStateValue("currentPhase2", connection->currentL2() / 1000.0);
thing->setStateValue("currentPhase3", connection->currentL3() / 1000.0);
thing->setStateValue("voltagePhase1", connection->voltageL1() / 10.0);
thing->setStateValue("voltagePhase2", connection->voltageL2() / 10.0);
thing->setStateValue("voltagePhase3", connection->voltageL3() / 10.0);
thing->setStateValue(terraAcTcpSessionEnergyStateTypeId, connection->sessionEnergy() / 1000.0);
thing->setStateValue(terraAcTcpErrorCodeStateTypeId, connection->errorCode());
thing->setSettingValue(terraAcTcpSettingsCommunicationTimeoutParamTypeId, connection->communicationTimeoutReadback());
}
void IntegrationPluginAbbterra::updateThing(Thing *thing, AbbTerraModbusRtuConnection *connection)
{
thing->setStateValue(terraAcRtuConnectedStateTypeId, connection->reachable());
thing->setStateValue(terraAcRtuPluggedInStateTypeId, AbbTerraUtils::isVehiclePluggedIn(connection->chargingStateRaw(), connection->socketLockState()));
thing->setStateValue(terraAcRtuChargingStateTypeId, AbbTerraUtils::isCharging(connection->chargingStateRaw(), connection->activePower()));
thing->setStateValue(terraAcRtuPowerStateTypeId, connection->chargingCurrentLimit() >= 6000);
thing->setStateValue(terraAcRtuMaxChargingCurrentStateTypeId, connection->chargingCurrentLimit() / 1000.0);
thing->setStateValue(terraAcRtuPhaseCountStateTypeId, AbbTerraUtils::phaseCount(connection->voltageL1(), connection->voltageL2(), connection->voltageL3()));
thing->setStateValue(terraAcRtuCurrentPowerStateTypeId, static_cast<double>(connection->activePower()));
thing->setStateValue("currentPhase1", connection->currentL1() / 1000.0);
thing->setStateValue("currentPhase2", connection->currentL2() / 1000.0);
thing->setStateValue("currentPhase3", connection->currentL3() / 1000.0);
thing->setStateValue("voltagePhase1", connection->voltageL1() / 10.0);
thing->setStateValue("voltagePhase2", connection->voltageL2() / 10.0);
thing->setStateValue("voltagePhase3", connection->voltageL3() / 10.0);
thing->setStateValue(terraAcRtuSessionEnergyStateTypeId, connection->sessionEnergy() / 1000.0);
thing->setStateValue(terraAcRtuErrorCodeStateTypeId, connection->errorCode());
thing->setSettingValue(terraAcRtuSettingsCommunicationTimeoutParamTypeId, connection->communicationTimeoutReadback());
}
void IntegrationPluginAbbterra::setDisconnectedState(Thing *thing)
{
if (thing->thingClassId() == terraAcTcpThingClassId) {
thing->setStateValue(terraAcTcpConnectedStateTypeId, false);
thing->setStateValue(terraAcTcpChargingStateTypeId, false);
thing->setStateValue(terraAcTcpPluggedInStateTypeId, false);
thing->setStateValue(terraAcTcpCurrentPowerStateTypeId, 0);
thing->setStateValue("currentPhase1", 0);
thing->setStateValue("currentPhase2", 0);
thing->setStateValue("currentPhase3", 0);
thing->setStateValue("voltagePhase1", 0);
thing->setStateValue("voltagePhase2", 0);
thing->setStateValue("voltagePhase3", 0);
return;
}
if (thing->thingClassId() == terraAcRtuThingClassId) {
thing->setStateValue(terraAcRtuConnectedStateTypeId, false);
thing->setStateValue(terraAcRtuChargingStateTypeId, false);
thing->setStateValue(terraAcRtuPluggedInStateTypeId, false);
thing->setStateValue(terraAcRtuCurrentPowerStateTypeId, 0);
thing->setStateValue("currentPhase1", 0);
thing->setStateValue("currentPhase2", 0);
thing->setStateValue("currentPhase3", 0);
thing->setStateValue("voltagePhase1", 0);
thing->setStateValue("voltagePhase2", 0);
thing->setStateValue("voltagePhase3", 0);
}
}

View File

@ -1,46 +0,0 @@
#ifndef INTEGRATIONPLUGINABBTERRA_H
#define INTEGRATIONPLUGINABBTERRA_H
#include <plugintimer.h>
#include "integrations/integrationplugin.h"
#include <network/networkdevicemonitor.h>
#include "extern-plugininfo.h"
#include "abbterramodbusrtuconnection.h"
#include "abbterramodbustcpconnection.h"
class IntegrationPluginAbbterra : public IntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginabbterra.json")
Q_INTERFACES(IntegrationPlugin)
public:
explicit IntegrationPluginAbbterra();
void discoverThings(ThingDiscoveryInfo *info) override;
void setupThing(ThingSetupInfo *info) override;
void postSetupThing(Thing *thing) override;
void thingRemoved(Thing *thing) override;
public slots:
void executeAction(ThingActionInfo *info) override;
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);
private:
PluginTimer *m_pluginTimer = nullptr;
QHash<Thing *, AbbTerraModbusTcpConnection *> m_tcpConnections;
QHash<Thing *, AbbTerraModbusRtuConnection *> m_rtuConnections;
QHash<Thing *, NetworkDeviceMonitor *> m_monitors;
};
#endif // INTEGRATIONPLUGINABBTERRA_H

View File

@ -1,416 +0,0 @@
{
"name": "AbbTerra",
"displayName": "ABB Terra AC",
"id": "d7f1cb28-b18b-449e-8cd2-1d99b9d8f681",
"paramTypes": [],
"vendors": [
{
"id": "0369ebad-5186-437d-b520-041a0b9b7582",
"name": "abb",
"displayName": "ABB",
"thingClasses": [
{
"id": "93ad828a-9a7a-4fca-be3f-88641317845f",
"name": "terraAcTcp",
"displayName": "Terra AC Charger (TCP)",
"interfaces": [
"evcharger",
"connectable",
"networkdevice"
],
"createMethods": [
"discovery",
"user"
],
"discoveryType": "weak",
"paramTypes": [
{
"id": "9b3332aa-6c26-4399-b3dc-d7fdbe3f4420",
"name": "macAddress",
"displayName": "MAC address",
"type": "QString",
"inputType": "MacAddress",
"defaultValue": "",
"readOnly": true
},
{
"id": "962ef9d9-30a2-4636-8ff2-2a28742277f4",
"name": "address",
"displayName": "Host address",
"type": "QString",
"inputType": "IPv4Address",
"defaultValue": ""
},
{
"id": "f9e6fed4-2a18-4f23-b70e-78919d4b01f8",
"name": "hostName",
"displayName": "Host name",
"type": "QString",
"inputType": "TextLine",
"defaultValue": ""
},
{
"id": "153258dd-e81b-48e5-9ba7-46d59e854d85",
"name": "port",
"displayName": "Port",
"type": "uint",
"defaultValue": 502
},
{
"id": "cc4c66c1-185f-4c97-88a0-2bc66319d157",
"name": "slaveId",
"displayName": "Slave ID",
"type": "uint",
"defaultValue": 1,
"minValue": 1,
"maxValue": 255
}
],
"settingsTypes": [
{
"id": "5a0e678a-ffc8-443a-9ae7-bb2243b0ec4b",
"name": "communicationTimeout",
"displayName": "Communication timeout",
"type": "uint",
"unit": "Seconds",
"defaultValue": 60,
"minValue": 10,
"maxValue": 65535
}
],
"stateTypes": [
{
"id": "21e1a2bb-0e05-462c-9909-4f9a0eada438",
"name": "connected",
"displayName": "Connected",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "2fb30a0b-dc5a-4831-b5c6-de653c0c9ee1",
"name": "pluggedIn",
"displayName": "Plugged in",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "0c685ced-27fa-46ba-8c0b-c49af82054f0",
"name": "charging",
"displayName": "Charging",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "207e2074-0147-4617-9a8b-3f326dcd6a0b",
"name": "power",
"displayName": "Charging enabled",
"displayNameAction": "Set charging enabled",
"type": "bool",
"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,
"writable": true
},
{
"id": "0764bce9-fd26-4da8-8d92-f6a5ce73e81e",
"name": "phaseCount",
"displayName": "Phase count",
"type": "uint",
"minValue": 1,
"maxValue": 3,
"defaultValue": 1
},
{
"id": "59b486a3-aa44-4a94-8478-1077af124441",
"name": "currentPower",
"displayName": "Active power",
"type": "double",
"unit": "Watt",
"defaultValue": 0,
"cached": false
},
{
"id": "953ce672-a9a2-4cd6-bf87-ccfe720c7595",
"name": "currentPhase1",
"displayName": "Current phase 1",
"type": "double",
"unit": "Ampere",
"defaultValue": 0
},
{
"id": "e4f97cde-191c-4c84-9668-169c5e648338",
"name": "currentPhase2",
"displayName": "Current phase 2",
"type": "double",
"unit": "Ampere",
"defaultValue": 0
},
{
"id": "c1cead50-9894-4b12-9211-c5bc84109b1d",
"name": "currentPhase3",
"displayName": "Current phase 3",
"type": "double",
"unit": "Ampere",
"defaultValue": 0
},
{
"id": "bcff4c2d-5567-40ff-adef-5b47dc5ace76",
"name": "voltagePhase1",
"displayName": "Voltage phase 1",
"type": "double",
"unit": "Volt",
"defaultValue": 0
},
{
"id": "db7af25a-cb7b-4640-9515-a7af345bd770",
"name": "voltagePhase2",
"displayName": "Voltage phase 2",
"type": "double",
"unit": "Volt",
"defaultValue": 0
},
{
"id": "fe67e1bf-6871-45a6-a253-819cb70c5ec4",
"name": "voltagePhase3",
"displayName": "Voltage phase 3",
"type": "double",
"unit": "Volt",
"defaultValue": 0
},
{
"id": "be2cc28e-79c2-4eaf-91ad-8131ac1f87e2",
"name": "sessionEnergy",
"displayName": "Session energy",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0
},
{
"id": "6d9b38a7-c6eb-47bc-8929-5a875d0fd5d0",
"name": "firmwareVersion",
"displayName": "Firmware version",
"type": "QString",
"defaultValue": ""
},
{
"id": "69c9f4e2-ec8c-4d65-9cf4-ce8b7a3f8c3b",
"name": "serialNumber",
"displayName": "Serial number",
"type": "QString",
"defaultValue": ""
},
{
"id": "ce98bfda-b27a-4f69-bd4e-49eb3e722245",
"name": "errorCode",
"displayName": "Error code",
"type": "uint",
"defaultValue": 0
}
],
"actionTypes": []
},
{
"id": "a385801e-600c-4e27-ad73-5184a7516860",
"name": "terraAcRtu",
"displayName": "Terra AC Charger (RTU)",
"interfaces": [
"evcharger",
"connectable"
],
"createMethods": [
"discovery",
"user"
],
"paramTypes": [
{
"id": "deb19a6b-33b3-417e-abf1-a1fb18585fe4",
"name": "rtuMaster",
"displayName": "Modbus RTU master",
"type": "QString",
"defaultValue": ""
},
{
"id": "23dbb93d-6605-435c-9a41-b8a8e8242ea0",
"name": "slaveId",
"displayName": "Modbus slave ID",
"type": "uint",
"defaultValue": 1,
"minValue": 1,
"maxValue": 247
}
],
"settingsTypes": [
{
"id": "c4e0a515-270e-403e-8453-02002859938e",
"name": "communicationTimeout",
"displayName": "Communication timeout",
"type": "uint",
"unit": "Seconds",
"defaultValue": 60,
"minValue": 10,
"maxValue": 65535
}
],
"stateTypes": [
{
"id": "c43068ca-dddc-4c43-9149-68927afae5e7",
"name": "connected",
"displayName": "Connected",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "14fcf045-52d7-4f47-b64e-2bf3f87c242f",
"name": "pluggedIn",
"displayName": "Plugged in",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "64708d42-bbfe-44a5-82ae-c8e66e25c5a5",
"name": "charging",
"displayName": "Charging",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "e35fd4fa-bf5a-45a1-8a39-f0d3d9efa4c6",
"name": "power",
"displayName": "Charging enabled",
"displayNameAction": "Set charging enabled",
"type": "bool",
"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,
"writable": true
},
{
"id": "cd1add95-18d9-46b5-a3d5-f0f29d5160c9",
"name": "phaseCount",
"displayName": "Phase count",
"type": "uint",
"minValue": 1,
"maxValue": 3,
"defaultValue": 1
},
{
"id": "152a58cb-0bf1-4d4a-aac2-233d3c68f81b",
"name": "currentPower",
"displayName": "Active power",
"type": "double",
"unit": "Watt",
"defaultValue": 0,
"cached": false
},
{
"id": "a8e2e2cf-b2ca-48c5-a702-9226062c43e3",
"name": "currentPhase1",
"displayName": "Current phase 1",
"type": "double",
"unit": "Ampere",
"defaultValue": 0
},
{
"id": "210ff017-ea75-4705-9f23-f73e324601ef",
"name": "currentPhase2",
"displayName": "Current phase 2",
"type": "double",
"unit": "Ampere",
"defaultValue": 0
},
{
"id": "3a5d6ce5-d3ed-4ba5-996f-15a2b3124faf",
"name": "currentPhase3",
"displayName": "Current phase 3",
"type": "double",
"unit": "Ampere",
"defaultValue": 0
},
{
"id": "52ebc781-a527-4641-b768-3a0bd0209f96",
"name": "voltagePhase1",
"displayName": "Voltage phase 1",
"type": "double",
"unit": "Volt",
"defaultValue": 0
},
{
"id": "bb513653-70ca-4ee1-a913-aab3d2881708",
"name": "voltagePhase2",
"displayName": "Voltage phase 2",
"type": "double",
"unit": "Volt",
"defaultValue": 0
},
{
"id": "c84a5e75-121d-4af8-a203-23f586613cf2",
"name": "voltagePhase3",
"displayName": "Voltage phase 3",
"type": "double",
"unit": "Volt",
"defaultValue": 0
},
{
"id": "7a9a6ec3-7572-42d8-833d-5b434ca95765",
"name": "sessionEnergy",
"displayName": "Session energy",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0
},
{
"id": "071d7408-fa96-49da-b56b-f5564bee9b5d",
"name": "firmwareVersion",
"displayName": "Firmware version",
"type": "QString",
"defaultValue": ""
},
{
"id": "c95ea476-4ce3-4c04-bc23-238bdee496ee",
"name": "serialNumber",
"displayName": "Serial number",
"type": "QString",
"defaultValue": ""
},
{
"id": "1f7d2791-c23e-47fe-8512-850ea25e09b3",
"name": "errorCode",
"displayName": "Error code",
"type": "uint",
"defaultValue": 0
}
],
"actionTypes": []
}
]
}
]
}

View File

@ -1,13 +0,0 @@
{
"title": "ABB Terra AC",
"tagline": "Connect ABB Terra AC chargers over Modbus TCP or Modbus RTU.",
"stability": "consumer",
"icon": "",
"offline": true,
"technologies": [
"network"
],
"categories": [
"energy"
]
}

View File

@ -1,296 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>AbbTerra</name>
<message>
<location filename="../plugininfo.h" line="80"/>
<source>ABB</source>
<extracomment>The name of the vendor ({0369ebad-5186-437d-b520-041a0b9b7582})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="83"/>
<source>ABB Terra AC</source>
<extracomment>The name of the plugin AbbTerra ({d7f1cb28-b18b-449e-8cd2-1d99b9d8f681})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="86"/>
<location filename="../plugininfo.h" line="89"/>
<source>Active power</source>
<extracomment>The name of the StateType ({152a58cb-0bf1-4d4a-aac2-233d3c68f81b}) of ThingClass terraAcRtu
----------
The name of the StateType ({59b486a3-aa44-4a94-8478-1077af124441}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="92"/>
<location filename="../plugininfo.h" line="95"/>
<source>Charging</source>
<extracomment>The name of the StateType ({64708d42-bbfe-44a5-82ae-c8e66e25c5a5}) of ThingClass terraAcRtu
----------
The name of the StateType ({0c685ced-27fa-46ba-8c0b-c49af82054f0}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="98"/>
<location filename="../plugininfo.h" line="101"/>
<location filename="../plugininfo.h" line="104"/>
<location filename="../plugininfo.h" line="107"/>
<source>Charging enabled</source>
<extracomment>The name of the ParamType (ThingClass: terraAcRtu, ActionType: power, ID: {e35fd4fa-bf5a-45a1-8a39-f0d3d9efa4c6})
----------
The name of the StateType ({e35fd4fa-bf5a-45a1-8a39-f0d3d9efa4c6}) of ThingClass terraAcRtu
----------
The name of the ParamType (ThingClass: terraAcTcp, ActionType: power, ID: {207e2074-0147-4617-9a8b-3f326dcd6a0b})
----------
The name of the StateType ({207e2074-0147-4617-9a8b-3f326dcd6a0b}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="110"/>
<location filename="../plugininfo.h" line="113"/>
<source>Communication timeout</source>
<extracomment>The name of the ParamType (ThingClass: terraAcRtu, Type: settings, ID: {c4e0a515-270e-403e-8453-02002859938e})
----------
The name of the ParamType (ThingClass: terraAcTcp, Type: settings, ID: {5a0e678a-ffc8-443a-9ae7-bb2243b0ec4b})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="116"/>
<location filename="../plugininfo.h" line="119"/>
<source>Connected</source>
<extracomment>The name of the StateType ({c43068ca-dddc-4c43-9149-68927afae5e7}) of ThingClass terraAcRtu
----------
The name of the StateType ({21e1a2bb-0e05-462c-9909-4f9a0eada438}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="122"/>
<location filename="../plugininfo.h" line="125"/>
<source>Current phase 1</source>
<extracomment>The name of the StateType ({a8e2e2cf-b2ca-48c5-a702-9226062c43e3}) of ThingClass terraAcRtu
----------
The name of the StateType ({953ce672-a9a2-4cd6-bf87-ccfe720c7595}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="128"/>
<location filename="../plugininfo.h" line="131"/>
<source>Current phase 2</source>
<extracomment>The name of the StateType ({210ff017-ea75-4705-9f23-f73e324601ef}) of ThingClass terraAcRtu
----------
The name of the StateType ({e4f97cde-191c-4c84-9668-169c5e648338}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="134"/>
<location filename="../plugininfo.h" line="137"/>
<source>Current phase 3</source>
<extracomment>The name of the StateType ({3a5d6ce5-d3ed-4ba5-996f-15a2b3124faf}) of ThingClass terraAcRtu
----------
The name of the StateType ({c1cead50-9894-4b12-9211-c5bc84109b1d}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="140"/>
<location filename="../plugininfo.h" line="143"/>
<source>Error code</source>
<extracomment>The name of the StateType ({1f7d2791-c23e-47fe-8512-850ea25e09b3}) of ThingClass terraAcRtu
----------
The name of the StateType ({ce98bfda-b27a-4f69-bd4e-49eb3e722245}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="146"/>
<location filename="../plugininfo.h" line="149"/>
<source>Firmware version</source>
<extracomment>The name of the StateType ({071d7408-fa96-49da-b56b-f5564bee9b5d}) of ThingClass terraAcRtu
----------
The name of the StateType ({6d9b38a7-c6eb-47bc-8929-5a875d0fd5d0}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="152"/>
<source>Host address</source>
<extracomment>The name of the ParamType (ThingClass: terraAcTcp, Type: thing, ID: {962ef9d9-30a2-4636-8ff2-2a28742277f4})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="155"/>
<source>Host name</source>
<extracomment>The name of the ParamType (ThingClass: terraAcTcp, Type: thing, ID: {f9e6fed4-2a18-4f23-b70e-78919d4b01f8})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="158"/>
<source>MAC address</source>
<extracomment>The name of the ParamType (ThingClass: terraAcTcp, Type: thing, ID: {9b3332aa-6c26-4399-b3dc-d7fdbe3f4420})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="161"/>
<location filename="../plugininfo.h" line="164"/>
<location filename="../plugininfo.h" line="167"/>
<location filename="../plugininfo.h" line="170"/>
<source>Maximum charging current</source>
<extracomment>The name of the ParamType (ThingClass: terraAcRtu, ActionType: maxChargingCurrent, ID: {ea933a77-a098-4303-bbdb-15c72dfd3634})
----------
The name of the StateType ({ea933a77-a098-4303-bbdb-15c72dfd3634}) of ThingClass terraAcRtu
----------
The name of the ParamType (ThingClass: terraAcTcp, ActionType: maxChargingCurrent, ID: {e3d27f8a-73d0-493a-b99a-29e7dc184485})
----------
The name of the StateType ({e3d27f8a-73d0-493a-b99a-29e7dc184485}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="173"/>
<source>Modbus RTU master</source>
<extracomment>The name of the ParamType (ThingClass: terraAcRtu, Type: thing, ID: {deb19a6b-33b3-417e-abf1-a1fb18585fe4})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="176"/>
<source>Modbus slave ID</source>
<extracomment>The name of the ParamType (ThingClass: terraAcRtu, Type: thing, ID: {23dbb93d-6605-435c-9a41-b8a8e8242ea0})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="179"/>
<location filename="../plugininfo.h" line="182"/>
<source>Phase count</source>
<extracomment>The name of the StateType ({cd1add95-18d9-46b5-a3d5-f0f29d5160c9}) of ThingClass terraAcRtu
----------
The name of the StateType ({0764bce9-fd26-4da8-8d92-f6a5ce73e81e}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="185"/>
<location filename="../plugininfo.h" line="188"/>
<source>Plugged in</source>
<extracomment>The name of the StateType ({14fcf045-52d7-4f47-b64e-2bf3f87c242f}) of ThingClass terraAcRtu
----------
The name of the StateType ({2fb30a0b-dc5a-4831-b5c6-de653c0c9ee1}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="191"/>
<source>Port</source>
<extracomment>The name of the ParamType (ThingClass: terraAcTcp, Type: thing, ID: {153258dd-e81b-48e5-9ba7-46d59e854d85})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="194"/>
<location filename="../plugininfo.h" line="197"/>
<source>Serial number</source>
<extracomment>The name of the StateType ({c95ea476-4ce3-4c04-bc23-238bdee496ee}) of ThingClass terraAcRtu
----------
The name of the StateType ({69c9f4e2-ec8c-4d65-9cf4-ce8b7a3f8c3b}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="200"/>
<location filename="../plugininfo.h" line="203"/>
<source>Session energy</source>
<extracomment>The name of the StateType ({7a9a6ec3-7572-42d8-833d-5b434ca95765}) of ThingClass terraAcRtu
----------
The name of the StateType ({be2cc28e-79c2-4eaf-91ad-8131ac1f87e2}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="206"/>
<location filename="../plugininfo.h" line="209"/>
<source>Set charging enabled</source>
<extracomment>The name of the ActionType ({e35fd4fa-bf5a-45a1-8a39-f0d3d9efa4c6}) of ThingClass terraAcRtu
----------
The name of the ActionType ({207e2074-0147-4617-9a8b-3f326dcd6a0b}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="212"/>
<location filename="../plugininfo.h" line="215"/>
<source>Set maximum charging current</source>
<extracomment>The name of the ActionType ({ea933a77-a098-4303-bbdb-15c72dfd3634}) of ThingClass terraAcRtu
----------
The name of the ActionType ({e3d27f8a-73d0-493a-b99a-29e7dc184485}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="218"/>
<source>Slave ID</source>
<extracomment>The name of the ParamType (ThingClass: terraAcTcp, Type: thing, ID: {cc4c66c1-185f-4c97-88a0-2bc66319d157})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="221"/>
<source>Terra AC Charger (RTU)</source>
<extracomment>The name of the ThingClass ({a385801e-600c-4e27-ad73-5184a7516860})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="224"/>
<source>Terra AC Charger (TCP)</source>
<extracomment>The name of the ThingClass ({93ad828a-9a7a-4fca-be3f-88641317845f})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="227"/>
<location filename="../plugininfo.h" line="230"/>
<source>Voltage phase 1</source>
<extracomment>The name of the StateType ({52ebc781-a527-4641-b768-3a0bd0209f96}) of ThingClass terraAcRtu
----------
The name of the StateType ({bcff4c2d-5567-40ff-adef-5b47dc5ace76}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="233"/>
<location filename="../plugininfo.h" line="236"/>
<source>Voltage phase 2</source>
<extracomment>The name of the StateType ({bb513653-70ca-4ee1-a913-aab3d2881708}) of ThingClass terraAcRtu
----------
The name of the StateType ({db7af25a-cb7b-4640-9515-a7af345bd770}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../plugininfo.h" line="239"/>
<location filename="../plugininfo.h" line="242"/>
<source>Voltage phase 3</source>
<extracomment>The name of the StateType ({c84a5e75-121d-4af8-a203-23f586613cf2}) of ThingClass terraAcRtu
----------
The name of the StateType ({fe67e1bf-6871-45a6-a253-819cb70c5ec4}) of ThingClass terraAcTcp</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>IntegrationPluginAbbterra</name>
<message>
<location filename="../integrationpluginabbterra.cpp" line="57"/>
<source>No connected Modbus RTU master available.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationpluginabbterra.cpp" line="141"/>
<location filename="../integrationpluginabbterra.cpp" line="186"/>
<source>The charging station is not reachable.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationpluginabbterra.cpp" line="289"/>
<location filename="../integrationpluginabbterra.cpp" line="365"/>
<source>Could not initialize the communication with the charger.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationpluginabbterra.cpp" line="298"/>
<location filename="../integrationpluginabbterra.cpp" line="374"/>
<source>The device does not match the ABB Terra AC Modbus register map.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationpluginabbterra.cpp" line="328"/>
<source>The Modbus RTU connection is not available.</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>