From d68f2ad2612059050d89142c7311f15c2387586c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 18 Jun 2025 13:45:18 +0200 Subject: [PATCH 1/2] Kostal: Switch to queued requests and add PIKO CI support --- kostal/kostal-registers.json | 36 ++---------------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/kostal/kostal-registers.json b/kostal/kostal-registers.json index 6572c99..191cbf2 100644 --- a/kostal/kostal-registers.json +++ b/kostal/kostal-registers.json @@ -3,6 +3,8 @@ "protocol": "TCP", "endianness": "LittleEndian", "errorLimitUntilNotReachable": 20, + "queuedRequests": true, + "queuedRequestsDelay": 100, "checkReachableRegister": "inverterState", "enums": [ { @@ -740,40 +742,6 @@ } ], "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, From 1b4e39125b71d3da9fc40827d66a53d17f093e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 30 Jun 2025 08:26:53 +0200 Subject: [PATCH 2/2] Kostal: Calculate missing power values for the KSEM G2 meter --- kostal/integrationpluginkostal.cpp | 48 +++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/kostal/integrationpluginkostal.cpp b/kostal/integrationpluginkostal.cpp index 5e9d742..3925934 100644 --- a/kostal/integrationpluginkostal.cpp +++ b/kostal/integrationpluginkostal.cpp @@ -449,7 +449,7 @@ void IntegrationPluginKostal::setupKostalConnection(ThingSetupInfo *info) if (meterThings.count() == 1) { Thing *meterThing = meterThings.first(); - // Power + // Current meterThing->setStateValue(kostalMeterCurrentPhaseAStateTypeId, kostalConnection->powerMeterCurrentPhase1()); meterThing->setStateValue(kostalMeterCurrentPhaseBStateTypeId, kostalConnection->powerMeterCurrentPhase2()); meterThing->setStateValue(kostalMeterCurrentPhaseCStateTypeId, kostalConnection->powerMeterCurrentPhase3()); @@ -459,18 +459,50 @@ void IntegrationPluginKostal::setupKostalConnection(ThingSetupInfo *info) meterThing->setStateValue(kostalMeterVoltagePhaseBStateTypeId, kostalConnection->powerMeterVoltagePhase2()); meterThing->setStateValue(kostalMeterVoltagePhaseCStateTypeId, kostalConnection->powerMeterVoltagePhase3()); - // Current - meterThing->setStateValue(kostalMeterCurrentPowerPhaseAStateTypeId, kostalConnection->powerMeterActivePowerPhase1()); - meterThing->setStateValue(kostalMeterCurrentPowerPhaseBStateTypeId, kostalConnection->powerMeterActivePowerPhase2()); - meterThing->setStateValue(kostalMeterCurrentPowerPhaseCStateTypeId, kostalConnection->powerMeterActivePowerPhase3()); - meterThing->setStateValue(kostalMeterFrequencyStateTypeId, kostalConnection->gridFrequencyPowerMeter()); meterThing->setStateValue(kostalMeterTotalEnergyConsumedStateTypeId, kostalConnection->totalHomeConsumptionFromGrid() / 1000.0); // kWh meterThing->setStateValue(kostalMeterTotalEnergyProducedStateTypeId, kostalConnection->totalEnergyAcToGrid() / 1000.0); // kWh - // Set the power as last value - meterThing->setStateValue(kostalMeterCurrentPowerStateTypeId, kostalConnection->powerMeterTotalActivePower()); + // Note: there is a special case with the Kostal KSEM G2 meter, which communicates voltage and current, but no power data + // Therefore we have to calculate them on our own and set the states accordingly. + + bool currentNotZero = kostalConnection->powerMeterCurrentPhase1() != 0 && + kostalConnection->powerMeterCurrentPhase2() != 0 && + kostalConnection->powerMeterCurrentPhase3() != 0; + + bool voltageNotZero = kostalConnection->powerMeterVoltagePhase1() != 0 && + kostalConnection->powerMeterVoltagePhase2() != 0 && + kostalConnection->powerMeterVoltagePhase3() != 0; + + bool powerZero = kostalConnection->powerMeterActivePowerPhase1() == 0 && + kostalConnection->powerMeterActivePowerPhase2() == 0 && + kostalConnection->powerMeterActivePowerPhase3() == 0 && + kostalConnection->powerMeterTotalActivePower() == 0; + + if (currentNotZero && voltageNotZero && powerZero) { + + // P = U * I + float powerPhase1 = kostalConnection->powerMeterCurrentPhase1() * kostalConnection->powerMeterVoltagePhase1() * -1.0; + float powerPhase2 = kostalConnection->powerMeterCurrentPhase2() * kostalConnection->powerMeterVoltagePhase2() * -1.0; + float powerPhase3 = kostalConnection->powerMeterCurrentPhase3() * kostalConnection->powerMeterVoltagePhase3() * -1.0; + + meterThing->setStateValue(kostalMeterCurrentPowerPhaseAStateTypeId, powerPhase1); + meterThing->setStateValue(kostalMeterCurrentPowerPhaseBStateTypeId, powerPhase2); + meterThing->setStateValue(kostalMeterCurrentPowerPhaseCStateTypeId, powerPhase3); + + // Set the total power as last value + meterThing->setStateValue(kostalMeterCurrentPowerStateTypeId, powerPhase1 + powerPhase2 + powerPhase3); + + } else { + // Power + meterThing->setStateValue(kostalMeterCurrentPowerPhaseAStateTypeId, kostalConnection->powerMeterActivePowerPhase1()); + meterThing->setStateValue(kostalMeterCurrentPowerPhaseBStateTypeId, kostalConnection->powerMeterActivePowerPhase2()); + meterThing->setStateValue(kostalMeterCurrentPowerPhaseCStateTypeId, kostalConnection->powerMeterActivePowerPhase3()); + + // Set the total power as last value + meterThing->setStateValue(kostalMeterCurrentPowerStateTypeId, kostalConnection->powerMeterTotalActivePower()); + } } });