From 8834286af8cb857913f3e9c256ac56ab45538b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 12 Nov 2021 17:21:47 +0100 Subject: [PATCH] Update to latest interface requirements and add provided interfaces for the datalogger --- fronius/froniusinverter.cpp | 2 + fronius/froniusmeter.cpp | 54 +++++++- fronius/froniusstorage.cpp | 8 +- fronius/froniusstorage.h | 2 +- fronius/integrationpluginfronius.cpp | 185 ++++++++++++++++---------- fronius/integrationpluginfronius.json | 145 +++++++++++++++++--- 6 files changed, 300 insertions(+), 96 deletions(-) diff --git a/fronius/froniusinverter.cpp b/fronius/froniusinverter.cpp index 36fdd9d7..9dd63109 100644 --- a/fronius/froniusinverter.cpp +++ b/fronius/froniusinverter.cpp @@ -78,6 +78,8 @@ void FroniusInverter::updateThingInfo(const QByteArray &data) QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); QVariantMap headMap = jsonDoc.toVariant().toMap().value("Head").toMap(); + qCDebug(dcFronius()) << "Inverter data" << qUtf8Printable(QJsonDocument::fromVariant(dataMap).toJson(QJsonDocument::Indented)); + // Set the inverter device state if (dataMap.contains("PAC")) { if(dataMap.value("PAC").toMap().values().at(0) == "W") diff --git a/fronius/froniusmeter.cpp b/fronius/froniusmeter.cpp index 7fd11271..0d767624 100644 --- a/fronius/froniusmeter.cpp +++ b/fronius/froniusmeter.cpp @@ -79,17 +79,63 @@ void FroniusMeter::updateThingInfo(const QByteArray &data) //Add Smart meter with following states: „PowerReal_P_Sum“, „EnergyReal_WAC_Sum_Produced“, „EnergyReal_WAC_Sum_Consumed“ - // Set the meter thing state + qCDebug(dcFronius()) << "Meter data" << qUtf8Printable(QJsonDocument::fromVariant(dataMap).toJson(QJsonDocument::Indented)); + + // Power if (dataMap.contains("PowerReal_P_Sum")) { - pluginThing()->setStateValue(meterCurrentPowerStateTypeId, dataMap.value("PowerReal_P_Sum").toInt()); + pluginThing()->setStateValue(meterCurrentPowerStateTypeId, dataMap.value("PowerReal_P_Sum").toDouble()); } + if (dataMap.contains("PowerReal_P_Phase_1")) { + pluginThing()->setStateValue(meterCurrentPowerPhaseAStateTypeId, dataMap.value("PowerReal_P_Phase_1").toDouble()); + } + + if (dataMap.contains("PowerReal_P_Phase_2")) { + pluginThing()->setStateValue(meterCurrentPowerPhaseBStateTypeId, dataMap.value("PowerReal_P_Phase_2").toDouble()); + } + + if (dataMap.contains("PowerReal_P_Phase_3")) { + pluginThing()->setStateValue(meterCurrentPowerPhaseCStateTypeId, dataMap.value("PowerReal_P_Phase_3").toDouble()); + } + + // Current + if (dataMap.contains("Current_AC_Phase_1")) { + pluginThing()->setStateValue(meterCurrentPhaseAStateTypeId, dataMap.value("Current_AC_Phase_1").toDouble()); + } + + if (dataMap.contains("Current_AC_Phase_2")) { + pluginThing()->setStateValue(meterCurrentPhaseBStateTypeId, dataMap.value("Current_AC_Phase_2").toDouble()); + } + + if (dataMap.contains("Current_AC_Phase_3")) { + pluginThing()->setStateValue(meterCurrentPhaseCStateTypeId, dataMap.value("Current_AC_Phase_3").toDouble()); + } + + // Voltage + if (dataMap.contains("Voltage_AC_Phase_1")) { + pluginThing()->setStateValue(meterVoltagePhaseAStateTypeId, dataMap.value("Voltage_AC_Phase_1").toDouble()); + } + + if (dataMap.contains("Voltage_AC_Phase_2")) { + pluginThing()->setStateValue(meterVoltagePhaseBStateTypeId, dataMap.value("Voltage_AC_Phase_2").toDouble()); + } + + if (dataMap.contains("Voltage_AC_Phase_3")) { + pluginThing()->setStateValue(meterVoltagePhaseCStateTypeId, dataMap.value("Voltage_AC_Phase_3").toDouble()); + } + + // Total energy if (dataMap.contains("EnergyReal_WAC_Sum_Produced")) { - pluginThing()->setStateValue(meterTotalEnergyProducedStateTypeId, dataMap.value("EnergyReal_WAC_Sum_Produced").toInt()/1000.00); + pluginThing()->setStateValue(meterTotalEnergyProducedStateTypeId, dataMap.value("EnergyReal_WAC_Sum_Produced").toInt()/1000.00); } if (dataMap.contains("EnergyReal_WAC_Sum_Consumed")) { - pluginThing()->setStateValue(meterTotalEnergyConsumedStateTypeId, dataMap.value("EnergyReal_WAC_Sum_Consumed").toInt()/1000.00); + pluginThing()->setStateValue(meterTotalEnergyConsumedStateTypeId, dataMap.value("EnergyReal_WAC_Sum_Consumed").toInt()/1000.00); + } + + // Frequency + if (dataMap.contains("Frequency_Phase_Average")) { + pluginThing()->setStateValue(meterFrequencyStateTypeId, dataMap.value("Frequency_Phase_Average").toDouble()); } //update successful diff --git a/fronius/froniusstorage.cpp b/fronius/froniusstorage.cpp index e8a9e312..792d2d5f 100644 --- a/fronius/froniusstorage.cpp +++ b/fronius/froniusstorage.cpp @@ -78,6 +78,8 @@ void FroniusStorage::updateThingInfo(const QByteArray &data) QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); // QVariantMap headMap = jsonDoc.toVariant().toMap().value("Head").toMap(); + qCDebug(dcFronius()) << "Storage data" << qUtf8Printable(QJsonDocument::fromVariant(dataMap).toJson(QJsonDocument::Indented)); + // create StorageInfo list map QVariantMap storageInfoMap = dataMap.value("Controller").toMap(); @@ -94,7 +96,9 @@ void FroniusStorage::updateThingInfo(const QByteArray &data) if (storageInfoMap.contains("Temperature_Cell")) pluginThing()->setStateValue(storageCellTemperatureStateTypeId, storageInfoMap.value("Temperature_Cell").toDouble()); - //update successful + if (storageInfoMap.contains("Capacity_Maximum")) + pluginThing()->setStateValue(storageCapacityStateTypeId, storageInfoMap.value("Capacity_Maximum").toDouble()); + pluginThing()->setStateValue(storageConnectedStateTypeId,true); } @@ -120,8 +124,8 @@ void FroniusStorage::updateActivityInfo(const QByteArray &data) // create StorageInfo list map QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); - float charge_akku = dataMap.value("Site").toMap().value("P_Akku").toFloat(); + pluginThing()->setStateValue(storageCurrentPowerStateTypeId, charge_akku); pluginThing()->setStateValue(storageChargingStateTypeId, charge_akku < 0); pluginThing()->setStateValue(storageDischargingStateTypeId, charge_akku > 0); } diff --git a/fronius/froniusstorage.h b/fronius/froniusstorage.h index 401244f1..551d6044 100644 --- a/fronius/froniusstorage.h +++ b/fronius/froniusstorage.h @@ -51,6 +51,6 @@ public: private: QString m_charging_state; - int m_charge; + int m_charge; }; #endif // FRONIUSSTORAGE_H diff --git a/fronius/integrationpluginfronius.cpp b/fronius/integrationpluginfronius.cpp index 38ca08cd..157aecc6 100644 --- a/fronius/integrationpluginfronius.cpp +++ b/fronius/integrationpluginfronius.cpp @@ -390,9 +390,8 @@ void IntegrationPluginFronius::searchNewThings(FroniusLogger *logger) if (!loggerThing) return; - QByteArray data = reply->readAll(); - // Convert the rawdata to a json document + QByteArray data = reply->readAll(); QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); if (error.error != QJsonParseError::NoError) { @@ -409,9 +408,9 @@ void IntegrationPluginFronius::searchNewThings(FroniusLogger *logger) // Parse reply for inverters at the host address QVariantMap inverterMap = bodyMap.value("Data").toMap().value("Inverter").toMap(); - foreach (QString inverterId, inverterMap.keys()) { + foreach (const QString &inverterId, inverterMap.keys()) { //check if thing already connected to logger - if (!thingExists(inverterThingIdParamTypeId,inverterId)) { + if (!thingExists(inverterThingIdParamTypeId, inverterId)) { QString thingName = loggerThing->name() + " Inverter " + inverterId; ThingDescriptor descriptor(inverterThingClassId, thingName, "Fronius Solar Inverter", loggerThing->id()); ParamList params; @@ -423,31 +422,111 @@ void IntegrationPluginFronius::searchNewThings(FroniusLogger *logger) // parse reply for meter things at the host address QVariantMap meterMap = bodyMap.value("Data").toMap().value("Meter").toMap(); - foreach (QString meterId, meterMap.keys()) { + foreach (const QString &meterId, meterMap.keys()) { //check if thing already connected to logger - if(!thingExists(meterThingIdParamTypeId, meterId)) { - QString thingName = loggerThing->name() + " Meter " + meterId; - ThingDescriptor descriptor(meterThingClassId, thingName, "Fronius Solar Meter", loggerThing->id()); - ParamList params; - params.append(Param(meterThingIdParamTypeId, meterId)); - descriptor.setParams(params); - thingDescriptors.append(descriptor); + if (!thingExists(meterThingIdParamTypeId, meterId)) { + // get meter infos + ///solar_api/v1/GetMeterRealtimeData.cgi?Scope=Device&DeviceId=0 + QUrl requestUrl; + requestUrl.setScheme("http"); + requestUrl.setHost(logger->hostAddress()); + requestUrl.setPath(logger->baseUrl() + "GetMeterRealtimeData.cgi"); + QUrlQuery query; + query.addQueryItem("Scope", "Device"); + query.addQueryItem("DeviceId", meterId); + requestUrl.setQuery(query); + + qCDebug(dcFronius()) << "Get meter information before setup"; + QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(requestUrl)); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + connect(reply, &QNetworkReply::finished, this, [=]() { + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Network request error:" << reply->error() << reply->errorString(); + return; + } + + QByteArray data = reply->readAll(); + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcFronius()) << "Failed to parse JSON data" << data << ":" << error.errorString(); + return; + } + + QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); + + QString thingName; + QString serialNumber; + if (dataMap.contains("Details")) { + QVariantMap details = dataMap.value("Details").toMap(); + thingName = details.value("Manufacturer", "Fronius").toString() + " " + details.value("Model", "Smart Meter").toString(); + serialNumber = details.value("Serial").toString(); + } else { + thingName = loggerThing->name() + " Meter " + meterId; + } + + ThingDescriptor descriptor(meterThingClassId, thingName, QString(), loggerThing->id()); + ParamList params; + params.append(Param(meterThingIdParamTypeId, meterId)); + params.append(Param(meterThingSerialNumberParamTypeId, serialNumber)); + descriptor.setParams(params); + emit autoThingsAppeared(ThingDescriptors() << descriptor); + }); } } // parse reply for storage things at the host address QVariantMap storageMap = bodyMap.value("Data").toMap().value("Storage").toMap(); - foreach (QString storageId, storageMap.keys()) { + foreach (const QString &storageId, storageMap.keys()) { //check if thing already connected to logger - if(!thingExists(storageThingIdParamTypeId,storageId)) { - QString thingName = loggerThing->name() + " Storage " + storageId; - ThingDescriptor descriptor(storageThingClassId, thingName, "Fronius Solar Storage", loggerThing->id()); - ParamList params; - params.append(Param(storageThingManufacturerParamTypeId, "")); - params.append(Param(storageThingCapacityParamTypeId, "")); - params.append(Param(storageThingIdParamTypeId, storageId)); - descriptor.setParams(params); - thingDescriptors.append(descriptor); + if (!thingExists(storageThingIdParamTypeId, storageId)) { + QUrlQuery query; + QUrl requestUrl; + requestUrl.setScheme("http"); + requestUrl.setHost(logger->hostAddress()); + requestUrl.setPath(logger->baseUrl() + "GetStorageRealtimeData.cgi"); + query.addQueryItem("Scope","Device"); + query.addQueryItem("DeviceId", storageId); + requestUrl.setQuery(query); + + qCDebug(dcFronius()) << "Get storage information before setup" << requestUrl.toString(); + QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(requestUrl)); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + connect(reply, &QNetworkReply::finished, this, [=]() { + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Network request error:" << reply->error() << reply->errorString(); + return; + } + + // Convert the rawdata to a json document + QByteArray data = reply->readAll(); + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcFronius()) << "Failed to parse JSON data" << data << ":" << error.errorString(); + return; + } + + QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap().value("Controller").toMap(); + + QString thingName; + QString serialNumber; + if (dataMap.contains("Details")) { + QVariantMap details = dataMap.value("Details").toMap(); + thingName = details.value("Manufacturer", "Fronius").toString() + " " + details.value("Model", "Energy Storage").toString(); + serialNumber = details.value("Serial").toString(); + } else { + thingName = loggerThing->name() + " Storage " + storageId; + } + + ThingDescriptor descriptor(storageThingClassId, thingName, QString(), loggerThing->id()); + ParamList params; + params.append(Param(storageThingIdParamTypeId, storageId)); + params.append(Param(storageThingSerialNumberParamTypeId, serialNumber)); + descriptor.setParams(params); + emit autoThingsAppeared(ThingDescriptors() << descriptor); + + }); } } @@ -475,7 +554,7 @@ void IntegrationPluginFronius::searchNewThings(FroniusLogger *logger) bool IntegrationPluginFronius::thingExists(const ParamTypeId &thingParamId, QString thingId) { - foreach(Thing *thing, myThings()) { + foreach (Thing *thing, myThings()) { if (thing->paramValue(thingParamId).toString() == thingId) { return true; } @@ -486,59 +565,13 @@ bool IntegrationPluginFronius::thingExists(const ParamTypeId &thingParamId, QStr void IntegrationPluginFronius::setupChild(ThingSetupInfo *info, Thing *loggerThing) { Thing *thing = info->thing(); - - if (thing->thingClassId() == storageThingClassId) { - FroniusStorage *newStorage = new FroniusStorage(thing, this); - newStorage->setDeviceId(thing->paramValue(storageThingIdParamTypeId).toString()); - newStorage->setBaseUrl(m_froniusLoggers.key(loggerThing)->baseUrl()); - newStorage->setHostAddress(m_froniusLoggers.key(loggerThing)->hostAddress()); - - // Get storage manufacturer and maximum capacity - QUrlQuery query; - QUrl requestUrl; - requestUrl.setScheme("http"); - requestUrl.setHost(newStorage->hostAddress()); - requestUrl.setPath(newStorage->baseUrl() + "GetStorageRealtimeData.cgi"); - query.addQueryItem("Scope","Device"); - query.addQueryItem("DeviceId", newStorage->deviceId()); - requestUrl.setQuery(query); - qCDebug(dcFronius()) << "Get Storage Data at address" << requestUrl.toString(); - QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(requestUrl)); - connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); - connect(reply, &QNetworkReply::finished, info, [this, info, newStorage, reply]() { - - QByteArray data = reply->readAll(); - - if (reply->error() != QNetworkReply::NoError) { - qCWarning(dcFronius()) << "Network request error:" << reply->error() << reply->errorString(); - info->finish(Thing::ThingErrorNoError); - return; - } - - // Convert the rawdata to a json document - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); - if (error.error != QJsonParseError::NoError) { - qCWarning(dcFronius()) << "Failed to parse JSON data" << data << ":" << error.errorString(); - info->finish(Thing::ThingErrorHardwareFailure, tr("Please try again")); - return; - } - - // Create StorageInfo list map - QVariantMap storageInfoMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap().value("Controller").toMap(); - - newStorage->pluginThing()->setParamValue(storageThingManufacturerParamTypeId, storageInfoMap.value("Details").toMap().value("Manufacturer").toString()); - newStorage->pluginThing()->setParamValue(storageThingCapacityParamTypeId, storageInfoMap.value("Capacity_Maximum").toInt()); - m_froniusStorages.insert(newStorage, info->thing()); - info->finish(Thing::ThingErrorNoError); - }); - } else if (thing->thingClassId() == inverterThingClassId) { + if (thing->thingClassId() == inverterThingClassId) { FroniusInverter *newInverter = new FroniusInverter(thing,this); newInverter->setDeviceId(thing->paramValue(inverterThingIdParamTypeId).toString()); newInverter->setBaseUrl(m_froniusLoggers.key(loggerThing)->baseUrl()); newInverter->setHostAddress(m_froniusLoggers.key(loggerThing)->hostAddress()); - // get inverter unique ID + // Get inverter unique ID QUrl requestUrl; requestUrl.setScheme("http"); requestUrl.setHost(newInverter->hostAddress()); @@ -577,6 +610,7 @@ void IntegrationPluginFronius::setupChild(ThingSetupInfo *info, Thing *loggerThi m_froniusInverters.insert(newInverter, info->thing()); info->finish(Thing::ThingErrorNoError); }); + } else if (thing->thingClassId() == meterThingClassId) { FroniusMeter *newMeter = new FroniusMeter(thing, this);; newMeter->setDeviceId(thing->paramValue(meterThingIdParamTypeId).toString()); @@ -585,5 +619,14 @@ void IntegrationPluginFronius::setupChild(ThingSetupInfo *info, Thing *loggerThi m_froniusMeters.insert(newMeter, thing); info->finish(Thing::ThingErrorNoError); + + } else if (thing->thingClassId() == storageThingClassId) { + FroniusStorage *newStorage = new FroniusStorage(thing, this); + newStorage->setDeviceId(thing->paramValue(storageThingIdParamTypeId).toString()); + newStorage->setBaseUrl(m_froniusLoggers.key(loggerThing)->baseUrl()); + newStorage->setHostAddress(m_froniusLoggers.key(loggerThing)->hostAddress()); + + m_froniusStorages.insert(newStorage, info->thing()); + info->finish(Thing::ThingErrorNoError); } } diff --git a/fronius/integrationpluginfronius.json b/fronius/integrationpluginfronius.json index 3e04c715..1486113e 100644 --- a/fronius/integrationpluginfronius.json +++ b/fronius/integrationpluginfronius.json @@ -11,9 +11,10 @@ { "id": "4fd79fed-42f1-4df9-be64-3df7b2e0bda2", "name": "datalogger", - "displayName": "Fronius Solar Connection", + "displayName": "Fronius Solar", "createMethods": ["discovery", "user"], "interfaces": ["gateway"], + "providedInterfaces": ["energymeter", "solarinverter", "energystorage"], "paramTypes": [ { "id": "52da0197-4b78-4fec-aa72-70f949e26edc", @@ -230,7 +231,7 @@ "name": "meter", "displayName": "Fronius smart meter", "createMethods": ["auto"], - "interfaces": [ "smartmeterconsumer", "smartmeterproducer", "connectable" ], + "interfaces": [ "energymeter", "connectable" ], "paramTypes": [ { "id": "cf3a7025-d368-475a-8f48-efc1344a8409", @@ -239,6 +240,14 @@ "type": "QString", "inputType": "TextLine", "readOnly": true + }, + { + "id": "dfc2eeef-38b2-4089-9953-48186aaee060", + "name": "serialNumber", + "displayName": "Serial number", + "type": "QString", + "inputType": "TextLine", + "readOnly": true } ], "stateTypes": [ @@ -251,6 +260,60 @@ "defaultValue": false, "cached": false }, + { + "id": "267bc59f-1113-4aff-a502-4618a591aa16", + "name": "voltagePhaseA", + "displayName": "Voltage phase A", + "displayNameEvent": "Voltage phase A changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0 + }, + { + "id": "bbcedb80-30f1-493e-81f0-5f77f2847353", + "name": "voltagePhaseB", + "displayName": "Voltage phase B", + "displayNameEvent": "Voltage phase B changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0 + }, + { + "id": "8037557b-40dc-411b-8937-bcd1695f898a", + "name": "voltagePhaseC", + "displayName": "Voltage phase C", + "displayNameEvent": "Voltage phase C changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0 + }, + { + "id": "a9673688-d84a-4848-8583-a70739130252", + "name": "currentPhaseA", + "displayName": "Current phase A", + "displayNameEvent": "Current phase A changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0 + }, + { + "id": "15632e49-95f9-496d-830c-53a31ca6d98e", + "name": "currentPhaseB", + "displayName": "Current phase B", + "displayNameEvent": "Current phase B changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0 + }, + { + "id": "10a24ba9-a57a-48a9-98f3-52671c09e855", + "name": "currentPhaseC", + "displayName": "Current phase C", + "displayNameEvent": "Current phase C changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0 + }, { "id": "e5056ea1-88a2-410b-9c5e-6322aca4cb17", "name": "currentPower", @@ -277,6 +340,42 @@ "type": "double", "unit": "KiloWattHour", "defaultValue": "0" + }, + { + "id": "6dbbb062-447b-47d6-b2e4-dceac9aff795", + "name": "currentPowerPhaseA", + "displayName": "Current power phase A", + "displayNameEvent": "Current power phase A changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0 + }, + { + "id": "f230e78e-15b0-47a4-b494-bae65be00755", + "name": "currentPowerPhaseB", + "displayName": "Current power phase B", + "displayNameEvent": "Current power phase B changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0 + }, + { + "id": "56b5d550-d902-4c33-9288-8ee972735a75", + "name": "currentPowerPhaseC", + "displayName": "Current power phase C", + "displayNameEvent": "Current power phase C changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0 + }, + { + "id": "9ff64b29-e023-4395-abd4-b6c366acfd9e", + "name": "frequency", + "displayName": "Frequency", + "displayNameEvent": "Frequency changed", + "type": "double", + "unit": "Hertz", + "defaultValue": 0.00 } ] }, @@ -287,22 +386,6 @@ "createMethods": ["auto"], "interfaces": [ "battery", "connectable" ], "paramTypes": [ - { - "id": "9665c38b-c13a-428f-b741-1470239c63dc", - "name": "manufacturer", - "displayName": "Manufacturer", - "type": "QString", - "defaultValue": "TextLine", - "readOnly": true - }, - { - "id": "59a68e91-1aad-46b7-b351-03b7b2216366", - "name": "capacity", - "displayName": "Maxmimum capacity", - "type": "QString", - "defaultValue": "TextLine", - "readOnly": true - }, { "id": "49087f31-abf5-4bb8-946b-a3626ee80566", "name": "id", @@ -310,6 +393,14 @@ "type": "QString", "inputType": "TextLine", "readOnly": true + }, + { + "id": "8b6c7053-5ba5-4808-8ff4-9024c624d77d", + "name": "serialNumber", + "displayName": "Serial number", + "type": "QString", + "inputType": "TextLine", + "readOnly": true } ], "stateTypes": [ @@ -338,6 +429,24 @@ "type": "bool", "defaultValue": false }, + { + "id": "5a89cd3f-3abf-4f51-ab2b-4039f1d211d9", + "name": "currentPower", + "displayName": "Current power", + "displayNameEvent": "Current power changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0 + }, + { + "id": "3b163deb-67a2-41d1-8441-b2d53ad846ef", + "name": "capacity", + "displayName": "Capacity", + "displayNameEvent": "Capacity changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0 + }, { "id": "5c6da672-9662-41bc-8c8c-aa0f32481251", "name": "batteryLevel",