From 6903391d18073d7e85138433f2867961a36f5808 Mon Sep 17 00:00:00 2001 From: "bernhard.trinnes" Date: Tue, 14 Jul 2020 13:29:09 +0200 Subject: [PATCH] added fronius plug-in --- debian/control | 17 + debian/nymea-plugin-fronius.install.in | 1 + fronius/README.md | 18 + fronius/fronius.png | Bin 0 -> 24765 bytes fronius/fronius.pro | 20 + fronius/froniusinverter.cpp | 135 ++++ fronius/froniusinverter.h | 56 ++ fronius/froniuslogger.cpp | 145 ++++ fronius/froniuslogger.h | 53 ++ fronius/froniusmeter.cpp | 127 +++ fronius/froniusmeter.h | 55 ++ fronius/froniusstorage.cpp | 138 ++++ fronius/froniusstorage.h | 60 ++ fronius/froniusthing.cpp | 102 +++ fronius/froniusthing.h | 82 ++ fronius/integrationpluginfronius.cpp | 512 ++++++++++++ fronius/integrationpluginfronius.h | 74 ++ fronius/integrationpluginfronius.json | 414 ++++++++++ fronius/meta.json | 13 + ...02319cfc-8b55-49ba-99bc-0588bbfab063-de.ts | 741 ++++++++++++++++++ ...19cfc-8b55-49ba-99bc-0588bbfab063-en_US.ts | 741 ++++++++++++++++++ nymea-plugins.pro | 1 + 22 files changed, 3505 insertions(+) create mode 100644 debian/nymea-plugin-fronius.install.in create mode 100644 fronius/README.md create mode 100644 fronius/fronius.png create mode 100644 fronius/fronius.pro create mode 100644 fronius/froniusinverter.cpp create mode 100644 fronius/froniusinverter.h create mode 100644 fronius/froniuslogger.cpp create mode 100644 fronius/froniuslogger.h create mode 100644 fronius/froniusmeter.cpp create mode 100644 fronius/froniusmeter.h create mode 100644 fronius/froniusstorage.cpp create mode 100644 fronius/froniusstorage.h create mode 100644 fronius/froniusthing.cpp create mode 100644 fronius/froniusthing.h create mode 100644 fronius/integrationpluginfronius.cpp create mode 100644 fronius/integrationpluginfronius.h create mode 100644 fronius/integrationpluginfronius.json create mode 100644 fronius/meta.json create mode 100644 fronius/translations/02319cfc-8b55-49ba-99bc-0588bbfab063-de.ts create mode 100644 fronius/translations/02319cfc-8b55-49ba-99bc-0588bbfab063-en_US.ts diff --git a/debian/control b/debian/control index f545e939..f57c6e7c 100644 --- a/debian/control +++ b/debian/control @@ -293,6 +293,22 @@ Description: nymea.io plugin for Xiaomi Flower care devices also know as Plant care or MiCare +Package: nymea-plugin-fronius +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, + ${misc:Depends}, + nymea-plugins-translations, +Description: nymea.io plugin for Fronius PV inverters + The nymea daemon is a plugin based IoT (Internet of Things) server. The + server works like a translator for devices, things and services and + allows them to interact. + With the powerful rule engine you are able to connect any device available + in the system and create individual scenes and behaviors for your environment. + . + This package will install the nymea.io plugin for Fronius + + Package: nymea-plugin-eq-3 Architecture: any Depends: ${shlibs:Depends}, @@ -978,6 +994,7 @@ Depends: nymea-plugin-anel, nymea-plugin-doorbird, nymea-plugin-eq-3, nymea-plugin-flowercare, + nymea-plugin-fronius, nymea-plugin-genericthings, nymea-plugin-kodi, nymea-plugin-lgsmarttv, diff --git a/debian/nymea-plugin-fronius.install.in b/debian/nymea-plugin-fronius.install.in new file mode 100644 index 00000000..1b725312 --- /dev/null +++ b/debian/nymea-plugin-fronius.install.in @@ -0,0 +1 @@ +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginfronius.so diff --git a/fronius/README.md b/fronius/README.md new file mode 100644 index 00000000..b0745868 --- /dev/null +++ b/fronius/README.md @@ -0,0 +1,18 @@ +# Fronius + +nymea plug-in for Fronius solar devices. + +## Supported Things + +* PV-Inverter +* Storage +* Data Logger +* Smart Meter + +## Requirements + +* The package "nymea-plugin-fronius" must be installed. + +## More +https://www.fronius.com/en/photovoltaics + diff --git a/fronius/fronius.png b/fronius/fronius.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd67fd738cb5bdab509a6d05208971900c41e39 GIT binary patch literal 24765 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. +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "froniusinverter.h" +#include +#include "extern-plugininfo.h" +#include + +FroniusInverter::FroniusInverter(Thing *thing, QObject *parent) : FroniusThing(thing, parent) +{ + +} + +QString FroniusInverter::activity() const +{ + return m_activity; +} + +void FroniusInverter::setActivity(const QString &activity) +{ + m_activity = activity; +} + +QUrl FroniusInverter::updateUrl() +{ + QUrl requestUrl; + requestUrl.setScheme("http"); + QUrlQuery query; + requestUrl.setHost(hostAddress()); + requestUrl.setPath(baseUrl() + "GetInverterRealtimeData.cgi"); + query.addQueryItem("Scope", "Device"); + query.addQueryItem("DeviceId", deviceId()); + query.addQueryItem("DataCollection", "CommonInverterData"); + requestUrl.setQuery(query); + + return requestUrl; +} + +void FroniusInverter::updateThingInfo(const QByteArray &data) +{ + // Convert the rawdata to a JSON document + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcFronius()) << "FroniusInverter: Failed to parse JSON data" << data << ":" << error.errorString(); + pluginThing()->setStateValue(inverterConnectedStateTypeId,false); + return; + } + + // Parse the data and update the states of our device + QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); + QVariantMap headMap = jsonDoc.toVariant().toMap().value("Head").toMap(); + + // Set the inverter device state + if (dataMap.contains("PAC")) { + if(dataMap.value("PAC").toMap().values().at(0) == "W") + pluginThing()->setStateValue(inverterCurrentPowerStateTypeId, dataMap.value("PAC").toMap().values().at(1).toInt()); + } + + if (dataMap.contains("DAY_ENERGY")) { + if (dataMap.value("DAY_ENERGY").toMap().values().at(0) == "Wh") + pluginThing()->setStateValue(inverterEdayStateTypeId, dataMap.value("DAY_ENERGY").toMap().values().at(1).toDouble()/1000); + } + + if (dataMap.contains("YEAR_ENERGY")) { + if(dataMap.value("YEAR_ENERGY").toMap().values().at(0) == "Wh") + pluginThing()->setStateValue(inverterEyearStateTypeId, dataMap.value("YEAR_ENERGY").toMap().values().at(1).toInt()/1000); + } + + if (dataMap.contains("TOTAL_ENERGY")) { + if(dataMap.value("TOTAL_ENERGY").toMap().values().at(0) == "Wh") + pluginThing()->setStateValue(inverterTotalEnergyProducedStateTypeId, dataMap.value("TOTAL_ENERGY").toMap().values().at(1).toInt()/1000); + } + + //update successful + pluginThing()->setStateValue(inverterConnectedStateTypeId,true); + +} + +QUrl FroniusInverter::activityUrl() +{ + QUrl requestUrl; + requestUrl.setScheme("http"); + requestUrl.setHost(hostAddress()); + requestUrl.setPath(baseUrl()+"GetPowerFlowRealtimeData.fcgi"); + + return requestUrl; +} + +void FroniusInverter::updateActivityInfo(const QByteArray &data) +{ + // Convert the rawdata to a json document + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if(error.error != QJsonParseError::NoError) { + qCWarning(dcFronius()) << "FroniusInverter: Failed to parse JSON data" << data << ":" << error.errorString(); + return; + } + + // create StorageInfo list map + QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); + + if (dataMap.value("Site").toMap().value("P_PV").toFloat() > 0) { + pluginThing()->setStateValue(inverterActiveStateTypeId, "production"); + } else { + pluginThing()->setStateValue(inverterActiveStateTypeId, "inactive"); + } +} diff --git a/fronius/froniusinverter.h b/fronius/froniusinverter.h new file mode 100644 index 00000000..0b67e59a --- /dev/null +++ b/fronius/froniusinverter.h @@ -0,0 +1,56 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef FRONIUSINVERTER_H +#define FRONIUSINVERTER_H + +#include +#include "froniusthing.h" + +class FroniusInverter : public FroniusThing +{ + Q_OBJECT + +public: + explicit FroniusInverter(Thing *thing, QObject *parent = 0); + + QString activity() const; + void setActivity(const QString &activity); + Thing* inverterThing() const; + QUrl updateUrl(); + void updateThingInfo(const QByteArray &data); + QUrl activityUrl(); + void updateActivityInfo(const QByteArray &data); + +private: + QString m_activity; +}; + +#endif // FRONIUSINVERTER_H diff --git a/fronius/froniuslogger.cpp b/fronius/froniuslogger.cpp new file mode 100644 index 00000000..e15651d5 --- /dev/null +++ b/fronius/froniuslogger.cpp @@ -0,0 +1,145 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "froniuslogger.h" +#include "extern-plugininfo.h" + +#include +#include + +FroniusLogger::FroniusLogger(Thing *thing, QObject *parent) : FroniusThing(thing, parent) +{ + +} + +QUrl FroniusLogger::updateUrl() +{ + QUrl requestUrl; + requestUrl.setScheme("http"); + requestUrl.setHost(hostAddress()); + requestUrl.setPath(baseUrl() + "GetLoggerInfo.cgi"); + + return requestUrl; +} + +void FroniusLogger::updateThingInfo(const QByteArray &data) +{ + // Convert the rawdata to a json document + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + // qCWarning(dcFroniusSolar()) << "Failed to parse JSON data" << data << ":" << error.errorString(); + pluginThing()->setStateValue(dataloggerConnectedStateTypeId,false); + return; + } + + // Parse the data and update the states of our device + QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); + QVariantMap headMap = jsonDoc.toVariant().toMap().value("Head").toMap(); + QVariantMap bodyMap = jsonDoc.toVariant().toMap().value("Body").toMap(); + + // print the fetched data in dataMap format to stdout + //qCDebug(dcFroniusSolar()) << dataMap; + + // create LoggerInfo list Map + QVariantMap LoggerInfoMap = bodyMap.value("LoggerInfo").toMap(); + + // copy retrieved information to device states + if (LoggerInfoMap.contains("ProductID")) + pluginThing()->setStateValue(dataloggerProductidStateTypeId, LoggerInfoMap.value("ProductID").toString()); + + if (LoggerInfoMap.contains("PlatformID")) + pluginThing()->setStateValue(dataloggerPlatformidStateTypeId, LoggerInfoMap.value("PlatformID").toString()); + + if (LoggerInfoMap.contains("HWVersion")) + pluginThing()->setStateValue(dataloggerHwversionStateTypeId, LoggerInfoMap.value("HWVersion").toString()); + + if (LoggerInfoMap.contains("SWVersion")) + pluginThing()->setStateValue(dataloggerSwversionStateTypeId, LoggerInfoMap.value("SWVersion").toString()); + + if (LoggerInfoMap.contains("TimezoneLocation")) + pluginThing()->setStateValue(dataloggerTzonelocStateTypeId, LoggerInfoMap.value("TimezoneLocation").toString()); + + if (LoggerInfoMap.contains("TimezoneName")) + pluginThing()->setStateValue(dataloggerTzoneStateTypeId, LoggerInfoMap.value("TimezoneName").toString()); + + if (LoggerInfoMap.contains("DefaultLanguage")) + pluginThing()->setStateValue(dataloggerDefaultlangStateTypeId, LoggerInfoMap.value("DefaultLanguage").toString()); + + if (LoggerInfoMap.contains("CashFactor")) + pluginThing()->setStateValue(dataloggerCashfactorStateTypeId, LoggerInfoMap.value("CashFactor").toDouble()); + + if (LoggerInfoMap.contains("CashCurrency")) + pluginThing()->setStateValue(dataloggerCashcurrencyStateTypeId, LoggerInfoMap.value("CashCurrency").toString()); + + if (LoggerInfoMap.contains("CO2Factor")) + pluginThing()->setStateValue(dataloggerCo2factorStateTypeId, LoggerInfoMap.value("CO2Factor").toDouble()); + + if (LoggerInfoMap.contains("CO2Unit")) + pluginThing()->setStateValue(dataloggerCo2unitStateTypeId, LoggerInfoMap.value("CO2Unit").toString()); + + //update successful + pluginThing()->setStateValue(dataloggerConnectedStateTypeId,true); +} + +void FroniusLogger::updatePowerRelayState(const QByteArray &data) +{ + // Convert the rawdata to a json document + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + // qCWarning(dcFroniusSolar()) << "Failed to parse JSON data" << data << ":" << error.errorString(); + pluginThing()->setStateValue(dataloggerConnectedStateTypeId,false); + return; + } + + // Parse the data and update the states of our device + QVariantMap bodyMap = jsonDoc.toVariant().toMap().value("Body").toMap(); + QVariantMap dataMap = bodyMap.value("Data").toMap(); + QVariantMap emrsMap = dataMap.value("emrs").toMap(); + + // create LoggerInfo list Map + QVariantMap GpiosMap = emrsMap.value("gpios").toMap(); + //qCDebug(dcFroniusSolar()) << "Body: " << GpiosMap; + + // copy retrieved information to device states + if (GpiosMap.contains("Reason")) { + qCDebug(dcFronius()) << "Power Relay State Reason: " << GpiosMap.value("Reason").toString(); + pluginThing()->setStateValue(dataloggerPowerManagmentRelayReasonStateTypeId, GpiosMap.value("Reason").toString()); + } + + if (GpiosMap.contains("State")) { + qCDebug(dcFronius()) << "Power Relay State: " << GpiosMap.value("State").toString(); + pluginThing()->setStateValue(dataloggerPowerManagmentRelayStateTypeId, GpiosMap.value("State").toBool()); + } + + //update successful + pluginThing()->setStateValue(dataloggerConnectedStateTypeId,true); +} diff --git a/fronius/froniuslogger.h b/fronius/froniuslogger.h new file mode 100644 index 00000000..afb94a53 --- /dev/null +++ b/fronius/froniuslogger.h @@ -0,0 +1,53 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef FRONIUSLOGGER_H +#define FRONIUSLOGGER_H + +#include +#include +#include "froniusinverter.h" +#include "froniusmeter.h" +#include "froniusstorage.h" + +class FroniusLogger : public FroniusThing +{ + Q_OBJECT + +public: + explicit FroniusLogger(Thing *thing, QObject *parent = 0); + + QUrl updateUrl(); + + void updateThingInfo(const QByteArray &data); + void updatePowerRelayState(const QByteArray &data); +}; + +#endif // FRONIUSLOGGER_H diff --git a/fronius/froniusmeter.cpp b/fronius/froniusmeter.cpp new file mode 100644 index 00000000..fe662306 --- /dev/null +++ b/fronius/froniusmeter.cpp @@ -0,0 +1,127 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "froniusmeter.h" +#include "extern-plugininfo.h" + +#include +#include + +FroniusMeter::FroniusMeter(Thing* thing, QObject *parent) : FroniusThing(thing, parent) +{ + +} + +QString FroniusMeter::activity() const +{ + return m_activity; +} + +void FroniusMeter::setActivity(const QString &activity) +{ + m_activity = activity; +} + +QUrl FroniusMeter::updateUrl() +{ + QUrl requestUrl; + requestUrl.setScheme("http"); + QUrlQuery query; + requestUrl.setHost(hostAddress()); + requestUrl.setPath(baseUrl() + "GetMeterRealtimeData.cgi"); + query.addQueryItem("Scope", "Device"); + query.addQueryItem("DeviceId", deviceId()); + requestUrl.setQuery(query); + return requestUrl; +} + +void FroniusMeter::updateThingInfo(const QByteArray &data) +{ + // Convert the rawdata to a JSON document + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcFronius()) << "FroniusMeter: Failed to parse JSON data" << data << ":" << error.errorString(); + pluginThing()->setStateValue(inverterConnectedStateTypeId,false); + return; + } + + // Parse the data and update the states of our thing + QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); + //QVariantMap headMap = jsonDoc.toVariant().toMap().value("Head").toMap(); + + //Add Smart meter with following states: „PowerReal_P_Sum“, „EnergyReal_WAC_Sum_Produced“, „EnergyReal_WAC_Sum_Consumed“ + + // Set the inverter thing state + if (dataMap.contains("PowerReal_P_Sum")) { + pluginThing()->setStateValue(meterCurrentPowerStateTypeId, dataMap.value("PowerReal_P_Sum").toInt()); + } + + if (dataMap.contains("EnergyReal_WAC_Sum_Produced")) { + pluginThing()->setStateValue(meterTotalEnergyProducedStateTypeId, dataMap.value("EnergyReal_WAC_Sum_Produced").toInt()/1000); + } + + if (dataMap.contains("EnergyReal_WAC_Sum_Consumed")) { + pluginThing()->setStateValue(meterTotalEnergyConsumedStateTypeId, dataMap.value("EnergyReal_WAC_Sum_Consumed").toInt()/1000); + } + + //update successful + pluginThing()->setStateValue(meterConnectedStateTypeId,true); +} + +QUrl FroniusMeter::activityUrl() +{ + QUrl requestUrl; + requestUrl.setScheme("http"); + requestUrl.setHost(hostAddress()); + requestUrl.setPath(baseUrl()+"GetPowerFlowRealtimeData.fcgi"); + + return requestUrl; +} + +void FroniusMeter::updateActivityInfo(const QByteArray &data) +{ + // Convert the rawdata to a json document + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if(error.error != QJsonParseError::NoError) { + qCWarning(dcFronius()) << "FroniusMeter: Failed to parse JSON data" << data << ":" << error.errorString(); + return; + } + + // create Meter Info list map + //QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); + + //if (dataMap.value("Site").toMap().value("P_PV").toFloat() > 0) { + // pluginThing()->setStateValue(inverteractivStateTypeId, "production"); + //} else { + // pluginThing()->setStateValue(inverteractivStateTypeId, "inactive"); + //} +} diff --git a/fronius/froniusmeter.h b/fronius/froniusmeter.h new file mode 100644 index 00000000..a629d8a9 --- /dev/null +++ b/fronius/froniusmeter.h @@ -0,0 +1,55 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef FRONIUSMETER_H +#define FRONIUSMETER_H + +#include +#include "froniusthing.h" + +class FroniusMeter : public FroniusThing +{ + Q_OBJECT +public: + explicit FroniusMeter(Thing* thing, QObject *parent = 0); + + QString activity() const; + void setActivity(const QString &activity); + Thing* inverterThing() const; + QUrl updateUrl(); + void updateThingInfo(const QByteArray &data); + QUrl activityUrl(); + void updateActivityInfo(const QByteArray &data); + +private: + QString m_activity; +}; + +#endif // FRONIUSMETER_H diff --git a/fronius/froniusstorage.cpp b/fronius/froniusstorage.cpp new file mode 100644 index 00000000..1567a46a --- /dev/null +++ b/fronius/froniusstorage.cpp @@ -0,0 +1,138 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "froniusstorage.h" +#include +#include "extern-plugininfo.h" +#include + +FroniusStorage::FroniusStorage(Thing* thing, QObject *parent) : FroniusThing(thing, parent) +{ + +} + +QString FroniusStorage::charging_state() const +{ + return m_charging_state; +} + +void FroniusStorage::setChargingState(const QString &charging_state) +{ + m_charging_state = charging_state; +} + +int FroniusStorage::charge() const +{ + return m_charge; +} + +void FroniusStorage::setCharge(const int &charge) +{ + m_charge = charge; +} + +QUrl FroniusStorage::updateUrl() +{ + QUrl requestUrl; + requestUrl.setScheme("http"); + QUrlQuery query; + requestUrl.setHost(hostAddress()); + requestUrl.setPath(baseUrl() + "GetStorageRealtimeData.cgi"); + query.addQueryItem("Scope", "Device"); + query.addQueryItem("DeviceId", deviceId()); + requestUrl.setQuery(query); + + return requestUrl; +} + +void FroniusStorage::updateThingInfo(const QByteArray &data) +{ + // Convert the rawdata to a JSON document + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + + if (error.error != QJsonParseError::NoError) { + qCWarning(dcFronius()) << "FroniusStorage: Failed to parse JSON data" << data << ":" << error.errorString(); + pluginThing()->setStateValue(storageConnectedStateTypeId,false); + return; + } + + // Parse the data and update the states of our thing + QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); + // QVariantMap headMap = jsonDoc.toVariant().toMap().value("Head").toMap(); + + // create StorageInfo list map + QVariantMap storageInfoMap = dataMap.value("Controller").toMap(); + + // copy retrieved information to thing states + if (storageInfoMap.contains("StateOfCharge_Relative")) { + pluginThing()->setStateValue(storageBatteryLevelStateTypeId, storageInfoMap.value("StateOfCharge_Relative").toInt()); + pluginThing()->setStateValue(storageBatteryCriticalStateTypeId, storageInfoMap.value("StateOfCharge_Relative").toInt() < 5); + } + + if (storageInfoMap.contains("Temperature_Cell")) + pluginThing()->setStateValue(storageCellTemperatureStateTypeId, storageInfoMap.value("Temperature_Cell").toDouble()); + + //update successful + pluginThing()->setStateValue(storageConnectedStateTypeId,true); +} + +QUrl FroniusStorage::activityUrl() +{ + QUrl requestUrl; + requestUrl.setScheme("http"); + requestUrl.setHost(hostAddress()); + requestUrl.setPath(baseUrl()+"GetPowerFlowRealtimeData.fcgi"); + + return requestUrl; +} + +void FroniusStorage::updateActivityInfo(const QByteArray &data) +{ + // Convert the rawdata to a json document + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if(error.error != QJsonParseError::NoError) { + qCWarning(dcFronius()) << "FroniusStorage: Failed to parse JSON data" << data << ":" << error.errorString(); + return; + } + + // 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(); + if (charge_akku == 0) { + pluginThing()->setStateValue(storageChargingStateTypeId, "inactive"); + } else if (charge_akku < 0) { + pluginThing()->setStateValue(storageChargingStateTypeId, "charging"); + } else { + pluginThing()->setStateValue(storageChargingStateTypeId, "discharging"); + } +} diff --git a/fronius/froniusstorage.h b/fronius/froniusstorage.h new file mode 100644 index 00000000..fd61dd40 --- /dev/null +++ b/fronius/froniusstorage.h @@ -0,0 +1,60 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef FRONIUSSTORAGE_H +#define FRONIUSSTORAGE_H + +#include +#include "froniusthing.h" + +class FroniusStorage : public FroniusThing +{ + Q_OBJECT + +public: + explicit FroniusStorage(Thing *thing, QObject *parent = 0); + + QString charging_state() const; + void setChargingState(const QString &charging_state); + + int charge() const; + void setCharge(const int &charge); + + QUrl updateUrl(); + void updateThingInfo(const QByteArray &data); + QUrl activityUrl(); + void updateActivityInfo(const QByteArray &data); + +private: + QString m_charging_state; + int m_charge; + +}; +#endif // FRONIUSSTORAGE_H diff --git a/fronius/froniusthing.cpp b/fronius/froniusthing.cpp new file mode 100644 index 00000000..af3903cd --- /dev/null +++ b/fronius/froniusthing.cpp @@ -0,0 +1,102 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "froniusthing.h" + +FroniusThing::FroniusThing(Thing *thing, QObject *parent) : + QObject(parent) +{ + m_thing = thing; +} + +QString FroniusThing::name() const +{ + return m_name; +} + +void FroniusThing::setName(const QString &name) +{ + m_name = name; +} + +QString FroniusThing::hostId() const +{ + return m_hostId; +} + +void FroniusThing::setHostId(const QString &hostId) +{ + m_hostId = hostId; +} + +QString FroniusThing::hostAddress() const +{ + return m_hostAddress; +} + +void FroniusThing::setHostAddress(const QString &hostAddress) +{ + m_hostAddress = hostAddress; +} + +QString FroniusThing::baseUrl() const +{ + return m_baseUrl; +} + +void FroniusThing::setBaseUrl(const QString &baseUrl) +{ + m_baseUrl = baseUrl; +} + +QString FroniusThing::uniqueId() const +{ + return m_uniqueId; +} + +void FroniusThing::setUniqueId(const QString &uniqueId) +{ + m_uniqueId = uniqueId; +} + +QString FroniusThing::deviceId() const +{ + return m_thingId; +} + +void FroniusThing::setDeviceId(const QString &thingId) +{ + m_thingId = thingId; +} + +Thing* FroniusThing::pluginThing() const +{ + return m_thing; +} diff --git a/fronius/froniusthing.h b/fronius/froniusthing.h new file mode 100644 index 00000000..9f7acbd7 --- /dev/null +++ b/fronius/froniusthing.h @@ -0,0 +1,82 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef FRONIUSTHING_H +#define FRONIUSTHING_H + +#include "extern-plugininfo.h" +#include "integrations/thing.h" + +#include +#include +#include + +class FroniusThing : public QObject +{ + Q_OBJECT + +public: + explicit FroniusThing(Thing *thing, QObject *parrent = 0); + + QString name() const; + void setName(const QString &name); + + QString hostId() const; + void setHostId(const QString &hostId); + + QString hostAddress() const; + void setHostAddress(const QString &hostAddress); + + QString baseUrl() const; + void setBaseUrl(const QString &baseUrl); + + QString uniqueId() const; + void setUniqueId(const QString &uniqueId); + + QString deviceId() const; + void setDeviceId(const QString &deviceId); + + Thing* pluginThing() const; + +private: + + Thing* m_thing; + + QString m_name; + QString m_hostId; + QString m_hostAddress; + QString m_apiVersion; + QString m_baseUrl; + QString m_uniqueId; + QString m_thingId; + +}; + +#endif // FRONIUSTHING_H diff --git a/fronius/integrationpluginfronius.cpp b/fronius/integrationpluginfronius.cpp new file mode 100644 index 00000000..bd3d2dde --- /dev/null +++ b/fronius/integrationpluginfronius.cpp @@ -0,0 +1,512 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "plugininfo.h" +#include "integrationpluginfronius.h" +#include "plugintimer.h" +#include "network/networkaccessmanager.h" + +#include +#include +#include +#include +#include + +// Notes: Test IPs: 93.82.221.82 | 88.117.152.99 + +IntegrationPluginFronius::IntegrationPluginFronius(QObject *parent): IntegrationPlugin(parent){ + +} + +void IntegrationPluginFronius::setupThing(ThingSetupInfo *info) +{ + qCDebug(dcFronius()) << "Setting up a new thing:" << info->thing()->name(); + + Thing *thing = info->thing(); + + if (thing->thingClassId() == dataloggerThingClassId) { + //check if a data logger is already added with this IPv4Address + foreach(FroniusLogger *logger, m_froniusLoggers.keys()){ + if(logger->hostAddress() == thing->paramValue(dataloggerThingLoggerHostParamTypeId).toString()){ + //this logger at this IPv4 address is already added + qCWarning(dcFronius()) << "thing at " << thing->paramValue(dataloggerThingLoggerHostParamTypeId).toString() << " already added!"; + info->finish(Thing::ThingErrorThingInUse); + return; + } + } + + // Perform a HTTP request on the given IPv4Address to find things + QUrl requestUrl; + requestUrl.setScheme("http"); + requestUrl.setHost(thing->paramValue(dataloggerThingLoggerHostParamTypeId).toString()); + requestUrl.setPath("/solar_api/GetAPIVersion.cgi"); + + qCDebug(dcFronius()) << "Search at address" << requestUrl.toString(); + + QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(requestUrl)); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + connect(reply, &QNetworkReply::finished, [this, info, thing, reply]() { + QByteArray data = reply->readAll(); + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Fronius: Network request error:" << reply->error() << reply->errorString() << reply->url(); + info->finish(Thing::ThingErrorHardwareNotAvailable, tr("Device not reachable")); + return; + } + + // Convert the rawdata to a JSON document + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcFronius()) << "Fronius: Failed to parse JSON data" << data << ":" << error.errorString() << data; + info->finish(Thing::ThingErrorHardwareFailure, tr("Please try again")); + return; + } + + FroniusLogger *newLogger = new FroniusLogger(thing, this); + newLogger->setBaseUrl(jsonDoc.toVariant().toMap().value("BaseURL").toString()); + newLogger->setHostAddress(thing->paramValue(dataloggerThingLoggerHostParamTypeId).toString()); + m_froniusLoggers.insert(newLogger, thing); + + info->finish(Thing::ThingErrorNoError); + }); + //Async Setup + } else if (thing->thingClassId() == inverterThingClassId) { + + FroniusInverter *newInverter = new FroniusInverter(thing,this); + newInverter->setDeviceId(thing->paramValue(inverterThingIdParamTypeId).toString()); + newInverter->setBaseUrl(thing->paramValue(inverterThingBaseParamTypeId).toString()); + newInverter->setHostAddress(thing->paramValue(inverterThingHostParamTypeId).toString()); + + m_froniusInverters.insert(newInverter,thing); + + // get inverter unique ID + QUrl requestUrl; + requestUrl.setScheme("http"); + requestUrl.setHost(newInverter->hostAddress()); + requestUrl.setPath(newInverter->baseUrl() + "GetInverterInfo.cgi"); + + QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(requestUrl)); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + connect(reply, &QNetworkReply::finished, [this, info, newInverter, reply]() { + QByteArray data = reply->readAll(); + reply->deleteLater(); + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Fronius: Network request error:" << reply->error() << reply->errorString(); + info->finish(Thing::ThingErrorHardwareNotAvailable, "Device not reachable"); + return; + } + + // Convert the rawdata to a json document + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcFronius()) << "Fronius: Failed to parse JSON data" << data << ":" << error.errorString(); + info->finish(Thing::ThingErrorHardwareNotAvailable, "Please try again"); + return; + } + + // Check reply information + QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); + // check for thing id in reply + if (dataMap.contains(newInverter->deviceId())) { + qCDebug(dcFronius()) << "Found Thing with unique:" << dataMap.value(newInverter->deviceId()).toMap().value("UniqueID").toString(); + newInverter->setUniqueId(dataMap.value(newInverter->deviceId()).toMap().value("UniqueID").toString()); + newInverter->pluginThing()->setParamValue(inverterThingUniqueIdParamTypeId,newInverter->uniqueId()); + qCDebug(dcFronius()) << "Stored unique ID:" << newInverter->uniqueId(); + } + info->finish(Thing::ThingErrorNoError); + }); + // Async Setup + } else if (thing->thingClassId() == storageThingClassId) { + + FroniusStorage *newStorage = new FroniusStorage(thing, this); + newStorage->setDeviceId(thing->paramValue(storageThingIdParamTypeId).toString()); + newStorage->setBaseUrl(thing->paramValue(storageThingBaseParamTypeId).toString()); + newStorage->setHostAddress(thing->paramValue(storageThingHostParamTypeId).toString()); + m_froniusStorages.insert(newStorage,thing); + + // 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, [this, info, newStorage, reply]() { + QByteArray data = reply->readAll(); + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Fronius: 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()) << "Fronius: 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()); + info->finish(Thing::ThingErrorNoError); + }); + //Async Setup + } else if (thing->thingClassId() == meterThingClassId) { + + FroniusMeter *newMeter = new FroniusMeter(thing, this);; + newMeter->setDeviceId(thing->paramValue(meterThingIdParamTypeId).toString()); + newMeter->setBaseUrl(thing->paramValue(meterThingBaseParamTypeId).toString()); + newMeter->setHostAddress(thing->paramValue(meterThingHostParamTypeId).toString()); + + m_froniusMeters.insert(newMeter, thing); + info->finish(Thing::ThingErrorNoError); + //Async setup + } else { + Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); + } +} + +void IntegrationPluginFronius::postSetupThing(Thing *thing) +{ + qCDebug(dcFronius()) << "Post setup" << thing->name(); + + if (!m_pluginTimer) { + m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(30); + connect(m_pluginTimer, &PluginTimer::timeout, this, [this]() { + foreach (Thing *logger, m_froniusLoggers) + updateThingStates(logger); + + foreach (Thing *inverter, m_froniusInverters) + updateThingStates(inverter); + + foreach (Thing *meter, m_froniusMeters) + updateThingStates(meter); + + foreach (Thing *storage, m_froniusStorages) + updateThingStates(storage); + }); + } + + if (thing->thingClassId() == dataloggerThingClassId) { + searchNewThings(m_froniusLoggers.key(thing)); + updateThingStates(thing); + } else if (thing->thingClassId() == inverterThingClassId) { + updateThingStates(thing); + } else if (thing->thingClassId() == meterThingClassId) { + updateThingStates(thing); + } else if (thing->thingClassId() == storageThingClassId) { + updateThingStates(thing); + } else { + Q_ASSERT_X(false, "postSetupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); + } +} + +void IntegrationPluginFronius::thingRemoved(Thing *thing) +{ + if (thing->thingClassId() == dataloggerThingClassId) { + FroniusLogger *logger = m_froniusLoggers.key(thing); + m_froniusLoggers.remove(logger); + logger->deleteLater(); + return; + } else if (thing->thingClassId() == inverterThingClassId) { + FroniusInverter *inverter = m_froniusInverters.key(thing); + m_froniusInverters.remove(inverter); + inverter->deleteLater(); + return; + } else if (thing->thingClassId() == meterThingClassId) { + FroniusMeter *meter = m_froniusMeters.key(thing); + m_froniusMeters.remove(meter); + meter->deleteLater(); + return; + } else if (thing->thingClassId() == storageThingClassId) { + FroniusStorage *storage = m_froniusStorages.key(thing); + m_froniusStorages.remove(storage); + storage->deleteLater(); + return; + } else { + Q_ASSERT_X(false, "thingRemoved", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); + } + + if (myThings().isEmpty()) { + hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer); + m_pluginTimer = nullptr; + } +} + + +void IntegrationPluginFronius::executeAction(ThingActionInfo *info) +{ + Action action = info->action(); + Thing *thing = info->thing(); + qCDebug(dcFronius()) << "Execute action" << thing->name() << action.actionTypeId().toString(); + + if (thing->thingClassId() == dataloggerThingClassId) { + + if (action.actionTypeId() == dataloggerSearchDevicesActionTypeId) { + searchNewThings(m_froniusLoggers.key(thing)); + info->finish(Thing::ThingErrorNoError); + } else { + Q_ASSERT_X(false, "executeAction", QString("Unhandled action: %1").arg(action.actionTypeId().toString()).toUtf8()); + } + } else { + Q_ASSERT_X(false, "executeAction", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); + } +} + +void IntegrationPluginFronius::updateThingStates(Thing *thing) +{ + qCDebug(dcFronius()) << "Update thing values for" << thing->name(); + + if(thing->thingClassId() == inverterThingClassId) { + QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(m_froniusInverters.key(thing)->updateUrl())); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + connect(reply, &QNetworkReply::finished, [this, thing, reply]() { + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Network request error:" << reply->error() << reply->errorString() << reply->request().url(); + return; + } + QByteArray data = reply->readAll(); + if(m_froniusInverters.values().contains(thing)){ // check if thing was not removed before reply was received + m_froniusInverters.key(thing)->updateThingInfo(data); + } + }); + QNetworkReply *next_reply = hardwareManager()->networkManager()->get(QNetworkRequest(m_froniusInverters.key(thing)->activityUrl())); + connect(next_reply, &QNetworkReply::finished, next_reply, &QNetworkReply::deleteLater); + connect(next_reply, &QNetworkReply::finished, [this, thing, next_reply]() { + if (next_reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Network request error:" << next_reply->error() << next_reply->errorString() << next_reply->request().url(); + return; + } + QByteArray data = next_reply->readAll(); + if(m_froniusInverters.values().contains(thing)){ // check if thing was not removed before reply was received + m_froniusInverters.key(thing)->updateActivityInfo(data); + } + }); + } else if (thing->thingClassId() == dataloggerThingClassId) { + QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(m_froniusLoggers.key(thing)->updateUrl())); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + connect(reply, &QNetworkReply::finished, [this, thing, reply]() { + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Network request error:" << reply->error() << reply->errorString() << reply->request().url(); + return; + } + QByteArray data = reply->readAll(); + if(m_froniusLoggers.values().contains(thing)){ // check if thing was not removed before reply was received + m_froniusLoggers.key(thing)->updateThingInfo(data); + } + }); + + } else if (thing->thingClassId() == meterThingClassId) { + QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(m_froniusMeters.key(thing)->updateUrl())); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + connect(reply, &QNetworkReply::finished, [this, thing, reply]() { + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Network request error:" << reply->error() << reply->errorString() << reply->request().url(); + return; + } + QByteArray data = reply->readAll(); + if(m_froniusMeters.values().contains(thing)){ // check if thing was not removed before reply was received + m_froniusMeters.key(thing)->updateThingInfo(data); + } + }); + QNetworkReply *next_reply = hardwareManager()->networkManager()->get(QNetworkRequest(m_froniusMeters.key(thing)->activityUrl())); + connect(next_reply, &QNetworkReply::finished, next_reply, &QNetworkReply::deleteLater); + connect(next_reply, &QNetworkReply::finished, [this, thing, next_reply]() { + + if (next_reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Network request error:" << next_reply->error() << next_reply->errorString() << next_reply->request().url(); + return; + } + QByteArray data = next_reply->readAll(); + if(m_froniusMeters.values().contains(thing)){ // check if thing was not removed before reply was received + m_froniusMeters.key(thing)->updateActivityInfo(data); + } + }); + } else if (thing->thingClassId() == storageThingClassId) { + QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(m_froniusStorages.key(thing)->updateUrl())); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + connect(reply, &QNetworkReply::finished, [this, thing, reply]() { + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Network request error:" << reply->error() << reply->errorString() << reply->request().url(); + return; + } + QByteArray data = reply->readAll(); + if(m_froniusStorages.values().contains(thing)){ // check if thing was not removed before reply was received + m_froniusStorages.key(thing)->updateThingInfo(data); + } + }); + QNetworkReply *next_reply = hardwareManager()->networkManager()->get(QNetworkRequest(m_froniusStorages.key(thing)->activityUrl())); + connect(next_reply, &QNetworkReply::finished, next_reply, &QNetworkReply::deleteLater); + connect(next_reply, &QNetworkReply::finished, [this, thing, next_reply]() { + next_reply->deleteLater(); + if (next_reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Network request error:" << next_reply->error() << next_reply->errorString() << next_reply->request().url(); + return; + } + QByteArray data = next_reply->readAll(); + if(m_froniusStorages.values().contains(thing)){ // check if thing was not removed before reply was received + m_froniusStorages.key(thing)->updateActivityInfo(data); + } + }); + } else { + Q_ASSERT_X(false, "updateThingState", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); + + } +} + +void IntegrationPluginFronius::searchNewThings(FroniusLogger *logger) +{ + QUrl url; QUrlQuery query; + query.addQueryItem("DeviceClass", "System"); + url.setScheme("http"); + url.setHost(logger->hostAddress()); + url.setPath(logger->baseUrl() + "GetActiveDeviceInfo.cgi"); + url.setQuery(query); + + qCDebug(dcFronius()) << "Search Things at address" << url.toString(); + QNetworkRequest request = QNetworkRequest(url); + request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json"); + + QNetworkReply *reply = hardwareManager()->networkManager()->get(request); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + connect(reply, &QNetworkReply::finished, [this, logger, reply]() { + + if (reply->error() != QNetworkReply::NoError) { + qCWarning(dcFronius()) << "Network request error:" << reply->error() << reply->errorString() << reply->request().url(); + return; + } + + Thing *loggerThing = m_froniusLoggers.value(logger); + if (!loggerThing) + return; + + QByteArray data = reply->readAll(); + + // Convert the rawdata to a json document + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(dcFronius()) << "Fronius: Failed to parse JSON data" << data << ":" << error.errorString(); + return; + } + + // Parse the data for thing information + QList thingDescriptors; + + // Check reply information + QVariantMap bodyMap = jsonDoc.toVariant().toMap().value("Body").toMap(); + + // Parse reply for inverters at the host address + QVariantMap inverterMap = bodyMap.value("Data").toMap().value("Inverter").toMap(); + foreach (QString inverterId, inverterMap.keys()) { + //check if thing already connected to logger + if(!existingThing(inverterThingIdParamTypeId,inverterId)) { + QString thingName = loggerThing->name() + " Inverter " + inverterId; + ThingDescriptor descriptor(inverterThingClassId, thingName, "Fronius Solar Inverter", loggerThing->id()); + ParamList params; + params.append(Param(inverterThingHostParamTypeId, m_froniusLoggers.key(loggerThing)->hostAddress())); + params.append(Param(inverterThingBaseParamTypeId, m_froniusLoggers.key(loggerThing)->baseUrl())); + params.append(Param(inverterThingIdParamTypeId, inverterId)); + params.append(Param(inverterThingUniqueIdParamTypeId, "")); + descriptor.setParams(params); + thingDescriptors.append(descriptor); + } + } + + // parse reply for meter things at the host address + QVariantMap meterMap = bodyMap.value("Data").toMap().value("Meter").toMap(); + foreach (QString meterId, meterMap.keys()) { + //check if thing already connected to logger + if(!existingThing(meterThingIdParamTypeId, meterId)) { + QString thingName = loggerThing->name() + " Meter " + meterId; + ThingDescriptor descriptor(meterThingClassId, thingName, "Fronius Solar Meter", loggerThing->id()); + ParamList params; + params.append(Param(meterThingHostParamTypeId, m_froniusLoggers.key(loggerThing)->hostAddress())); + params.append(Param(meterThingBaseParamTypeId, m_froniusLoggers.key(loggerThing)->baseUrl())); + params.append(Param(meterThingIdParamTypeId, meterId)); + params.append(Param(meterThingUniqueIdParamTypeId, meterMap.value(meterId).toMap().value("Serial").toString())); + descriptor.setParams(params); + thingDescriptors.append(descriptor); + } + } + + // parse reply for storage things at the host address + QVariantMap storageMap = bodyMap.value("Data").toMap().value("Storage").toMap(); + foreach (QString storageId, storageMap.keys()) { + //check if thing already connected to logger + if(!existingThing(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(storageThingHostParamTypeId, m_froniusLoggers.key(loggerThing)->hostAddress())); + params.append(Param(storageThingBaseParamTypeId, m_froniusLoggers.key(loggerThing)->baseUrl())); + params.append(Param(storageThingIdParamTypeId, storageId)); + params.append(Param(storageThingUniqueIdParamTypeId, storageMap.value(storageId).toMap().value("Serial").toString())); + descriptor.setParams(params); + thingDescriptors.append(descriptor); + } + } + + if (!thingDescriptors.empty()) { + emit autoThingsAppeared(thingDescriptors); + thingDescriptors.clear(); + } + }); +} + +bool IntegrationPluginFronius::existingThing(ParamTypeId thingParamId, QString thingId) +{ + foreach(Thing *thing, myThings()) { + if(thing->paramValue(thingParamId).toString() == thingId) { + return true; + } + } + return false; +} + diff --git a/fronius/integrationpluginfronius.h b/fronius/integrationpluginfronius.h new file mode 100644 index 00000000..88ad357a --- /dev/null +++ b/fronius/integrationpluginfronius.h @@ -0,0 +1,74 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 3. This project is distributed in the hope that +* it will be useful, but WITHOUT ANY WARRANTY; without even the implied +* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef INTEGRATIONPLUGINFRONIUS_H +#define INTEGRATIONPLUGINFRONIUS_H + +#include "integrations/integrationplugin.h" +#include "froniuslogger.h" + +#include +#include +#include +#include + +class PluginTimer; + +class IntegrationPluginFronius : public IntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginfronius.json") + Q_INTERFACES(IntegrationPlugin) + +public: + explicit IntegrationPluginFronius(QObject *parent = nullptr); + + void setupThing(ThingSetupInfo *thing) override; + void postSetupThing(Thing* thing) override; + void executeAction(ThingActionInfo *info) override; + void thingRemoved(Thing* thing) override; + +private: + PluginTimer *m_pluginTimer = nullptr; + + QHash m_froniusLoggers; + QHash m_froniusInverters; + QHash m_froniusMeters; + QHash m_froniusStorages; + + QHash m_asyncActions; + + void updateThingStates(Thing *thing); + + void searchNewThings(FroniusLogger *logger); + bool existingThing(ParamTypeId thingParamId, QString thingId); +}; + +#endif // INTEGRATIONPLUGINFRONIUS_H diff --git a/fronius/integrationpluginfronius.json b/fronius/integrationpluginfronius.json new file mode 100644 index 00000000..05edeb30 --- /dev/null +++ b/fronius/integrationpluginfronius.json @@ -0,0 +1,414 @@ +{ + "id": "02319cfc-8b55-49ba-99bc-0588bbfab063", + "name": "fronius", + "displayName": "Fronius Solar", + "vendors": [ + { + "id": "2286fc38-afd9-4128-ab7e-0fba527d53ba", + "name": "Fronius", + "displayName": "Fronius", + "thingClasses": [ + { + "id": "4fd79fed-42f1-4df9-be64-3df7b2e0bda2", + "name": "datalogger", + "displayName": "Fronius Solar Connection", + "createMethods": ["user"], + "interfaces": ["gateway"], + "paramTypes": [ + { + "id": "52da0197-4b78-4fec-aa72-70f949e26edc", + "name": "loggerHost", + "displayName": "Host address", + "type": "QString", + "inputType": "IPv4Address", + "defaultValue": "88.117.152.99" + } + ], + "stateTypes": [ + { + "id": "98e4476f-e745-4a7f-b795-19269cb70c40", + "name": "connected", + "displayName": "Reachable", + "displayNameEvent": "logger reachable changed", + "type": "bool", + "defaultValue": false + }, + { + "id": "b22052ef-14da-43d2-982b-f2c2d8c03206", + "name": "productid", + "displayName": "Product ID", + "displayNameEvent": "Product ID changed", + "type": "QString", + "defaultValue": "-" + }, + { + "id": "65c068e6-4a0b-4672-9724-ae95216c4c9c", + "name": "platformid", + "displayName": "Platform ID", + "displayNameEvent": "Platform ID changed", + "type": "QString", + "defaultValue": "-" + }, + { + "id": "3b4206e5-74c7-4708-96b8-2abfab0c41d6", + "name": "hwversion", + "displayName": "Hardware version", + "displayNameEvent": "Hardware version changed", + "type": "QString", + "defaultValue": "-" + }, + { + "id": "31743ca5-4353-4f26-b2ad-5da43e5b9d86", + "name": "swversion", + "displayName": "Software version", + "displayNameEvent": "Software version changed", + "type": "QString", + "defaultValue": "-" + }, + { + "id": "d034f59d-dc34-450a-a6f3-68264767a3e4", + "name": "tzoneloc", + "displayName": "Timezone location", + "displayNameEvent": "Timezone location changed", + "type": "QString", + "defaultValue": "-" + }, + { + "id": "6bdfeeda-7a47-4043-a011-5eb96308a7d6", + "name": "tzone", + "displayName": "Time zone", + "displayNameEvent": "Time zone changed", + "type": "QString", + "defaultValue": "-" + }, + { + "id": "18b250e2-080a-4991-b368-177c4da83eca", + "name": "defaultlang", + "displayName": "Default language", + "displayNameEvent": "Default language changed", + "type": "QString", + "defaultValue": "-" + }, + { + "id": "bc18595b-17c7-4a1f-8002-b908a3d9239d", + "name": "cashfactor", + "displayName": "Cash factor", + "displayNameEvent": "Cash factor changed", + "type": "double", + "defaultValue": "-" + }, + { + "id": "84da30c8-a7fb-49c6-884c-9521f9f62bbc", + "name": "cashcurrency", + "displayName": "Cash currency", + "displayNameEvent": "Cash Currency changed", + "type": "QString", + "defaultValue": "-" + }, + { + "id": "8ab01225-7be5-4482-a99b-314108ae0e2b", + "name": "co2factor", + "displayName": "CO2 factor", + "displayNameEvent": "CO2 factor changed", + "type": "double", + "defaultValue": "-" + }, + { + "id": "b0e655f8-27d0-4add-918b-461cadc8efcc", + "name": "co2unit", + "displayName": "CO2 unit", + "displayNameEvent": "CO2 unit changed", + "type": "QString", + "defaultValue": "-" + }, + { + "id": "b217acf6-0c5e-4a3e-a50c-4c0133c871c2", + "name": "powerManagmentRelay", + "displayName": "Power management relay", + "displayNameEvent": "Power management relay status changed", + "type": "bool", + "defaultValue": false + }, + { + "id": "5650ce9b-0d7d-4c52-b410-ea618889b4bb", + "name": "powerManagmentRelayReason", + "displayName": "Power management relay reason", + "displayNameEvent": "Power management relay reason changed", + "type": "QString", + "defaultValue": "" + } + ], + "actionTypes": [ + { + "id": "c217fdc1-de18-41dc-b5d8-8072f84e7b6c", + "name": "searchDevices", + "displayName": "Search new devices" + } + ] + }, + { + "id": "540aa956-8b8f-4982-9f58-343a76cea846", + "name": "inverter", + "displayName": "Fronius Solar Inverter", + "createMethods": ["auto"], + "interfaces" : ["extendedsmartmeterproducer", "connectable"], + "paramTypes": [ + { + "id": "1aa82e12-ee8c-4142-8b89-a4f1e85556d0", + "name": "host", + "displayName": "Host address", + "type": "QString", + "inputType": "TextLine" + }, + { + "id": "ec1f792a-b453-49f0-8ea6-677ad3c25a5c", + "name": "base", + "displayName": "Base url", + "type": "QString", + "inputType": "TextLine" + }, + { + "id": "f2f8c2f5-dd6a-4786-b336-82fc84e5bb98", + "name": "id", + "displayName": "Device id", + "type": "QString", + "inputType": "TextLine" + }, + { + "id": "8fadc0e8-9d69-4b9d-b493-b6ac3eb59c49", + "name": "uniqueId", + "displayName": "Unique id", + "type": "QString", + "inputType": "TextLine" + } + ], + "stateTypes": [ + { + "id": "eda29c50-73ac-40e0-9c92-26fee352e688", + "name": "connected", + "displayName": "Reachable", + "displayNameEvent": "Reachable changed", + "type": "bool", + "defaultValue": false + }, + { + "id": "e763baa7-5eaf-438c-83f0-4fa6c0f7eeb0", + "name": "active", + "displayName": "Inverter active", + "displayNameEvent": "Inverter active changed", + "type": "QString", + "defaultValue": "-" + }, + { + "id": "788accbc-b86e-471b-b37f-14c9c6411526", + "name": "currentPower", + "displayName": "Current power", + "displayNameEvent": "Current Power changed", + "type": "double", + "unit": "Watt", + "defaultValue": "0" + }, + { + "id": "b6af1bf5-753d-47b6-a151-e4d801fe6ff8", + "name": "eday", + "displayName": "Energy of current day", + "displayNameEvent": "Energy of day changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": "0" + }, + { + "id": "7fd2fa28-9bcc-4f01-a823-459437d185f6", + "name": "eyear", + "displayName": "Energy of current year", + "displayNameEvent": "Energy of year changed", + "type": "int", + "unit": "KiloWattHour", + "defaultValue": "0" + }, + { + "id": "d6dbb879-4cbc-4db3-830e-b92ba91a13e5", + "name": "totalEnergyProduced", + "displayName": "Energy total", + "displayNameEvent": "Energy total changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": "0" + } + ] + }, + { + "id": "c3cb53a4-32dd-434d-9d9c-aada41f8129c", + "name": "meter", + "displayName": "Fronius Smart Meter", + "createMethods": ["auto"], + "interfaces": [ "extendedsmartmeterconsumer", "extendedsmartmeterproducer", "connectable" ], + "paramTypes": [ + { + "id": "ddcb8689-b0b8-4b94-b022-4ce4cf9e0ec2", + "name": "host", + "displayName": "Address", + "type": "QString", + "inputType": "TextLine" + }, + { + "id": "2cb4acd6-a663-48c3-8366-ab538c7b4e7d", + "name": "base", + "displayName": "Base URL", + "type": "QString", + "inputType": "TextLine" + }, + { + "id": "cf3a7025-d368-475a-8f48-efc1344a8409", + "name": "id", + "displayName": "Device ID", + "type": "QString", + "inputType": "TextLine" + }, + { + "id": "285eabb2-47c8-4406-8123-6621b21558c1", + "name": "uniqueId", + "displayName": "Unique ID", + "type": "QString", + "inputType": "TextLine" + } + ], + "stateTypes": [ + { + "id": "b70b61a4-54cb-47ec-b62a-b498eb1f650e", + "name": "connected", + "displayName": "Reachable", + "displayNameEvent": "Reachable changed", + "type": "bool", + "defaultValue": false + }, + { + "id": "e5056ea1-88a2-410b-9c5e-6322aca4cb17", + "name": "currentPower", + "displayName": "Total current power", + "displayNameEvent": "Total current power changed", + "type": "double", + "unit": "Watt", + "defaultValue": "0" + }, + { + "id": "ca14cca5-d9f0-49c5-a8f7-907d4c0825f0", + "name": "totalEnergyProduced", + "displayName": "Energy Produced", + "displayNameEvent": "Energy production changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": "0" + }, + { + "id": "f3451818-48d2-42a5-94fd-ad094c06967f", + "name": "totalEnergyConsumed", + "displayName": "Energy Consumed", + "displayNameEvent": "Energy consumption changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": "0" + } + ] + }, + { + "id": "b00139fa-7386-48b1-8697-2fdd21a57ced", + "name": "storage", + "displayName": "Fronius Solar Storage", + "createMethods": ["auto"], + "interfaces": [ "batterylevel", "connectable" ], + "paramTypes": [ + { + "id": "9665c38b-c13a-428f-b741-1470239c63dc", + "name": "manufacturer", + "displayName": "Manufacturer", + "type": "QString", + "defaultValue": "TextLine" + }, + { + "id": "59a68e91-1aad-46b7-b351-03b7b2216366", + "name": "capacity", + "displayName": "Maxmimum capacity", + "type": "QString", + "defaultValue": "TextLine" + }, + { + "id": "84bd8a41-2411-4bb0-87a9-ab7e01044b10", + "name": "host", + "displayName": "Address", + "type": "QString", + "inputType": "TextLine" + }, + { + "id": "d19b5d81-4e62-48be-bad6-287b0019274a", + "name": "base", + "displayName": "Base URL", + "type": "QString", + "inputType": "TextLine" + }, + { + "id": "49087f31-abf5-4bb8-946b-a3626ee80566", + "name": "id", + "displayName": "Device ID", + "type": "QString", + "inputType": "TextLine" + }, + { + "id": "0d62432a-38bc-48b8-99d2-895f17fcf0b2", + "name": "uniqueId", + "displayName": "Unique ID", + "type": "QString", + "inputType": "TextLine" + } + ], + "stateTypes": [ + { + "id": "2f7e1267-b0be-4b78-9aa3-832b86c4efad", + "name": "connected", + "displayName": "Reachable", + "displayNameEvent": "Reachable changed", + "type": "bool", + "defaultValue": false + }, + { + "id": "2de34a1f-de2e-43ad-8998-8a5460dff9ae", + "name": "charging", + "displayName": "State of charge", + "displayNameEvent": "Charge state changed", + "type": "QString", + "defaultValue": "-" + }, + { + "id": "5c6da672-9662-41bc-8c8c-aa0f32481251", + "name": "batteryLevel", + "displayName": "Battery level", + "displayNameEvent": "Battery level changed", + "type": "int", + "unit": "Percentage", + "defaultValue": "0", + "minValue": 0, + "maxValue": 100 + }, + { + "id": "4417499c-1757-4309-868a-be5cf3455c4a", + "name": "cellTemperature", + "displayName": "Cell temperature", + "displayNameEvent": "Cell temperature changed", + "type": "double", + "unit": "DegreeCelsius", + "defaultValue": "0" + }, + { + "id": "e5396312-b50e-4d6f-b628-5b51448971d3", + "name": "batteryCritical", + "displayName": "Battery level critical", + "displayNameEvent": "Battery level critical changed", + "type": "bool", + "defaultValue": false + } + ] + } + ] + } + ] +} diff --git a/fronius/meta.json b/fronius/meta.json new file mode 100644 index 00000000..d8dd467b --- /dev/null +++ b/fronius/meta.json @@ -0,0 +1,13 @@ +{ + "title": "Fronius", + "tagline": "Connect to Fronius Solar devices.", + "icon": "fronius.png", + "stability": "community", + "offline": true, + "technologies": [ + "network" + ], + "categories": [ + + ] +} diff --git a/fronius/translations/02319cfc-8b55-49ba-99bc-0588bbfab063-de.ts b/fronius/translations/02319cfc-8b55-49ba-99bc-0588bbfab063-de.ts new file mode 100644 index 00000000..e4dea36a --- /dev/null +++ b/fronius/translations/02319cfc-8b55-49ba-99bc-0588bbfab063-de.ts @@ -0,0 +1,741 @@ + + + + + IntegrationPluginFronius + + + Device not reachable + Gerät nicht erreichbar + + + + + Please try again + Bitte versuchen Sie es erneut + + + + fronius + + + + + Address + The name of the ParamType (ThingClass: sunspecStorage, Type: thing, ID: {830a3cc6-ae0a-4cc3-94d6-86575e410e49}) +---------- +The name of the ParamType (ThingClass: storage, Type: thing, ID: {84bd8a41-2411-4bb0-87a9-ab7e01044b10}) +---------- +The name of the ParamType (ThingClass: meter, Type: thing, ID: {ddcb8689-b0b8-4b94-b022-4ce4cf9e0ec2}) + Adresse + + + + + Base URL + The name of the ParamType (ThingClass: storage, Type: thing, ID: {d19b5d81-4e62-48be-bad6-287b0019274a}) +---------- +The name of the ParamType (ThingClass: meter, Type: thing, ID: {2cb4acd6-a663-48c3-8366-ab538c7b4e7d}) + Basis URL + + + + Base url + The name of the ParamType (ThingClass: inverter, Type: thing, ID: {ec1f792a-b453-49f0-8ea6-677ad3c25a5c}) + Basis URL + + + + + Battery critical + The name of the ParamType (ThingClass: sunspecStorage, EventType: batteryCritical, ID: {3171a6e0-43a7-4de8-8e20-f748e44af7ac}) +---------- +The name of the StateType ({3171a6e0-43a7-4de8-8e20-f748e44af7ac}) of ThingClass sunspecStorage + Batterie kritisch + + + + Battery critical changed + The name of the EventType ({3171a6e0-43a7-4de8-8e20-f748e44af7ac}) of ThingClass sunspecStorage + Batterie kritisch geändert + + + + + + + Battery level + The name of the ParamType (ThingClass: sunspecStorage, EventType: batteryLevel, ID: {0bf53f80-97f8-488b-b514-58f9fe08c183}) +---------- +The name of the StateType ({0bf53f80-97f8-488b-b514-58f9fe08c183}) of ThingClass sunspecStorage +---------- +The name of the ParamType (ThingClass: storage, EventType: batteryLevel, ID: {5c6da672-9662-41bc-8c8c-aa0f32481251}) +---------- +The name of the StateType ({5c6da672-9662-41bc-8c8c-aa0f32481251}) of ThingClass storage + Batteriestand + + + + + Battery level changed + The name of the EventType ({0bf53f80-97f8-488b-b514-58f9fe08c183}) of ThingClass sunspecStorage +---------- +The name of the EventType ({5c6da672-9662-41bc-8c8c-aa0f32481251}) of ThingClass storage + Batteriestand geändert + + + + + Battery level critical + The name of the ParamType (ThingClass: storage, EventType: batteryCritical, ID: {e5396312-b50e-4d6f-b628-5b51448971d3}) +---------- +The name of the StateType ({e5396312-b50e-4d6f-b628-5b51448971d3}) of ThingClass storage + Batteriestand kritisch + + + + Battery level critical changed + The name of the EventType ({e5396312-b50e-4d6f-b628-5b51448971d3}) of ThingClass storage + Batteriestand kritisch geändert + + + + + CO2 factor + The name of the ParamType (ThingClass: datalogger, EventType: co2factor, ID: {8ab01225-7be5-4482-a99b-314108ae0e2b}) +---------- +The name of the StateType ({8ab01225-7be5-4482-a99b-314108ae0e2b}) of ThingClass datalogger + CO2 Faktor + + + + CO2 factor changed + The name of the EventType ({8ab01225-7be5-4482-a99b-314108ae0e2b}) of ThingClass datalogger + CO2 Faktor geändert + + + + + CO2 unit + The name of the ParamType (ThingClass: datalogger, EventType: co2unit, ID: {b0e655f8-27d0-4add-918b-461cadc8efcc}) +---------- +The name of the StateType ({b0e655f8-27d0-4add-918b-461cadc8efcc}) of ThingClass datalogger + CO2-Einheit + + + + CO2 unit changed + The name of the EventType ({b0e655f8-27d0-4add-918b-461cadc8efcc}) of ThingClass datalogger + CO2-Einheit geändert + + + + Cash Currency changed + The name of the EventType ({84da30c8-a7fb-49c6-884c-9521f9f62bbc}) of ThingClass datalogger + Bargeldwährung geändert + + + + + Cash currency + The name of the ParamType (ThingClass: datalogger, EventType: cashcurrency, ID: {84da30c8-a7fb-49c6-884c-9521f9f62bbc}) +---------- +The name of the StateType ({84da30c8-a7fb-49c6-884c-9521f9f62bbc}) of ThingClass datalogger + Bargeldwährung + + + + + Cash factor + The name of the ParamType (ThingClass: datalogger, EventType: cashfactor, ID: {bc18595b-17c7-4a1f-8002-b908a3d9239d}) +---------- +The name of the StateType ({bc18595b-17c7-4a1f-8002-b908a3d9239d}) of ThingClass datalogger + Cash-Faktor + + + + Cash factor changed + The name of the EventType ({bc18595b-17c7-4a1f-8002-b908a3d9239d}) of ThingClass datalogger + Cash-Faktor geändert + + + + + Cell temperature + The name of the ParamType (ThingClass: storage, EventType: cellTemperature, ID: {4417499c-1757-4309-868a-be5cf3455c4a}) +---------- +The name of the StateType ({4417499c-1757-4309-868a-be5cf3455c4a}) of ThingClass storage + Zellentemperatur + + + + Cell temperature changed + The name of the EventType ({4417499c-1757-4309-868a-be5cf3455c4a}) of ThingClass storage + Zellentemperatur geändert + + + + Charge state changed + The name of the EventType ({2de34a1f-de2e-43ad-8998-8a5460dff9ae}) of ThingClass storage + Ladezustand geändert + + + + + + Charging limit + The name of the ParamType (ThingClass: sunspecStorage, ActionType: enableChargingLimit, ID: {1f530f79-c0d2-466b-90e1-79149e34d92f}) +---------- +The name of the ParamType (ThingClass: sunspecStorage, EventType: enableChargingLimit, ID: {1f530f79-c0d2-466b-90e1-79149e34d92f}) +---------- +The name of the StateType ({1f530f79-c0d2-466b-90e1-79149e34d92f}) of ThingClass sunspecStorage + Ladelimit + + + + + + Charging rate + The name of the ParamType (ThingClass: sunspecStorage, ActionType: chargingRate, ID: {7f469bbc-64a5-4045-8d5f-9a1a85039851}) +---------- +The name of the ParamType (ThingClass: sunspecStorage, EventType: chargingRate, ID: {7f469bbc-64a5-4045-8d5f-9a1a85039851}) +---------- +The name of the StateType ({7f469bbc-64a5-4045-8d5f-9a1a85039851}) of ThingClass sunspecStorage + Laderate + + + + Charging rate changed + The name of the EventType ({7f469bbc-64a5-4045-8d5f-9a1a85039851}) of ThingClass sunspecStorage + Laderate geändert + + + + + Connected + The name of the ParamType (ThingClass: sunspecStorage, EventType: connected, ID: {50ed3a6f-6ad3-445f-950b-eb6d1b7e7ef7}) +---------- +The name of the StateType ({50ed3a6f-6ad3-445f-950b-eb6d1b7e7ef7}) of ThingClass sunspecStorage + Verbunden + + + + Current Power changed + The name of the EventType ({788accbc-b86e-471b-b37f-14c9c6411526}) of ThingClass inverter + Aktuelle Leistung geändert + + + + + Current power + The name of the ParamType (ThingClass: inverter, EventType: currentPower, ID: {788accbc-b86e-471b-b37f-14c9c6411526}) +---------- +The name of the StateType ({788accbc-b86e-471b-b37f-14c9c6411526}) of ThingClass inverter + Aktuelle Leistung + + + + + Default language + The name of the ParamType (ThingClass: datalogger, EventType: defaultlang, ID: {18b250e2-080a-4991-b368-177c4da83eca}) +---------- +The name of the StateType ({18b250e2-080a-4991-b368-177c4da83eca}) of ThingClass datalogger + Standardsprache + + + + Default language changed + The name of the EventType ({18b250e2-080a-4991-b368-177c4da83eca}) of ThingClass datalogger + Standardsprache geändert + + + + + Device ID + The name of the ParamType (ThingClass: storage, Type: thing, ID: {49087f31-abf5-4bb8-946b-a3626ee80566}) +---------- +The name of the ParamType (ThingClass: meter, Type: thing, ID: {cf3a7025-d368-475a-8f48-efc1344a8409}) + Geräte ID + + + + Device id + The name of the ParamType (ThingClass: inverter, Type: thing, ID: {f2f8c2f5-dd6a-4786-b336-82fc84e5bb98}) + Geräte ID + + + + + + Discharging limit + The name of the ParamType (ThingClass: sunspecStorage, ActionType: enableDischargingLimit, ID: {bc99a159-815a-40ab-a6e8-b46f315305f7}) +---------- +The name of the ParamType (ThingClass: sunspecStorage, EventType: enableDischargingLimit, ID: {bc99a159-815a-40ab-a6e8-b46f315305f7}) +---------- +The name of the StateType ({bc99a159-815a-40ab-a6e8-b46f315305f7}) of ThingClass sunspecStorage + Entladelimit + + + + + + Discharging rate + The name of the ParamType (ThingClass: sunspecStorage, ActionType: dischargingRate, ID: {6068f030-acce-44a2-b95f-bd00dd5ca760}) +---------- +The name of the ParamType (ThingClass: sunspecStorage, EventType: dischargingRate, ID: {6068f030-acce-44a2-b95f-bd00dd5ca760}) +---------- +The name of the StateType ({6068f030-acce-44a2-b95f-bd00dd5ca760}) of ThingClass sunspecStorage + Entladerate + + + + Discharging rate changed + The name of the EventType ({6068f030-acce-44a2-b95f-bd00dd5ca760}) of ThingClass sunspecStorage + Entladerate geändert + + + + Enable Charging Limit + The name of the ActionType ({1f530f79-c0d2-466b-90e1-79149e34d92f}) of ThingClass sunspecStorage + Aktiviere Ladelimit + + + + Enable Discharging Limit + The name of the ActionType ({bc99a159-815a-40ab-a6e8-b46f315305f7}) of ThingClass sunspecStorage + Aktiviere Entladelimit + + + + + Energy Consumed + The name of the ParamType (ThingClass: meter, EventType: totalEnergyConsumed, ID: {f3451818-48d2-42a5-94fd-ad094c06967f}) +---------- +The name of the StateType ({f3451818-48d2-42a5-94fd-ad094c06967f}) of ThingClass meter + Energie verbraucht + + + + + Energy Produced + The name of the ParamType (ThingClass: meter, EventType: totalEnergyProduced, ID: {ca14cca5-d9f0-49c5-a8f7-907d4c0825f0}) +---------- +The name of the StateType ({ca14cca5-d9f0-49c5-a8f7-907d4c0825f0}) of ThingClass meter + Energie produziert + + + + Energy consumption changed + The name of the EventType ({f3451818-48d2-42a5-94fd-ad094c06967f}) of ThingClass meter + Energieverbrauch geändert + + + + + Energy of current day + The name of the ParamType (ThingClass: inverter, EventType: eday, ID: {b6af1bf5-753d-47b6-a151-e4d801fe6ff8}) +---------- +The name of the StateType ({b6af1bf5-753d-47b6-a151-e4d801fe6ff8}) of ThingClass inverter + Energie dieses Tages + + + + + Energy of current year + The name of the ParamType (ThingClass: inverter, EventType: eyear, ID: {7fd2fa28-9bcc-4f01-a823-459437d185f6}) +---------- +The name of the StateType ({7fd2fa28-9bcc-4f01-a823-459437d185f6}) of ThingClass inverter + Energie dieses Jahres + + + + Energy of day changed + The name of the EventType ({b6af1bf5-753d-47b6-a151-e4d801fe6ff8}) of ThingClass inverter + Energie dieses Tages geändert + + + + Energy of year changed + The name of the EventType ({7fd2fa28-9bcc-4f01-a823-459437d185f6}) of ThingClass inverter + Energie dieses Jahres geändert + + + + Energy production changed + The name of the EventType ({ca14cca5-d9f0-49c5-a8f7-907d4c0825f0}) of ThingClass meter + Energieproduktion geändert + + + + + Energy total + The name of the ParamType (ThingClass: inverter, EventType: totalEnergyProduced, ID: {d6dbb879-4cbc-4db3-830e-b92ba91a13e5}) +---------- +The name of the StateType ({d6dbb879-4cbc-4db3-830e-b92ba91a13e5}) of ThingClass inverter + Energie gesamt + + + + Energy total changed + The name of the EventType ({d6dbb879-4cbc-4db3-830e-b92ba91a13e5}) of ThingClass inverter + Energie gesamt geändert + + + + Fronius + The name of the vendor ({2286fc38-afd9-4128-ab7e-0fba527d53ba}) + Fronius + + + + Fronius Smart Meter + The name of the ThingClass ({c3cb53a4-32dd-434d-9d9c-aada41f8129c}) + Fronius Smart Meter + + + + Fronius Solar + The name of the plugin fronius ({02319cfc-8b55-49ba-99bc-0588bbfab063}) + Fronius Solar + + + + Fronius Solar Connection + The name of the ThingClass ({4fd79fed-42f1-4df9-be64-3df7b2e0bda2}) + Fronius Solar Verbindung + + + + Fronius Solar Inverter + The name of the ThingClass ({540aa956-8b8f-4982-9f58-343a76cea846}) + Fronius Solar Inverter + + + + Fronius Solar Storage + The name of the ThingClass ({b00139fa-7386-48b1-8697-2fdd21a57ced}) + Fronius Solar Speicher + + + + + + Grid charging + The name of the ParamType (ThingClass: sunspecStorage, ActionType: gridCharging, ID: {221a2ef6-0a92-4ff0-87fe-7bd920dbec0b}) +---------- +The name of the ParamType (ThingClass: sunspecStorage, EventType: gridCharging, ID: {221a2ef6-0a92-4ff0-87fe-7bd920dbec0b}) +---------- +The name of the StateType ({221a2ef6-0a92-4ff0-87fe-7bd920dbec0b}) of ThingClass sunspecStorage + Netzaufladung + + + + Grid charging changed + The name of the EventType ({221a2ef6-0a92-4ff0-87fe-7bd920dbec0b}) of ThingClass sunspecStorage + Netzaufladung geändert + + + + + Hardware version + The name of the ParamType (ThingClass: datalogger, EventType: hwversion, ID: {3b4206e5-74c7-4708-96b8-2abfab0c41d6}) +---------- +The name of the StateType ({3b4206e5-74c7-4708-96b8-2abfab0c41d6}) of ThingClass datalogger + Hardwareversion + + + + Hardware version changed + The name of the EventType ({3b4206e5-74c7-4708-96b8-2abfab0c41d6}) of ThingClass datalogger + Hardwareversion geändert + + + + + Host address + The name of the ParamType (ThingClass: inverter, Type: thing, ID: {1aa82e12-ee8c-4142-8b89-a4f1e85556d0}) +---------- +The name of the ParamType (ThingClass: datalogger, Type: thing, ID: {52da0197-4b78-4fec-aa72-70f949e26edc}) + Adresse + + + + + Inverter active + The name of the ParamType (ThingClass: inverter, EventType: active, ID: {e763baa7-5eaf-438c-83f0-4fa6c0f7eeb0}) +---------- +The name of the StateType ({e763baa7-5eaf-438c-83f0-4fa6c0f7eeb0}) of ThingClass inverter + Inverter aktiv + + + + Inverter active changed + The name of the EventType ({e763baa7-5eaf-438c-83f0-4fa6c0f7eeb0}) of ThingClass inverter + Inverter aktiv geändert + + + + Manufacturer + The name of the ParamType (ThingClass: storage, Type: thing, ID: {9665c38b-c13a-428f-b741-1470239c63dc}) + Hersteller + + + + Maxmimum capacity + The name of the ParamType (ThingClass: storage, Type: thing, ID: {59a68e91-1aad-46b7-b351-03b7b2216366}) + Maximale Kapazität + + + + Set grid charging + The name of the ActionType ({221a2ef6-0a92-4ff0-87fe-7bd920dbec0b}) of ThingClass sunspecStorage + Aktiviere Netzladung + + + + State changed + The name of the EventType ({da2b19c5-0f48-49d1-93f0-abdc0051407d}) of ThingClass sunspecStorage + Zustand geändert + + + + + Unique ID + The name of the ParamType (ThingClass: storage, Type: thing, ID: {0d62432a-38bc-48b8-99d2-895f17fcf0b2}) +---------- +The name of the ParamType (ThingClass: meter, Type: thing, ID: {285eabb2-47c8-4406-8123-6621b21558c1}) + Unique ID + + + + Unique id + The name of the ParamType (ThingClass: inverter, Type: thing, ID: {8fadc0e8-9d69-4b9d-b493-b6ac3eb59c49}) + Unique ID + + + + + Platform ID + The name of the ParamType (ThingClass: datalogger, EventType: platformid, ID: {65c068e6-4a0b-4672-9724-ae95216c4c9c}) +---------- +The name of the StateType ({65c068e6-4a0b-4672-9724-ae95216c4c9c}) of ThingClass datalogger + Plattform ID + + + + Charging limit changed + The name of the EventType ({1f530f79-c0d2-466b-90e1-79149e34d92f}) of ThingClass sunspecStorage + Ladelimit geändert + + + + Connected changed + The name of the EventType ({50ed3a6f-6ad3-445f-950b-eb6d1b7e7ef7}) of ThingClass sunspecStorage + Verbunden geändert + + + + Discharging limit changed + The name of the EventType ({bc99a159-815a-40ab-a6e8-b46f315305f7}) of ThingClass sunspecStorage + Entladelimit geändert + + + + Platform ID changed + The name of the EventType ({65c068e6-4a0b-4672-9724-ae95216c4c9c}) of ThingClass datalogger + Plattform-ID geändert + + + + + Power management relay + The name of the ParamType (ThingClass: datalogger, EventType: powerManagmentRelay, ID: {b217acf6-0c5e-4a3e-a50c-4c0133c871c2}) +---------- +The name of the StateType ({b217acf6-0c5e-4a3e-a50c-4c0133c871c2}) of ThingClass datalogger + Leistungsmanagement Relais + + + + + Power management relay reason + The name of the ParamType (ThingClass: datalogger, EventType: powerManagmentRelayReason, ID: {5650ce9b-0d7d-4c52-b410-ea618889b4bb}) +---------- +The name of the StateType ({5650ce9b-0d7d-4c52-b410-ea618889b4bb}) of ThingClass datalogger + Leistungsmanagement Relais Grund + + + + Power management relay reason changed + The name of the EventType ({5650ce9b-0d7d-4c52-b410-ea618889b4bb}) of ThingClass datalogger + Leistungsmanagement Relais Grund geändert + + + + Power management relay status changed + The name of the EventType ({b217acf6-0c5e-4a3e-a50c-4c0133c871c2}) of ThingClass datalogger + Leistungsmanagement Relais Status geändert + + + + + Product ID + The name of the ParamType (ThingClass: datalogger, EventType: productid, ID: {b22052ef-14da-43d2-982b-f2c2d8c03206}) +---------- +The name of the StateType ({b22052ef-14da-43d2-982b-f2c2d8c03206}) of ThingClass datalogger + Produkt-ID + + + + Product ID changed + The name of the EventType ({b22052ef-14da-43d2-982b-f2c2d8c03206}) of ThingClass datalogger + Produkt-ID geändert + + + + + + + + + + + Reachable + The name of the ParamType (ThingClass: storage, EventType: connected, ID: {2f7e1267-b0be-4b78-9aa3-832b86c4efad}) +---------- +The name of the StateType ({2f7e1267-b0be-4b78-9aa3-832b86c4efad}) of ThingClass storage +---------- +The name of the ParamType (ThingClass: meter, EventType: connected, ID: {b70b61a4-54cb-47ec-b62a-b498eb1f650e}) +---------- +The name of the StateType ({b70b61a4-54cb-47ec-b62a-b498eb1f650e}) of ThingClass meter +---------- +The name of the ParamType (ThingClass: inverter, EventType: connected, ID: {eda29c50-73ac-40e0-9c92-26fee352e688}) +---------- +The name of the StateType ({eda29c50-73ac-40e0-9c92-26fee352e688}) of ThingClass inverter +---------- +The name of the ParamType (ThingClass: datalogger, EventType: connected, ID: {98e4476f-e745-4a7f-b795-19269cb70c40}) +---------- +The name of the StateType ({98e4476f-e745-4a7f-b795-19269cb70c40}) of ThingClass datalogger + Erreichbar + + + + + + Reachable changed + The name of the EventType ({2f7e1267-b0be-4b78-9aa3-832b86c4efad}) of ThingClass storage +---------- +The name of the EventType ({b70b61a4-54cb-47ec-b62a-b498eb1f650e}) of ThingClass meter +---------- +The name of the EventType ({eda29c50-73ac-40e0-9c92-26fee352e688}) of ThingClass inverter + Erreichbar geändert + + + + Search new devices + The name of the ActionType ({c217fdc1-de18-41dc-b5d8-8072f84e7b6c}) of ThingClass datalogger + Suche neue Geräte + + + + Set charging rate + The name of the ActionType ({7f469bbc-64a5-4045-8d5f-9a1a85039851}) of ThingClass sunspecStorage + Setze Laderate + + + + Set discharging rate + The name of the ActionType ({6068f030-acce-44a2-b95f-bd00dd5ca760}) of ThingClass sunspecStorage + Setze Entladerate + + + + + Software version + The name of the ParamType (ThingClass: datalogger, EventType: swversion, ID: {31743ca5-4353-4f26-b2ad-5da43e5b9d86}) +---------- +The name of the StateType ({31743ca5-4353-4f26-b2ad-5da43e5b9d86}) of ThingClass datalogger + Softwareversion + + + + Software version changed + The name of the EventType ({31743ca5-4353-4f26-b2ad-5da43e5b9d86}) of ThingClass datalogger + Softwareversion geändert + + + + + State + The name of the ParamType (ThingClass: sunspecStorage, EventType: storageState, ID: {da2b19c5-0f48-49d1-93f0-abdc0051407d}) +---------- +The name of the StateType ({da2b19c5-0f48-49d1-93f0-abdc0051407d}) of ThingClass sunspecStorage + Status + + + + + State of charge + The name of the ParamType (ThingClass: storage, EventType: charging, ID: {2de34a1f-de2e-43ad-8998-8a5460dff9ae}) +---------- +The name of the StateType ({2de34a1f-de2e-43ad-8998-8a5460dff9ae}) of ThingClass storage + Ladezustand + + + + SunSpec Storage + The name of the ThingClass ({e14d622f-5d8f-4788-b189-0774a6382a9b}) + SunSpec Speicher + + + + + Time zone + The name of the ParamType (ThingClass: datalogger, EventType: tzone, ID: {6bdfeeda-7a47-4043-a011-5eb96308a7d6}) +---------- +The name of the StateType ({6bdfeeda-7a47-4043-a011-5eb96308a7d6}) of ThingClass datalogger + Zeitzone + + + + Time zone changed + The name of the EventType ({6bdfeeda-7a47-4043-a011-5eb96308a7d6}) of ThingClass datalogger + Zeitzone geändert + + + + + Timezone location + The name of the ParamType (ThingClass: datalogger, EventType: tzoneloc, ID: {d034f59d-dc34-450a-a6f3-68264767a3e4}) +---------- +The name of the StateType ({d034f59d-dc34-450a-a6f3-68264767a3e4}) of ThingClass datalogger + Zeitzone Ort + + + + Timezone location changed + The name of the EventType ({d034f59d-dc34-450a-a6f3-68264767a3e4}) of ThingClass datalogger + Zeitzone Ort geändert + + + + + Total current power + The name of the ParamType (ThingClass: meter, EventType: currentPower, ID: {e5056ea1-88a2-410b-9c5e-6322aca4cb17}) +---------- +The name of the StateType ({e5056ea1-88a2-410b-9c5e-6322aca4cb17}) of ThingClass meter + Gesamte Momentanleistung + + + + Total current power changed + The name of the EventType ({e5056ea1-88a2-410b-9c5e-6322aca4cb17}) of ThingClass meter + Gesamte Momentanleistung geändert + + + + logger reachable changed + The name of the EventType ({98e4476f-e745-4a7f-b795-19269cb70c40}) of ThingClass datalogger + Logger erriechbar geändert + + + diff --git a/fronius/translations/02319cfc-8b55-49ba-99bc-0588bbfab063-en_US.ts b/fronius/translations/02319cfc-8b55-49ba-99bc-0588bbfab063-en_US.ts new file mode 100644 index 00000000..53558eed --- /dev/null +++ b/fronius/translations/02319cfc-8b55-49ba-99bc-0588bbfab063-en_US.ts @@ -0,0 +1,741 @@ + + + + + IntegrationPluginFronius + + + Device not reachable + + + + + + Please try again + + + + + fronius + + + + + Address + The name of the ParamType (ThingClass: sunspecStorage, Type: thing, ID: {830a3cc6-ae0a-4cc3-94d6-86575e410e49}) +---------- +The name of the ParamType (ThingClass: storage, Type: thing, ID: {84bd8a41-2411-4bb0-87a9-ab7e01044b10}) +---------- +The name of the ParamType (ThingClass: meter, Type: thing, ID: {ddcb8689-b0b8-4b94-b022-4ce4cf9e0ec2}) + + + + + + Base URL + The name of the ParamType (ThingClass: storage, Type: thing, ID: {d19b5d81-4e62-48be-bad6-287b0019274a}) +---------- +The name of the ParamType (ThingClass: meter, Type: thing, ID: {2cb4acd6-a663-48c3-8366-ab538c7b4e7d}) + + + + + Base url + The name of the ParamType (ThingClass: inverter, Type: thing, ID: {ec1f792a-b453-49f0-8ea6-677ad3c25a5c}) + + + + + + Battery critical + The name of the ParamType (ThingClass: sunspecStorage, EventType: batteryCritical, ID: {3171a6e0-43a7-4de8-8e20-f748e44af7ac}) +---------- +The name of the StateType ({3171a6e0-43a7-4de8-8e20-f748e44af7ac}) of ThingClass sunspecStorage + + + + + Battery critical changed + The name of the EventType ({3171a6e0-43a7-4de8-8e20-f748e44af7ac}) of ThingClass sunspecStorage + + + + + + + + Battery level + The name of the ParamType (ThingClass: sunspecStorage, EventType: batteryLevel, ID: {0bf53f80-97f8-488b-b514-58f9fe08c183}) +---------- +The name of the StateType ({0bf53f80-97f8-488b-b514-58f9fe08c183}) of ThingClass sunspecStorage +---------- +The name of the ParamType (ThingClass: storage, EventType: batteryLevel, ID: {5c6da672-9662-41bc-8c8c-aa0f32481251}) +---------- +The name of the StateType ({5c6da672-9662-41bc-8c8c-aa0f32481251}) of ThingClass storage + + + + + + Battery level changed + The name of the EventType ({0bf53f80-97f8-488b-b514-58f9fe08c183}) of ThingClass sunspecStorage +---------- +The name of the EventType ({5c6da672-9662-41bc-8c8c-aa0f32481251}) of ThingClass storage + + + + + + Battery level critical + The name of the ParamType (ThingClass: storage, EventType: batteryCritical, ID: {e5396312-b50e-4d6f-b628-5b51448971d3}) +---------- +The name of the StateType ({e5396312-b50e-4d6f-b628-5b51448971d3}) of ThingClass storage + + + + + Battery level critical changed + The name of the EventType ({e5396312-b50e-4d6f-b628-5b51448971d3}) of ThingClass storage + + + + + + CO2 factor + The name of the ParamType (ThingClass: datalogger, EventType: co2factor, ID: {8ab01225-7be5-4482-a99b-314108ae0e2b}) +---------- +The name of the StateType ({8ab01225-7be5-4482-a99b-314108ae0e2b}) of ThingClass datalogger + + + + + CO2 factor changed + The name of the EventType ({8ab01225-7be5-4482-a99b-314108ae0e2b}) of ThingClass datalogger + + + + + + CO2 unit + The name of the ParamType (ThingClass: datalogger, EventType: co2unit, ID: {b0e655f8-27d0-4add-918b-461cadc8efcc}) +---------- +The name of the StateType ({b0e655f8-27d0-4add-918b-461cadc8efcc}) of ThingClass datalogger + + + + + CO2 unit changed + The name of the EventType ({b0e655f8-27d0-4add-918b-461cadc8efcc}) of ThingClass datalogger + + + + + Cash Currency changed + The name of the EventType ({84da30c8-a7fb-49c6-884c-9521f9f62bbc}) of ThingClass datalogger + + + + + + Cash currency + The name of the ParamType (ThingClass: datalogger, EventType: cashcurrency, ID: {84da30c8-a7fb-49c6-884c-9521f9f62bbc}) +---------- +The name of the StateType ({84da30c8-a7fb-49c6-884c-9521f9f62bbc}) of ThingClass datalogger + + + + + + Cash factor + The name of the ParamType (ThingClass: datalogger, EventType: cashfactor, ID: {bc18595b-17c7-4a1f-8002-b908a3d9239d}) +---------- +The name of the StateType ({bc18595b-17c7-4a1f-8002-b908a3d9239d}) of ThingClass datalogger + + + + + Cash factor changed + The name of the EventType ({bc18595b-17c7-4a1f-8002-b908a3d9239d}) of ThingClass datalogger + + + + + + Cell temperature + The name of the ParamType (ThingClass: storage, EventType: cellTemperature, ID: {4417499c-1757-4309-868a-be5cf3455c4a}) +---------- +The name of the StateType ({4417499c-1757-4309-868a-be5cf3455c4a}) of ThingClass storage + + + + + Cell temperature changed + The name of the EventType ({4417499c-1757-4309-868a-be5cf3455c4a}) of ThingClass storage + + + + + Charge state changed + The name of the EventType ({2de34a1f-de2e-43ad-8998-8a5460dff9ae}) of ThingClass storage + + + + + + + Charging limit + The name of the ParamType (ThingClass: sunspecStorage, ActionType: enableChargingLimit, ID: {1f530f79-c0d2-466b-90e1-79149e34d92f}) +---------- +The name of the ParamType (ThingClass: sunspecStorage, EventType: enableChargingLimit, ID: {1f530f79-c0d2-466b-90e1-79149e34d92f}) +---------- +The name of the StateType ({1f530f79-c0d2-466b-90e1-79149e34d92f}) of ThingClass sunspecStorage + + + + + + + Charging rate + The name of the ParamType (ThingClass: sunspecStorage, ActionType: chargingRate, ID: {7f469bbc-64a5-4045-8d5f-9a1a85039851}) +---------- +The name of the ParamType (ThingClass: sunspecStorage, EventType: chargingRate, ID: {7f469bbc-64a5-4045-8d5f-9a1a85039851}) +---------- +The name of the StateType ({7f469bbc-64a5-4045-8d5f-9a1a85039851}) of ThingClass sunspecStorage + + + + + Charging rate changed + The name of the EventType ({7f469bbc-64a5-4045-8d5f-9a1a85039851}) of ThingClass sunspecStorage + + + + + + Connected + The name of the ParamType (ThingClass: sunspecStorage, EventType: connected, ID: {50ed3a6f-6ad3-445f-950b-eb6d1b7e7ef7}) +---------- +The name of the StateType ({50ed3a6f-6ad3-445f-950b-eb6d1b7e7ef7}) of ThingClass sunspecStorage + + + + + Current Power changed + The name of the EventType ({788accbc-b86e-471b-b37f-14c9c6411526}) of ThingClass inverter + + + + + + Current power + The name of the ParamType (ThingClass: inverter, EventType: currentPower, ID: {788accbc-b86e-471b-b37f-14c9c6411526}) +---------- +The name of the StateType ({788accbc-b86e-471b-b37f-14c9c6411526}) of ThingClass inverter + + + + + + Default language + The name of the ParamType (ThingClass: datalogger, EventType: defaultlang, ID: {18b250e2-080a-4991-b368-177c4da83eca}) +---------- +The name of the StateType ({18b250e2-080a-4991-b368-177c4da83eca}) of ThingClass datalogger + + + + + Default language changed + The name of the EventType ({18b250e2-080a-4991-b368-177c4da83eca}) of ThingClass datalogger + + + + + + Device ID + The name of the ParamType (ThingClass: storage, Type: thing, ID: {49087f31-abf5-4bb8-946b-a3626ee80566}) +---------- +The name of the ParamType (ThingClass: meter, Type: thing, ID: {cf3a7025-d368-475a-8f48-efc1344a8409}) + + + + + Device id + The name of the ParamType (ThingClass: inverter, Type: thing, ID: {f2f8c2f5-dd6a-4786-b336-82fc84e5bb98}) + + + + + + + Discharging limit + The name of the ParamType (ThingClass: sunspecStorage, ActionType: enableDischargingLimit, ID: {bc99a159-815a-40ab-a6e8-b46f315305f7}) +---------- +The name of the ParamType (ThingClass: sunspecStorage, EventType: enableDischargingLimit, ID: {bc99a159-815a-40ab-a6e8-b46f315305f7}) +---------- +The name of the StateType ({bc99a159-815a-40ab-a6e8-b46f315305f7}) of ThingClass sunspecStorage + + + + + + + Discharging rate + The name of the ParamType (ThingClass: sunspecStorage, ActionType: dischargingRate, ID: {6068f030-acce-44a2-b95f-bd00dd5ca760}) +---------- +The name of the ParamType (ThingClass: sunspecStorage, EventType: dischargingRate, ID: {6068f030-acce-44a2-b95f-bd00dd5ca760}) +---------- +The name of the StateType ({6068f030-acce-44a2-b95f-bd00dd5ca760}) of ThingClass sunspecStorage + + + + + Discharging rate changed + The name of the EventType ({6068f030-acce-44a2-b95f-bd00dd5ca760}) of ThingClass sunspecStorage + + + + + Enable Charging Limit + The name of the ActionType ({1f530f79-c0d2-466b-90e1-79149e34d92f}) of ThingClass sunspecStorage + + + + + Enable Discharging Limit + The name of the ActionType ({bc99a159-815a-40ab-a6e8-b46f315305f7}) of ThingClass sunspecStorage + + + + + + Energy Consumed + The name of the ParamType (ThingClass: meter, EventType: totalEnergyConsumed, ID: {f3451818-48d2-42a5-94fd-ad094c06967f}) +---------- +The name of the StateType ({f3451818-48d2-42a5-94fd-ad094c06967f}) of ThingClass meter + + + + + + Energy Produced + The name of the ParamType (ThingClass: meter, EventType: totalEnergyProduced, ID: {ca14cca5-d9f0-49c5-a8f7-907d4c0825f0}) +---------- +The name of the StateType ({ca14cca5-d9f0-49c5-a8f7-907d4c0825f0}) of ThingClass meter + + + + + Energy consumption changed + The name of the EventType ({f3451818-48d2-42a5-94fd-ad094c06967f}) of ThingClass meter + + + + + + Energy of current day + The name of the ParamType (ThingClass: inverter, EventType: eday, ID: {b6af1bf5-753d-47b6-a151-e4d801fe6ff8}) +---------- +The name of the StateType ({b6af1bf5-753d-47b6-a151-e4d801fe6ff8}) of ThingClass inverter + + + + + + Energy of current year + The name of the ParamType (ThingClass: inverter, EventType: eyear, ID: {7fd2fa28-9bcc-4f01-a823-459437d185f6}) +---------- +The name of the StateType ({7fd2fa28-9bcc-4f01-a823-459437d185f6}) of ThingClass inverter + + + + + Energy of day changed + The name of the EventType ({b6af1bf5-753d-47b6-a151-e4d801fe6ff8}) of ThingClass inverter + + + + + Energy of year changed + The name of the EventType ({7fd2fa28-9bcc-4f01-a823-459437d185f6}) of ThingClass inverter + + + + + Energy production changed + The name of the EventType ({ca14cca5-d9f0-49c5-a8f7-907d4c0825f0}) of ThingClass meter + + + + + + Energy total + The name of the ParamType (ThingClass: inverter, EventType: totalEnergyProduced, ID: {d6dbb879-4cbc-4db3-830e-b92ba91a13e5}) +---------- +The name of the StateType ({d6dbb879-4cbc-4db3-830e-b92ba91a13e5}) of ThingClass inverter + + + + + Energy total changed + The name of the EventType ({d6dbb879-4cbc-4db3-830e-b92ba91a13e5}) of ThingClass inverter + + + + + Fronius + The name of the vendor ({2286fc38-afd9-4128-ab7e-0fba527d53ba}) + + + + + Fronius Smart Meter + The name of the ThingClass ({c3cb53a4-32dd-434d-9d9c-aada41f8129c}) + + + + + Fronius Solar + The name of the plugin fronius ({02319cfc-8b55-49ba-99bc-0588bbfab063}) + + + + + Fronius Solar Connection + The name of the ThingClass ({4fd79fed-42f1-4df9-be64-3df7b2e0bda2}) + + + + + Fronius Solar Inverter + The name of the ThingClass ({540aa956-8b8f-4982-9f58-343a76cea846}) + + + + + Fronius Solar Storage + The name of the ThingClass ({b00139fa-7386-48b1-8697-2fdd21a57ced}) + + + + + + + Grid charging + The name of the ParamType (ThingClass: sunspecStorage, ActionType: gridCharging, ID: {221a2ef6-0a92-4ff0-87fe-7bd920dbec0b}) +---------- +The name of the ParamType (ThingClass: sunspecStorage, EventType: gridCharging, ID: {221a2ef6-0a92-4ff0-87fe-7bd920dbec0b}) +---------- +The name of the StateType ({221a2ef6-0a92-4ff0-87fe-7bd920dbec0b}) of ThingClass sunspecStorage + + + + + Grid charging changed + The name of the EventType ({221a2ef6-0a92-4ff0-87fe-7bd920dbec0b}) of ThingClass sunspecStorage + + + + + + Hardware version + The name of the ParamType (ThingClass: datalogger, EventType: hwversion, ID: {3b4206e5-74c7-4708-96b8-2abfab0c41d6}) +---------- +The name of the StateType ({3b4206e5-74c7-4708-96b8-2abfab0c41d6}) of ThingClass datalogger + + + + + Hardware version changed + The name of the EventType ({3b4206e5-74c7-4708-96b8-2abfab0c41d6}) of ThingClass datalogger + + + + + + Host address + The name of the ParamType (ThingClass: inverter, Type: thing, ID: {1aa82e12-ee8c-4142-8b89-a4f1e85556d0}) +---------- +The name of the ParamType (ThingClass: datalogger, Type: thing, ID: {52da0197-4b78-4fec-aa72-70f949e26edc}) + + + + + + Inverter active + The name of the ParamType (ThingClass: inverter, EventType: active, ID: {e763baa7-5eaf-438c-83f0-4fa6c0f7eeb0}) +---------- +The name of the StateType ({e763baa7-5eaf-438c-83f0-4fa6c0f7eeb0}) of ThingClass inverter + + + + + Inverter active changed + The name of the EventType ({e763baa7-5eaf-438c-83f0-4fa6c0f7eeb0}) of ThingClass inverter + + + + + Manufacturer + The name of the ParamType (ThingClass: storage, Type: thing, ID: {9665c38b-c13a-428f-b741-1470239c63dc}) + + + + + Maxmimum capacity + The name of the ParamType (ThingClass: storage, Type: thing, ID: {59a68e91-1aad-46b7-b351-03b7b2216366}) + + + + + Set grid charging + The name of the ActionType ({221a2ef6-0a92-4ff0-87fe-7bd920dbec0b}) of ThingClass sunspecStorage + + + + + State changed + The name of the EventType ({da2b19c5-0f48-49d1-93f0-abdc0051407d}) of ThingClass sunspecStorage + + + + + + Unique ID + The name of the ParamType (ThingClass: storage, Type: thing, ID: {0d62432a-38bc-48b8-99d2-895f17fcf0b2}) +---------- +The name of the ParamType (ThingClass: meter, Type: thing, ID: {285eabb2-47c8-4406-8123-6621b21558c1}) + + + + + Unique id + The name of the ParamType (ThingClass: inverter, Type: thing, ID: {8fadc0e8-9d69-4b9d-b493-b6ac3eb59c49}) + + + + + + Platform ID + The name of the ParamType (ThingClass: datalogger, EventType: platformid, ID: {65c068e6-4a0b-4672-9724-ae95216c4c9c}) +---------- +The name of the StateType ({65c068e6-4a0b-4672-9724-ae95216c4c9c}) of ThingClass datalogger + + + + + Charging limit changed + The name of the EventType ({1f530f79-c0d2-466b-90e1-79149e34d92f}) of ThingClass sunspecStorage + + + + + Connected changed + The name of the EventType ({50ed3a6f-6ad3-445f-950b-eb6d1b7e7ef7}) of ThingClass sunspecStorage + + + + + Discharging limit changed + The name of the EventType ({bc99a159-815a-40ab-a6e8-b46f315305f7}) of ThingClass sunspecStorage + + + + + Platform ID changed + The name of the EventType ({65c068e6-4a0b-4672-9724-ae95216c4c9c}) of ThingClass datalogger + + + + + + Power management relay + The name of the ParamType (ThingClass: datalogger, EventType: powerManagmentRelay, ID: {b217acf6-0c5e-4a3e-a50c-4c0133c871c2}) +---------- +The name of the StateType ({b217acf6-0c5e-4a3e-a50c-4c0133c871c2}) of ThingClass datalogger + + + + + + Power management relay reason + The name of the ParamType (ThingClass: datalogger, EventType: powerManagmentRelayReason, ID: {5650ce9b-0d7d-4c52-b410-ea618889b4bb}) +---------- +The name of the StateType ({5650ce9b-0d7d-4c52-b410-ea618889b4bb}) of ThingClass datalogger + + + + + Power management relay reason changed + The name of the EventType ({5650ce9b-0d7d-4c52-b410-ea618889b4bb}) of ThingClass datalogger + + + + + Power management relay status changed + The name of the EventType ({b217acf6-0c5e-4a3e-a50c-4c0133c871c2}) of ThingClass datalogger + + + + + + Product ID + The name of the ParamType (ThingClass: datalogger, EventType: productid, ID: {b22052ef-14da-43d2-982b-f2c2d8c03206}) +---------- +The name of the StateType ({b22052ef-14da-43d2-982b-f2c2d8c03206}) of ThingClass datalogger + + + + + Product ID changed + The name of the EventType ({b22052ef-14da-43d2-982b-f2c2d8c03206}) of ThingClass datalogger + + + + + + + + + + + + Reachable + The name of the ParamType (ThingClass: storage, EventType: connected, ID: {2f7e1267-b0be-4b78-9aa3-832b86c4efad}) +---------- +The name of the StateType ({2f7e1267-b0be-4b78-9aa3-832b86c4efad}) of ThingClass storage +---------- +The name of the ParamType (ThingClass: meter, EventType: connected, ID: {b70b61a4-54cb-47ec-b62a-b498eb1f650e}) +---------- +The name of the StateType ({b70b61a4-54cb-47ec-b62a-b498eb1f650e}) of ThingClass meter +---------- +The name of the ParamType (ThingClass: inverter, EventType: connected, ID: {eda29c50-73ac-40e0-9c92-26fee352e688}) +---------- +The name of the StateType ({eda29c50-73ac-40e0-9c92-26fee352e688}) of ThingClass inverter +---------- +The name of the ParamType (ThingClass: datalogger, EventType: connected, ID: {98e4476f-e745-4a7f-b795-19269cb70c40}) +---------- +The name of the StateType ({98e4476f-e745-4a7f-b795-19269cb70c40}) of ThingClass datalogger + + + + + + + Reachable changed + The name of the EventType ({2f7e1267-b0be-4b78-9aa3-832b86c4efad}) of ThingClass storage +---------- +The name of the EventType ({b70b61a4-54cb-47ec-b62a-b498eb1f650e}) of ThingClass meter +---------- +The name of the EventType ({eda29c50-73ac-40e0-9c92-26fee352e688}) of ThingClass inverter + + + + + Search new devices + The name of the ActionType ({c217fdc1-de18-41dc-b5d8-8072f84e7b6c}) of ThingClass datalogger + + + + + Set charging rate + The name of the ActionType ({7f469bbc-64a5-4045-8d5f-9a1a85039851}) of ThingClass sunspecStorage + + + + + Set discharging rate + The name of the ActionType ({6068f030-acce-44a2-b95f-bd00dd5ca760}) of ThingClass sunspecStorage + + + + + + Software version + The name of the ParamType (ThingClass: datalogger, EventType: swversion, ID: {31743ca5-4353-4f26-b2ad-5da43e5b9d86}) +---------- +The name of the StateType ({31743ca5-4353-4f26-b2ad-5da43e5b9d86}) of ThingClass datalogger + + + + + Software version changed + The name of the EventType ({31743ca5-4353-4f26-b2ad-5da43e5b9d86}) of ThingClass datalogger + + + + + + State + The name of the ParamType (ThingClass: sunspecStorage, EventType: storageState, ID: {da2b19c5-0f48-49d1-93f0-abdc0051407d}) +---------- +The name of the StateType ({da2b19c5-0f48-49d1-93f0-abdc0051407d}) of ThingClass sunspecStorage + + + + + + State of charge + The name of the ParamType (ThingClass: storage, EventType: charging, ID: {2de34a1f-de2e-43ad-8998-8a5460dff9ae}) +---------- +The name of the StateType ({2de34a1f-de2e-43ad-8998-8a5460dff9ae}) of ThingClass storage + + + + + SunSpec Storage + The name of the ThingClass ({e14d622f-5d8f-4788-b189-0774a6382a9b}) + + + + + + Time zone + The name of the ParamType (ThingClass: datalogger, EventType: tzone, ID: {6bdfeeda-7a47-4043-a011-5eb96308a7d6}) +---------- +The name of the StateType ({6bdfeeda-7a47-4043-a011-5eb96308a7d6}) of ThingClass datalogger + + + + + Time zone changed + The name of the EventType ({6bdfeeda-7a47-4043-a011-5eb96308a7d6}) of ThingClass datalogger + + + + + + Timezone location + The name of the ParamType (ThingClass: datalogger, EventType: tzoneloc, ID: {d034f59d-dc34-450a-a6f3-68264767a3e4}) +---------- +The name of the StateType ({d034f59d-dc34-450a-a6f3-68264767a3e4}) of ThingClass datalogger + + + + + Timezone location changed + The name of the EventType ({d034f59d-dc34-450a-a6f3-68264767a3e4}) of ThingClass datalogger + + + + + + Total current power + The name of the ParamType (ThingClass: meter, EventType: currentPower, ID: {e5056ea1-88a2-410b-9c5e-6322aca4cb17}) +---------- +The name of the StateType ({e5056ea1-88a2-410b-9c5e-6322aca4cb17}) of ThingClass meter + + + + + Total current power changed + The name of the EventType ({e5056ea1-88a2-410b-9c5e-6322aca4cb17}) of ThingClass meter + + + + + logger reachable changed + The name of the EventType ({98e4476f-e745-4a7f-b795-19269cb70c40}) of ThingClass datalogger + + + + diff --git a/nymea-plugins.pro b/nymea-plugins.pro index c734ab56..0a670cd6 100644 --- a/nymea-plugins.pro +++ b/nymea-plugins.pro @@ -19,6 +19,7 @@ PLUGIN_DIRS = \ elgato \ eq-3 \ flowercare \ + fronius \ genericelements \ genericthings \ gpio \