Add login during setup for SMA inverters
parent
d1eaeb62e6
commit
76437b34c1
|
|
@ -177,6 +177,32 @@ void IntegrationPluginSma::discoverThings(ThingDiscoveryInfo *info)
|
|||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginSma::startPairing(ThingPairingInfo *info)
|
||||
{
|
||||
info->finish(Thing::ThingErrorNoError, QT_TR_NOOP("Please enter the password of your inverter. If no password has been explicitly set, leave it empty to use the default password for SMA inverters."));
|
||||
}
|
||||
|
||||
void IntegrationPluginSma::confirmPairing(ThingPairingInfo *info, const QString &username, const QString &secret)
|
||||
{
|
||||
Q_UNUSED(username)
|
||||
|
||||
// Init with the default password
|
||||
QString password = "0000";
|
||||
if (!secret.isEmpty()) {
|
||||
qCDebug(dcSma()) << "Pairing: Using password" << secret;
|
||||
password = secret;
|
||||
} else {
|
||||
qCDebug(dcSma()) << "Pairing: Secret is empty. Using default password" << password;
|
||||
}
|
||||
|
||||
// Just store details, we'll test the login in setupDevice
|
||||
pluginStorage()->beginGroup(info->thingId().toString());
|
||||
pluginStorage()->setValue("password", password);
|
||||
pluginStorage()->endGroup();
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
||||
{
|
||||
Thing *thing = info->thing();
|
||||
|
|
@ -213,7 +239,9 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||
connect(sunnyWebBox, &SunnyWebBox::plantOverviewReceived, this, &IntegrationPluginSma::onPlantOverviewReceived);
|
||||
m_sunnyWebBoxes.insert(info->thing(), sunnyWebBox);
|
||||
});
|
||||
|
||||
} else if (thing->thingClassId() == speedwireMeterThingClassId) {
|
||||
|
||||
QHostAddress address = QHostAddress(thing->paramValue(speedwireMeterThingHostParamTypeId).toString());
|
||||
quint32 serialNumber = static_cast<quint32>(thing->paramValue(speedwireMeterThingSerialNumberParamTypeId).toUInt());
|
||||
quint16 modelId = static_cast<quint16>(thing->paramValue(speedwireMeterThingModelIdParamTypeId).toUInt());
|
||||
|
|
@ -258,7 +286,9 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||
|
||||
m_speedwireMeters.insert(thing, meter);
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
|
||||
} else if (thing->thingClassId() == speedwireInverterThingClassId) {
|
||||
|
||||
QHostAddress address = QHostAddress(thing->paramValue(speedwireInverterThingHostParamTypeId).toString());
|
||||
quint32 serialNumber = static_cast<quint32>(thing->paramValue(speedwireInverterThingSerialNumberParamTypeId).toUInt());
|
||||
quint16 modelId = static_cast<quint16>(thing->paramValue(speedwireInverterThingModelIdParamTypeId).toUInt());
|
||||
|
|
@ -276,6 +306,31 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||
|
||||
qCDebug(dcSma()) << "Inverter: Interface initialized successfully.";
|
||||
|
||||
QString password;
|
||||
pluginStorage()->beginGroup(info->thing()->id().toString());
|
||||
password = pluginStorage()->value("password", "0000").toString();
|
||||
pluginStorage()->endGroup();
|
||||
|
||||
// Connection exists only as long info exists
|
||||
connect(inverter, &SpeedwireInverter::loginFinished, info, [=](bool success){
|
||||
if (!success) {
|
||||
qCWarning(dcSma()) << "Failed to set up inverter. Wrong password.";
|
||||
delete inverter;
|
||||
info->finish(Thing::ThingErrorAuthenticationFailure, QT_TR_NOOP("Failed to log in with the given password. Please try again."));
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcSma()) << "Inverter set up successfully.";
|
||||
m_speedwireInverters.insert(thing, inverter);
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
// Note: the data is already refreshing here
|
||||
});
|
||||
|
||||
// Make sure an aborted setup will clean up the object
|
||||
connect(info, &ThingSetupInfo::aborted, inverter, &SpeedwireInverter::deleteLater);
|
||||
|
||||
|
||||
// Runtime connections
|
||||
connect(inverter, &SpeedwireInverter::reachableChanged, this, [=](bool reachable){
|
||||
thing->setStateValue(speedwireInverterConnectedStateTypeId, reachable);
|
||||
});
|
||||
|
|
@ -296,14 +351,11 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||
|
||||
thing->setStateValue(speedwireInverterCurrentPowerMpp1StateTypeId, inverter->powerDcMpp1());
|
||||
thing->setStateValue(speedwireInverterCurrentPowerMpp2StateTypeId, inverter->powerDcMpp2());
|
||||
|
||||
});
|
||||
|
||||
m_speedwireInverters.insert(thing, inverter);
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
qCDebug(dcSma()) << "Inverter: Start connecting using password" << password;
|
||||
inverter->startConnecting(password);
|
||||
|
||||
// Initial refresh data
|
||||
inverter->refresh();
|
||||
} else {
|
||||
Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ public:
|
|||
|
||||
void init() override;
|
||||
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||
|
||||
void startPairing(ThingPairingInfo *info) override;
|
||||
void confirmPairing(ThingPairingInfo *info, const QString &username, const QString &secret) override;
|
||||
|
||||
void setupThing(ThingSetupInfo *info) override;
|
||||
void postSetupThing(Thing *thing) override;
|
||||
void thingRemoved(Thing *thing) override;
|
||||
|
|
|
|||
|
|
@ -315,6 +315,7 @@
|
|||
"name": "speedwireInverter",
|
||||
"displayName": "SMA Inverter",
|
||||
"createMethods": ["discovery", "user"],
|
||||
"setupMethod": "EnterPin",
|
||||
"interfaces": [ "solarinverter" ],
|
||||
"paramTypes": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2021, nymea GmbH
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
|
@ -39,11 +39,9 @@ SpeedwireInverter::SpeedwireInverter(const QHostAddress &address, quint16 modelI
|
|||
m_modelId(modelId),
|
||||
m_serialNumber(serialNumber)
|
||||
{
|
||||
|
||||
qCDebug(dcSma()) << "Inverter: setup interface on" << m_address.toString();
|
||||
m_interface = new SpeedwireInterface(m_address, false, this);
|
||||
connect(m_interface, &SpeedwireInterface::dataReceived, this, &SpeedwireInverter::processData);
|
||||
|
||||
}
|
||||
|
||||
bool SpeedwireInverter::initialize()
|
||||
|
|
@ -197,7 +195,7 @@ SpeedwireInverterReply *SpeedwireInverter::sendLoginRequest(const QString &passw
|
|||
encodedPassword[i] = (passwordData.at(i) + (loginAsUser ? 0x88 : 0xBB) % 0xff);
|
||||
}
|
||||
|
||||
// Add endoced password
|
||||
// Add encoded password
|
||||
for (int i = 0; i < encodedPassword.count(); i++) {
|
||||
stream << static_cast<quint8>(encodedPassword.at(i));
|
||||
}
|
||||
|
|
@ -328,6 +326,12 @@ SpeedwireInverterReply *SpeedwireInverter::sendDeviceTypeRequest()
|
|||
return createReply(request);
|
||||
}
|
||||
|
||||
void SpeedwireInverter::startConnecting(const QString &password)
|
||||
{
|
||||
m_password = password;
|
||||
refresh();
|
||||
}
|
||||
|
||||
void SpeedwireInverter::refresh()
|
||||
{
|
||||
// Only refresh if not already busy...
|
||||
|
|
@ -1082,10 +1086,16 @@ void SpeedwireInverter::setState(State state)
|
|||
if (reply->error() != SpeedwireInverterReply::ErrorNoError) {
|
||||
if (reply->error() == SpeedwireInverterReply::ErrorTimeout) {
|
||||
qCWarning(dcSma()) << "Inverter: Failed to query data from inverter:" << reply->request().command() << reply->error();
|
||||
|
||||
// TODO: try to send identify request and retry 3 times before giving up,
|
||||
// still need to figure out why the inverter stops responding sometimes and how we can
|
||||
// make it communicative again, a reconfugre always fixes this issue...somehow...
|
||||
|
||||
setState(StateDisconnected);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reachable, but received an inverter error, probably not logged
|
||||
if (reply->error() == SpeedwireInverterReply::ErrorInverterError) {
|
||||
qCDebug(dcSma()) << "Inverter: Query data request finished with inverter error. Try to login...";
|
||||
setState(StateLogin);
|
||||
|
|
@ -1093,10 +1103,14 @@ void SpeedwireInverter::setState(State state)
|
|||
}
|
||||
}
|
||||
|
||||
// We where able to read data...emit the signal for the setup just incase
|
||||
emit loginFinished(true);
|
||||
|
||||
qCDebug(dcSma()) << "Inverter: Query request finished successfully" << reply->request().command();
|
||||
processAcPowerResponse(reply->responseData());
|
||||
|
||||
if (deviceInformationFetched) {
|
||||
|
||||
if (m_deviceInformationFetched) {
|
||||
setState(StateQueryData);
|
||||
} else {
|
||||
setState(StateGetInformation);
|
||||
|
|
@ -1104,18 +1118,18 @@ void SpeedwireInverter::setState(State state)
|
|||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case StateLogin: {
|
||||
setState(StateLogin);
|
||||
SpeedwireInverterReply *loginReply = sendLoginRequest();
|
||||
SpeedwireInverterReply *loginReply = sendLoginRequest(m_password);
|
||||
connect(loginReply, &SpeedwireInverterReply::finished, this, [=](){
|
||||
if (loginReply->error() != SpeedwireInverterReply::ErrorNoError) {
|
||||
qCWarning(dcSma()) << "Inverter: Failed to login to inverter:" << loginReply->error();
|
||||
emit loginFinished(false);
|
||||
setState(StateDisconnected);
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcSma()) << "Inverter: Login request finished successfully.";
|
||||
emit loginFinished(true);
|
||||
setReachable(true);
|
||||
|
||||
// Logged in successfully, reinit the data fetch process
|
||||
|
|
@ -1145,7 +1159,7 @@ void SpeedwireInverter::setState(State state)
|
|||
|
||||
qCDebug(dcSma()) << "Inverter: Get device information finished successfully.";
|
||||
processDeviceTypeResponse(deviceTypeReply->responsePayload());
|
||||
deviceInformationFetched = true;
|
||||
m_deviceInformationFetched = true;
|
||||
setState(StateQueryData);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2021, nymea GmbH
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
|
|
@ -101,19 +101,22 @@ public:
|
|||
SpeedwireInverterReply *sendDeviceTypeRequest();
|
||||
|
||||
// Start connecting
|
||||
void startConnecting();
|
||||
void startConnecting(const QString &password = "0000");
|
||||
|
||||
public slots:
|
||||
void refresh();
|
||||
|
||||
signals:
|
||||
void reachableChanged(bool reachable);
|
||||
void loginFinished(bool success);
|
||||
void stateChanged(State state);
|
||||
void valuesUpdated();
|
||||
|
||||
private:
|
||||
SpeedwireInterface *m_interface = nullptr;
|
||||
QHostAddress m_address;
|
||||
QString m_password;
|
||||
|
||||
bool m_initialized = false;
|
||||
quint16 m_modelId = 0;
|
||||
quint32 m_serialNumber = 0;
|
||||
|
|
@ -122,7 +125,7 @@ private:
|
|||
State m_state = StateDisconnected;
|
||||
quint16 m_packetId = 1;
|
||||
|
||||
bool deviceInformationFetched = false;
|
||||
bool m_deviceInformationFetched = false;
|
||||
|
||||
SpeedwireInverterReply *m_currentReply = nullptr;
|
||||
QQueue<SpeedwireInverterReply *> m_replyQueue;
|
||||
|
|
|
|||
Loading…
Reference in New Issue