Shelly: Add support for Gen3 hardware and fix #739
This commit is contained in:
parent
93ed882bdb
commit
f3bdee26bf
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2020, nymea GmbH
|
* Copyright 2013 - 2025, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -32,24 +32,24 @@
|
|||||||
#include "plugininfo.h"
|
#include "plugininfo.h"
|
||||||
#include "shellyjsonrpcclient.h"
|
#include "shellyjsonrpcclient.h"
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
#include <QNetworkReply>
|
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QColor>
|
#include <QNetworkReply>
|
||||||
#include <QNetworkInterface>
|
#include <QNetworkInterface>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "hardwaremanager.h"
|
#include <hardwaremanager.h>
|
||||||
#include "network/networkaccessmanager.h"
|
#include <network/networkaccessmanager.h>
|
||||||
#include "network/mqtt/mqttprovider.h"
|
#include <network/mqtt/mqttprovider.h>
|
||||||
#include "network/mqtt/mqttchannel.h"
|
#include <network/mqtt/mqttchannel.h>
|
||||||
|
#include <plugintimer.h>
|
||||||
|
|
||||||
#include "plugintimer.h"
|
#include <qmath.h>
|
||||||
|
|
||||||
#include "qmath.h"
|
#include <network/zeroconf/zeroconfservicebrowser.h>
|
||||||
|
#include <platform/platformzeroconfcontroller.h>
|
||||||
#include "network/zeroconf/zeroconfservicebrowser.h"
|
|
||||||
#include "platform/platformzeroconfcontroller.h"
|
|
||||||
|
|
||||||
#include <coap/coap.h>
|
#include <coap/coap.h>
|
||||||
|
|
||||||
@ -63,10 +63,12 @@ static QHash<QString, QString> updateStatusMap = {
|
|||||||
|
|
||||||
IntegrationPluginShelly::IntegrationPluginShelly()
|
IntegrationPluginShelly::IntegrationPluginShelly()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IntegrationPluginShelly::~IntegrationPluginShelly()
|
IntegrationPluginShelly::~IntegrationPluginShelly()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginShelly::init()
|
void IntegrationPluginShelly::init()
|
||||||
@ -81,61 +83,64 @@ void IntegrationPluginShelly::init()
|
|||||||
void IntegrationPluginShelly::discoverThings(ThingDiscoveryInfo *info)
|
void IntegrationPluginShelly::discoverThings(ThingDiscoveryInfo *info)
|
||||||
{
|
{
|
||||||
foreach (const ZeroConfServiceEntry &entry, m_zeroconfBrowser->serviceEntries()) {
|
foreach (const ZeroConfServiceEntry &entry, m_zeroconfBrowser->serviceEntries()) {
|
||||||
qCDebug(dcShelly()) << "Have entry" << entry;
|
if (entry.protocol() != QAbstractSocket::IPv4Protocol)
|
||||||
QRegExp namePattern;
|
|
||||||
if (info->thingClassId() == shelly1ThingClassId) {
|
|
||||||
namePattern = QRegExp("^shelly1-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyPlus1ThingClassId) {
|
|
||||||
namePattern = QRegExp("^ShellyPlus1-[0-9A-Z]+$", Qt::CaseInsensitive);
|
|
||||||
} else if (info->thingClassId() == shelly1pmThingClassId) {
|
|
||||||
namePattern = QRegExp("^shelly1pm-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyPlus1pmThingClassId) {
|
|
||||||
namePattern = QRegExp("^ShellyPlus1PM-[0-9A-Z]+$", Qt::CaseInsensitive);
|
|
||||||
} else if (info->thingClassId() == shellyPro1PmThingClassId) {
|
|
||||||
namePattern = QRegExp("^ShellyPro1PM-[0-9A-Z]+$", Qt::CaseInsensitive);
|
|
||||||
} else if (info->thingClassId() == shelly1lThingClassId) {
|
|
||||||
namePattern = QRegExp("^shelly1l-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyPlugThingClassId) {
|
|
||||||
namePattern = QRegExp("^shellyplug(-s)?-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyPlusPlugThingClassId) {
|
|
||||||
namePattern = QRegExp("^(ShellyPlusPlugS|ShellyPlug(US|IT|UK))-[0-9A-Z]+$", Qt::CaseInsensitive);
|
|
||||||
} else if (info->thingClassId() == shellyRgbw2ThingClassId) {
|
|
||||||
namePattern = QRegExp("^shellyrgbw2-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyDimmerThingClassId) {
|
|
||||||
namePattern = QRegExp("^(shellydimmer(2)?|ShellyVintage)-[0-9A-Z]+$", Qt::CaseInsensitive);
|
|
||||||
} else if (info->thingClassId() == shelly2ThingClassId) {
|
|
||||||
namePattern = QRegExp("^shellyswitch-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shelly25ThingClassId) {
|
|
||||||
namePattern = QRegExp("^(shellyswitch25|ShellyPlus2PM)-[0-9A-Z]+$", Qt::CaseInsensitive);
|
|
||||||
} else if (info->thingClassId() == shellyButton1ThingClassId) {
|
|
||||||
namePattern = QRegExp("^shellybutton1-[0-9-A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyEmThingClassId) {
|
|
||||||
namePattern = QRegExp("^shellyem-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyEm3ThingClassId) {
|
|
||||||
namePattern = QRegExp("^shellyem3-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyPro3EMThingClassId) {
|
|
||||||
namePattern = QRegExp("^ShellyPro3EM-[0-9A-Z]+$", Qt::CaseInsensitive);
|
|
||||||
} else if (info->thingClassId() == shellyHTThingClassId) {
|
|
||||||
namePattern = QRegExp("shellyht-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyI3ThingClassId) {
|
|
||||||
namePattern = QRegExp("shellyix3-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyMotionThingClassId) {
|
|
||||||
namePattern = QRegExp("shellymotionsensor-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyTrvThingClassId) {
|
|
||||||
namePattern = QRegExp("shellytrv-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyFloodThingClassId) {
|
|
||||||
namePattern = QRegExp("^shellyflood-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellySmokeThingClassId) {
|
|
||||||
namePattern = QRegExp("^shellysmoke-[0-9A-Z]+$");
|
|
||||||
} else if (info->thingClassId() == shellyPlusSmokeThingClassId) {
|
|
||||||
namePattern = QRegExp("^shellyplussmoke-[0-9A-Z]+$", Qt::CaseInsensitive);
|
|
||||||
} else if (info->thingClassId() == shellyGasThingClassId) {
|
|
||||||
namePattern = QRegExp("^shellygas-[0-9A-Z]+$");
|
|
||||||
}
|
|
||||||
if (!entry.name().contains(namePattern)) {
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
qCDebug(dcShelly()) << "Have entry" << entry;
|
||||||
|
QRegularExpression namePattern;
|
||||||
|
if (info->thingClassId() == shelly1ThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shelly1(mini)?(g3)?-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shellyPlus1ThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^ShellyPlus1-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shelly1pmThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shelly1pm(g3)?-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shellyPlus1pmThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^ShellyPlus1PM-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shellyPro1PmThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^ShellyPro1PM-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shelly1lThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shelly1l-[0-9A-Z]+$");
|
||||||
|
} else if (info->thingClassId() == shellyPlugThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shellyplug(-s)?(sg3)?-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shellyPlusPlugThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^(ShellyPlusPlugS|ShellyPlug(US|IT|UK))-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shellyRgbw2ThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shellyrgbw2-[0-9A-Z]+$");
|
||||||
|
} else if (info->thingClassId() == shellyDimmerThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^(shellydimmer(2)?(g3)?|ShellyVintage)-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shelly2ThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shellyswitch-[0-9A-Z]+$");
|
||||||
|
} else if (info->thingClassId() == shelly25ThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^(shellyswitch25|ShellyPlus2PM)-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shellyButton1ThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shellybutton1-[0-9-A-Z]+$");
|
||||||
|
} else if (info->thingClassId() == shellyEmThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shellyem(g3)?-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shellyEm3ThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shellyem3-[0-9A-Z]+$");
|
||||||
|
} else if (info->thingClassId() == shellyPro3EMThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^ShellyPro3EM-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shellyHTThingClassId) {
|
||||||
|
namePattern = QRegularExpression("shellyht(g3)?-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shellyI3ThingClassId) {
|
||||||
|
namePattern = QRegularExpression("shellyix3-[0-9A-Z]+$");
|
||||||
|
} else if (info->thingClassId() == shellyMotionThingClassId) {
|
||||||
|
namePattern = QRegularExpression("shellymotionsensor-[0-9A-Z]+$");
|
||||||
|
} else if (info->thingClassId() == shellyTrvThingClassId) {
|
||||||
|
namePattern = QRegularExpression("shellytrv-[0-9A-Z]+$");
|
||||||
|
} else if (info->thingClassId() == shellyFloodThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shellyflood-[0-9A-Z]+$");
|
||||||
|
} else if (info->thingClassId() == shellySmokeThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shellysmoke-[0-9A-Z]+$");
|
||||||
|
} else if (info->thingClassId() == shellyPlusSmokeThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shellyplussmoke-[0-9A-Z]+$", QRegularExpression::CaseInsensitiveOption);
|
||||||
|
} else if (info->thingClassId() == shellyGasThingClassId) {
|
||||||
|
namePattern = QRegularExpression("^shellygas-[0-9A-Z]+$");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!entry.name().contains(namePattern))
|
||||||
|
continue;
|
||||||
|
|
||||||
ThingDescriptor descriptor(info->thingClassId(), entry.name(), entry.hostAddress().toString());
|
ThingDescriptor descriptor(info->thingClassId(), entry.name(), entry.hostAddress().toString());
|
||||||
ParamList params;
|
ParamList params;
|
||||||
ThingClass thingClass = supportedThings().findById(info->thingClassId());
|
ThingClass thingClass = supportedThings().findById(info->thingClassId());
|
||||||
@ -176,7 +181,7 @@ void IntegrationPluginShelly::confirmPairing(ThingPairingInfo *info, const QStri
|
|||||||
QString shellyId = info->params().paramValue(thingClass.paramTypes().findByName("id").id()).toString();
|
QString shellyId = info->params().paramValue(thingClass.paramTypes().findByName("id").id()).toString();
|
||||||
ZeroConfServiceEntry zeroConfEntry;
|
ZeroConfServiceEntry zeroConfEntry;
|
||||||
foreach (const ZeroConfServiceEntry &entry, m_zeroconfBrowser->serviceEntries()) {
|
foreach (const ZeroConfServiceEntry &entry, m_zeroconfBrowser->serviceEntries()) {
|
||||||
if (entry.name() == shellyId) {
|
if (entry.name() == shellyId && entry.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||||
zeroConfEntry = entry;
|
zeroConfEntry = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,7 +200,8 @@ void IntegrationPluginShelly::confirmPairing(ThingPairingInfo *info, const QStri
|
|||||||
// GetDeviceInfo wouldn't require authentication if enabled, so if the setup is changed to fetch some info from GetDeviceInfo,
|
// GetDeviceInfo wouldn't require authentication if enabled, so if the setup is changed to fetch some info from GetDeviceInfo,
|
||||||
// make sure to not just replace the GetStatus call, or authentication verification won't work any more.
|
// make sure to not just replace the GetStatus call, or authentication verification won't work any more.
|
||||||
ShellyRpcReply *reply = client->sendRequest("Shelly.GetStatus");
|
ShellyRpcReply *reply = client->sendRequest("Shelly.GetStatus");
|
||||||
connect(reply, &ShellyRpcReply::finished, info, [info, client, this, password](ShellyRpcReply::Status status, const QVariantMap &/*response*/){
|
connect(reply, &ShellyRpcReply::finished, info, [info, this, password](ShellyRpcReply::Status status, const QVariantMap &response){
|
||||||
|
Q_UNUSED(response)
|
||||||
if (status != ShellyRpcReply::StatusSuccess) {
|
if (status != ShellyRpcReply::StatusSuccess) {
|
||||||
qCWarning(dcShelly) << "Error during shelly paring";
|
qCWarning(dcShelly) << "Error during shelly paring";
|
||||||
info->finish(Thing::ThingErrorHardwareFailure);
|
info->finish(Thing::ThingErrorHardwareFailure);
|
||||||
@ -218,9 +224,11 @@ void IntegrationPluginShelly::setupThing(ThingSetupInfo *info)
|
|||||||
if (!thing->thingClass().paramTypes().findByName("id").id().isNull()) {
|
if (!thing->thingClass().paramTypes().findByName("id").id().isNull()) {
|
||||||
|
|
||||||
QString shellyId = info->thing()->paramValue("id").toString();
|
QString shellyId = info->thing()->paramValue("id").toString();
|
||||||
if (isGen2(shellyId)) {
|
if (isGen2Plus(shellyId)) {
|
||||||
setupGen2(info);
|
qCDebug(dcShelly()) << "Setting up" << shellyId << "Gen2+";
|
||||||
|
setupGen2Plus(info);
|
||||||
} else {
|
} else {
|
||||||
|
qCDebug(dcShelly()) << "Setting up" << shellyId << "Gen1";
|
||||||
setupGen1(info);
|
setupGen1(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,8 +246,8 @@ void IntegrationPluginShelly::postSetupThing(Thing *thing)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (thing->parentId().isNull()) {
|
if (thing->parentId().isNull()) {
|
||||||
if (isGen2(thing->paramValue("id").toString())) {
|
if (isGen2Plus(thing->paramValue("id").toString())) {
|
||||||
fetchStatusGen2(thing);
|
fetchStatusGen2Plus(thing);
|
||||||
} else {
|
} else {
|
||||||
fetchStatusGen1(thing);
|
fetchStatusGen1(thing);
|
||||||
}
|
}
|
||||||
@ -324,7 +332,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info)
|
|||||||
|
|
||||||
ActionType actionType = thing->thingClass().actionTypes().findById(action.actionTypeId());
|
ActionType actionType = thing->thingClass().actionTypes().findById(action.actionTypeId());
|
||||||
if (actionType.name() == "reboot") {
|
if (actionType.name() == "reboot") {
|
||||||
if (isGen2(shellyId)) {
|
if (isGen2Plus(shellyId)) {
|
||||||
ShellyRpcReply *reply = m_rpcClients.value(thing)->sendRequest("Shelly.Reboot");
|
ShellyRpcReply *reply = m_rpcClients.value(thing)->sendRequest("Shelly.Reboot");
|
||||||
connect(reply, &ShellyRpcReply::finished, info, [info](ShellyRpcReply::Status status, const QVariantMap &/*response*/){
|
connect(reply, &ShellyRpcReply::finished, info, [info](ShellyRpcReply::Status status, const QVariantMap &/*response*/){
|
||||||
info->finish(status == ShellyRpcReply::StatusSuccess ? Thing::ThingErrorNoError : Thing::ThingErrorHardwareFailure);
|
info->finish(status == ShellyRpcReply::StatusSuccess ? Thing::ThingErrorNoError : Thing::ThingErrorHardwareFailure);
|
||||||
@ -344,7 +352,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (actionType.name() == "performUpdate") {
|
if (actionType.name() == "performUpdate") {
|
||||||
if (isGen2(shellyId)) {
|
if (isGen2Plus(shellyId)) {
|
||||||
ShellyRpcReply *reply = m_rpcClients.value(thing)->sendRequest("Shelly.Update");
|
ShellyRpcReply *reply = m_rpcClients.value(thing)->sendRequest("Shelly.Update");
|
||||||
connect(reply, &ShellyRpcReply::finished, info, [info](ShellyRpcReply::Status status, const QVariantMap &/*response*/){
|
connect(reply, &ShellyRpcReply::finished, info, [info](ShellyRpcReply::Status status, const QVariantMap &/*response*/){
|
||||||
info->finish(status == ShellyRpcReply::StatusSuccess ? Thing::ThingErrorNoError : Thing::ThingErrorHardwareFailure);
|
info->finish(status == ShellyRpcReply::StatusSuccess ? Thing::ThingErrorNoError : Thing::ThingErrorHardwareFailure);
|
||||||
@ -535,7 +543,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action.actionTypeId() == shellyRollerOpenActionTypeId) {
|
if (action.actionTypeId() == shellyRollerOpenActionTypeId) {
|
||||||
if (isGen2(shellyId)) {
|
if (isGen2Plus(shellyId)) {
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1;
|
int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1;
|
||||||
params.insert("id", channelNbr);
|
params.insert("id", channelNbr);
|
||||||
@ -558,7 +566,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action.actionTypeId() == shellyRollerCloseActionTypeId) {
|
if (action.actionTypeId() == shellyRollerCloseActionTypeId) {
|
||||||
if (isGen2(shellyId)) {
|
if (isGen2Plus(shellyId)) {
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1;
|
int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1;
|
||||||
params.insert("id", channelNbr);
|
params.insert("id", channelNbr);
|
||||||
@ -581,7 +589,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action.actionTypeId() == shellyRollerStopActionTypeId) {
|
if (action.actionTypeId() == shellyRollerStopActionTypeId) {
|
||||||
if (isGen2(shellyId)) {
|
if (isGen2Plus(shellyId)) {
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1;
|
int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1;
|
||||||
params.insert("id", channelNbr);
|
params.insert("id", channelNbr);
|
||||||
@ -604,7 +612,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action.actionTypeId() == shellyRollerCalibrateActionTypeId) {
|
if (action.actionTypeId() == shellyRollerCalibrateActionTypeId) {
|
||||||
if (isGen2(shellyId)) {
|
if (isGen2Plus(shellyId)) {
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1;
|
int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1;
|
||||||
params.insert("id", channelNbr);
|
params.insert("id", channelNbr);
|
||||||
@ -624,7 +632,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (action.actionTypeId() == shellyRollerPercentageActionTypeId) {
|
if (action.actionTypeId() == shellyRollerPercentageActionTypeId) {
|
||||||
if (isGen2(shellyId)) {
|
if (isGen2Plus(shellyId)) {
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1;
|
int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1;
|
||||||
int positionTarget = info->action().paramValue(shellyRollerPercentageActionPercentageParamTypeId).toInt();
|
int positionTarget = info->action().paramValue(shellyRollerPercentageActionPercentageParamTypeId).toInt();
|
||||||
@ -738,7 +746,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info)
|
|||||||
ParamTypeId powerParamTypeId = actionType.id();
|
ParamTypeId powerParamTypeId = actionType.id();
|
||||||
bool on = action.param(powerParamTypeId).value().toBool();
|
bool on = action.param(powerParamTypeId).value().toBool();
|
||||||
|
|
||||||
if (isGen2(shellyId)) {
|
if (isGen2Plus(shellyId)) {
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
params.insert("id", relay - 1);
|
params.insert("id", relay - 1);
|
||||||
params.insert("on", on);
|
params.insert("on", on);
|
||||||
@ -1202,8 +1210,8 @@ void IntegrationPluginShelly::updateStatus()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGen2(thing->paramValue("id").toString())) {
|
if (isGen2Plus(thing->paramValue("id").toString())) {
|
||||||
fetchStatusGen2(thing);
|
fetchStatusGen2Plus(thing);
|
||||||
} else {
|
} else {
|
||||||
//Skipping sleepy devices, as they won't reply to cyclic requests.
|
//Skipping sleepy devices, as they won't reply to cyclic requests.
|
||||||
if (thing->thingClassId() == shellyFloodThingClassId
|
if (thing->thingClassId() == shellyFloodThingClassId
|
||||||
@ -1260,13 +1268,11 @@ void IntegrationPluginShelly::fetchStatusGen1(Thing *thing)
|
|||||||
child->setStateValue("signalStrength", signalStrength);
|
child->setStateValue("signalStrength", signalStrength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QVariantMap updateMap = map.value("update").toMap();
|
QVariantMap updateMap = map.value("update").toMap();
|
||||||
thing->setStateValue("currentVersion", updateMap.value("old_version").toString());
|
thing->setStateValue("currentVersion", updateMap.value("old_version").toString());
|
||||||
thing->setStateValue("availableVersion", updateMap.value("new_version").toString());
|
thing->setStateValue("availableVersion", updateMap.value("new_version").toString());
|
||||||
thing->setStateValue("updateStatus", updateStatusMap.value(updateMap.value("status").toString()));
|
thing->setStateValue("updateStatus", updateStatusMap.value(updateMap.value("status").toString()));
|
||||||
|
|
||||||
|
|
||||||
// Sometimes, some shellies just stop to send CoIoT messages until they are rebooted...
|
// Sometimes, some shellies just stop to send CoIoT messages until they are rebooted...
|
||||||
// If communication to the shelly per se works fine, but we didn't receive anything in more than a minute,
|
// If communication to the shelly per se works fine, but we didn't receive anything in more than a minute,
|
||||||
// let's reconfigure coap and reboot the shelly
|
// let's reconfigure coap and reboot the shelly
|
||||||
@ -1315,7 +1321,7 @@ void IntegrationPluginShelly::fetchStatusGen1(Thing *thing)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginShelly::fetchStatusGen2(Thing *thing)
|
void IntegrationPluginShelly::fetchStatusGen2Plus(Thing *thing)
|
||||||
{
|
{
|
||||||
ShellyJsonRpcClient *client = m_rpcClients.value(thing);
|
ShellyJsonRpcClient *client = m_rpcClients.value(thing);
|
||||||
ShellyRpcReply *statusReply = client->sendRequest("Shelly.GetStatus");
|
ShellyRpcReply *statusReply = client->sendRequest("Shelly.GetStatus");
|
||||||
@ -1637,7 +1643,7 @@ void IntegrationPluginShelly::setupGen1(ThingSetupInfo *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginShelly::setupGen2(ThingSetupInfo *info)
|
void IntegrationPluginShelly::setupGen2Plus(ThingSetupInfo *info)
|
||||||
{
|
{
|
||||||
Thing *thing = info->thing();
|
Thing *thing = info->thing();
|
||||||
QHostAddress address = getIP(thing);
|
QHostAddress address = getIP(thing);
|
||||||
@ -1772,7 +1778,22 @@ void IntegrationPluginShelly::setupGen2(ThingSetupInfo *info)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->thing()->thingClassId() == shelly1ThingClassId) {
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->thing()->thingClassId() == shelly1pmThingClassId) {
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (info->thing()->thingClassId() == shellyDimmerThingClassId) {
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->thing()->thingClassId() == shellyPro3EMThingClassId) {
|
if (info->thing()->thingClassId() == shellyPro3EMThingClassId) {
|
||||||
@ -1780,6 +1801,21 @@ void IntegrationPluginShelly::setupGen2(ThingSetupInfo *info)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info->thing()->thingClassId() == shellyEmThingClassId) {
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->thing()->thingClassId() == shellyHTThingClassId) {
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->thing()->thingClassId() == shellyPlugThingClassId) {
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (info->thing()->thingClassId() == shellyPlusSmokeThingClassId) {
|
if (info->thing()->thingClassId() == shellyPlusSmokeThingClassId) {
|
||||||
info->finish(Thing::ThingErrorNoError);
|
info->finish(Thing::ThingErrorNoError);
|
||||||
return;
|
return;
|
||||||
@ -1799,7 +1835,7 @@ void IntegrationPluginShelly::setupGen2(ThingSetupInfo *info)
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (thing->setupStatus() == Thing::ThingSetupStatusComplete) {
|
if (thing->setupStatus() == Thing::ThingSetupStatusComplete) {
|
||||||
fetchStatusGen2(thing);
|
fetchStatusGen2Plus(thing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1924,7 +1960,6 @@ void IntegrationPluginShelly::setupGen2(ThingSetupInfo *info)
|
|||||||
QVariantMap map = notification.value("smoke:0").toMap();
|
QVariantMap map = notification.value("smoke:0").toMap();
|
||||||
thing->setStateValue(shellyPlusSmokeFireDetectedStateTypeId, map.value("alarm").toBool());
|
thing->setStateValue(shellyPlusSmokeFireDetectedStateTypeId, map.value("alarm").toBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1964,10 +1999,8 @@ void IntegrationPluginShelly::setupGen2(ThingSetupInfo *info)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginShelly::setupShellyChild(ThingSetupInfo *info)
|
void IntegrationPluginShelly::setupShellyChild(ThingSetupInfo *info)
|
||||||
@ -2068,7 +2101,7 @@ QHostAddress IntegrationPluginShelly::getIP(Thing *thing) const
|
|||||||
|
|
||||||
ZeroConfServiceEntry zeroConfEntry;
|
ZeroConfServiceEntry zeroConfEntry;
|
||||||
foreach (const ZeroConfServiceEntry &entry, m_zeroconfBrowser->serviceEntries()) {
|
foreach (const ZeroConfServiceEntry &entry, m_zeroconfBrowser->serviceEntries()) {
|
||||||
if (entry.name() == shellyId) {
|
if (entry.name() == shellyId && entry.protocol() == QAbstractSocket::IPv4Protocol) {
|
||||||
zeroConfEntry = entry;
|
zeroConfEntry = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2089,10 +2122,11 @@ QHostAddress IntegrationPluginShelly::getIP(Thing *thing) const
|
|||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IntegrationPluginShelly::isGen2(const QString &shellyId) const
|
bool IntegrationPluginShelly::isGen2Plus(const QString &shellyId) const
|
||||||
{
|
{
|
||||||
return shellyId.contains("Plus", Qt::CaseInsensitive)
|
return shellyId.contains("Plus", Qt::CaseInsensitive)
|
||||||
|| shellyId.contains("Pro", Qt::CaseInsensitive)
|
|| shellyId.contains("Pro", Qt::CaseInsensitive)
|
||||||
|
|| shellyId.contains("G3", Qt::CaseInsensitive) // Gen3 devices have API 2
|
||||||
|| QRegExp("^(ShellyPlusPlugS|ShellyPlug(US|IT|UK))-[0-9A-Z]+$", Qt::CaseInsensitive).exactMatch(shellyId) // Plus plug variants need to be matched quite precisely to not also match the v1 Plug
|
|| QRegExp("^(ShellyPlusPlugS|ShellyPlug(US|IT|UK))-[0-9A-Z]+$", Qt::CaseInsensitive).exactMatch(shellyId) // Plus plug variants need to be matched quite precisely to not also match the v1 Plug
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*
|
*
|
||||||
* Copyright 2013 - 2020, nymea GmbH
|
* Copyright 2013 - 2025, nymea GmbH
|
||||||
* Contact: contact@nymea.io
|
* Contact: contact@nymea.io
|
||||||
*
|
*
|
||||||
* This file is part of nymea.
|
* This file is part of nymea.
|
||||||
@ -31,15 +31,15 @@
|
|||||||
#ifndef INTEGRATIONPLUGINSHELLY_H
|
#ifndef INTEGRATIONPLUGINSHELLY_H
|
||||||
#define INTEGRATIONPLUGINSHELLY_H
|
#define INTEGRATIONPLUGINSHELLY_H
|
||||||
|
|
||||||
#include "integrations/integrationplugin.h"
|
#include <integrations/integrationplugin.h>
|
||||||
|
|
||||||
#include "extern-plugininfo.h"
|
|
||||||
|
|
||||||
#include <coap/coap.h>
|
#include <coap/coap.h>
|
||||||
|
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
|
|
||||||
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
class ZeroConfServiceBrowser;
|
class ZeroConfServiceBrowser;
|
||||||
class PluginTimer;
|
class PluginTimer;
|
||||||
|
|
||||||
@ -57,7 +57,6 @@ public:
|
|||||||
explicit IntegrationPluginShelly();
|
explicit IntegrationPluginShelly();
|
||||||
~IntegrationPluginShelly() override;
|
~IntegrationPluginShelly() override;
|
||||||
|
|
||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
void discoverThings(ThingDiscoveryInfo *info) override;
|
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||||
void startPairing(ThingPairingInfo *info) override;
|
void startPairing(ThingPairingInfo *info) override;
|
||||||
@ -73,15 +72,15 @@ private slots:
|
|||||||
|
|
||||||
void updateStatus();
|
void updateStatus();
|
||||||
void fetchStatusGen1(Thing *thing);
|
void fetchStatusGen1(Thing *thing);
|
||||||
void fetchStatusGen2(Thing *thing);
|
void fetchStatusGen2Plus(Thing *thing);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupGen1(ThingSetupInfo *info);
|
void setupGen1(ThingSetupInfo *info);
|
||||||
void setupGen2(ThingSetupInfo *info);
|
void setupGen2Plus(ThingSetupInfo *info);
|
||||||
void setupShellyChild(ThingSetupInfo *info);
|
void setupShellyChild(ThingSetupInfo *info);
|
||||||
|
|
||||||
QHostAddress getIP(Thing *thing) const;
|
QHostAddress getIP(Thing *thing) const;
|
||||||
bool isGen2(const QString &shellyId) const;
|
bool isGen2Plus(const QString &shellyId) const;
|
||||||
|
|
||||||
void handleInputEvent(Thing *thing, const QString &buttonName, const QString &inputEventString, int inputEventCount);
|
void handleInputEvent(Thing *thing, const QString &buttonName, const QString &inputEventString, int inputEventCount);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user