From 1875a2361d2a96b29e6cb6d8492f13bc9c83ef33 Mon Sep 17 00:00:00 2001 From: frankenbubble Date: Wed, 11 Oct 2023 00:05:34 +0100 Subject: [PATCH] add support for a connected smartmeter to collect totals --- huawei/huawei-fusion-solar-registers.json | 26 +++++++ huawei/huawei-registers.json | 26 +++++++ huawei/huaweifusionsolar.cpp | 94 ++++++++++++++++++++++- huawei/integrationpluginhuawei.cpp | 30 ++++++++ 4 files changed, 175 insertions(+), 1 deletion(-) diff --git a/huawei/huawei-fusion-solar-registers.json b/huawei/huawei-fusion-solar-registers.json index 5c3c47c..34733bc 100644 --- a/huawei/huawei-fusion-solar-registers.json +++ b/huawei/huawei-fusion-solar-registers.json @@ -247,6 +247,32 @@ "defaultValue": "0", "access": "RO" }, + { + "id": "powerMeterEnergyReturned", + "address": 37119, + "size": 2, + "type": "int32", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": " Positive active electricity - To Grid", + "unit": "kWh", + "staticScaleFactor": -2, + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterEnergyAquired", + "address": 37121, + "size": 2, + "type": "int32", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Reverse active power - From Grid", + "unit": "kWh", + "staticScaleFactor": -2, + "defaultValue": "0", + "access": "RO" + }, { "id": "lunaBattery1Status", "address": 37000, diff --git a/huawei/huawei-registers.json b/huawei/huawei-registers.json index d6f235b..7a2004f 100644 --- a/huawei/huawei-registers.json +++ b/huawei/huawei-registers.json @@ -330,6 +330,32 @@ "defaultValue": "0", "access": "RO" }, + { + "id": "powerMeterEnergyReturned", + "address": 37119, + "size": 2, + "type": "int32", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": " Positive active electricity - To Grid", + "unit": "kWh", + "staticScaleFactor": -2, + "defaultValue": "0", + "access": "RO" + }, + { + "id": "powerMeterEnergyAquired", + "address": 37121, + "size": 2, + "type": "int32", + "registerType": "holdingRegister", + "readSchedule": "update", + "description": "Reverse active power - From Grid", + "unit": "kWh", + "staticScaleFactor": -2, + "defaultValue": "0", + "access": "RO" + }, { "id": "lunaBattery1Status", "address": 37000, diff --git a/huawei/huaweifusionsolar.cpp b/huawei/huaweifusionsolar.cpp index d8ae56e..e78c6ad 100644 --- a/huawei/huaweifusionsolar.cpp +++ b/huawei/huaweifusionsolar.cpp @@ -1,4 +1,4 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright 2013 - 2022, nymea GmbH * Contact: contact@nymea.io @@ -71,6 +71,8 @@ bool HuaweiFusionSolar::update() m_registersQueue.enqueue(HuaweiFusionModbusTcpConnection::RegisterLunaBattery2Power); m_registersQueue.enqueue(HuaweiFusionModbusTcpConnection::RegisterPowerMeterActivePower); + m_registersQueue.enqueue(HuaweiFusionModbusTcpConnection::RegisterPowerMeterEnergyReturned); + m_registersQueue.enqueue(HuaweiFusionModbusTcpConnection::RegisterPowerMeterEnergyAquired); m_registersQueue.enqueue(HuaweiFusionModbusTcpConnection::RegisterInverterEnergyProduced); m_registersQueue.enqueue(HuaweiFusionModbusTcpConnection::RegisterInverterDeviceStatus); @@ -330,6 +332,96 @@ void HuaweiFusionSolar::readNextRegister() break; } + case HuaweiFusionModbusTcpConnection::RegisterPowerMeterEnergyReturned: { + // Update registers from Power meter active power + qCDebug(dcHuaweiFusionSolar()) << "--> Read \"Power meter Positive active electricity\" register:" << 37119 << "size:" << 2; + QModbusReply *reply = readPowerMeterEnergyReturned(); + if (!reply) { + qCWarning(dcHuaweiFusionSolar()) << "Error occurred while reading \"Power meter Positive active electricity\" registers from" << modbusTcpMaster()->hostAddress().toString() << modbusTcpMaster()->errorString(); + finishRequest(); + return; + } + + if (reply->isFinished()) { + reply->deleteLater(); // Broadcast reply returns immediatly + finishRequest(); + return; + } + + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + handleModbusError(reply->error()); + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Power meter Positive active electricity\" register" << 37119 << "size:" << 2 << "valueCount:" << unit.valueCount() << unit.values() << unit.values().count(); + if (!valuesAreVaild(unit.values(), 2)) { + qCWarning(dcHuaweiFusionSolar()) << "<-- Received invalid values. Requested" << 2 << "but received" << unit.values(); + } else { + processPowerMeterEnergyReturnedRegisterValues(unit.values()); + } + } + finishRequest(); + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + if (reply->error() == QModbusDevice::ProtocolError) { + QModbusResponse response = reply->rawResult(); + if (response.isException()) { + qCDebug(dcHuaweiFusionSolar()) << "Modbus reply error occurred while updating \"Power meter Positive active electricity\" registers from" << modbusTcpMaster()->hostAddress().toString() << exceptionToString(response.exceptionCode()); + } + } else { + qCWarning(dcHuaweiFusionSolar()) << "Modbus reply error occurred while updating \"Power meter Positive active electricity\" registers from" << modbusTcpMaster()->hostAddress().toString() << error << reply->errorString(); + } + }); + + break; + + } + case HuaweiFusionModbusTcpConnection::RegisterPowerMeterEnergyAquired: { + // Update registers from Power meter active power + qCDebug(dcHuaweiFusionSolar()) << "--> Read \"Power meter Reverse active power\" register:" << 37121 << "size:" << 2; + QModbusReply *reply = readPowerMeterEnergyAquired(); + if (!reply) { + qCWarning(dcHuaweiFusionSolar()) << "Error occurred while reading \"Power meter Reverse active power\" registers from" << modbusTcpMaster()->hostAddress().toString() << modbusTcpMaster()->errorString(); + finishRequest(); + return; + } + + if (reply->isFinished()) { + reply->deleteLater(); // Broadcast reply returns immediatly + finishRequest(); + return; + } + + connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater); + connect(reply, &QModbusReply::finished, this, [this, reply](){ + handleModbusError(reply->error()); + if (reply->error() == QModbusDevice::NoError) { + const QModbusDataUnit unit = reply->result(); + qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Power meter Reverse active power\" register" << 37121 << "size:" << 2 << "valueCount:" << unit.valueCount() << unit.values() << unit.values().count(); + if (!valuesAreVaild(unit.values(), 2)) { + qCWarning(dcHuaweiFusionSolar()) << "<-- Received invalid values. Requested" << 2 << "but received" << unit.values(); + } else { + processPowerMeterEnergyAquiredRegisterValues(unit.values()); + } + } + finishRequest(); + }); + + connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){ + if (reply->error() == QModbusDevice::ProtocolError) { + QModbusResponse response = reply->rawResult(); + if (response.isException()) { + qCDebug(dcHuaweiFusionSolar()) << "Modbus reply error occurred while updating \"Power meter Reverse active power\" registers from" << modbusTcpMaster()->hostAddress().toString() << exceptionToString(response.exceptionCode()); + } + } else { + qCWarning(dcHuaweiFusionSolar()) << "Modbus reply error occurred while updating \"Power meter Reverse active power\" registers from" << modbusTcpMaster()->hostAddress().toString() << error << reply->errorString(); + } + }); + + break; + + } case HuaweiFusionModbusTcpConnection::RegisterLunaBattery1Status: { // Update registers from Luna 2000 Battery 1 status qCDebug(dcHuaweiFusionSolar()) << "--> Read \"Luna 2000 Battery 1 status\" register:" << 37000 << "size:" << 1; diff --git a/huawei/integrationpluginhuawei.cpp b/huawei/integrationpluginhuawei.cpp index 28760bb..7d49f51 100644 --- a/huawei/integrationpluginhuawei.cpp +++ b/huawei/integrationpluginhuawei.cpp @@ -241,6 +241,22 @@ void IntegrationPluginHuawei::setupThing(ThingSetupInfo *info) } }); + connect(connection, &HuaweiModbusRtuConnection::powerMeterEnergyReturnedChanged, thing, [this, thing](qint32 powerMeterEnergyReturned){ + Things meterThings = myThings().filterByParentId(thing->id()).filterByThingClassId(huaweiMeterThingClassId); + if (!meterThings.isEmpty()) { + qCDebug(dcHuawei()) << "Meter Total Energy Returned changed" << powerMeterEnergyReturned << "KWh"; + meterThings.first()->setStateValue(huaweiMeterTotalEnergyProducedStateTypeId, powerMeterEnergyReturned); + } + }); + + connect(connection, &HuaweiModbusRtuConnection::powerMeterEnergyAquiredChanged, thing, [this, thing](qint32 powerMeterEnergyAquired){ + Things meterThings = myThings().filterByParentId(thing->id()).filterByThingClassId(huaweiMeterThingClassId); + if (!meterThings.isEmpty()) { + qCDebug(dcHuawei()) << "Meter power Energy Aquired changed" << powerMeterEnergyAquired << "KWh"; + meterThings.first()->setStateValue(huaweiMeterTotalEnergyConsumedStateTypeId, powerMeterEnergyAquired); + } + }); + // Battery 1 connect(connection, &HuaweiModbusRtuConnection::lunaBattery1StatusChanged, thing, [this, thing](HuaweiModbusRtuConnection::BatteryDeviceStatus lunaBattery1Status){ qCDebug(dcHuawei()) << "Battery 1 status changed" << lunaBattery1Status; @@ -526,6 +542,20 @@ void IntegrationPluginHuawei::setupFusionSolar(ThingSetupInfo *info) meterThings.first()->setStateValue(huaweiMeterCurrentPowerStateTypeId, -powerMeterActivePower); } }); + connect(connection, &HuaweiFusionSolar::powerMeterEnergyReturnedReadFinished, thing, [this, thing](qint32 powerMeterEnergyReturned){ + Things meterThings = myThings().filterByParentId(thing->id()).filterByThingClassId(huaweiMeterThingClassId); + if (!meterThings.isEmpty()) { + qCDebug(dcHuawei()) << "Meter power Returned changed" << powerMeterEnergyReturned << "kWh"; + meterThings.first()->setStateValue(huaweiMeterTotalEnergyProducedStateTypeId, powerMeterEnergyReturned); + } + }); + connect(connection, &HuaweiFusionSolar::powerMeterEnergyAquiredReadFinished, thing, [this, thing](qint32 powerMeterEnergyAquired){ + Things meterThings = myThings().filterByParentId(thing->id()).filterByThingClassId(huaweiMeterThingClassId); + if (!meterThings.isEmpty()) { + qCDebug(dcHuawei()) << "Meter power Aquired changed" << powerMeterEnergyAquired << "kWh"; + meterThings.first()->setStateValue(huaweiMeterTotalEnergyConsumedStateTypeId, powerMeterEnergyAquired); + } + }); // Battery 1 connect(connection, &HuaweiFusionSolar::lunaBattery1StatusReadFinished, thing, [this, thing](HuaweiFusionSolar::BatteryDeviceStatus lunaBattery1Status){