From a9277e5d720389fca2367075ce2dc69b75e719fa Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sun, 19 Mar 2023 00:10:10 +0100 Subject: [PATCH] Shelly: Add support for the Shelly Pro 3EM --- shelly/README.md | 1 + shelly/integrationpluginshelly.cpp | 201 +++++++++------------- shelly/integrationpluginshelly.h | 1 + shelly/integrationpluginshelly.json | 250 ++++++++++++++++++++++++++++ 4 files changed, 333 insertions(+), 120 deletions(-) diff --git a/shelly/README.md b/shelly/README.md index 70876c0b..c6fa266c 100644 --- a/shelly/README.md +++ b/shelly/README.md @@ -17,6 +17,7 @@ The currently supported devices are: * Shelly Button 1 * Shelly EM * Shelly 3EM +* Shelly Pro 3EM * Shelly H+T * Shelly i3 * Shelly Motion diff --git a/shelly/integrationpluginshelly.cpp b/shelly/integrationpluginshelly.cpp index 32314260..c92df2a2 100644 --- a/shelly/integrationpluginshelly.cpp +++ b/shelly/integrationpluginshelly.cpp @@ -61,84 +61,6 @@ static QHash updateStatusMap = { {"unknown", "idle"} }; -static QHash idParamTypeMap = { - {shelly1ThingClassId, shelly1ThingIdParamTypeId}, - {shelly1pmThingClassId, shelly1pmThingIdParamTypeId}, - {shelly1lThingClassId, shelly1lThingIdParamTypeId}, - {shellyPlugThingClassId, shellyPlugThingIdParamTypeId}, - {shellyPlusPlugThingClassId, shellyPlusPlugThingIdParamTypeId}, - {shellyRgbw2ThingClassId, shellyRgbw2ThingIdParamTypeId}, - {shellyDimmerThingClassId, shellyDimmerThingIdParamTypeId}, - {shelly2ThingClassId, shelly2ThingIdParamTypeId}, - {shelly25ThingClassId, shelly25ThingIdParamTypeId}, - {shellyButton1ThingClassId, shellyButton1ThingIdParamTypeId}, - {shellyEmThingClassId, shellyEmThingIdParamTypeId}, - {shellyEm3ThingClassId, shellyEm3ThingIdParamTypeId}, - {shellyHTThingClassId, shellyHTThingIdParamTypeId}, - {shellyI3ThingClassId, shellyI3ThingIdParamTypeId}, - {shellyMotionThingClassId, shellyMotionThingIdParamTypeId}, - {shellyTrvThingClassId, shellyTrvThingIdParamTypeId}, - {shellyFloodThingClassId, shellyFloodThingIdParamTypeId}, - {shellySmokeThingClassId, shellySmokeThingIdParamTypeId}, - {shellyGasThingClassId, shellyGasThingIdParamTypeId} -}; - -static QHash usernameParamTypeMap = { - {shelly1ThingClassId, shelly1ThingUsernameParamTypeId}, - {shelly1pmThingClassId, shelly1pmThingUsernameParamTypeId}, - {shelly1lThingClassId, shelly1lThingUsernameParamTypeId}, - {shellyPlugThingClassId, shellyPlugThingUsernameParamTypeId}, - {shellyPlusPlugThingClassId, shellyPlusPlugThingUsernameParamTypeId}, - {shellyRgbw2ThingClassId, shellyRgbw2ThingUsernameParamTypeId}, - {shellyDimmerThingClassId, shellyDimmerThingUsernameParamTypeId}, - {shelly2ThingClassId, shelly2ThingUsernameParamTypeId}, - {shelly25ThingClassId, shelly25ThingUsernameParamTypeId}, - {shellyButton1ThingClassId, shellyButton1ThingUsernameParamTypeId}, - {shellyEmThingClassId, shellyEmThingUsernameParamTypeId}, - {shellyEm3ThingClassId, shellyEm3ThingUsernameParamTypeId}, - {shellyHTThingClassId, shellyHTThingUsernameParamTypeId}, - {shellyI3ThingClassId, shellyI3ThingUsernameParamTypeId}, - {shellyMotionThingClassId, shellyMotionThingUsernameParamTypeId}, - {shellyTrvThingClassId, shellyTrvThingUsernameParamTypeId}, - {shellyFloodThingClassId, shellyFloodThingUsernameParamTypeId}, - {shellySmokeThingClassId, shellySmokeThingUsernameParamTypeId}, - {shellyGasThingClassId, shellyGasThingUsernameParamTypeId} -}; - -static QHash passwordParamTypeMap = { - {shelly1ThingClassId, shelly1ThingPasswordParamTypeId}, - {shelly1pmThingClassId, shelly1pmThingPasswordParamTypeId}, - {shelly1lThingClassId, shelly1lThingPasswordParamTypeId}, - {shellyPlugThingClassId, shellyPlugThingPasswordParamTypeId}, - {shellyPlusPlugThingClassId, shellyPlusPlugThingPasswordParamTypeId}, - {shellyRgbw2ThingClassId, shellyRgbw2ThingPasswordParamTypeId}, - {shellyDimmerThingClassId, shellyDimmerThingPasswordParamTypeId}, - {shelly2ThingClassId, shelly2ThingPasswordParamTypeId}, - {shelly25ThingClassId, shelly25ThingPasswordParamTypeId}, - {shellyButton1ThingClassId, shellyButton1ThingPasswordParamTypeId}, - {shellyEmThingClassId, shellyEmThingPasswordParamTypeId}, - {shellyEm3ThingClassId, shellyEm3ThingPasswordParamTypeId}, - {shellyHTThingClassId, shellyHTThingPasswordParamTypeId}, - {shellyI3ThingClassId, shellyI3ThingPasswordParamTypeId}, - {shellyMotionThingClassId, shellyMotionThingPasswordParamTypeId}, - {shellyTrvThingClassId, shellyTrvThingPasswordParamTypeId}, - {shellyFloodThingClassId, shellyFloodThingPasswordParamTypeId}, - {shellySmokeThingClassId, shellySmokeThingPasswordParamTypeId}, - {shellyGasThingClassId, shellyGasThingPasswordParamTypeId} -}; - -static QHash rollerModeParamTypeMap = { - {shelly2ThingClassId, shelly2ThingRollerModeParamTypeId}, - {shelly25ThingClassId, shelly25ThingRollerModeParamTypeId} -}; - -static QHash channelParamTypeMap = { - {shellySwitchThingClassId, shellySwitchThingChannelParamTypeId}, - {shellyRollerThingClassId, shellyRollerThingChannelParamTypeId}, - {shellyPowerMeterChannelThingClassId, shellyPowerMeterChannelThingChannelParamTypeId}, - {shellyEmChannelThingClassId, shellyEmChannelThingChannelParamTypeId}, -}; - static QHash colorTemperatureStateTypeMap = { {shellyRgbw2ThingClassId, shellyRgbw2ColorTemperatureStateTypeId}, }; @@ -321,6 +243,8 @@ void IntegrationPluginShelly::discoverThings(ThingDiscoveryInfo *info) 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]+$"); } else if (info->thingClassId() == shellyHTThingClassId) { namePattern = QRegExp("shellyht-[0-9A-Z]+$"); } else if (info->thingClassId() == shellyI3ThingClassId) { @@ -342,15 +266,17 @@ void IntegrationPluginShelly::discoverThings(ThingDiscoveryInfo *info) ThingDescriptor descriptor(info->thingClassId(), entry.name(), entry.hostAddress().toString()); ParamList params; - params << Param(idParamTypeMap.value(info->thingClassId()), entry.name()); - params << Param(usernameParamTypeMap.value(info->thingClassId()), ""); - params << Param(passwordParamTypeMap.value(info->thingClassId()), ""); - if (rollerModeParamTypeMap.contains(info->thingClassId())) { - params << Param(rollerModeParamTypeMap.value(info->thingClassId()), false); + ThingClass thingClass = supportedThings().findById(info->thingClassId()); + + params << Param(thingClass.paramTypes().findByName("id").id(), entry.name()); + params << Param(thingClass.paramTypes().findByName("username").id(), ""); + params << Param(thingClass.paramTypes().findByName("password").id(), ""); + if (!thingClass.paramTypes().findByName("rollerMode").id().isNull()) { + params << Param(thingClass.paramTypes().findByName("rollerMode").id(), false); } descriptor.setParams(params); - Things existingThings = myThings().filterByParam(idParamTypeMap.value(info->thingClassId()), entry.name()); + Things existingThings = myThings().filterByParam(thingClass.paramTypes().findByName("id").id(), entry.name()); if (existingThings.count() == 1) { qCInfo(dcShelly()) << "This existing shelly:" << entry; descriptor.setThingId(existingThings.first()->id()); @@ -368,12 +294,10 @@ void IntegrationPluginShelly::setupThing(ThingSetupInfo *info) { Thing *thing = info->thing(); - if (idParamTypeMap.contains(thing->thingClassId())) { + if (!thing->thingClass().paramTypes().findByName("id").id().isNull()) { - QString shellyId = info->thing()->paramValue(idParamTypeMap.value(info->thing()->thingClassId())).toString(); - if (shellyId.contains("Plus") - || shellyId.startsWith("ShellyPlug") // Plus plug variants don't have Plus in the name, but are camelcased as opposed to 1st gen plugs - ) { + QString shellyId = info->thing()->paramValue("id").toString(); + if (isGen2(shellyId)) { setupGen2(info); } else { setupGen1(info); @@ -393,7 +317,7 @@ void IntegrationPluginShelly::postSetupThing(Thing *thing) } if (thing->parentId().isNull()) { - if (thing->paramValue("id").toString().contains("Plus")) { + if (isGen2(thing->paramValue("id").toString())) { fetchStatusGen2(thing); } else { fetchStatusGen1(thing); @@ -427,13 +351,13 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info) QUrl url; url.setScheme("http"); url.setHost(getIP(info->thing()).toString()); - if (!thing->paramValue(usernameParamTypeMap.value(thing->thingClassId())).toString().isEmpty()) { - url.setUserName(thing->paramValue(usernameParamTypeMap.value(thing->thingClassId())).toString()); - url.setPassword(thing->paramValue(passwordParamTypeMap.value(thing->thingClassId())).toString()); + if (!thing->paramValue("id").toString().isEmpty()) { + url.setUserName(thing->paramValue("username").toString()); + url.setPassword(thing->paramValue("password").toString()); } if (rebootActionTypeMap.contains(action.actionTypeId())) { - if (shellyId.contains("Plus")) { + if (isGen2(shellyId)) { ShellyRpcReply *reply = m_rpcClients.value(thing)->sendRequest("Shelly.Reboot"); connect(reply, &ShellyRpcReply::finished, info, [info](ShellyRpcReply::Status status, const QVariantMap &/*response*/){ info->finish(status == ShellyRpcReply::StatusSuccess ? Thing::ThingErrorNoError : Thing::ThingErrorHardwareFailure); @@ -471,8 +395,8 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info) {shelly25Channel1ActionTypeId, 1}, {shelly25Channel2ActionTypeId, 2} }; - if (channelParamTypeMap.contains(thing->thingClassId())) { - relay = thing->paramValue(channelParamTypeMap.value(thing->thingClassId())).toInt(); + if (!thing->thingClass().paramTypes().findByName("channel").id().isNull()) { + relay = thing->paramValue("channel").toInt(); } else if (actionChannelMap.contains(action.actionTypeId())) { relay = actionChannelMap.value(action.actionTypeId()); } @@ -480,7 +404,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info) ParamTypeId powerParamTypeId = powerActionParamTypesMap.value(action.actionTypeId()); bool on = action.param(powerParamTypeId).value().toBool(); - if (shellyId.contains("Plus")) { + if (isGen2(shellyId)) { QVariantMap params; params.insert("id", relay - 1); params.insert("on", on); @@ -675,7 +599,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info) } if (action.actionTypeId() == shellyRollerOpenActionTypeId) { - if (shellyId.contains("Plus")) { + if (isGen2(shellyId)) { QVariantMap params; int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1; params.insert("id", channelNbr); @@ -698,7 +622,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info) } if (action.actionTypeId() == shellyRollerCloseActionTypeId) { - if (shellyId.contains("Plus")) { + if (isGen2(shellyId)) { QVariantMap params; int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1; params.insert("id", channelNbr); @@ -721,7 +645,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info) } if (action.actionTypeId() == shellyRollerStopActionTypeId) { - if (shellyId.contains("Plus")) { + if (isGen2(shellyId)) { QVariantMap params; int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1; params.insert("id", channelNbr); @@ -744,7 +668,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info) } if (action.actionTypeId() == shellyRollerCalibrateActionTypeId) { - if (shellyId.contains("Plus")) { + if (isGen2(shellyId)) { QVariantMap params; int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1; params.insert("id", channelNbr); @@ -764,7 +688,7 @@ void IntegrationPluginShelly::executeAction(ThingActionInfo *info) } if (action.actionTypeId() == shellyRollerPercentageActionTypeId) { - if (shellyId.contains("Plus")) { + if (isGen2(shellyId)) { QVariantMap params; int channelNbr = info->thing()->paramValue(shellyRollerThingChannelParamTypeId).toInt() - 1; int positionTarget = info->action().paramValue(shellyRollerPercentageActionPercentageParamTypeId).toInt(); @@ -1278,7 +1202,7 @@ void IntegrationPluginShelly::onMulticastMessageReceived(const QHostAddress &sou void IntegrationPluginShelly::updateStatus() { foreach (Thing *thing, myThings().filterByParentId(ThingId())) { - if (thing->paramValue("id").toString().contains("Plus")) { + if (isGen2(thing->paramValue("id").toString())) { fetchStatusGen2(thing); } else { //Skipping sleepy devices, as they won't reply to cyclic requests. @@ -1298,8 +1222,8 @@ void IntegrationPluginShelly::fetchStatusGen1(Thing *thing) url.setScheme("http"); url.setHost(getIP(thing).toString()); url.setPath("/status"); - url.setUserName(thing->paramValue(usernameParamTypeMap.value(thing->thingClassId())).toString()); - url.setPassword(thing->paramValue(passwordParamTypeMap.value(thing->thingClassId())).toString()); + url.setUserName(thing->paramValue("username").toString()); + url.setPassword(thing->paramValue("password").toString()); QNetworkReply *reply = hardwareManager()->networkManager()->get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, &QNetworkReply::deleteLater); connect(reply, &QNetworkReply::finished, thing, [this, thing, reply](){ @@ -1386,7 +1310,7 @@ void IntegrationPluginShelly::setupGen1(ThingSetupInfo *info) bool rollerMode = false; if (info->thing()->thingClassId() == shelly2ThingClassId || info->thing()->thingClassId() == shelly25ThingClassId) { - rollerMode = info->thing()->paramValue(rollerModeParamTypeMap.value(info->thing()->thingClassId())).toBool(); + rollerMode = info->thing()->paramValue("rollerMode").toBool(); } QUrl url; @@ -1394,9 +1318,9 @@ void IntegrationPluginShelly::setupGen1(ThingSetupInfo *info) url.setHost(address.toString()); url.setPort(80); url.setPath("/settings"); - if (!thing->paramValue(usernameParamTypeMap.value(thing->thingClassId())).toString().isEmpty()) { - url.setUserName(info->thing()->paramValue(usernameParamTypeMap.value(info->thing()->thingClassId())).toString()); - url.setPassword(info->thing()->paramValue(passwordParamTypeMap.value(info->thing()->thingClassId())).toString()); + if (!thing->paramValue("username").toString().isEmpty()) { + url.setUserName(info->thing()->paramValue("username").toString()); + url.setPassword(info->thing()->paramValue("password").toString()); } QUrlQuery query; @@ -1531,8 +1455,8 @@ void IntegrationPluginShelly::setupGen1(ThingSetupInfo *info) emit autoThingsAppeared(autoChilds); // Make sure authentication is enalbed if the user wants it - QString username = info->thing()->paramValue(usernameParamTypeMap.value(info->thing()->thingClassId())).toString(); - QString password = info->thing()->paramValue(passwordParamTypeMap.value(info->thing()->thingClassId())).toString(); + QString username = info->thing()->paramValue("username").toString(); + QString password = info->thing()->paramValue("password").toString(); if (!username.isEmpty()) { QUrl url; url.setScheme("http"); @@ -1586,8 +1510,8 @@ void IntegrationPluginShelly::setupGen1(ThingSetupInfo *info) url.setScheme("http"); url.setHost(address); url.setPort(80); - url.setUserName(thing->paramValue(usernameParamTypeMap.value(thing->thingClassId())).toString()); - url.setPassword(thing->paramValue(passwordParamTypeMap.value(thing->thingClassId())).toString()); + url.setUserName(thing->paramValue("username").toString()); + url.setPassword(thing->paramValue("password").toString()); QUrlQuery query; if (settingTypeId == shellyPlugSettingsDefaultStateParamTypeId) { @@ -1683,7 +1607,7 @@ void IntegrationPluginShelly::setupGen2(ThingSetupInfo *info) if (info->thing()->thingClassId() == shelly25ThingClassId) { // Make sure the shelly 2.5 is in the mode we expect it to be (roller/cover or relay/switch) - bool rollerMode = info->thing()->paramValue(rollerModeParamTypeMap.value(info->thing()->thingClassId())).toBool(); + bool rollerMode = info->thing()->paramValue("rollerMode").toBool(); QVariantMap params; if(rollerMode) { params.insert("name", "cover"); @@ -1768,6 +1692,11 @@ void IntegrationPluginShelly::setupGen2(ThingSetupInfo *info) return; } + + if (info->thing()->thingClassId() == shellyPro3EMThingClassId) { + info->finish(Thing::ThingErrorNoError); + return; + } }); }); @@ -1864,11 +1793,35 @@ void IntegrationPluginShelly::setupGen2(ThingSetupInfo *info) t->emitEvent("pressed"); } } + if (notification.contains("em:0")) { + QVariantMap em0 = notification.value("em:0").toMap(); + thing->setStateValue(shellyPro3EMCurrentPowerPhaseAStateTypeId, em0.value("a_act_power").toDouble()); + thing->setStateValue(shellyPro3EMVoltagePhaseAStateTypeId, em0.value("a_voltage").toDouble()); + thing->setStateValue(shellyPro3EMCurrentPhaseAStateTypeId, em0.value("a_current").toDouble()); + thing->setStateValue(shellyPro3EMCurrentPowerPhaseBStateTypeId, em0.value("b_act_power").toDouble()); + thing->setStateValue(shellyPro3EMVoltagePhaseBStateTypeId, em0.value("b_voltage").toDouble()); + thing->setStateValue(shellyPro3EMCurrentPhaseCStateTypeId, em0.value("c_current").toDouble()); + thing->setStateValue(shellyPro3EMCurrentPowerPhaseCStateTypeId, em0.value("c_act_power").toDouble()); + thing->setStateValue(shellyPro3EMVoltagePhaseCStateTypeId, em0.value("c_voltage").toDouble()); + thing->setStateValue(shellyPro3EMCurrentPhaseCStateTypeId, em0.value("c_current").toDouble()); + + thing->setStateValue(shellyPro3EMCurrentPowerStateTypeId, em0.value("total_act_power").toDouble()); + } + if (notification.contains("emdata:0")) { + QVariantMap emdata0 = notification.value("emdata:0").toMap(); + thing->setStateValue(shellyPro3EMEnergyConsumedPhaseAStateTypeId, emdata0.value("a_total_act_energy").toDouble() / 1000); + thing->setStateValue(shellyPro3EMEnergyProducedPhaseAStateTypeId, emdata0.value("a_total_act_ret_energy").toDouble() / 1000); + thing->setStateValue(shellyPro3EMEnergyConsumedPhaseBStateTypeId, emdata0.value("b_total_act_energy").toDouble() / 1000); + thing->setStateValue(shellyPro3EMEnergyProducedPhaseBStateTypeId, emdata0.value("b_total_act_ret_energy").toDouble() / 1000); + thing->setStateValue(shellyPro3EMEnergyConsumedPhaseCStateTypeId, emdata0.value("c_total_act_energy").toDouble() / 1000); + thing->setStateValue(shellyPro3EMEnergyProducedPhaseCStateTypeId, emdata0.value("c_total_act_ret_energy").toDouble() / 1000); thing->setStateValue(shellyPro3EMTotalEnergyConsumedStateTypeId, emdata0.value("total_act").toDouble() / 1000); + thing->setStateValue(shellyPro3EMTotalEnergyProducedStateTypeId, emdata0.value("total_act_ret").toDouble() / 1000); + } }); // Handle thing settings of devices if (info->thing()->thingClassId() == shellyPlusPlugThingClassId) { - connect(info->thing(), &Thing::settingChanged, this, [this, thing, client, shellyId](const ParamTypeId &settingTypeId, const QVariant &value) { + connect(info->thing(), &Thing::settingChanged, this, [thing, client, shellyId](const ParamTypeId &settingTypeId, const QVariant &value) { if (settingTypeId == shellyPlusPlugSettingsDefaultStateParamTypeId) { // this works QString defaultState = value.toString(); QVariantMap config; @@ -1878,7 +1831,7 @@ void IntegrationPluginShelly::setupGen2(ThingSetupInfo *info) params.insert("config", config); ShellyRpcReply *reply3 = client->sendRequest("Switch.SetConfig", params); - connect(reply3, &ShellyRpcReply::finished, thing, [thing](ShellyRpcReply::Status status, const QVariantMap &/*response*/){ + connect(reply3, &ShellyRpcReply::finished, thing, [](ShellyRpcReply::Status status, const QVariantMap &/*response*/){ if (status != ShellyRpcReply::StatusSuccess) { qCWarning(dcShelly) << "Error setting new value"; return; @@ -1895,7 +1848,7 @@ void IntegrationPluginShelly::setupGen2(ThingSetupInfo *info) params.insert("config", config); ShellyRpcReply *reply3 = client->sendRequest("PLUGS_UI.SetConfig", params); - connect(reply3, &ShellyRpcReply::finished, thing, [thing](ShellyRpcReply::Status status, const QVariantMap &/*response*/){ + connect(reply3, &ShellyRpcReply::finished, thing, [](ShellyRpcReply::Status status, const QVariantMap &/*response*/){ if (status != ShellyRpcReply::StatusSuccess) { qCWarning(dcShelly) << "Error setting LED mode"; return; @@ -1968,9 +1921,9 @@ void IntegrationPluginShelly::setupShellyChild(ThingSetupInfo *info) url.setScheme("http"); url.setHost(address); url.setPort(80); - url.setPath(QString("/settings/relay/%0").arg(thing->paramValue(channelParamTypeMap.value(thing->thingClassId())).toInt() - 1)); - url.setUserName(parent->paramValue(usernameParamTypeMap.value(parent->thingClassId())).toString()); - url.setPassword(parent->paramValue(passwordParamTypeMap.value(parent->thingClassId())).toString()); + url.setPath(QString("/settings/relay/%0").arg(thing->paramValue("channel").toInt() - 1)); + url.setUserName(parent->paramValue("username").toString()); + url.setPassword(parent->paramValue("password").toString()); QUrlQuery query; if (paramTypeId == shellySwitchSettingsButtonTypeParamTypeId) { @@ -2026,6 +1979,14 @@ QHostAddress IntegrationPluginShelly::getIP(Thing *thing) const return address; } +bool IntegrationPluginShelly::isGen2(const QString &shellyId) const +{ + return shellyId.contains("Plus") + || shellyId.contains("Pro") + || shellyId.startsWith("ShellyPlug") // Plus plug variants don't have Plus in the name, but are camelcased as opposed to 1st gen plugs + ; +} + void IntegrationPluginShelly::handleInputEvent(Thing *thing, const QString &buttonName, const QString &inputEventString, int inputEventCount) { pluginStorage()->beginGroup(thing->id().toString()); diff --git a/shelly/integrationpluginshelly.h b/shelly/integrationpluginshelly.h index e926591d..2da38343 100644 --- a/shelly/integrationpluginshelly.h +++ b/shelly/integrationpluginshelly.h @@ -76,6 +76,7 @@ private: void setupShellyChild(ThingSetupInfo *info); QHostAddress getIP(Thing *thing) const; + bool isGen2(const QString &shellyId) const; void handleInputEvent(Thing *thing, const QString &buttonName, const QString &inputEventString, int inputEventCount); diff --git a/shelly/integrationpluginshelly.json b/shelly/integrationpluginshelly.json index 65835dbb..d3fe79f2 100644 --- a/shelly/integrationpluginshelly.json +++ b/shelly/integrationpluginshelly.json @@ -2713,6 +2713,256 @@ } ] }, + { + "id": "d7962c7c-82fe-4d2c-8e79-0b9ff2ee5573", + "name": "shellyPro3EM", + "displayName": "Shelly Pro 3EM", + "createMethods": ["discovery"], + "interfaces": [ "energymeter", "wirelessconnectable", "update"], + "paramTypes": [ + { + "id": "0896373b-545e-4765-9ea6-22c4161c916d", + "name":"id", + "displayName": "Shelly ID", + "type": "QString", + "readOnly": true + }, + { + "id": "32e1d2a2-7d03-466e-aa87-0fc507ae2d3a", + "name": "username", + "displayName": "Username (optional)", + "type": "QString" + }, + { + "id": "5713d503-7975-4500-a254-23aa1e3a97f9", + "name": "password", + "displayName": "Password (optional)", + "type": "QString" + } + ], + "stateTypes": [ + { + "id": "a29300d0-cfde-465b-9aca-9f48f15360bc", + "name": "connected", + "displayName": "Connected", + "type": "bool", + "defaultValue": false, + "cached": false + }, + { + "id": "837618f5-cb59-40c1-a7b7-c036d9d8772f", + "name": "signalStrength", + "displayName": "Signal strength", + "type": "uint", + "minValue": 0, + "maxValue": 100, + "unit": "Percentage", + "defaultValue": 0, + "cached": false + }, + { + "id": "c09b5307-b0f8-4cc3-95f2-544513424623", + "name": "totalEnergyConsumed", + "displayName": "Total consumed energy", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0 + }, + { + "id": "8e6ddedc-7764-470d-b319-36b39c9ff62e", + "name": "totalEnergyProduced", + "displayName": "Total returned energy", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0 + }, + { + "id": "eec71598-e307-4917-abb3-53a2b8c14625", + "name": "currentPower", + "displayName": "Current power", + "type": "double", + "unit": "Watt", + "defaultValue": 0, + "cached": false + }, + { + "id": "a2577f97-70c5-406c-90df-63228c6ce30b", + "name": "currentPowerPhaseA", + "displayName": "Power usage (Phase A)", + "type": "double", + "unit": "Watt", + "defaultValue": 0, + "cached": false + }, + { + "id": "821e323f-0f51-4a81-a1c4-c31b8f41fa19", + "name": "currentPhaseA", + "displayName": "Current (Phase A)", + "type": "double", + "unit": "Ampere", + "defaultValue": 0, + "cached": false + }, + { + "id": "134e412f-5a2e-4e65-b4f2-e8f0698e7000", + "name": "voltagePhaseA", + "displayName": "Voltage (Phase A)", + "type": "double", + "unit": "Volt", + "defaultValue": 0, + "cached": false, + "filter": "adaptive" + }, + { + "id": "0cce4d7b-c673-401b-a654-b2e3ab27bd61", + "name": "energyConsumedPhaseA", + "displayName": "Total consumed energy (Phase A)", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0 + }, + { + "id": "9042012f-64e7-4594-a900-599f635f93b1", + "name": "energyProducedPhaseA", + "displayName": "Total returned energy (Phase A)", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0 + }, + { + "id": "0852caaa-6704-4b03-8ba6-c1460c2f023d", + "name": "currentPowerPhaseB", + "displayName": "Power usage (Phase B)", + "type": "double", + "unit": "Watt", + "defaultValue": 0, + "cached": false + }, + { + "id": "f1ea6d35-c74a-43e3-8f06-8387a4595b51", + "name": "currentPhaseB", + "displayName": "Current (Phase B)", + "type": "double", + "unit": "Ampere", + "defaultValue": 0, + "cached": false + }, + { + "id": "37bcd9a2-1f98-45e1-83bc-e9bfb40d0353", + "name": "voltagePhaseB", + "displayName": "Voltage (Phase B)", + "type": "double", + "unit": "Volt", + "defaultValue": 0, + "cached": false, + "filter": "adaptive" + }, + { + "id": "aef8d193-75c6-431f-b013-0a5c08d6225d", + "name": "energyConsumedPhaseB", + "displayName": "Total consumed energy (Phase B)", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0 + }, + { + "id": "74c234fd-22c9-4eab-ab8f-e0ba17b7403a", + "name": "energyProducedPhaseB", + "displayName": "Total returned energy (Phase B)", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0 + }, + { + "id": "0c615174-562b-428a-9879-687cfeb5a9bd", + "name": "currentPowerPhaseC", + "displayName": "Power usage (Phase C)", + "type": "double", + "unit": "Watt", + "defaultValue": 0, + "cached": false + }, + { + "id": "b75373ed-acd5-4980-a0f1-565db2f1351c", + "name": "currentPhaseC", + "displayName": "Current (Phase C)", + "type": "double", + "unit": "Ampere", + "defaultValue": 0, + "cached": false + }, + { + "id": "f6d5128a-305f-488b-b586-b52ba163c8a7", + "name": "voltagePhaseC", + "displayName": "Voltage (Phase C)", + "type": "double", + "unit": "Volt", + "defaultValue": 0, + "cached": false, + "filter": "adaptive" + }, + { + "id": "cf1761b5-09b5-4688-8875-40627fa945bc", + "name": "energyConsumedPhaseC", + "displayName": "Total consumed energy (Phase C)", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0 + }, + { + "id": "6a30cfcf-601d-4fdc-9465-f58b5d0caab8", + "name": "energyProducedPhaseC", + "displayName": "Total returned energy (Phase C)", + "type": "double", + "unit": "KiloWattHour", + "defaultValue": 0 + }, + { + "id": "839f3192-1841-4293-b60f-8e7976510d36", + "name": "updateStatus", + "displayName": "Update status", + "type": "QString", + "possibleValues": ["idle", "available", "updating"], + "defaultValue": "idle" + }, + { + "id": "a8c8e190-ab9f-49f7-9690-f12fb49920cb", + "name": "currentVersion", + "displayName": "Current firmware version", + "type": "QString", + "defaultValue": "" + }, + { + "id": "2acba99c-9c4a-40bb-850a-036312995e8b", + "name": "availableVersion", + "displayName": "Available firmware version", + "type": "QString", + "defaultValue": "" + }, + { + "id": "f8621a0a-5b03-4a78-be48-934472b82900", + "name": "power", + "displayName": "Powered", + "displayNameAction": "Turn on or off", + "type": "bool", + "defaultValue": false, + "writable": true, + "ioType": "digitalOutput" + } + ], + "actionTypes": [ + { + "id": "9b268961-5aa4-4a59-a533-aeaf8c376919", + "name": "performUpdate", + "displayName": "Start firmware update" + }, + { + "id": "b0043a22-21e4-4dfc-a813-2a11908a6c04", + "name": "reset", + "displayName": "Reset data" + } + ] + }, { "id": "bcc7326d-555a-4763-80ce-7354e67cc700", "name": "shellyEm",