Fronius: Add support for S0 meters

master
Simon Stürz 2024-05-15 10:48:33 +02:00
parent d4d9ad698d
commit adc2b8d0d4
2 changed files with 45 additions and 5 deletions

View File

@ -375,15 +375,26 @@ void IntegrationPluginFronius::refreshConnection(FroniusSolarConnection *connect
QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap();
QString thingName; QString thingName;
QString serialNumber; QString serialNumber;
QString model;
if (dataMap.contains("Details")) { if (dataMap.contains("Details")) {
QVariantMap details = dataMap.value("Details").toMap(); QVariantMap details = dataMap.value("Details").toMap();
thingName = details.value("Manufacturer", "Fronius").toString() + " " + details.value("Model", "Smart Meter").toString(); model = dataMap.value("Details").toMap().value("Model", "Smart Meter").toString();
thingName = details.value("Manufacturer", "Fronius").toString() + " " + model;
serialNumber = details.value("Serial").toString(); serialNumber = details.value("Serial").toString();
} else { } else {
thingName = connectionThing->name() + " Meter " + meterId; thingName = connectionThing->name() + " Meter " + meterId;
} }
// Note: some inverters have a S0 meter connected, which measures the load, not the grid power and also provides only the current power and no additionl information
// Since we assume a meter on the grid root of the household, we don't update the meter here, but in the updatePowerFlow method.
if (model.toLower().contains("s0") && !dataMap.contains("EnergyReal_WAC_Sum_Produced") && !dataMap.contains("EnergyReal_WAC_Sum_Consumed")) {
qCDebug(dcFronius()) << "Detected weak meter on inverter (S0). Using the plant overview grid power as meter information for this one.";
m_weakMeterConnections[connection] = true;
} else {
m_weakMeterConnections[connection] = false;
}
ThingDescriptor descriptor(meterThingClassId, thingName, QString(), connectionThing->id()); ThingDescriptor descriptor(meterThingClassId, thingName, QString(), connectionThing->id());
ParamList params; ParamList params;
params.append(Param(meterThingIdParamTypeId, meterId)); params.append(Param(meterThingIdParamTypeId, meterId));
@ -529,6 +540,15 @@ void IntegrationPluginFronius::updatePowerFlow(FroniusSolarConnection *connectio
} }
} }
Things availableMeters = myThings().filterByParentId(parentThing->id()).filterByThingClassId(meterThingClassId);
if (availableMeters.count() == 1 && m_weakMeterConnections.value(connection)) {
Thing *meterThing = availableMeters.first();
double gridPower = dataMap.value("Site").toMap().value("P_Grid").toDouble();
meterThing->setStateValue(meterCurrentPowerStateTypeId, gridPower);
qCDebug(dcFronius()) << "Using power flow grid power for the weak S0 meter" << gridPower << "House consumption" << dataMap.value("Site").toMap().value("P_Load").toDouble();
}
}); });
} }
@ -601,7 +621,7 @@ void IntegrationPluginFronius::updateMeters(FroniusSolarConnection *connection)
{ {
Thing *parentThing = m_froniusConnections.value(connection); Thing *parentThing = m_froniusConnections.value(connection);
foreach (Thing *meterThing, myThings().filterByParentId(parentThing->id()).filterByThingClassId(meterThingClassId)) { foreach (Thing *meterThing, myThings().filterByParentId(parentThing->id()).filterByThingClassId(meterThingClassId)) {
int meterId = meterThing->paramValue(inverterThingIdParamTypeId).toInt(); int meterId = meterThing->paramValue(meterThingIdParamTypeId).toInt();
// Get the inverter realtime data // Get the inverter realtime data
FroniusNetworkReply *realtimeDataReply = connection->getMeterRealtimeData(meterId); FroniusNetworkReply *realtimeDataReply = connection->getMeterRealtimeData(meterId);
@ -622,9 +642,29 @@ void IntegrationPluginFronius::updateMeters(FroniusSolarConnection *connection)
return; return;
} }
// Parse the data and update the states of our device // Parse the data and update the states of our device
QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap(); QVariantMap dataMap = jsonDoc.toVariant().toMap().value("Body").toMap().value("Data").toMap();
//qCDebug(dcFronius()) << "Meter data" << qUtf8Printable(QJsonDocument::fromVariant(dataMap).toJson(QJsonDocument::Indented)); qCDebug(dcFronius()) << "Meter data" << qUtf8Printable(QJsonDocument::fromVariant(dataMap).toJson(QJsonDocument::Indented));
meterThing->setStateValue("connected", true);
// Note: some inverters have a S0 meter connected, which measures the load, not the grid power and also provides only the current power and no additionl information
// Since we assume a meter on the grid root of the household, we don't update the meter here, but in the updatePowerFlow method.
QString model;
if (dataMap.contains("Details")) {
model = dataMap.value("Details").toMap().value("Model", "Smart Meter").toString();
}
// Note: maybe we find a better way to detect a weak meter, for now, we only knwo it does not provide any additional informaiton and has a S0 in the name
if (model.toLower().contains("s0") && !dataMap.contains("EnergyReal_WAC_Sum_Produced") && !dataMap.contains("EnergyReal_WAC_Sum_Consumed")) {
qCDebug(dcFronius()) << "Ignoring this meter since there are not enought information available (S0). Using the plant overview grid power as meter information.";
m_weakMeterConnections[connection] = true;
return;
} else {
m_weakMeterConnections[connection] = false;
}
// Power // Power
if (dataMap.contains("PowerReal_P_Sum")) { if (dataMap.contains("PowerReal_P_Sum")) {
@ -682,8 +722,6 @@ void IntegrationPluginFronius::updateMeters(FroniusSolarConnection *connection)
if (dataMap.contains("Frequency_Phase_Average")) { if (dataMap.contains("Frequency_Phase_Average")) {
meterThing->setStateValue(meterFrequencyStateTypeId, dataMap.value("Frequency_Phase_Average").toDouble()); meterThing->setStateValue(meterFrequencyStateTypeId, dataMap.value("Frequency_Phase_Average").toDouble());
} }
meterThing->setStateValue("connected", true);
}); });
} }
} }
@ -772,3 +810,4 @@ void IntegrationPluginFronius::markStorageAsDisconnected(Thing *thing)
thing->setStateValue("chargingState", "idle"); thing->setStateValue("chargingState", "idle");
// Note: do not reset the energy counters since they are always counting up until reset on the device // Note: do not reset the energy counters since they are always counting up until reset on the device
} }

View File

@ -59,6 +59,7 @@ private:
QHash<FroniusSolarConnection *, Thing *> m_froniusConnections; QHash<FroniusSolarConnection *, Thing *> m_froniusConnections;
QHash<Thing *, NetworkDeviceMonitor *> m_monitors; QHash<Thing *, NetworkDeviceMonitor *> m_monitors;
QHash<FroniusSolarConnection *, bool> m_weakMeterConnections;
void refreshConnection(FroniusSolarConnection *connection); void refreshConnection(FroniusSolarConnection *connection);