Sma: Fix setup of monitor based sma devices

master
Simon Stürz 2025-05-22 13:43:46 +02:00
parent 8f47c12b23
commit 59f15b8fdb
1 changed files with 94 additions and 113 deletions

View File

@ -73,7 +73,7 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info)
description = networkDeviceInfo.address().toString(); description = networkDeviceInfo.address().toString();
if (!macInfo.vendorName().isEmpty()) if (!macInfo.vendorName().isEmpty())
description += " - " + networkDeviceInfo.macAddressInfos().constFirst().vendorName(); description += " - " + networkDeviceInfo.macAddressInfos().constFirst().vendorName();
break; break;
case NetworkDeviceInfo::MonitorModeHostName: case NetworkDeviceInfo::MonitorModeHostName:
description = networkDeviceInfo.address().toString(); description = networkDeviceInfo.address().toString();
break; break;
@ -594,18 +594,26 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
} }
}); });
// Wait for the monitor to be ready
if (monitor->reachable()) { // If this is the initial setup, wait for the monitor to be reachable and make sure
// Thing already reachable...let's continue with the setup // we have an IP address, otherwise let the monitor do his work
setupModbusSolarInverterConnection(info); if (info->isInitialSetup()) {
// Continue with setup only if we know that the network device is reachable
if (monitor->reachable()) {
setupModbusSolarInverterConnection(info);
} else {
// otherwise wait until we reach the networkdevice before setting up the device
qCDebug(dcSma()) << "Network device" << thing->name() << "is not reachable yet. Continue with the setup once reachable.";
connect(monitor, &NetworkDeviceMonitor::reachableChanged, info, [=](bool reachable){
if (reachable) {
qCDebug(dcSma()) << "Network device" << thing->name() << "is now reachable. Continue with the setup...";
setupModbusSolarInverterConnection(info);
}
});
}
} else { } else {
qCDebug(dcSma()) << "Waiting for the network monitor to get reachable before continue to set up the connection" << thing->name() << address.toString() << "..."; // Continue setup with monitor...
connect(monitor, &NetworkDeviceMonitor::reachableChanged, info, [=](bool reachable){ setupModbusSolarInverterConnection(info);
if (reachable) {
qCDebug(dcSma()) << "The monitor for thing setup" << thing->name() << "is now reachable. Continue setup...";
setupModbusSolarInverterConnection(info);
}
});
} }
} else if (thing->thingClassId() == modbusBatteryInverterThingClassId) { } else if (thing->thingClassId() == modbusBatteryInverterThingClassId) {
@ -645,18 +653,25 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
} }
}); });
// Wait for the monitor to be ready // If this is the initial setup, wait for the monitor to be reachable and make sure
if (monitor->reachable()) { // we have an IP address, otherwise let the monitor do his work
// Thing already reachable...let's continue with the setup if (info->isInitialSetup()) {
setupModbusBatteryInverterConnection(info); // Continue with setup only if we know that the network device is reachable
if (monitor->reachable()) {
setupModbusBatteryInverterConnection(info);
} else {
// otherwise wait until we reach the networkdevice before setting up the device
qCDebug(dcSma()) << "Network device" << thing->name() << "is not reachable yet. Continue with the setup once reachable.";
connect(monitor, &NetworkDeviceMonitor::reachableChanged, info, [=](bool reachable){
if (reachable) {
qCDebug(dcSma()) << "Network device" << thing->name() << "is now reachable. Continue with the setup...";
setupModbusBatteryInverterConnection(info);
}
});
}
} else { } else {
qCDebug(dcSma()) << "Waiting for the network monitor to become reachable before continue to set up the connection" << thing->name() << address.toString() << "..."; // Continue setup with monitor...
connect(monitor, &NetworkDeviceMonitor::reachableChanged, info, [=](bool reachable){ setupModbusBatteryInverterConnection(info);
if (reachable) {
qCDebug(dcSma()) << "The monitor for thing setup" << thing->name() << "is now reachable. Continuing with setup...";
setupModbusBatteryInverterConnection(info);
}
});
} }
} else { } else {
@ -748,8 +763,8 @@ void IntegrationPluginSma::thingRemoved(Thing *thing)
} }
if (myThings().filterByThingClassId(speedwireMeterThingClassId).isEmpty() if (myThings().filterByThingClassId(speedwireMeterThingClassId).isEmpty()
&& myThings().filterByThingClassId(speedwireInverterThingClassId).isEmpty() && myThings().filterByThingClassId(speedwireInverterThingClassId).isEmpty()
&& myThings().filterByThingClassId(speedwireBatteryThingClassId).isEmpty()) { && myThings().filterByThingClassId(speedwireBatteryThingClassId).isEmpty()) {
// Delete shared multicast socket... // Delete shared multicast socket...
m_speedwireInterface->deleteLater(); m_speedwireInterface->deleteLater();
m_speedwireInterface = nullptr; m_speedwireInterface = nullptr;
@ -810,12 +825,12 @@ void IntegrationPluginSma::setupRefreshTimer()
inverter->refresh(); inverter->refresh();
} }
foreach (SmaSolarInverterModbusTcpConnection *connection, m_modbusSolarInverters) { foreach (SmaSolarInverterModbusTcpConnection *connection, m_modbusSolarInverters)
connection->update(); connection->update();
}
foreach (SmaBatteryInverterModbusTcpConnection *connection, m_modbusBatteryInverters) { foreach (SmaBatteryInverterModbusTcpConnection *connection, m_modbusBatteryInverters)
connection->update(); connection->update();
}
}); });
m_refreshTimer->start(); m_refreshTimer->start();
@ -881,78 +896,59 @@ void IntegrationPluginSma::setupModbusSolarInverterConnection(ThingSetupInfo *in
} }
}); });
connect(connection, &SmaSolarInverterModbusTcpConnection::initializationFinished, info, [=](bool success){ connect(connection, &SmaSolarInverterModbusTcpConnection::updateFinished, thing, [=](){
if (!success) { qCDebug(dcSma()) << "Updated" << connection;
qCWarning(dcSma()) << "Connection init finished with errors" << thing->name() << connection->modbusTcpMaster()->hostAddress().toString();
hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(monitor);
connection->deleteLater();
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Could not initialize the communication with the inverter."));
return;
}
qCDebug(dcSma()) << "Connection init finished successfully" << connection; // Grid voltage
m_modbusSolarInverters.insert(thing, connection); if (isModbusValueValid(connection->gridVoltagePhaseA()))
info->finish(Thing::ThingErrorNoError); thing->setStateValue(modbusSolarInverterVoltagePhaseAStateTypeId, connection->gridVoltagePhaseA() / 100.0);
// Set connected true if (isModbusValueValid(connection->gridVoltagePhaseB()))
thing->setStateValue("connected", true); thing->setStateValue(modbusSolarInverterVoltagePhaseBStateTypeId, connection->gridVoltagePhaseB() / 100.0);
foreach (Thing *childThing, myThings().filterByParentId(thing->id())) {
childThing->setStateValue("connected", true);
}
connect(connection, &SmaSolarInverterModbusTcpConnection::updateFinished, thing, [=](){ if (isModbusValueValid(connection->gridVoltagePhaseC()))
qCDebug(dcSma()) << "Updated" << connection; thing->setStateValue(modbusSolarInverterVoltagePhaseCStateTypeId, connection->gridVoltagePhaseC() / 100.0);
// Grid voltage // Grid current
if (isModbusValueValid(connection->gridVoltagePhaseA())) if (isModbusValueValid(connection->gridCurrentPhaseA()))
thing->setStateValue(modbusSolarInverterVoltagePhaseAStateTypeId, connection->gridVoltagePhaseA() / 100.0); thing->setStateValue(modbusSolarInverterCurrentPhaseAStateTypeId, connection->gridCurrentPhaseA() / 1000.0);
if (isModbusValueValid(connection->gridVoltagePhaseB())) if (isModbusValueValid(connection->gridCurrentPhaseB()))
thing->setStateValue(modbusSolarInverterVoltagePhaseBStateTypeId, connection->gridVoltagePhaseB() / 100.0); thing->setStateValue(modbusSolarInverterCurrentPhaseBStateTypeId, connection->gridCurrentPhaseB() / 1000.0);
if (isModbusValueValid(connection->gridVoltagePhaseC())) if (isModbusValueValid(connection->gridCurrentPhaseC()))
thing->setStateValue(modbusSolarInverterVoltagePhaseCStateTypeId, connection->gridVoltagePhaseC() / 100.0); thing->setStateValue(modbusSolarInverterCurrentPhaseCStateTypeId, connection->gridCurrentPhaseC() / 1000.0);
// Grid current // Phase power
if (isModbusValueValid(connection->gridCurrentPhaseA())) if (isModbusValueValid(connection->currentPowerPhaseA()))
thing->setStateValue(modbusSolarInverterCurrentPhaseAStateTypeId, connection->gridCurrentPhaseA() / 1000.0); thing->setStateValue(modbusSolarInverterCurrentPowerPhaseAStateTypeId, connection->currentPowerPhaseA());
if (isModbusValueValid(connection->gridCurrentPhaseB())) if (isModbusValueValid(connection->currentPowerPhaseB()))
thing->setStateValue(modbusSolarInverterCurrentPhaseBStateTypeId, connection->gridCurrentPhaseB() / 1000.0); thing->setStateValue(modbusSolarInverterCurrentPowerPhaseBStateTypeId, connection->currentPowerPhaseB());
if (isModbusValueValid(connection->gridCurrentPhaseC())) if (isModbusValueValid(connection->currentPowerPhaseC()))
thing->setStateValue(modbusSolarInverterCurrentPhaseCStateTypeId, connection->gridCurrentPhaseC() / 1000.0); thing->setStateValue(modbusSolarInverterCurrentPowerPhaseCStateTypeId, connection->currentPowerPhaseC());
// Phase power // Others
if (isModbusValueValid(connection->currentPowerPhaseA())) if (isModbusValueValid(connection->totalYield()))
thing->setStateValue(modbusSolarInverterCurrentPowerPhaseAStateTypeId, connection->currentPowerPhaseA()); thing->setStateValue(modbusSolarInverterTotalEnergyProducedStateTypeId, connection->totalYield() / 1000.0); // kWh
if (isModbusValueValid(connection->currentPowerPhaseB())) if (isModbusValueValid(connection->dailyYield()))
thing->setStateValue(modbusSolarInverterCurrentPowerPhaseBStateTypeId, connection->currentPowerPhaseB()); thing->setStateValue(modbusSolarInverterEnergyProducedTodayStateTypeId, connection->dailyYield() / 1000.0); // kWh
if (isModbusValueValid(connection->currentPowerPhaseC())) // Power
thing->setStateValue(modbusSolarInverterCurrentPowerPhaseCStateTypeId, connection->currentPowerPhaseC()); if (isModbusValueValid(connection->currentPower()))
thing->setStateValue(modbusSolarInverterCurrentPowerStateTypeId, -connection->currentPower());
// Others // Version
if (isModbusValueValid(connection->totalYield())) thing->setStateValue(modbusSolarInverterFirmwareVersionStateTypeId, Sma::buildSoftwareVersionString(connection->softwarePackage()));
thing->setStateValue(modbusSolarInverterTotalEnergyProducedStateTypeId, connection->totalYield() / 1000.0); // kWh
if (isModbusValueValid(connection->dailyYield()))
thing->setStateValue(modbusSolarInverterEnergyProducedTodayStateTypeId, connection->dailyYield() / 1000.0); // kWh
// Power
if (isModbusValueValid(connection->currentPower()))
thing->setStateValue(modbusSolarInverterCurrentPowerStateTypeId, -connection->currentPower());
// Version
thing->setStateValue(modbusSolarInverterFirmwareVersionStateTypeId, Sma::buildSoftwareVersionString(connection->softwarePackage()));
});
// Update registers
connection->update();
}); });
connection->connectDevice(); m_modbusSolarInverters.insert(thing, connection);
info->finish(Thing::ThingErrorNoError);
if (monitor->reachable())
connection->connectDevice();
} }
void IntegrationPluginSma::setupModbusBatteryInverterConnection(ThingSetupInfo *info) void IntegrationPluginSma::setupModbusBatteryInverterConnection(ThingSetupInfo *info)
@ -1012,37 +1008,22 @@ void IntegrationPluginSma::setupModbusBatteryInverterConnection(ThingSetupInfo *
} }
}); });
connect(connection, &SmaBatteryInverterModbusTcpConnection::initializationFinished, info, [=](bool success){ connect(connection, &SmaBatteryInverterModbusTcpConnection::updateFinished, thing, [=](){
if (!success) { qCDebug(dcSma()) << "Updated" << connection;
qCWarning(dcSma()) << "Connection init finished with errors" << thing->name() << connection->modbusTcpMaster()->hostAddress().toString(); thing->setStateValue(modbusBatteryInverterFirmwareVersionStateTypeId, Sma::buildSoftwareVersionString(connection->softwarePackage()));
hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(monitor);
connection->deleteLater();
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Could not initialize the communication with the battery inverter."));
return;
}
qCDebug(dcSma()) << "Connection init finished successfully" << connection; thing->setStateValue(modbusBatteryInverterBatteryLevelStateTypeId, connection->batterySOC());
m_modbusBatteryInverters.insert(thing, connection); thing->setStateValue(modbusBatteryInverterBatteryCriticalStateTypeId, connection->batterySOC() <= 5);
info->finish(Thing::ThingErrorNoError); thing->setStateValue(modbusBatteryInverterCurrentPowerStateTypeId, -connection->currentPower());
thing->setStateValue(modbusBatteryInverterChargingStateStateTypeId, connection->currentPower() == 0 ? "idle" : (connection->currentPower() > 0 ? "charging" : "discharging"));
thing->setStateValue("connected", true);
connect(connection, &SmaBatteryInverterModbusTcpConnection::updateFinished, thing, [=](){
qCDebug(dcSma()) << "Updated" << connection;
thing->setStateValue(modbusBatteryInverterFirmwareVersionStateTypeId, Sma::buildSoftwareVersionString(connection->softwarePackage()));
thing->setStateValue(modbusBatteryInverterBatteryLevelStateTypeId, connection->batterySOC());
thing->setStateValue(modbusBatteryInverterBatteryCriticalStateTypeId, connection->batterySOC() <= 5);
thing->setStateValue(modbusBatteryInverterCurrentPowerStateTypeId, -connection->currentPower());
thing->setStateValue(modbusBatteryInverterChargingStateStateTypeId, connection->currentPower() == 0 ? "idle" : (connection->currentPower() > 0 ? "charging" : "discharging"));
});
// Update registers
connection->update();
}); });
connection->connectDevice(); m_modbusBatteryInverters.insert(thing, connection);
info->finish(Thing::ThingErrorNoError);
if (monitor->reachable())
connection->connectDevice();
} }
SpeedwireInterface *IntegrationPluginSma::getSpeedwireInterface() SpeedwireInterface *IntegrationPluginSma::getSpeedwireInterface()