diff --git a/debian/control b/debian/control index b329878..d90f9f9 100644 --- a/debian/control +++ b/debian/control @@ -120,6 +120,16 @@ Description: nymea integration plugin for Huawei FusionSolar energy devices based on Modbus TCP. +Package: nymea-plugin-kostal +Architecture: any +Multi-Arch: same +Section: libs +Depends: ${shlibs:Depends}, + ${misc:Depends} +Description: nymea.io plugin for Kostal Solar inverters + This package will install the nymea.io plugin for Kostal Solar inverters + + Package: nymea-plugin-modbuscommander Architecture: any Section: libs diff --git a/debian/nymea-plugin-kostal.install.in b/debian/nymea-plugin-kostal.install.in new file mode 100644 index 0000000..464f022 --- /dev/null +++ b/debian/nymea-plugin-kostal.install.in @@ -0,0 +1,2 @@ +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginkostal.so +kostal/translations/*qm usr/share/nymea/translations/ diff --git a/kostal/integrationpluginkostal.cpp b/kostal/integrationpluginkostal.cpp new file mode 100644 index 0000000..cea7a27 --- /dev/null +++ b/kostal/integrationpluginkostal.cpp @@ -0,0 +1,447 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2022, 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 "integrationpluginkostal.h" + +#include "network/networkdevicediscovery.h" +#include "hardwaremanager.h" +#include "plugininfo.h" + +IntegrationPluginKostal::IntegrationPluginKostal() +{ + +} + +void IntegrationPluginKostal::discoverThings(ThingDiscoveryInfo *info) +{ + if (!hardwareManager()->networkDeviceDiscovery()->available()) { + qCWarning(dcKostal()) << "The network discovery is not available on this platform."; + info->finish(Thing::ThingErrorUnsupportedFeature, QT_TR_NOOP("The network device discovery is not available.")); + return; + } + + NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover(); + connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){ + foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) { + + qCDebug(dcKostal()) << "Found" << networkDeviceInfo; + + QString title; + if (networkDeviceInfo.hostName().isEmpty()) { + title = networkDeviceInfo.address().toString(); + } else { + title = networkDeviceInfo.hostName() + " (" + networkDeviceInfo.address().toString() + ")"; + } + + QString description; + if (networkDeviceInfo.macAddressManufacturer().isEmpty()) { + description = networkDeviceInfo.macAddress(); + } else { + description = networkDeviceInfo.macAddress() + " (" + networkDeviceInfo.macAddressManufacturer() + ")"; + } + + ThingDescriptor descriptor(kostalInverterThingClassId, title, description); + ParamList params; + params << Param(kostalInverterThingIpAddressParamTypeId, networkDeviceInfo.address().toString()); + params << Param(kostalInverterThingMacAddressParamTypeId, networkDeviceInfo.macAddress()); + descriptor.setParams(params); + + // Check if we already have set up this device + Things existingThings = myThings().filterByParam(kostalInverterThingMacAddressParamTypeId, networkDeviceInfo.macAddress()); + if (existingThings.count() == 1) { + qCDebug(dcKostal()) << "This connection already exists in the system:" << networkDeviceInfo; + descriptor.setThingId(existingThings.first()->id()); + } + + info->addThingDescriptor(descriptor); + } + + info->finish(Thing::ThingErrorNoError); + }); +} + +void IntegrationPluginKostal::startMonitoringAutoThings() +{ + +} + +void IntegrationPluginKostal::setupThing(ThingSetupInfo *info) +{ + Thing *thing = info->thing(); + qCDebug(dcKostal()) << "Setup" << thing << thing->params(); + + if (thing->thingClassId() == kostalInverterThingClassId) { + QHostAddress hostAddress = QHostAddress(thing->paramValue(kostalInverterThingIpAddressParamTypeId).toString()); + if (hostAddress.isNull()) { + info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("No IP address given")); + return; + } + + uint port = thing->paramValue(kostalInverterThingPortParamTypeId).toUInt(); + quint16 slaveId = thing->paramValue(kostalInverterThingSlaveIdParamTypeId).toUInt(); + + KostalModbusTcpConnection *kostalConnection = new KostalModbusTcpConnection(hostAddress, port, slaveId, this); + connect(kostalConnection, &KostalModbusTcpConnection::initializationFinished, this, [this, thing, kostalConnection, info]{ + qCDebug(dcKostal()) << "Connection init" << kostalConnection; + + // FIXME: check if success + + m_kostalConnections.insert(thing, kostalConnection); + info->finish(Thing::ThingErrorNoError); + + // Set connected true + thing->setStateValue(kostalInverterConnectedStateTypeId, true); + foreach (Thing *childThing, myThings().filterByParentId(thing->id())) { + if (childThing->thingClassId() == kostalBatteryThingClassId) { + childThing->setStateValue(kostalBatteryConnectedStateTypeId, true); + } else if (childThing->thingClassId() == kostalMeterThingClassId) { + childThing->setStateValue(kostalMeterConnectedStateTypeId, true); + } + } + + connect(kostalConnection, &KostalModbusTcpConnection::totalAcPowerChanged, this, [thing](float totalAcPower){ + qCDebug(dcKostal()) << thing << "total AC power changed" << totalAcPower << "W"; + thing->setStateValue(kostalInverterCurrentPowerStateTypeId, - totalAcPower); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::totalYieldChanged, this, [thing](float totalYield){ + qCDebug(dcKostal()) << thing << "total yeald changed" << totalYield << "Wh"; + thing->setStateValue(kostalInverterTotalEnergyProducedStateTypeId, totalYield / 1000.0); // kWh + }); + + // Current + connect(kostalConnection, &KostalModbusTcpConnection::currentPhase1Changed, this, [thing](float currentPhase1){ + qCDebug(dcKostal()) << thing << "current phase 1 changed" << currentPhase1 << "A"; + thing->setStateValue(kostalInverterPhaseACurrentStateTypeId, currentPhase1); // A + }); + + connect(kostalConnection, &KostalModbusTcpConnection::currentPhase2Changed, this, [thing](float currentPhase2){ + qCDebug(dcKostal()) << thing << "current phase 2 changed" << currentPhase2 << "A"; + thing->setStateValue(kostalInverterPhaseBCurrentStateTypeId, currentPhase2); // A + }); + + connect(kostalConnection, &KostalModbusTcpConnection::currentPhase3Changed, this, [thing](float currentPhase3){ + qCDebug(dcKostal()) << thing << "current phase 3 changed" << currentPhase3 << "A"; + thing->setStateValue(kostalInverterPhaseCCurrentStateTypeId, currentPhase3); // A + }); + + // Voltage + connect(kostalConnection, &KostalModbusTcpConnection::voltagePhase1Changed, this, [thing](float voltagePhase1){ + qCDebug(dcKostal()) << thing << "voltage phase 1 changed" << voltagePhase1 << "V"; + thing->setStateValue(kostalInverterVoltagePhaseAStateTypeId, voltagePhase1); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::voltagePhase2Changed, this, [thing](float voltagePhase2){ + qCDebug(dcKostal()) << thing << "voltage phase 2 changed" << voltagePhase2 << "V"; + thing->setStateValue(kostalInverterVoltagePhaseBStateTypeId, voltagePhase2); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::voltagePhase3Changed, this, [thing](float voltagePhase3){ + qCDebug(dcKostal()) << thing << "voltage phase 3 changed" << voltagePhase3 << "V"; + thing->setStateValue(kostalInverterVoltagePhaseCStateTypeId, voltagePhase3); + }); + + // Current power + connect(kostalConnection, &KostalModbusTcpConnection::activePowerPhase1Changed, this, [thing](float activePowerPhase1){ + qCDebug(dcKostal()) << thing << "active power phase 1 changed" << activePowerPhase1 << "W"; + thing->setStateValue(kostalInverterCurrentPowerPhaseAStateTypeId, activePowerPhase1); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::activePowerPhase2Changed, this, [thing](float activePowerPhase2){ + qCDebug(dcKostal()) << thing << "active power phase 2 changed" << activePowerPhase2 << "W"; + thing->setStateValue(kostalInverterCurrentPowerPhaseBStateTypeId, activePowerPhase2); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::activePowerPhase3Changed, this, [thing](float activePowerPhase3){ + qCDebug(dcKostal()) << thing << "active power phase 3 changed" << activePowerPhase3 << "W"; + thing->setStateValue(kostalInverterCurrentPowerPhaseCStateTypeId, activePowerPhase3); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::gridFrequencyInverterChanged, this, [thing](float gridFrequencyInverter){ + qCDebug(dcKostal()) << thing << "grid frequency changed" << gridFrequencyInverter << "Hz"; + thing->setStateValue(kostalInverterFrequencyStateTypeId, gridFrequencyInverter); + }); + + + // Update registers + kostalConnection->update(); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::connectionStateChanged, this, [this, thing, kostalConnection](bool status){ + qCDebug(dcKostal()) << "Connected changed to" << status << "for" << thing; + if (status) { + // Connected true will be set after successfull init + kostalConnection->initialize(); + } else { + thing->setStateValue(kostalInverterConnectedStateTypeId, false); + foreach (Thing *childThing, myThings().filterByParentId(thing->id())) { + if (childThing->thingClassId() == kostalBatteryThingClassId) { + childThing->setStateValue(kostalBatteryConnectedStateTypeId, false); + } else if (childThing->thingClassId() == kostalMeterThingClassId) { + childThing->setStateValue(kostalMeterConnectedStateTypeId, false); + } + } + } + }); + + kostalConnection->connectDevice(); + return; + } + + if (thing->thingClassId() == kostalMeterThingClassId) { + // Get the parent thing and the associated connection + Thing *connectionThing = myThings().findById(thing->parentId()); + if (!connectionThing) { + qCWarning(dcKostal()) << "Failed to set up kostal energy meter because the parent thing with ID" << thing->parentId().toString() << "could not be found."; + info->finish(Thing::ThingErrorHardwareNotAvailable); + return; + } + + KostalModbusTcpConnection *kostalConnection = m_kostalConnections.value(connectionThing); + if (!kostalConnection) { + qCWarning(dcKostal()) << "Failed to set up kostal energy meter because the connection for" << connectionThing << "does not exist."; + info->finish(Thing::ThingErrorHardwareNotAvailable); + return; + } + + // Note: The connected state will be handled in the parent inverter thing + + // Update the meter data from the kostal connection containing all information + + connect(kostalConnection, &KostalModbusTcpConnection::powerMeterTotalActivePowerChanged, this, [thing](float powerMeterTotalActivePower){ + qCDebug(dcKostal()) << thing << "total active power changed" << powerMeterTotalActivePower << "W"; + thing->setStateValue(kostalMeterCurrentPowerStateTypeId, powerMeterTotalActivePower); + }); + + // TODO: set toal energy consumed/produced + + connect(kostalConnection, &KostalModbusTcpConnection::powerMeterTotalActivePowerChanged, this, [thing](float powerMeterTotalActivePower){ + qCDebug(dcKostal()) << thing << "total active power changed" << powerMeterTotalActivePower << "W"; + thing->setStateValue(kostalMeterCurrentPowerStateTypeId, powerMeterTotalActivePower); + }); + + // Current + connect(kostalConnection, &KostalModbusTcpConnection::powerMeterCurrentPhase1Changed, this, [thing](float powerMeterCurrentPhase1){ + qCDebug(dcKostal()) << thing << "current phase 1 changed" << powerMeterCurrentPhase1 << "A"; + thing->setStateValue(kostalMeterCurrentPhaseAStateTypeId, powerMeterCurrentPhase1); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::powerMeterCurrentPhase2Changed, this, [thing](float powerMeterCurrentPhase2){ + qCDebug(dcKostal()) << thing << "current phase 2 changed" << powerMeterCurrentPhase2 << "A"; + thing->setStateValue(kostalMeterCurrentPhaseBStateTypeId, powerMeterCurrentPhase2); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::powerMeterCurrentPhase3Changed, this, [thing](float powerMeterCurrentPhase3){ + qCDebug(dcKostal()) << thing << "current phase 3 changed" << powerMeterCurrentPhase3 << "A"; + thing->setStateValue(kostalMeterCurrentPhaseCStateTypeId, powerMeterCurrentPhase3); + }); + + // Voltage + connect(kostalConnection, &KostalModbusTcpConnection::powerMeterVoltagePhase1Changed, this, [thing](float powerMeterVoltagePhase1){ + qCDebug(dcKostal()) << thing << "voltage phase 1 changed" << powerMeterVoltagePhase1 << "V"; + thing->setStateValue(kostalMeterVoltagePhaseAStateTypeId, powerMeterVoltagePhase1); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::powerMeterVoltagePhase2Changed, this, [thing](float powerMeterVoltagePhase2){ + qCDebug(dcKostal()) << thing << "voltage phase 2 changed" << powerMeterVoltagePhase2 << "V"; + thing->setStateValue(kostalMeterVoltagePhaseBStateTypeId, powerMeterVoltagePhase2); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::powerMeterVoltagePhase3Changed, this, [thing](float powerMeterVoltagePhase3){ + qCDebug(dcKostal()) << thing << "voltage phase 3 changed" << powerMeterVoltagePhase3 << "V"; + thing->setStateValue(kostalMeterVoltagePhaseCStateTypeId, powerMeterVoltagePhase3); + }); + + // Power + connect(kostalConnection, &KostalModbusTcpConnection::powerMeterActivePowerPhase1Changed, this, [thing](float powerMeterActivePowerPhase1){ + qCDebug(dcKostal()) << thing << "power phase 1 changed" << powerMeterActivePowerPhase1 << "W"; + thing->setStateValue(kostalMeterCurrentPowerPhaseAStateTypeId, powerMeterActivePowerPhase1); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::powerMeterActivePowerPhase2Changed, this, [thing](float powerMeterActivePowerPhase2){ + qCDebug(dcKostal()) << thing << "power phase 2 changed" << powerMeterActivePowerPhase2 << "W"; + thing->setStateValue(kostalMeterCurrentPowerPhaseBStateTypeId, powerMeterActivePowerPhase2); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::powerMeterActivePowerPhase3Changed, this, [thing](float powerMeterActivePowerPhase3){ + qCDebug(dcKostal()) << thing << "power phase 3 changed" << powerMeterActivePowerPhase3 << "W"; + thing->setStateValue(kostalMeterCurrentPowerPhaseCStateTypeId, powerMeterActivePowerPhase3); + }); + + connect(kostalConnection, &KostalModbusTcpConnection::gridFrequencyPowerMeterChanged, this, [thing](float gridFrequency){ + qCDebug(dcKostal()) << thing << "grid frequency changed" << gridFrequency << "Hz"; + thing->setStateValue(kostalMeterFrequencyStateTypeId, gridFrequency); + }); + + info->finish(Thing::ThingErrorNoError); + } + + if (thing->thingClassId() == kostalBatteryThingClassId) { + // Get the parent thing and the associated connection + Thing *connectionThing = myThings().findById(thing->parentId()); + if (!connectionThing) { + qCWarning(dcKostal()) << "Failed to set up kostal battery because the parent thing with ID" << thing->parentId().toString() << "could not be found."; + info->finish(Thing::ThingErrorHardwareNotAvailable); + return; + } + + KostalModbusTcpConnection *kostalConnection = m_kostalConnections.value(connectionThing); + if (!kostalConnection) { + qCWarning(dcKostal()) << "Failed to set up kostal battery because the connection for" << connectionThing << "does not exist."; + info->finish(Thing::ThingErrorHardwareNotAvailable); + return; + } + + // Note: The connected state will be handled in the parent inverter thing + + connect(kostalConnection, &KostalModbusTcpConnection::batteryStateOfChargeChanged, this, [thing](quint16 batteryStateOfCharge){ + qCDebug(dcKostal()) << thing << "battery SoC changed" << batteryStateOfCharge << "%"; + thing->setStateValue(kostalBatteryBatteryLevelStateTypeId, batteryStateOfCharge); + thing->setStateValue(kostalBatteryBatteryCriticalStateTypeId, batteryStateOfCharge < 5); + }); + + + connect(kostalConnection, &KostalModbusTcpConnection::batteryActualPowerChanged, this, [thing](float batteryActualPower){ + qCDebug(dcKostal()) << thing << "battery charge current changed" << batteryActualPower << "W"; + thing->setStateValue(kostalBatteryCurrentPowerStateTypeId, batteryActualPower); + if (batteryActualPower == 0) { + thing->setStateValue(kostalBatteryChargingStateStateTypeId, "idle"); + } else if (batteryActualPower > 0) { + thing->setStateValue(kostalBatteryChargingStateStateTypeId, "discharging"); + } else if (batteryActualPower < 0) { + thing->setStateValue(kostalBatteryChargingStateStateTypeId, "charging"); + } + }); + + connect(kostalConnection, &KostalModbusTcpConnection::batteryWorkCapacityChanged, this, [thing](quint32 batteryWorkCapacity){ + qCDebug(dcKostal()) << thing << "battery work capacity changed" << batteryWorkCapacity << "Wh"; + thing->setStateValue(kostalBatteryCapacityStateTypeId, batteryWorkCapacity / 1000.0); // kWh + }); + + info->finish(Thing::ThingErrorNoError); + } +} + +void IntegrationPluginKostal::postSetupThing(Thing *thing) +{ + if (thing->thingClassId() == kostalInverterThingClassId) { + + KostalModbusTcpConnection *kostalConnection = m_kostalConnections.value(thing); + + // Check if we have to create the meter for the Kostal inverter + if (myThings().filterByParentId(thing->id()).filterByThingClassId(kostalMeterThingClassId).isEmpty()) { + + qCDebug(dcKostal()) << "--> Read block \"powerMeterValues\" registers from:" << 220 << "size:" << 38; + QModbusReply *reply = kostalConnection->readBlockPowerMeterValues(); + if (reply) { + if (!reply->isFinished()) { + connect(reply, &QModbusReply::finished, this, [=](){ + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + const QVector blockValues = unit.values(); + + bool notZero = false; + for (int i = 0; i < blockValues.size(); i++) { + if (blockValues.at(i) != 0) { + notZero = true; + break; + } + } + + if (notZero) { + qCDebug(dcKostal()) << "There is a meter connected but not set up yet. Creating a meter..."; + // No meter thing created for this inverter, lets create one with the inverter as parent + ThingClass meterThingClass = thingClass(kostalMeterThingClassId); + ThingDescriptor descriptor(kostalMeterThingClassId, meterThingClass.name(), QString(), thing->id()); + // No params required, all we need is the connection + emit autoThingsAppeared(ThingDescriptors() << descriptor); + } else { + qCDebug(dcKostal()) << "There is no meter connected to the inverter" << thing; + } + } + }); + + connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){ + qCWarning(dcKostal()) << "Modbus reply error occurred while updating block \"powerMeterValues\" registers" << error << reply->errorString(); + emit reply->finished(); + }); + } + } else { + qCWarning(dcKostal()) << "Error occurred while reading block \"powerMeterValues\" registers"; + } + } + + // Check if we have to create the battery for the Kostal inverter + if (myThings().filterByParentId(thing->id()).filterByThingClassId(kostalBatteryThingClassId).isEmpty()) { + if (kostalConnection->batteryType() == KostalModbusTcpConnection::BatteryTypeNoBattery) { + qCDebug(dcKostal()) << "There is no battery connected to the inverter" << thing; + return; + } + + qCDebug(dcKostal()) << "There is a battery connected but not set up yet. Creating a battery" << kostalConnection->batteryType(); + ThingClass batteryThingClass = thingClass(kostalBatteryThingClassId); + ThingDescriptor descriptor(kostalBatteryThingClassId, kostalConnection->batteryManufacturer() + " - " + kostalConnection->batteryModelId(), QString(), thing->id()); + // No params required, all we need is the connection + emit autoThingsAppeared(ThingDescriptors() << descriptor); + } + + if (!m_pluginTimer) { + qCDebug(dcKostal()) << "Starting plugin timer..."; + m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(4); + connect(m_pluginTimer, &PluginTimer::timeout, this, [this] { + foreach(KostalModbusTcpConnection *connection, m_kostalConnections) { + if (connection->connected()) { + connection->update(); + } + } + }); + } + } +} + +void IntegrationPluginKostal::thingRemoved(Thing *thing) +{ + if (thing->thingClassId() == kostalInverterThingClassId && m_kostalConnections.contains(thing)) { + KostalModbusTcpConnection *connection = m_kostalConnections.take(thing); + delete connection; + } + + if (myThings().isEmpty() && m_pluginTimer) { + hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer); + m_pluginTimer = nullptr; + } +} + +void IntegrationPluginKostal::executeAction(ThingActionInfo *info) +{ + info->finish(Thing::ThingErrorNoError); +} + + diff --git a/kostal/integrationpluginkostal.h b/kostal/integrationpluginkostal.h new file mode 100644 index 0000000..866ab1d --- /dev/null +++ b/kostal/integrationpluginkostal.h @@ -0,0 +1,67 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2022, 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 INTEGRATIONPLUGINKOSTAL_H +#define INTEGRATIONPLUGINKOSTAL_H + +#include +#include + +#include "kostalmodbustcpconnection.h" + +class IntegrationPluginKostal: public IntegrationPlugin +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginkostal.json") + Q_INTERFACES(IntegrationPlugin) + +public: + /** Constructor */ + explicit IntegrationPluginKostal(); + + void discoverThings(ThingDiscoveryInfo *info) override; + void startMonitoringAutoThings() override; + void setupThing(ThingSetupInfo *info) override; + void postSetupThing(Thing *thing) override; + void thingRemoved(Thing *thing) override; + void executeAction(ThingActionInfo *info) override; + +private: + PluginTimer *m_pluginTimer = nullptr; + QHash m_kostalConnections; + + + +}; + +#endif // INTEGRATIONPLUGINKOSTAL_H + + diff --git a/kostal/integrationpluginkostal.json b/kostal/integrationpluginkostal.json new file mode 100644 index 0000000..dfd6487 --- /dev/null +++ b/kostal/integrationpluginkostal.json @@ -0,0 +1,405 @@ +{ + "name": "Kostal", + "displayName": "Kostal", + "id": "51a2c7d5-084d-4474-a65a-e0447ab9ac45", + "vendors": [ + { + "name": "kostal", + "displayName": "KOSTAL Solar Electric", + "id": "862d1ebf-cb78-4c55-89b2-819fddfd9acd", + "thingClasses": [ + { + "name": "kostalInverter", + "displayName": "KOSTAL Inverter", + "id": "7dc6db14-6f5a-4ac8-9684-4c6a526bd0de", + "createMethods": ["discovery", "user"], + "interfaces": ["solarinverter", "connectable"], + "providedInterfaces": [ "energymeter", "energystorage"], + "paramTypes": [ + { + "id": "f1c43b1e-cffe-4d30-bda0-c23ed648dd71", + "name": "ipAddress", + "displayName": "IP address", + "type": "QString", + "inputType": "IPv4Address", + "defaultValue": "127.0.0.1" + }, + { + "id": "906f6099-d0e1-4297-a2b3-f8ec4482c578", + "name":"macAddress", + "displayName": "MAC address", + "type": "QString", + "inputType": "MacAddress", + "defaultValue": "" + }, + { + "id": "9d2175af-afb9-4b31-b3dc-e53a369bad9e", + "name":"port", + "displayName": "Port", + "type": "int", + "defaultValue": 1502 + }, + { + "id": "b3e04cb0-8f9a-4c9f-9c67-5c08da0273e3", + "name":"slaveId", + "displayName": "Slave ID", + "type": "int", + "defaultValue": 71 + } + ], + "stateTypes": [ + { + "id": "8d64954a-855d-44ea-8bc9-88a71ab47b6b", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "bd68fa44-2628-4e4e-ac9b-5f2cf563eb4d", + "name": "currentPower", + "displayName": "Active power", + "displayNameEvent": "Active power changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0, + "cached": false + }, + { + "id": "5c1546d2-92be-4809-bc56-8bbdaab436d2", + "name": "totalEnergyProduced", + "displayName": "Total AC energy", + "displayNameEvent": "Total AC energy changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.0, + "cached": true + }, + { + "id": "567bb3c2-4a0c-4194-a86e-b8dc29815092", + "name": "phaseACurrent", + "displayName": "Phase A current", + "displayNameEvent": "Phase A current changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "84e9282a-b72b-4dbf-9e4b-99083e5539a5", + "name": "phaseBCurrent", + "displayName": "Phase B current", + "displayNameEvent": "Phase B current changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "4f7c308f-2cb2-4327-8a68-77222f920e61", + "name": "phaseCCurrent", + "displayName": "Phase C current", + "displayNameEvent": "Phase C current changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "7fcade2d-9243-4694-a29f-36a517f54844", + "name": "voltagePhaseA", + "displayName": "Voltage phase A", + "displayNameEvent": "Voltage phase A changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "8f1b229d-af39-47ec-b005-eecd6f174294", + "name": "voltagePhaseB", + "displayName": "Voltage phase B", + "displayNameEvent": "Voltage phase B changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "51e0d1c7-e75a-4bc4-a7e4-6170a959e6cc", + "name": "voltagePhaseC", + "displayName": "Voltage phase C", + "displayNameEvent": "Voltage phase C changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "aed44263-d15e-46d6-b6a3-66005ceb53c9", + "name": "currentPowerPhaseA", + "displayName": "Current power phase A", + "displayNameEvent": "Current power phase A changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "8d8cd634-00dd-46c8-b34b-bbff552d0121", + "name": "currentPowerPhaseB", + "displayName": "Current power phase B", + "displayNameEvent": "Current power phase B changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "95f1ad78-0cb1-44cf-87b2-03e28b115f00", + "name": "currentPowerPhaseC", + "displayName": "Current power phase C", + "displayNameEvent": "Current power phase C changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "634a4659-5c73-40e9-a77d-4f2e555d05bb", + "name": "frequency", + "displayName": "Frequency", + "displayNameEvent": "Frequency changed", + "type": "double", + "unit": "Hertz", + "defaultValue": 0.00, + "cached": false + } + ], + "actionTypes": [ ] + }, + { + "name": "kostalMeter", + "displayName": "KOSTAL Meter", + "id": "61af1e07-6a59-4465-a563-3cbf4a9fcbc3", + "createMethods": ["auto"], + "interfaces": [ "energymeter", "connectable"], + "paramTypes": [ + ], + "stateTypes": [ + { + "id": "5c510989-d6e1-4b06-b10f-f8b9e52a254c", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "992b0da8-e6bd-47ab-af60-be8802fc7ecf", + "name": "currentPower", + "displayName": "Total real power", + "displayNameEvent": "Total real power changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "902ce047-ef6b-4868-9f7c-61a2ebe61a5b", + "name": "totalEnergyProduced", + "displayName": "AC energy", + "displayNameEvent": "AC energy changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00, + "cached": true + }, + { + "id": "f40e8bd9-db0e-4f69-8fa1-f1cfd4b144f3", + "name": "totalEnergyConsumed", + "displayName": "Total real energy imported", + "displayNameEvent": "Total real energy imported changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00, + "cached": true + }, + { + "id": "1681ee7d-5d22-4794-8cfe-febaa1ddf29f", + "name": "currentPhaseA", + "displayName": "Phase A current", + "displayNameEvent": "Phase A current changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "b54e7182-6cb2-4184-96c5-2324e8139b6e", + "name": "currentPhaseB", + "displayName": "Phase B current", + "displayNameEvent": "Phase B current changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "546eeb76-b17f-4c51-a9fa-01e7403913cd", + "name": "currentPhaseC", + "displayName": "Phase C current", + "displayNameEvent": "Phase C current changed", + "type": "double", + "unit": "Ampere", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "2b1250eb-4c22-4025-ba7c-c3e8f27af3dc", + "name": "currentPowerPhaseA", + "displayName": "Current power phase A", + "displayNameEvent": "Current power phase A changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "0c43d20d-843c-4edd-9955-dafab6caecf6", + "name": "currentPowerPhaseB", + "displayName": "Current power phase B", + "displayNameEvent": "Current power phase B changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "a1e46df0-43e5-42f0-846a-5d2f24808a67", + "name": "currentPowerPhaseC", + "displayName": "Current power phase C", + "displayNameEvent": "Current power phase C changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "10a34381-cfb1-4aeb-a25f-e6b0d8b96510", + "name": "voltagePhaseA", + "displayName": "Voltage phase A", + "displayNameEvent": "Voltage phase A changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "b0be1395-c7d2-449e-9632-5b6bf3298797", + "name": "voltagePhaseB", + "displayName": "Voltage phase B", + "displayNameEvent": "Voltage phase B changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "b422d7a9-4c43-4827-be39-e4694f2cab64", + "name": "voltagePhaseC", + "displayName": "Voltage phase C", + "displayNameEvent": "Voltage phase C changed", + "type": "double", + "unit": "Volt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "7c86ea72-505b-4924-80ef-3cf3ff31a380", + "name": "frequency", + "displayName": "Frequency", + "displayNameEvent": "Frequency changed", + "type": "double", + "unit": "Hertz", + "defaultValue": 0.00, + "cached": false + } + ], + "actionTypes": [ ] + }, + { + "name": "kostalBattery", + "displayName": "KOSTAL Battery", + "id": "d6dbdfe8-adbb-47d8-840d-9b787683fc69", + "createMethods": ["auto"], + "interfaces": [ "energystorage", "connectable"], + "paramTypes": [ + ], + "stateTypes": [ + { + "id": "4a5a5a38-b623-4024-b557-410a46ebc495", + "name": "connected", + "displayName": "Connected", + "displayNameEvent": "Connected changed", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "897616db-e815-4cda-b890-13b37a94ad17", + "name": "batteryCritical", + "displayName": "Battery critical", + "displayNameEvent": "Battery critical changed", + "type": "bool", + "defaultValue": false + }, + { + "id": "a4b0c8c9-44f0-43e2-ab25-63fdc9772fb8", + "name": "batteryLevel", + "displayName": "Battery level", + "displayNameEvent": "Battery level changed", + "type": "int", + "unit": "Percentage", + "minValue": 0, + "maxValue": 100, + "defaultValue": 0 + }, + { + "id": "6d72ccea-7761-4f00-b43f-463d05cbe559", + "name": "currentPower", + "displayName": "Total real power", + "displayNameEvent": "Total real power changed", + "type": "double", + "unit": "Watt", + "defaultValue": 0.00, + "cached": false + }, + { + "id": "98099dbd-3f66-43b3-8192-f2e3fdcd5d62", + "name": "capacity", + "displayName": "Capacity", + "displayNameEvent": "Capacity changed", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0.00 + }, + { + "id": "829173e8-7535-4aba-b403-d498ff68250e", + "name": "chargingState", + "displayName": "Charging state", + "displayNameEvent": "Charging state changed", + "type": "QString", + "possibleValues": ["idle", "charging", "discharging"], + "defaultValue": "idle" + } + ], + "actionTypes": [ ] + } + ] + } + ] +} diff --git a/kostal/kostal-registers.json b/kostal/kostal-registers.json new file mode 100644 index 0000000..df21a96 --- /dev/null +++ b/kostal/kostal-registers.json @@ -0,0 +1,965 @@ +{ + "className": "Kostal", + "protocol": "TCP", + "endianness": "LittleEndian", + "enums": [ + { + "name": "ByteOrder", + "values": [ + { + "key": "LittleEndian", + "value": 0 + }, + { + "key": "BigEndian", + "value": 1 + } + ] + }, + { + "name": "InverterState", + "values": [ + { + "key": "Off", + "value": 0 + }, + { + "key": "Init", + "value": 1 + }, + { + "key": "IsoMeas", + "value": 2 + }, + { + "key": "GridCheck", + "value": 3 + }, + { + "key": "StartUp", + "value": 4 + }, + { + "key": "FeedIn", + "value": 6 + }, + { + "key": "Throttled", + "value": 7 + }, + { + "key": "ExtSwitchOff", + "value": 8 + }, + { + "key": "Update", + "value": 9 + }, + { + "key": "Standby", + "value": 10 + }, + { + "key": "GridSync", + "value": 11 + }, + { + "key": "GridPreCheck", + "value": 12 + }, + { + "key": "GridSwitchOff", + "value": 13 + }, + { + "key": "Overheating", + "value": 14 + }, + { + "key": "Shutdown", + "value": 15 + }, + { + "key": "ImproperDcVoltage", + "value": 16 + }, + { + "key": "Esb", + "value": 17 + }, + { + "key": "Unknown", + "value": 18 + } + ] + }, + { + "name": "EnergyManagementState", + "values": [ + { + "key": "Idle", + "value": 0 + }, + { + "key": "EmergencyBatteryCharge", + "value": 2 + }, + { + "key": "WinterModeStep1", + "value": 8 + }, + { + "key": "WinterModeStep2", + "value": 16 + } + ] + }, + { + "name": "BatteryType", + "values": [ + { + "key": "NoBattery", + "value": 0 + }, + { + "key": "SonyMurata", + "value": 2 + }, + { + "key": "BydBbox", + "value": 4 + } + ] + } + ], + "blocks": [ + { + "id": "basics", + "readSchedule": "init", + "registers": [ + { + "id": "modbusUnitId", + "address": 4, + "size": 1, + "type": "uint16", + "registerType": "holdingRegister", + "description": "MODBUS Unit-ID", + "defaultValue": "1", + "access": "RO" + }, + { + "id": "modbusByteOrder", + "address": 5, + "size": 1, + "type": "uint16", + "enum": "ByteOrder", + "registerType": "holdingRegister", + "description": "MODBUS Byte Order Note", + "defaultValue": "ByteOrderLittleEndian", + "access": "RO" + }, + { + "id": "inverterArticleNumber", + "address": 6, + "size": 8, + "type": "string", + "registerType": "holdingRegister", + "description": "Inverter article number", + "access": "RO" + }, + { + "id": "inverterSerialNumber1", + "address": 14, + "size": 8, + "type": "string", + "registerType": "holdingRegister", + "description": "Inverter serial number 1", + "access": "RO" + } + ] + }, + { + "id": "information", + "readSchedule": "init", + "registers": [ + { + "id": "hardwareVersion", + "address": 36, + "size": 2, + "type": "uint32", + "registerType": "holdingRegister", + "description": "Hardware-Version", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "softwareVersionMainController", + "address": 38, + "size": 8, + "type": "string", + "registerType": "holdingRegister", + "description": "Software-Version Maincontroller (MC)", + "access": "RO" + }, + { + "id": "softwareVersionIoController", + "address": 46, + "size": 8, + "type": "string", + "registerType": "holdingRegister", + "description": "Software-Version IO-Controller (IOC)", + "access": "RO" + }, + { + "id": "powerId", + "address": 54, + "size": 1, + "type": "uint16", + "registerType": "holdingRegister", + "description": "Power-ID", + "defaultValue": "0", + "access": "RO" + } + ] + }, + { + "id": "consumptions", + "readSchedule": "update", + "registers": [ + { + "id": "energyManagementState", + "address": 104, + "size": 2, + "type": "uint32", + "enum": "EnergyManagementState", + "registerType": "holdingRegister", + "description": "State of energy manager", + "defaultValue": "EnergyManagementStateIdle", + "access": "RO" + }, + { + "id": "homeOwnConsumptionFromBattery", + "address": 106, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Home own consumption from battery", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "homeOwnConsumptionFromGrid", + "address": 108, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Home own consumption from grid", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "totalHomeConsumptionFromBattery", + "address": 110, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Total home consumption Battery", + "unit": "Wh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "totalHomeConsumptionFromGrid", + "address": 112, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Total home consumption grid", + "unit": "Wh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "totalHomeConsumptionFromPv", + "address": 114, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Total home consumption from PV", + "unit": "Wh", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "homeOwnConsumptionPv", + "address": 116, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Home own consumption from PV", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "totalHomeConsumption", + "address": 118, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Total home consumption", + "unit": "Wh", + "defaultValue": "0", + "access": "RO" + } + ] + }, + { + "id": "inverterValues", + "readSchedule": "update", + "registers": [ + { + "id": "gridFrequencyInverter", + "address": 152, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Grid frequency inverter", + "unit": "Hz", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "currentPhase1", + "address": 154, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Current phase 1", + "unit": "A", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "activePowerPhase1", + "address": 156, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Active power phase 1", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "voltagePhase1", + "address": 158, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Voltage phase 1", + "unit": "V", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "currentPhase2", + "address": 160, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Current phase 2", + "unit": "A", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "activePowerPhase2", + "address": 162, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Active power phase 2", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "voltagePhase2", + "address": 164, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Voltage phase 2", + "unit": "V", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "currentPhase3", + "address": 166, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Current phase 3", + "unit": "A", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "activePowerPhase3", + "address": 168, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Active power phase 3", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "voltagePhase3", + "address": 170, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Voltage phase 3", + "unit": "V", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "totalAcPower", + "address": 172, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Total AC power", + "unit": "W", + "defaultValue": "0", + "access": "RO" + } + ] + }, + { + "id": "powerMeterValues", + "readSchedule": "update", + "registers": [ + { + "id": "gridFrequencyPowerMeter", + "address": 220, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Grid frequency (powermeter)", + "unit": "Hz", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterCurrentPhase1", + "address": 222, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Current phase 1 (powermeter)", + "unit": "A", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterActivePowerPhase1", + "address": 224, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Active power phase 1 (powermeter)", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterReactivePowerPhase1", + "address": 226, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Reactive power phase 1 (powermeter)", + "unit": "var", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterApparentPowerPhase1", + "address": 228, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Apparent power phase 1 (powermeter)", + "unit": "VA", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterVoltagePhase1", + "address": 230, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Voltage phase 1 (powermeter)", + "unit": "V", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterCurrentPhase2", + "address": 232, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Current phase 2 (powermeter)", + "unit": "A", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterActivePowerPhase2", + "address": 234, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Active power phase 2 (powermeter)", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterReactivePowerPhase2", + "address": 236, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Reactive power phase 2 (powermeter)", + "unit": "var", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterApparentPowerPhase2", + "address": 238, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Apparent power phase 2 (powermeter)", + "unit": "VA", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterVoltagePhase2", + "address": 240, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Voltage phase 2 (powermeter)", + "unit": "V", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterCurrentPhase3", + "address": 242, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Current phase 3 (powermeter)", + "unit": "A", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterActivePowerPhase3", + "address": 244, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Active power phase 3 (powermeter)", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterReactivePowerPhase3", + "address": 246, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Reactive power phase 3 (powermeter)", + "unit": "var", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterApparentPowerPhase3", + "address": 248, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Apparent power phase 3 (powermeter)", + "unit": "VA", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterVoltagePhase3", + "address": 250, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Voltage phase 3 (powermeter)", + "unit": "V", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterTotalActivePower", + "address": 252, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Total active power (powermeter)", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterTotalReactivePower", + "address": 254, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Total reactive power (powermeter)", + "unit": "var", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterTotalApparentPower", + "address": 256, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "description": "Total apparent power (powermeter)", + "unit": "VA", + "defaultValue": "0", + "access": "RO" + } + ] + }, + { + "id": "yield", + "readSchedule": "update", + "registers": [ + { + "id": "totalYield", + "address": 320, + "size": 2, + "type": "float", + "description": "Total yield", + "registerType": "holdingRegister", + "defaultValue": "0", + "unit": "Wh", + "access": "RO" + }, + { + "id": "dailyYield", + "address": 322, + "size": 2, + "type": "float", + "description": "Daily yield", + "registerType": "holdingRegister", + "defaultValue": "0", + "unit": "Wh", + "access": "RO" + }, + { + "id": "yearlyYield", + "address": 324, + "size": 2, + "type": "float", + "description": "Yearly yield", + "registerType": "holdingRegister", + "defaultValue": "0", + "unit": "Wh", + "access": "RO" + }, + { + "id": "MonthlyYield", + "address": 326, + "size": 2, + "type": "float", + "description": "Monthly yield", + "registerType": "holdingRegister", + "defaultValue": "0", + "unit": "Wh", + "access": "RO" + } + ] + } + ], + "registers": [ + { + "id": "bidirectionalConverterNumber", + "address": 30, + "size": 1, + "type": "uint16", + "readSchedule": "init", + "registerType": "holdingRegister", + "description": "Number of bidirectional converter", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "acPhasesNumber", + "address": 32, + "size": 1, + "type": "uint16", + "readSchedule": "init", + "registerType": "holdingRegister", + "description": "Number of bidirectional converter", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "numberPvStrings", + "address": 34, + "size": 1, + "type": "uint16", + "readSchedule": "init", + "registerType": "holdingRegister", + "description": "Number of PV strings", + "unit": "", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "inverterState", + "address": 56, + "size": 1, + "type": "uint16", + "readSchedule": "update", + "registerType": "holdingRegister", + "description": "Inverter state", + "defaultValue": "InverterStateUnknown", + "enum": "InverterState", + "access": "RO" + }, + { + "id": "totalDcPower", + "address": 100, + "size": 2, + "type": "float", + "readSchedule": "update", + "registerType": "holdingRegister", + "description": "Total DC power", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "batteryChargeCurrent", + "address": 190, + "size": 2, + "type": "float", + "readSchedule": "update", + "registerType": "holdingRegister", + "description": "Battery charge current", + "unit": "A", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "numberOfBytteryCycles", + "address": 194, + "size": 2, + "type": "float", + "readSchedule": "update", + "registerType": "holdingRegister", + "description": "Number of battery cycles", + "unit": "", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "actualBatteryChargeCurrent", + "address": 200, + "size": 2, + "type": "float", + "readSchedule": "update", + "registerType": "holdingRegister", + "description": "Actual battery charge (-) / discharge (+) current", + "unit": "A", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "batteryTemperature", + "address": 214, + "size": 2, + "type": "float", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Battery temperature", + "unit": "°C", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "batteryVoltage", + "address": 216, + "size": 2, + "type": "float", + "readSchedule": "update", + "registerType": "holdingRegister", + "description": "Battery voltage", + "unit": "V", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "batteryStateOfCharge", + "address": 514, + "size": 1, + "type": "uint16", + "readSchedule": "update", + "registerType": "holdingRegister", + "description": "Battery SoC", + "unit": "%", + "access": "RO" + }, + { + "id": "batteryManufacturer", + "address": 517, + "size": 8, + "type": "string", + "readSchedule": "init", + "registerType": "holdingRegister", + "description": "Battery Manufacturer", + "access": "RO" + }, + { + "id": "batteryModelId", + "address": 525, + "size": 2, + "type": "uint32", + "readSchedule": "init", + "description": "Battery model ID", + "registerType": "holdingRegister", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "batterySerialNumber", + "address": 527, + "size": 2, + "type": "uint32", + "readSchedule": "init", + "description": "Battery serial number", + "registerType": "holdingRegister", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "batteryWorkCapacity", + "address": 529, + "size": 2, + "type": "uint32", + "readSchedule": "init", + "description": "Battery work capacity", + "registerType": "holdingRegister", + "defaultValue": "0", + "unit": "Wh", + "access": "RO" + }, + { + "id": "inverterManufacturer", + "address": 535, + "size": 16, + "type": "string", + "readSchedule": "init", + "registerType": "holdingRegister", + "description": "Inverter manufacturer", + "access": "RO" + }, + { + "id": "inverterSerialNumber2", + "address": 559, + "size": 16, + "type": "string", + "readSchedule": "init", + "registerType": "holdingRegister", + "description": "Inverter serial number 2", + "access": "RO" + }, + { + "id": "energyScaleFactor", + "address": 579, + "size": 1, + "type": "int16", + "readSchedule": "init", + "description": "Energy scale factor", + "registerType": "holdingRegister", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "batteryActualPower", + "address": 582, + "size": 1, + "type": "int16", + "readSchedule": "update", + "registerType": "holdingRegister", + "description": "Actual battery charge/discharge power", + "unit": "W", + "defaultValue": "0", + "access": "RO" + }, + { + "id": "batteryType", + "address": 588, + "size": 1, + "type": "uint16", + "enum": "BatteryType", + "readSchedule": "init", + "registerType": "holdingRegister", + "description": "Battery type", + "defaultValue": "BatteryTypeNoBattery", + "access": "RO" + }, + { + "id": "productName", + "address": 768, + "size": 32, + "type": "string", + "readSchedule": "init", + "registerType": "holdingRegister", + "description": "Productname", + "access": "RO" + }, + { + "id": "totalEnergyAcToGrid", + "address": 1064, + "size": 2, + "type": "int32", + "scaleFactor": "energyScaleFactor", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Total energy AC-side to grid", + "unit": "Wh", + "defaultValue": "0", + "access": "RO" + } + ] +} diff --git a/kostal/kostal.pro b/kostal/kostal.pro new file mode 100644 index 0000000..b5d31e6 --- /dev/null +++ b/kostal/kostal.pro @@ -0,0 +1,12 @@ +include(../plugins.pri) + +# Generate modbus connection +MODBUS_CONNECTIONS += kostal-registers.json +#MODBUS_TOOLS_CONFIG += VERBOSE +include(../modbus.pri) + +HEADERS += \ + integrationpluginkostal.h + +SOURCES += \ + integrationpluginkostal.cpp diff --git a/kostal/translations/51a2c7d5-084d-4474-a65a-e0447ab9ac45-en_US.ts b/kostal/translations/51a2c7d5-084d-4474-a65a-e0447ab9ac45-en_US.ts new file mode 100644 index 0000000..47c0a0c --- /dev/null +++ b/kostal/translations/51a2c7d5-084d-4474-a65a-e0447ab9ac45-en_US.ts @@ -0,0 +1,479 @@ + + + + + IntegrationPluginKostal + + + The network device discovery is not available. + + + + + No IP address given + + + + + Kostal + + + + AC energy + The name of the ParamType (ThingClass: kostalInverter, EventType: totalEnergyProduced, ID: {5c1546d2-92be-4809-bc56-8bbdaab436d2}) +---------- +The name of the StateType ({5c1546d2-92be-4809-bc56-8bbdaab436d2}) of ThingClass kostalInverter + + + + + AC energy changed + The name of the EventType ({5c1546d2-92be-4809-bc56-8bbdaab436d2}) of ThingClass kostalInverter + + + + + + + + + + Connected + The name of the ParamType (ThingClass: kostalBattery, EventType: connected, ID: {4a5a5a38-b623-4024-b557-410a46ebc495}) +---------- +The name of the StateType ({4a5a5a38-b623-4024-b557-410a46ebc495}) of ThingClass kostalBattery +---------- +The name of the ParamType (ThingClass: kostalMeter, EventType: connected, ID: {5c510989-d6e1-4b06-b10f-f8b9e52a254c}) +---------- +The name of the StateType ({5c510989-d6e1-4b06-b10f-f8b9e52a254c}) of ThingClass kostalMeter +---------- +The name of the ParamType (ThingClass: kostalInverter, EventType: connected, ID: {8d64954a-855d-44ea-8bc9-88a71ab47b6b}) +---------- +The name of the StateType ({8d64954a-855d-44ea-8bc9-88a71ab47b6b}) of ThingClass kostalInverter + + + + + + + Connected changed + The name of the EventType ({4a5a5a38-b623-4024-b557-410a46ebc495}) of ThingClass kostalBattery +---------- +The name of the EventType ({5c510989-d6e1-4b06-b10f-f8b9e52a254c}) of ThingClass kostalMeter +---------- +The name of the EventType ({8d64954a-855d-44ea-8bc9-88a71ab47b6b}) of ThingClass kostalInverter + + + + + + Current power phase A + The name of the ParamType (ThingClass: kostalMeter, EventType: currentPowerPhaseA, ID: {2b1250eb-4c22-4025-ba7c-c3e8f27af3dc}) +---------- +The name of the StateType ({2b1250eb-4c22-4025-ba7c-c3e8f27af3dc}) of ThingClass kostalMeter + + + + + Current power phase A changed + The name of the EventType ({2b1250eb-4c22-4025-ba7c-c3e8f27af3dc}) of ThingClass kostalMeter + + + + + + Current power phase B + The name of the ParamType (ThingClass: kostalMeter, EventType: currentPowerPhaseB, ID: {0c43d20d-843c-4edd-9955-dafab6caecf6}) +---------- +The name of the StateType ({0c43d20d-843c-4edd-9955-dafab6caecf6}) of ThingClass kostalMeter + + + + + Current power phase B changed + The name of the EventType ({0c43d20d-843c-4edd-9955-dafab6caecf6}) of ThingClass kostalMeter + + + + + + Current power phase C + The name of the ParamType (ThingClass: kostalMeter, EventType: currentPowerPhaseC, ID: {a1e46df0-43e5-42f0-846a-5d2f24808a67}) +---------- +The name of the StateType ({a1e46df0-43e5-42f0-846a-5d2f24808a67}) of ThingClass kostalMeter + + + + + Current power phase C changed + The name of the EventType ({a1e46df0-43e5-42f0-846a-5d2f24808a67}) of ThingClass kostalMeter + + + + + + Energy consumend phase A + The name of the ParamType (ThingClass: kostalMeter, EventType: energyConsumedPhaseA, ID: {5c4de028-5b97-47c9-a5a4-dd1081b9b59b}) +---------- +The name of the StateType ({5c4de028-5b97-47c9-a5a4-dd1081b9b59b}) of ThingClass kostalMeter + + + + + Energy consumend phase A changed + The name of the EventType ({5c4de028-5b97-47c9-a5a4-dd1081b9b59b}) of ThingClass kostalMeter + + + + + + Energy consumend phase B + The name of the ParamType (ThingClass: kostalMeter, EventType: energyConsumedPhaseB, ID: {d9f3ee48-8fa6-463e-bc12-86c9361e01e0}) +---------- +The name of the StateType ({d9f3ee48-8fa6-463e-bc12-86c9361e01e0}) of ThingClass kostalMeter + + + + + Energy consumend phase B changed + The name of the EventType ({d9f3ee48-8fa6-463e-bc12-86c9361e01e0}) of ThingClass kostalMeter + + + + + + Energy consumend phase C + The name of the ParamType (ThingClass: kostalMeter, EventType: energyConsumedPhaseC, ID: {ccc38dd9-9e8e-48ce-9076-d3ef934cfbf2}) +---------- +The name of the StateType ({ccc38dd9-9e8e-48ce-9076-d3ef934cfbf2}) of ThingClass kostalMeter + + + + + Energy consumend phase C changed + The name of the EventType ({ccc38dd9-9e8e-48ce-9076-d3ef934cfbf2}) of ThingClass kostalMeter + + + + + + Energy produced phase A + The name of the ParamType (ThingClass: kostalMeter, EventType: energyProducedPhaseA, ID: {2185140f-1a73-47da-974a-ebc943613648}) +---------- +The name of the StateType ({2185140f-1a73-47da-974a-ebc943613648}) of ThingClass kostalMeter + + + + + Energy produced phase A changed + The name of the EventType ({2185140f-1a73-47da-974a-ebc943613648}) of ThingClass kostalMeter + + + + + + Energy produced phase B + The name of the ParamType (ThingClass: kostalMeter, EventType: energyProducedPhaseB, ID: {580811fc-419a-4be1-802d-c9eaa4765f65}) +---------- +The name of the StateType ({580811fc-419a-4be1-802d-c9eaa4765f65}) of ThingClass kostalMeter + + + + + Energy produced phase B changed + The name of the EventType ({580811fc-419a-4be1-802d-c9eaa4765f65}) of ThingClass kostalMeter + + + + + + Energy produced phase C + The name of the ParamType (ThingClass: kostalMeter, EventType: energyProducedPhaseC, ID: {df9f65fd-0cad-447f-b5a9-22daf9f020bf}) +---------- +The name of the StateType ({df9f65fd-0cad-447f-b5a9-22daf9f020bf}) of ThingClass kostalMeter + + + + + Energy produced phase C changed + The name of the EventType ({df9f65fd-0cad-447f-b5a9-22daf9f020bf}) of ThingClass kostalMeter + + + + + + + + Frequency + The name of the ParamType (ThingClass: kostalMeter, EventType: frequency, ID: {7c86ea72-505b-4924-80ef-3cf3ff31a380}) +---------- +The name of the StateType ({7c86ea72-505b-4924-80ef-3cf3ff31a380}) of ThingClass kostalMeter +---------- +The name of the ParamType (ThingClass: kostalInverter, EventType: frequency, ID: {9493939e-601b-460a-ab48-91772b4db823}) +---------- +The name of the StateType ({9493939e-601b-460a-ab48-91772b4db823}) of ThingClass kostalInverter + + + + + + Frequency changed + The name of the EventType ({7c86ea72-505b-4924-80ef-3cf3ff31a380}) of ThingClass kostalMeter +---------- +The name of the EventType ({9493939e-601b-460a-ab48-91772b4db823}) of ThingClass kostalInverter + + + + + + + IP address + The name of the ParamType (ThingClass: kostalBattery, Type: thing, ID: {7c803cd7-7159-447f-8794-4b35eadeab06}) +---------- +The name of the ParamType (ThingClass: kostalMeter, Type: thing, ID: {61c6a9fe-93c8-41fa-a7bf-113d3425c1cc}) +---------- +The name of the ParamType (ThingClass: kostalInverter, Type: thing, ID: {f1c43b1e-cffe-4d30-bda0-c23ed648dd71}) + + + + + KOSTAL Battery + The name of the ThingClass ({d6dbdfe8-adbb-47d8-840d-9b787683fc69}) + + + + + KOSTAL Inverter + The name of the ThingClass ({7dc6db14-6f5a-4ac8-9684-4c6a526bd0de}) + + + + + KOSTAL Meter + The name of the ThingClass ({61af1e07-6a59-4465-a563-3cbf4a9fcbc3}) + + + + + KOSTAL Solar Electric + The name of the vendor ({862d1ebf-cb78-4c55-89b2-819fddfd9acd}) + + + + + Kostal + The name of the plugin Kostal ({51a2c7d5-084d-4474-a65a-e0447ab9ac45}) + + + + + + + MAC address + The name of the ParamType (ThingClass: kostalBattery, Type: thing, ID: {b20845d1-4f09-4d68-b37c-6350bc33c1fa}) +---------- +The name of the ParamType (ThingClass: kostalMeter, Type: thing, ID: {e69acdd3-ba4f-41a9-b89e-89ed108aa850}) +---------- +The name of the ParamType (ThingClass: kostalInverter, Type: thing, ID: {906f6099-d0e1-4297-a2b3-f8ec4482c578}) + + + + + + + + Phase A current + The name of the ParamType (ThingClass: kostalMeter, EventType: currentPhaseA, ID: {1681ee7d-5d22-4794-8cfe-febaa1ddf29f}) +---------- +The name of the StateType ({1681ee7d-5d22-4794-8cfe-febaa1ddf29f}) of ThingClass kostalMeter +---------- +The name of the ParamType (ThingClass: kostalInverter, EventType: phaseACurrent, ID: {567bb3c2-4a0c-4194-a86e-b8dc29815092}) +---------- +The name of the StateType ({567bb3c2-4a0c-4194-a86e-b8dc29815092}) of ThingClass kostalInverter + + + + + + Phase A current changed + The name of the EventType ({1681ee7d-5d22-4794-8cfe-febaa1ddf29f}) of ThingClass kostalMeter +---------- +The name of the EventType ({567bb3c2-4a0c-4194-a86e-b8dc29815092}) of ThingClass kostalInverter + + + + + + + + Phase B current + The name of the ParamType (ThingClass: kostalMeter, EventType: currentPhaseB, ID: {b54e7182-6cb2-4184-96c5-2324e8139b6e}) +---------- +The name of the StateType ({b54e7182-6cb2-4184-96c5-2324e8139b6e}) of ThingClass kostalMeter +---------- +The name of the ParamType (ThingClass: kostalInverter, EventType: phaseBCurrent, ID: {84e9282a-b72b-4dbf-9e4b-99083e5539a5}) +---------- +The name of the StateType ({84e9282a-b72b-4dbf-9e4b-99083e5539a5}) of ThingClass kostalInverter + + + + + + Phase B current changed + The name of the EventType ({b54e7182-6cb2-4184-96c5-2324e8139b6e}) of ThingClass kostalMeter +---------- +The name of the EventType ({84e9282a-b72b-4dbf-9e4b-99083e5539a5}) of ThingClass kostalInverter + + + + + + + + Phase C current + The name of the ParamType (ThingClass: kostalMeter, EventType: currentPhaseC, ID: {546eeb76-b17f-4c51-a9fa-01e7403913cd}) +---------- +The name of the StateType ({546eeb76-b17f-4c51-a9fa-01e7403913cd}) of ThingClass kostalMeter +---------- +The name of the ParamType (ThingClass: kostalInverter, EventType: phaseCCurrent, ID: {4f7c308f-2cb2-4327-8a68-77222f920e61}) +---------- +The name of the StateType ({4f7c308f-2cb2-4327-8a68-77222f920e61}) of ThingClass kostalInverter + + + + + + Phase C current changed + The name of the EventType ({546eeb76-b17f-4c51-a9fa-01e7403913cd}) of ThingClass kostalMeter +---------- +The name of the EventType ({4f7c308f-2cb2-4327-8a68-77222f920e61}) of ThingClass kostalInverter + + + + + Port + The name of the ParamType (ThingClass: kostalInverter, Type: thing, ID: {9d2175af-afb9-4b31-b3dc-e53a369bad9e}) + + + + + Slave ID + The name of the ParamType (ThingClass: kostalInverter, Type: thing, ID: {b3e04cb0-8f9a-4c9f-9c67-5c08da0273e3}) + + + + + + + + Total AC current + The name of the ParamType (ThingClass: kostalMeter, EventType: totalCurrent, ID: {bf0195a3-3ff4-4828-b64d-1707b458679e}) +---------- +The name of the StateType ({bf0195a3-3ff4-4828-b64d-1707b458679e}) of ThingClass kostalMeter +---------- +The name of the ParamType (ThingClass: kostalInverter, EventType: totalCurrent, ID: {d11b8e29-44e9-4b5c-bb4e-aa2ca87db5d3}) +---------- +The name of the StateType ({d11b8e29-44e9-4b5c-bb4e-aa2ca87db5d3}) of ThingClass kostalInverter + + + + + + Total AC current changed + The name of the EventType ({bf0195a3-3ff4-4828-b64d-1707b458679e}) of ThingClass kostalMeter +---------- +The name of the EventType ({d11b8e29-44e9-4b5c-bb4e-aa2ca87db5d3}) of ThingClass kostalInverter + + + + + + Total real energy exported + The name of the ParamType (ThingClass: kostalMeter, EventType: totalEnergyProduced, ID: {d551a8b0-734a-41e9-a1a2-e58de13d0191}) +---------- +The name of the StateType ({d551a8b0-734a-41e9-a1a2-e58de13d0191}) of ThingClass kostalMeter + + + + + Total real energy exported changed + The name of the EventType ({d551a8b0-734a-41e9-a1a2-e58de13d0191}) of ThingClass kostalMeter + + + + + + Total real energy imported + The name of the ParamType (ThingClass: kostalMeter, EventType: totalEnergyConsumed, ID: {5f88e230-906b-4185-9a4d-db96d447e8ea}) +---------- +The name of the StateType ({5f88e230-906b-4185-9a4d-db96d447e8ea}) of ThingClass kostalMeter + + + + + Total real energy imported changed + The name of the EventType ({5f88e230-906b-4185-9a4d-db96d447e8ea}) of ThingClass kostalMeter + + + + + + Total real power + The name of the ParamType (ThingClass: kostalMeter, EventType: currentPower, ID: {992b0da8-e6bd-47ab-af60-be8802fc7ecf}) +---------- +The name of the StateType ({992b0da8-e6bd-47ab-af60-be8802fc7ecf}) of ThingClass kostalMeter + + + + + Total real power changed + The name of the EventType ({992b0da8-e6bd-47ab-af60-be8802fc7ecf}) of ThingClass kostalMeter + + + + + + Voltage phase A + The name of the ParamType (ThingClass: kostalMeter, EventType: voltagePhaseA, ID: {10a34381-cfb1-4aeb-a25f-e6b0d8b96510}) +---------- +The name of the StateType ({10a34381-cfb1-4aeb-a25f-e6b0d8b96510}) of ThingClass kostalMeter + + + + + Voltage phase A changed + The name of the EventType ({10a34381-cfb1-4aeb-a25f-e6b0d8b96510}) of ThingClass kostalMeter + + + + + + Voltage phase B + The name of the ParamType (ThingClass: kostalMeter, EventType: voltagePhaseB, ID: {b0be1395-c7d2-449e-9632-5b6bf3298797}) +---------- +The name of the StateType ({b0be1395-c7d2-449e-9632-5b6bf3298797}) of ThingClass kostalMeter + + + + + Voltage phase B changed + The name of the EventType ({b0be1395-c7d2-449e-9632-5b6bf3298797}) of ThingClass kostalMeter + + + + + + Voltage phase C + The name of the ParamType (ThingClass: kostalMeter, EventType: voltagePhaseC, ID: {b422d7a9-4c43-4827-be39-e4694f2cab64}) +---------- +The name of the StateType ({b422d7a9-4c43-4827-be39-e4694f2cab64}) of ThingClass kostalMeter + + + + + Voltage phase C changed + The name of the EventType ({b422d7a9-4c43-4827-be39-e4694f2cab64}) of ThingClass kostalMeter + + + + diff --git a/nymea-plugins-modbus.pro b/nymea-plugins-modbus.pro index 63ea758..fa6b837 100644 --- a/nymea-plugins-modbus.pro +++ b/nymea-plugins-modbus.pro @@ -11,6 +11,7 @@ PLUGIN_DIRS = \ huawei \ idm \ inepro \ + kostal \ modbuscommander \ mtec \ mypv \