From 380a0ca79bce0466db9133db6f95b5c149560152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 1 Aug 2022 16:44:13 +0200 Subject: [PATCH] Make use of the byte order register and configure the kostal connection --- kostal/integrationpluginkostal.cpp | 167 ++++++++++++----------------- kostal/kostal-registers.json | 2 +- 2 files changed, 67 insertions(+), 102 deletions(-) diff --git a/kostal/integrationpluginkostal.cpp b/kostal/integrationpluginkostal.cpp index 20c1e30..7dca36f 100644 --- a/kostal/integrationpluginkostal.cpp +++ b/kostal/integrationpluginkostal.cpp @@ -75,44 +75,6 @@ void IntegrationPluginKostal::discoverThings(ThingDiscoveryInfo *info) // Start the discovery process discovery->startDiscovery(); - -// 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(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::setupThing(ThingSetupInfo *info) @@ -173,6 +135,7 @@ void IntegrationPluginKostal::setupThing(ThingSetupInfo *info) } }); } + return; } @@ -198,71 +161,60 @@ void IntegrationPluginKostal::setupThing(ThingSetupInfo *info) // 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); + return; } if (thing->thingClassId() == kostalBatteryThingClassId) { @@ -284,14 +236,11 @@ void IntegrationPluginKostal::setupThing(ThingSetupInfo *info) // 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"); @@ -303,11 +252,11 @@ void IntegrationPluginKostal::setupThing(ThingSetupInfo *info) }); 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); + return; } } @@ -315,6 +264,20 @@ void IntegrationPluginKostal::postSetupThing(Thing *thing) { if (thing->thingClassId() == kostalInverterThingClassId) { + // Create the update timer if not already set up + if (!m_pluginTimer) { + qCDebug(dcKostal()) << "Starting plugin timer..."; + m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(2); + connect(m_pluginTimer, &PluginTimer::timeout, this, [this] { + foreach(KostalModbusTcpConnection *connection, m_kostalConnections) { + qCDebug(dcKostal()) << "Update connection" << connection->hostAddress().toString(); + connection->update(); + } + }); + + m_pluginTimer->start(); + } + KostalModbusTcpConnection *kostalConnection = m_kostalConnections.value(thing); // Check if we have to create the meter for the Kostal inverter @@ -376,18 +339,16 @@ void IntegrationPluginKostal::postSetupThing(Thing *thing) emit autoThingsAppeared(ThingDescriptors() << descriptor); } - // Create the update timer if not already set up - 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(); - } - } - }); + return; + } + + if (thing->thingClassId() == kostalMeterThingClassId || thing->thingClassId() == kostalBatteryThingClassId) { + Thing *connectionThing = myThings().findById(thing->parentId()); + if (connectionThing) { + thing->setStateValue("connected", connectionThing->stateValue("connected")); } + + return; } } @@ -437,6 +398,32 @@ void IntegrationPluginKostal::setupKostalConnection(ThingSetupInfo *info) } }); + connect(kostalConnection, &KostalModbusTcpConnection::reachableChanged, thing, [this, thing, kostalConnection](bool reachable){ + qCDebug(dcKostal()) << "Reachable changed to" << reachable << "for" << thing; + if (reachable) { + // Connected true will be set after successfull init + kostalConnection->initialize(); + } else { + thing->setStateValue("connected", false); + foreach (Thing *childThing, myThings().filterByParentId(thing->id())) { + childThing->setStateValue("connected", false); + } + } + }); + + connect(kostalConnection, &KostalModbusTcpConnection::initializationFinished, thing, [=](bool success){ + if (!thing->setupComplete()) + return; + + if (success) { + thing->setStateValue("connected", true); + } else { + thing->setStateValue("connected", false); + // Try once to reconnect the device + kostalConnection->reconnectDevice(); + } + }); + connect(kostalConnection, &KostalModbusTcpConnection::initializationFinished, info, [=](bool success){ if (!success) { qCWarning(dcKostal()) << "Connection init finished with errors" << thing->name() << kostalConnection->hostAddress().toString(); @@ -456,66 +443,68 @@ void IntegrationPluginKostal::setupKostalConnection(ThingSetupInfo *info) childThing->setStateValue("connected", true); } + // Make sure we use the same endianness as the inverter (register size 1, so independent from endianess) + switch (kostalConnection->modbusByteOrder()) { + case KostalModbusTcpConnection::ByteOrderBigEndian: + kostalConnection->setEndianness(ModbusDataUtils::ByteOrderBigEndian); + break; + case KostalModbusTcpConnection::ByteOrderLittleEndian: + kostalConnection->setEndianness(ModbusDataUtils::ByteOrderLittleEndian); + break; + } + + connect(kostalConnection, &KostalModbusTcpConnection::updateFinished, thing, [=](){ + qCDebug(dcKostal()) << "Updated" << kostalConnection; + }); + connect(kostalConnection, &KostalModbusTcpConnection::totalAcPowerChanged, thing, [thing](float totalAcPower){ - qCDebug(dcKostal()) << thing << "total AC power changed" << totalAcPower << "W"; thing->setStateValue(kostalInverterCurrentPowerStateTypeId, - totalAcPower); }); connect(kostalConnection, &KostalModbusTcpConnection::totalYieldChanged, thing, [thing](float totalYield){ - qCDebug(dcKostal()) << thing << "total yeald changed" << totalYield << "Wh"; thing->setStateValue(kostalInverterTotalEnergyProducedStateTypeId, totalYield / 1000.0); // kWh }); // Current connect(kostalConnection, &KostalModbusTcpConnection::currentPhase1Changed, thing, [thing](float currentPhase1){ - qCDebug(dcKostal()) << thing << "current phase 1 changed" << currentPhase1 << "A"; thing->setStateValue(kostalInverterPhaseACurrentStateTypeId, currentPhase1); // A }); connect(kostalConnection, &KostalModbusTcpConnection::currentPhase2Changed, thing, [thing](float currentPhase2){ - qCDebug(dcKostal()) << thing << "current phase 2 changed" << currentPhase2 << "A"; thing->setStateValue(kostalInverterPhaseBCurrentStateTypeId, currentPhase2); // A }); connect(kostalConnection, &KostalModbusTcpConnection::currentPhase3Changed, thing, [thing](float currentPhase3){ - qCDebug(dcKostal()) << thing << "current phase 3 changed" << currentPhase3 << "A"; thing->setStateValue(kostalInverterPhaseCCurrentStateTypeId, currentPhase3); // A }); // Voltage connect(kostalConnection, &KostalModbusTcpConnection::voltagePhase1Changed, thing, [thing](float voltagePhase1){ - qCDebug(dcKostal()) << thing << "voltage phase 1 changed" << voltagePhase1 << "V"; thing->setStateValue(kostalInverterVoltagePhaseAStateTypeId, voltagePhase1); }); connect(kostalConnection, &KostalModbusTcpConnection::voltagePhase2Changed, thing, [thing](float voltagePhase2){ - qCDebug(dcKostal()) << thing << "voltage phase 2 changed" << voltagePhase2 << "V"; thing->setStateValue(kostalInverterVoltagePhaseBStateTypeId, voltagePhase2); }); connect(kostalConnection, &KostalModbusTcpConnection::voltagePhase3Changed, thing, [thing](float voltagePhase3){ - qCDebug(dcKostal()) << thing << "voltage phase 3 changed" << voltagePhase3 << "V"; thing->setStateValue(kostalInverterVoltagePhaseCStateTypeId, voltagePhase3); }); // Current power connect(kostalConnection, &KostalModbusTcpConnection::activePowerPhase1Changed, thing, [thing](float activePowerPhase1){ - qCDebug(dcKostal()) << thing << "active power phase 1 changed" << activePowerPhase1 << "W"; thing->setStateValue(kostalInverterCurrentPowerPhaseAStateTypeId, activePowerPhase1); }); connect(kostalConnection, &KostalModbusTcpConnection::activePowerPhase2Changed, thing, [thing](float activePowerPhase2){ - qCDebug(dcKostal()) << thing << "active power phase 2 changed" << activePowerPhase2 << "W"; thing->setStateValue(kostalInverterCurrentPowerPhaseBStateTypeId, activePowerPhase2); }); connect(kostalConnection, &KostalModbusTcpConnection::activePowerPhase3Changed, thing, [thing](float activePowerPhase3){ - qCDebug(dcKostal()) << thing << "active power phase 3 changed" << activePowerPhase3 << "W"; thing->setStateValue(kostalInverterCurrentPowerPhaseCStateTypeId, activePowerPhase3); }); connect(kostalConnection, &KostalModbusTcpConnection::gridFrequencyInverterChanged, thing, [thing](float gridFrequencyInverter){ - qCDebug(dcKostal()) << thing << "grid frequency changed" << gridFrequencyInverter << "Hz"; thing->setStateValue(kostalInverterFrequencyStateTypeId, gridFrequencyInverter); }); @@ -523,29 +512,5 @@ void IntegrationPluginKostal::setupKostalConnection(ThingSetupInfo *info) kostalConnection->update(); }); - connect(kostalConnection, &KostalModbusTcpConnection::reachableChanged, thing, [this, thing, kostalConnection](bool reachable){ - qCDebug(dcKostal()) << "Reachable changed to" << reachable << "for" << thing; - if (reachable) { - // Connected true will be set after successfull init - kostalConnection->initialize(); - } else { - thing->setStateValue("connected", false); - foreach (Thing *childThing, myThings().filterByParentId(thing->id())) { - childThing->setStateValue("connected", false); - } - } - }); - - - connect(kostalConnection, &KostalModbusTcpConnection::initializationFinished, info, [=](bool success){ - if (success) { - thing->setStateValue("connected", true); - } else { - thing->setStateValue("connected", false); - // Try once to reconnect the device - kostalConnection->reconnectDevice(); - } - }); - kostalConnection->connectDevice(); } diff --git a/kostal/kostal-registers.json b/kostal/kostal-registers.json index 48878c4..e072c26 100644 --- a/kostal/kostal-registers.json +++ b/kostal/kostal-registers.json @@ -157,7 +157,7 @@ "enum": "ByteOrder", "registerType": "holdingRegister", "description": "MODBUS Byte Order Note", - "defaultValue": "ByteOrderLittleEndian", + "defaultValue": "ByteOrderBigEndian", "access": "RO" }, {