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..14f66e6 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](float 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](float 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](float 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](float 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){ diff --git a/huawei/translations/fc3e4509-47f3-4622-9bc4-0a90fe2b6262-en_US.ts b/huawei/translations/fc3e4509-47f3-4622-9bc4-0a90fe2b6262-en_US.ts index 1fba59d..72513ad 100644 --- a/huawei/translations/fc3e4509-47f3-4622-9bc4-0a90fe2b6262-en_US.ts +++ b/huawei/translations/fc3e4509-47f3-4622-9bc4-0a90fe2b6262-en_US.ts @@ -1,6 +1,228 @@ + + Huawei + + + + + AC energy + The name of the StateType ({759554dd-74c5-4836-9792-96e02eb816f0}) of ThingClass huaweiMeter +---------- +The name of the StateType ({49b92919-301c-4ff7-ae63-0c1a2184e3f4}) of ThingClass huaweiRtuInverter +---------- +The name of the StateType ({e97fe328-6ca4-4fe4-86f7-fee6e9e406a5}) of ThingClass huaweiFusionSolarInverter + + + + + + Active power + The name of the StateType ({6064d90e-1b6b-40fd-9da0-6ebc713efb7d}) of ThingClass huaweiRtuInverter +---------- +The name of the StateType ({52a84e06-ff13-4c82-99e2-c8a2691a99d7}) of ThingClass huaweiFusionSolarInverter + + + + + Battery critical + The name of the StateType ({223ddf60-ff73-4acf-b8ab-6337aeb972e8}) of ThingClass huaweiBattery + + + + + Battery level + The name of the StateType ({94d609bf-1f67-47c4-a23d-2fd14e7c0b21}) of ThingClass huaweiBattery + + + + + Capacity + The name of the StateType ({3eed974a-0acb-4e38-bcb8-0e3f6fbfd51a}) of ThingClass huaweiBattery + + + + + Charging state + The name of the StateType ({d9604513-d5a9-463a-ad18-d2f259a7a99d}) of ThingClass huaweiBattery + + + + + + + + Connected + The name of the StateType ({917bc284-9d43-430c-a8c3-642d302448e6}) of ThingClass huaweiBattery +---------- +The name of the StateType ({720ece7a-b0b3-4fa3-9f52-6f23042624a5}) of ThingClass huaweiMeter +---------- +The name of the StateType ({191ffa22-de6f-4325-8698-56b817f78df5}) of ThingClass huaweiRtuInverter +---------- +The name of the StateType ({a51f0ceb-bd2c-444f-8b39-77cf8a4e1bc6}) of ThingClass huaweiFusionSolarInverter + + + + + Current power + The name of the StateType ({f463f36e-69f9-4614-b690-664ce22d76e0}) of ThingClass huaweiFusionSolarInverter + + + + + Current power phase A + The name of the StateType ({ecc03e9b-88b1-424f-a179-66bbdebaaea9}) of ThingClass huaweiMeter + + + + + Current power phase B + The name of the StateType ({7971cbde-b2ea-4474-b68a-71e040ed3b1d}) of ThingClass huaweiMeter + + + + + Current power phase C + The name of the StateType ({7ca21c4d-6763-49e4-a056-4c9c76923971}) of ThingClass huaweiMeter + + + + + Frequency + The name of the StateType ({1e2252be-80b3-4e9a-97f7-105d6d1c50f9}) of ThingClass huaweiMeter + + + + + Huawei + The name of the vendor ({f654c99d-a286-4abb-b33e-1a71843d8da0}) + + + + + Huawei Battery + The name of the ThingClass ({40104aac-0456-475d-8bd6-18f946597d96}) + + + + + Huawei FusionSolar + The name of the plugin Huawei ({fc3e4509-47f3-4622-9bc4-0a90fe2b6262}) + + + + + Huawei FusionSolar Inverter (Modbus RTU) + The name of the ThingClass ({77558007-5076-4ca6-bd46-169f215c3e29}) + + + + + Huawei FusionSolar Inverter (SmartDongle) + The name of the ThingClass ({87e75ee0-d544-457b-add3-bd4e58160fcd}) + + + + + Huawei Meter + The name of the ThingClass ({529c2a19-ca6a-4df2-b56e-3fb2673fa95f}) + + + + + MAC address + The name of the ParamType (ThingClass: huaweiFusionSolarInverter, Type: thing, ID: {93517bff-1928-4c4a-8207-5fe596c86eba}) + + + + + Modbus RTU master + The name of the ParamType (ThingClass: huaweiRtuInverter, Type: thing, ID: {5c7b28b1-3691-452e-8f49-d80ae7bcbe2c}) + + + + + Modbus slave address + The name of the ParamType (ThingClass: huaweiRtuInverter, Type: thing, ID: {de06f027-7940-4c45-9c96-30930ac2796d}) + + + + + Phase A current + The name of the StateType ({af48ff45-11ba-401e-a812-bb1db0896449}) of ThingClass huaweiMeter + + + + + Phase B current + The name of the StateType ({fb5082e4-a2d8-4958-a47d-e80928795ece}) of ThingClass huaweiMeter + + + + + Phase C current + The name of the StateType ({bdd9aa8b-93fe-4b6b-8a31-08e99d85a06c}) of ThingClass huaweiMeter + + + + + Port + The name of the ParamType (ThingClass: huaweiFusionSolarInverter, Type: thing, ID: {55c4ec99-6342-4309-84a8-d1615f19b2e8}) + + + + + Slave ID + The name of the ParamType (ThingClass: huaweiFusionSolarInverter, Type: thing, ID: {aa6e978e-a16b-4722-8330-e706f3c7c21e}) + + + + + Slave address + The name of the ParamType (ThingClass: huaweiRtuInverter, Type: discovery, ID: {93a4d3a8-c7d0-470b-b6e3-d8fc43b8e8d0}) + + + + + Total real energy imported + The name of the StateType ({2cf8d885-37f7-478f-819e-c4e20f2dbe01}) of ThingClass huaweiMeter + + + + + + Total real power + The name of the StateType ({53ca1f8a-0267-40aa-b563-762a943c8f55}) of ThingClass huaweiBattery +---------- +The name of the StateType ({f480dc82-68e2-44e2-839c-df38b9c10310}) of ThingClass huaweiMeter + + + + + Unit + The name of the ParamType (ThingClass: huaweiBattery, Type: thing, ID: {019287a6-c593-45a8-9695-2e1ad8e81c32}) + + + + + Voltage phase A + The name of the StateType ({ea5d7924-19a8-415c-aeeb-e04ce08bed33}) of ThingClass huaweiMeter + + + + + Voltage phase B + The name of the StateType ({f15856d1-645f-4d34-89a7-c1585ca329cc}) of ThingClass huaweiMeter + + + + + Voltage phase C + The name of the StateType ({aafb5de4-caa1-4a90-8149-cdf85ae5dc2b}) of ThingClass huaweiMeter + + + IntegrationPluginHuawei @@ -39,7 +261,7 @@ - + Could not initialize the communication with the SmartDongle.