Add login during setup for SMA inverters
This commit is contained in:
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)
|
void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
||||||
{
|
{
|
||||||
Thing *thing = info->thing();
|
Thing *thing = info->thing();
|
||||||
@ -213,7 +239,9 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||||||
connect(sunnyWebBox, &SunnyWebBox::plantOverviewReceived, this, &IntegrationPluginSma::onPlantOverviewReceived);
|
connect(sunnyWebBox, &SunnyWebBox::plantOverviewReceived, this, &IntegrationPluginSma::onPlantOverviewReceived);
|
||||||
m_sunnyWebBoxes.insert(info->thing(), sunnyWebBox);
|
m_sunnyWebBoxes.insert(info->thing(), sunnyWebBox);
|
||||||
});
|
});
|
||||||
|
|
||||||
} else if (thing->thingClassId() == speedwireMeterThingClassId) {
|
} else if (thing->thingClassId() == speedwireMeterThingClassId) {
|
||||||
|
|
||||||
QHostAddress address = QHostAddress(thing->paramValue(speedwireMeterThingHostParamTypeId).toString());
|
QHostAddress address = QHostAddress(thing->paramValue(speedwireMeterThingHostParamTypeId).toString());
|
||||||
quint32 serialNumber = static_cast<quint32>(thing->paramValue(speedwireMeterThingSerialNumberParamTypeId).toUInt());
|
quint32 serialNumber = static_cast<quint32>(thing->paramValue(speedwireMeterThingSerialNumberParamTypeId).toUInt());
|
||||||
quint16 modelId = static_cast<quint16>(thing->paramValue(speedwireMeterThingModelIdParamTypeId).toUInt());
|
quint16 modelId = static_cast<quint16>(thing->paramValue(speedwireMeterThingModelIdParamTypeId).toUInt());
|
||||||
@ -258,7 +286,9 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||||||
|
|
||||||
m_speedwireMeters.insert(thing, meter);
|
m_speedwireMeters.insert(thing, meter);
|
||||||
info->finish(Thing::ThingErrorNoError);
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
|
||||||
} else if (thing->thingClassId() == speedwireInverterThingClassId) {
|
} else if (thing->thingClassId() == speedwireInverterThingClassId) {
|
||||||
|
|
||||||
QHostAddress address = QHostAddress(thing->paramValue(speedwireInverterThingHostParamTypeId).toString());
|
QHostAddress address = QHostAddress(thing->paramValue(speedwireInverterThingHostParamTypeId).toString());
|
||||||
quint32 serialNumber = static_cast<quint32>(thing->paramValue(speedwireInverterThingSerialNumberParamTypeId).toUInt());
|
quint32 serialNumber = static_cast<quint32>(thing->paramValue(speedwireInverterThingSerialNumberParamTypeId).toUInt());
|
||||||
quint16 modelId = static_cast<quint16>(thing->paramValue(speedwireInverterThingModelIdParamTypeId).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.";
|
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){
|
connect(inverter, &SpeedwireInverter::reachableChanged, this, [=](bool reachable){
|
||||||
thing->setStateValue(speedwireInverterConnectedStateTypeId, reachable);
|
thing->setStateValue(speedwireInverterConnectedStateTypeId, reachable);
|
||||||
});
|
});
|
||||||
@ -296,14 +351,11 @@ void IntegrationPluginSma::setupThing(ThingSetupInfo *info)
|
|||||||
|
|
||||||
thing->setStateValue(speedwireInverterCurrentPowerMpp1StateTypeId, inverter->powerDcMpp1());
|
thing->setStateValue(speedwireInverterCurrentPowerMpp1StateTypeId, inverter->powerDcMpp1());
|
||||||
thing->setStateValue(speedwireInverterCurrentPowerMpp2StateTypeId, inverter->powerDcMpp2());
|
thing->setStateValue(speedwireInverterCurrentPowerMpp2StateTypeId, inverter->powerDcMpp2());
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
m_speedwireInverters.insert(thing, inverter);
|
qCDebug(dcSma()) << "Inverter: Start connecting using password" << password;
|
||||||
info->finish(Thing::ThingErrorNoError);
|
inverter->startConnecting(password);
|
||||||
|
|
||||||
// Initial refresh data
|
|
||||||
inverter->refresh();
|
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
|
Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,10 @@ public:
|
|||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
void discoverThings(ThingDiscoveryInfo *info) 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 setupThing(ThingSetupInfo *info) override;
|
||||||
void postSetupThing(Thing *thing) override;
|
void postSetupThing(Thing *thing) override;
|
||||||
void thingRemoved(Thing *thing) override;
|
void thingRemoved(Thing *thing) override;
|
||||||
|
|||||||
@ -315,6 +315,7 @@
|
|||||||
"name": "speedwireInverter",
|
"name": "speedwireInverter",
|
||||||
"displayName": "SMA Inverter",
|
"displayName": "SMA Inverter",
|
||||||
"createMethods": ["discovery", "user"],
|
"createMethods": ["discovery", "user"],
|
||||||
|
"setupMethod": "EnterPin",
|
||||||
"interfaces": [ "solarinverter" ],
|
"interfaces": [ "solarinverter" ],
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2021, nymea GmbH
|
* Copyright 2013 - 2022, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -39,11 +39,9 @@ SpeedwireInverter::SpeedwireInverter(const QHostAddress &address, quint16 modelI
|
|||||||
m_modelId(modelId),
|
m_modelId(modelId),
|
||||||
m_serialNumber(serialNumber)
|
m_serialNumber(serialNumber)
|
||||||
{
|
{
|
||||||
|
|
||||||
qCDebug(dcSma()) << "Inverter: setup interface on" << m_address.toString();
|
qCDebug(dcSma()) << "Inverter: setup interface on" << m_address.toString();
|
||||||
m_interface = new SpeedwireInterface(m_address, false, this);
|
m_interface = new SpeedwireInterface(m_address, false, this);
|
||||||
connect(m_interface, &SpeedwireInterface::dataReceived, this, &SpeedwireInverter::processData);
|
connect(m_interface, &SpeedwireInterface::dataReceived, this, &SpeedwireInverter::processData);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpeedwireInverter::initialize()
|
bool SpeedwireInverter::initialize()
|
||||||
@ -197,7 +195,7 @@ SpeedwireInverterReply *SpeedwireInverter::sendLoginRequest(const QString &passw
|
|||||||
encodedPassword[i] = (passwordData.at(i) + (loginAsUser ? 0x88 : 0xBB) % 0xff);
|
encodedPassword[i] = (passwordData.at(i) + (loginAsUser ? 0x88 : 0xBB) % 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add endoced password
|
// Add encoded password
|
||||||
for (int i = 0; i < encodedPassword.count(); i++) {
|
for (int i = 0; i < encodedPassword.count(); i++) {
|
||||||
stream << static_cast<quint8>(encodedPassword.at(i));
|
stream << static_cast<quint8>(encodedPassword.at(i));
|
||||||
}
|
}
|
||||||
@ -328,6 +326,12 @@ SpeedwireInverterReply *SpeedwireInverter::sendDeviceTypeRequest()
|
|||||||
return createReply(request);
|
return createReply(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpeedwireInverter::startConnecting(const QString &password)
|
||||||
|
{
|
||||||
|
m_password = password;
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
void SpeedwireInverter::refresh()
|
void SpeedwireInverter::refresh()
|
||||||
{
|
{
|
||||||
// Only refresh if not already busy...
|
// Only refresh if not already busy...
|
||||||
@ -1082,10 +1086,16 @@ void SpeedwireInverter::setState(State state)
|
|||||||
if (reply->error() != SpeedwireInverterReply::ErrorNoError) {
|
if (reply->error() != SpeedwireInverterReply::ErrorNoError) {
|
||||||
if (reply->error() == SpeedwireInverterReply::ErrorTimeout) {
|
if (reply->error() == SpeedwireInverterReply::ErrorTimeout) {
|
||||||
qCWarning(dcSma()) << "Inverter: Failed to query data from inverter:" << reply->request().command() << reply->error();
|
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);
|
setState(StateDisconnected);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reachable, but received an inverter error, probably not logged
|
||||||
if (reply->error() == SpeedwireInverterReply::ErrorInverterError) {
|
if (reply->error() == SpeedwireInverterReply::ErrorInverterError) {
|
||||||
qCDebug(dcSma()) << "Inverter: Query data request finished with inverter error. Try to login...";
|
qCDebug(dcSma()) << "Inverter: Query data request finished with inverter error. Try to login...";
|
||||||
setState(StateLogin);
|
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();
|
qCDebug(dcSma()) << "Inverter: Query request finished successfully" << reply->request().command();
|
||||||
processAcPowerResponse(reply->responseData());
|
processAcPowerResponse(reply->responseData());
|
||||||
|
|
||||||
if (deviceInformationFetched) {
|
|
||||||
|
if (m_deviceInformationFetched) {
|
||||||
setState(StateQueryData);
|
setState(StateQueryData);
|
||||||
} else {
|
} else {
|
||||||
setState(StateGetInformation);
|
setState(StateGetInformation);
|
||||||
@ -1104,18 +1118,18 @@ void SpeedwireInverter::setState(State state)
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case StateLogin: {
|
case StateLogin: {
|
||||||
setState(StateLogin);
|
SpeedwireInverterReply *loginReply = sendLoginRequest(m_password);
|
||||||
SpeedwireInverterReply *loginReply = sendLoginRequest();
|
|
||||||
connect(loginReply, &SpeedwireInverterReply::finished, this, [=](){
|
connect(loginReply, &SpeedwireInverterReply::finished, this, [=](){
|
||||||
if (loginReply->error() != SpeedwireInverterReply::ErrorNoError) {
|
if (loginReply->error() != SpeedwireInverterReply::ErrorNoError) {
|
||||||
qCWarning(dcSma()) << "Inverter: Failed to login to inverter:" << loginReply->error();
|
qCWarning(dcSma()) << "Inverter: Failed to login to inverter:" << loginReply->error();
|
||||||
|
emit loginFinished(false);
|
||||||
setState(StateDisconnected);
|
setState(StateDisconnected);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcSma()) << "Inverter: Login request finished successfully.";
|
qCDebug(dcSma()) << "Inverter: Login request finished successfully.";
|
||||||
|
emit loginFinished(true);
|
||||||
setReachable(true);
|
setReachable(true);
|
||||||
|
|
||||||
// Logged in successfully, reinit the data fetch process
|
// 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.";
|
qCDebug(dcSma()) << "Inverter: Get device information finished successfully.";
|
||||||
processDeviceTypeResponse(deviceTypeReply->responsePayload());
|
processDeviceTypeResponse(deviceTypeReply->responsePayload());
|
||||||
deviceInformationFetched = true;
|
m_deviceInformationFetched = true;
|
||||||
setState(StateQueryData);
|
setState(StateQueryData);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2021, nymea GmbH
|
* Copyright 2013 - 2022, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -101,19 +101,22 @@ public:
|
|||||||
SpeedwireInverterReply *sendDeviceTypeRequest();
|
SpeedwireInverterReply *sendDeviceTypeRequest();
|
||||||
|
|
||||||
// Start connecting
|
// Start connecting
|
||||||
void startConnecting();
|
void startConnecting(const QString &password = "0000");
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void refresh();
|
void refresh();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void reachableChanged(bool reachable);
|
void reachableChanged(bool reachable);
|
||||||
|
void loginFinished(bool success);
|
||||||
void stateChanged(State state);
|
void stateChanged(State state);
|
||||||
void valuesUpdated();
|
void valuesUpdated();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SpeedwireInterface *m_interface = nullptr;
|
SpeedwireInterface *m_interface = nullptr;
|
||||||
QHostAddress m_address;
|
QHostAddress m_address;
|
||||||
|
QString m_password;
|
||||||
|
|
||||||
bool m_initialized = false;
|
bool m_initialized = false;
|
||||||
quint16 m_modelId = 0;
|
quint16 m_modelId = 0;
|
||||||
quint32 m_serialNumber = 0;
|
quint32 m_serialNumber = 0;
|
||||||
@ -122,7 +125,7 @@ private:
|
|||||||
State m_state = StateDisconnected;
|
State m_state = StateDisconnected;
|
||||||
quint16 m_packetId = 1;
|
quint16 m_packetId = 1;
|
||||||
|
|
||||||
bool deviceInformationFetched = false;
|
bool m_deviceInformationFetched = false;
|
||||||
|
|
||||||
SpeedwireInverterReply *m_currentReply = nullptr;
|
SpeedwireInverterReply *m_currentReply = nullptr;
|
||||||
QQueue<SpeedwireInverterReply *> m_replyQueue;
|
QQueue<SpeedwireInverterReply *> m_replyQueue;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user