diff --git a/garadget/Garadget.pro b/garadget/Garadget.pro
deleted file mode 100644
index b38efde7..00000000
--- a/garadget/Garadget.pro
+++ /dev/null
@@ -1,14 +0,0 @@
-include($$[QT_INSTALL_PREFIX]/include/nymea/plugin.pri)
-
-QT += network
-
-PKGCONFIG += nymea-mqtt
-
-TARGET = $$qtLibraryTarget(nymea_integrationpluginGaradget)
-
-SOURCES += \
- integrationpluginGaradget.cpp
-
-HEADERS += \
- integrationpluginGaradget.h
-
diff --git a/garadget/garadget.pro b/garadget/garadget.pro
new file mode 100644
index 00000000..d2f5044e
--- /dev/null
+++ b/garadget/garadget.pro
@@ -0,0 +1,12 @@
+include(../plugins.pri)
+
+QT += network
+
+PKGCONFIG += nymea-mqtt
+
+SOURCES += \
+ integrationplugingaradget.cpp
+
+HEADERS += \
+ integrationplugingaradget.h
+
diff --git a/garadget/integrationpluginGaradget.cpp b/garadget/integrationpluginGaradget.cpp
deleted file mode 100644
index 77ddd049..00000000
--- a/garadget/integrationpluginGaradget.cpp
+++ /dev/null
@@ -1,406 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* Copyright 2013 - 2020, nymea GmbH
-* Contact: contact@nymea.io
-*
-* This file is part of nymea.
-* This project including source code and documentation is protected by
-* copyright law, and remains the property of nymea GmbH. All rights, including
-* reproduction, publication, editing and translation, are reserved. The use of
-* this project is subject to the terms of a license agreement to be concluded
-* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
-* under https://nymea.io/license
-*
-* GNU Lesser General Public License Usage
-* Alternatively, this project may be redistributed and/or modified under the
-* terms of the GNU Lesser General Public License as published by the Free
-* Software Foundation; version 3. This project is distributed in the hope that
-* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
-* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-* Lesser General Public License for more details.
-*
-* You should have received a copy of the GNU Lesser General Public License
-* along with this project. If not, see .
-*
-* For any further details and any questions please contact us under
-* contact@nymea.io or see our FAQ/Licensing Information on
-* https://nymea.io/license/faq
-*
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#include "integrationpluginGaradget.h"
-#include "plugininfo.h"
-
-#include
-#include
-#include
-#include
-
-#include "hardwaremanager.h"
-#include "network/networkaccessmanager.h"
-#include "network/mqtt/mqttprovider.h"
-#include "network/mqtt/mqttchannel.h"
-
-static QHash sonoff_basicPowerStateTypeIds = {
- {"POWER1", sonoff_basicPowerStateTypeId},
-};
-static QHash> stateMaps = {
- {sonoff_basicThingClassId, sonoff_basicPowerStateTypeIds},
-};
-
-// bee add static id
-
-static QHash sonoff_basicstateStateTypeIds = {
- {"closed", sonoff_basicStateStateTypeId},
-};
-
-static QHash> stateStateMAPS = {
- {sonoff_basicThingClassId, sonoff_basicstateStateTypeIds},
-};
-
-static QHash sonoff_basicClosingOutputStateTypeIds = {
- {"CLOSE1", sonoff_basicClosingOutputStateTypeId},
-};
-
-static QHash> stateClosingOutputMaps = {
- {sonoff_basicThingClassId, sonoff_basicClosingOutputStateTypeIds},
-};
-
-static QHash sonoff_basicOpeningOutputStateTypeIds = {
- {"OPEN1", sonoff_basicOpeningOutputStateTypeId},
-};
-
-static QHash> stateOpeningMaps = {
- {sonoff_basicThingClassId, sonoff_basicOpeningOutputStateTypeIds},
-};
-
-static QHash sonoff_basicMovingStateTypeIds = {
- {"STOP1", sonoff_basicMovingStateTypeId},
-};
-
-static QHash> stateMovingMaps = {
- {sonoff_basicThingClassId, sonoff_basicMovingStateTypeIds},
-};
-
-
-IntegrationPluginGaradget::IntegrationPluginGaradget()
-{
- // Helper maps for parent devices (aka sonoff_*)
- m_ipAddressParamTypeMap[sonoff_basicThingClassId] = sonoff_basicThingIpAddressParamTypeId;
-
-
- // Helper maps for all devices
- m_connectedStateTypeMap[sonoff_basicThingClassId] = sonoff_basicConnectedStateTypeId;
-
- m_signalStrengthStateTypeMap[sonoff_basicThingClassId] = sonoff_basicSignalStrengthStateTypeId;
-
- // bee adders for extendedgaragestate
-
- m_stateStateTypeMap[sonoff_basicThingClassId] = sonoff_basicStateStateTypeId;
-
- m_movingStateTypeMap[sonoff_basicThingClassId] = sonoff_basicMovingStateTypeId;
-
- m_percentageStateTypeMap[sonoff_basicThingClassId] = sonoff_basicPercentageStateTypeId;
-
- m_closingOutputStateTypeMap[sonoff_basicThingClassId] = sonoff_basicClosingOutputStateTypeId;
-
- m_openingOutputStateTypeMap[sonoff_basicThingClassId] = sonoff_basicOpeningOutputStateTypeId;
-
-}
-
-IntegrationPluginGaradget::~IntegrationPluginGaradget()
-{
-}
-
-void IntegrationPluginGaradget::init()
-{
-}
-
-void IntegrationPluginGaradget::setupThing(ThingSetupInfo *info)
-{
- Thing *thing = info->thing();
-
- if (m_ipAddressParamTypeMap.contains(thing->thingClassId())) {
-// ParamTypeId ipAddressParamTypeId = m_ipAddressParamTypeMap.value(thing->thingClassId());
-
-// QHostAddress deviceAddress = QHostAddress(thing->paramValue(ipAddressParamTypeId).toString());
- // ipaddress is defined here but not sure how to get rid of and still have the mqtt channel. Garadget only works with the broker.
- QHostAddress deviceAddress = QHostAddress("192.168.1.174");
- if (deviceAddress.isNull()) {
- qCWarning(dcGaradget) << "Not a valid IP address given for IP address parameter";
- //: Error setting up thing
- return info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("The given IP address is not valid."));
- }
-// MqttChannel *channel = hardwareManager()->mqttProvider()->createChannel(thing->id().toString().remove(QRegExp("[{}-]")), deviceAddress );
- MqttChannel *channel = hardwareManager()->mqttProvider()->createChannel("garage", deviceAddress );
- if (!channel) {
- qCWarning(dcGaradget) << "Failed to create MQTT channel.";
- //: Error setting up thing
- return info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error creating MQTT channel. Please check MQTT server settings."));
- }
-
- qCDebug(dcGaradget) << "initial setup instructions:" << deviceAddress.toString() << channel;
-/*
- QUrl url(QString("http://%1/cm").arg(deviceAddress.toString()));
- QUrlQuery query;
- QMap configItems;
- configItems.insert("MqttHost", channel->serverAddress().toString());
- configItems.insert("MqttPort", QString::number(channel->serverPort()));
- configItems.insert("MqttClient", channel->clientId());
- configItems.insert("MqttUser", channel->username());
- configItems.insert("MqttPassword", channel->password());
- configItems.insert("Topic", "sonoff");
- configItems.insert("FullTopic", channel->topicPrefixList().first() + "/%topic%/");
-
- QStringList configList;
- foreach (const QString &key, configItems.keys()) {
- configList << key + ' ' + configItems.value(key);
- }
- QString fullCommand = "Backlog " + configList.join(';');
- query.addQueryItem("cmnd", fullCommand.toUtf8().toPercentEncoding());
-
- url.setQuery(query);
-
- QNetworkRequest request(url);
- QNetworkReply *reply = hardwareManager()->networkManager()->get(request);
- connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
- connect(reply, &QNetworkReply::finished, info, [this, info, channel, reply](){
- if (reply->error() != QNetworkReply::NoError) {
- qCDebug(dcTasmota) << "Sonoff thing setup call failed:" << reply->error() << reply->errorString() << reply->readAll();
- hardwareManager()->mqttProvider()->releaseChannel(channel);
- //: Error setting up thing
- info->finish(Thing::ThingErrorSetupFailed, QT_TR_NOOP("Could not connect to Tasmota device."));
- return;
- }
-*/
-//BEE mod
-
- m_mqttChannels.insert(info->thing(), channel);
- connect(channel, &MqttChannel::clientConnected, this, &IntegrationPluginGaradget::onClientConnected);
- connect(channel, &MqttChannel::clientDisconnected, this, &IntegrationPluginGaradget::onClientDisconnected);
- connect(channel, &MqttChannel::publishReceived, this, &IntegrationPluginGaradget::onPublishReceived);
- qCDebug(dcGaradget) << "Garadget setup complete";
- info->finish(Thing::ThingErrorNoError);
- foreach (Thing *child, myThings()) {
- if (child->parentId() == info->thing()->id()) {
- // Already have child devices... We're done here
- return;
- }
- }
-// });
-
-// insert to reprogram client Garadget to new device/topic name
- QJsonObject garadgetobj;
- garadgetobj.insert("nme", QString(channel->topicPrefixList().first()));
- QJsonDocument garadgetdoc(garadgetobj);
- QByteArray garadgetdata = garadgetdoc.toJson(QJsonDocument::Compact);
- QString jsonString(garadgetdata);
- qCDebug(dcGaradget) << "Publishing:" << "garadget/" + channel->topicPrefixList().first() << garadgetdata;
- channel->publish("garadget/" + channel->topicPrefixList().first() + "/set-config", garadgetdata);
- return;
- }
-
- if (m_connectedStateTypeMap.contains(thing->thingClassId())) {
- qCDebug(dcGaradget) << "entered connectedStateTypeMap function";
- Thing* parentDevice = myThings().findById(thing->parentId());
- StateTypeId connectedStateTypeId = m_connectedStateTypeMap.value(thing->thingClassId());
- thing->setStateValue(m_connectedStateTypeMap.value(thing->thingClassId()), parentDevice->stateValue(connectedStateTypeId));
- return info->finish(Thing::ThingErrorNoError);
- }
-
- qCWarning(dcGaradget) << "Unhandled ThingClass in setupDevice" << thing->thingClassId();
-}
-
-void IntegrationPluginGaradget::thingRemoved(Thing *thing)
-{
- qCDebug(dcGaradget) << "Device removed" << thing->name();
- if (m_mqttChannels.contains(thing)) {
- qCDebug(dcGaradget) << "Releasing MQTT channel";
- MqttChannel* channel = m_mqttChannels.take(thing);
-
- // insert to reprogram client Garadget to new device/topic name
- QJsonObject garadgetobj;
- garadgetobj.insert("nme","garage" );
- QJsonDocument garadgetdoc(garadgetobj);
- QByteArray garadgetdata = garadgetdoc.toJson(QJsonDocument::Compact);
- QString jsonString(garadgetdata);
- qCDebug(dcGaradget) << "garadget/" + QString(channel->topicPrefixList().first()) + "/set-config" << " topic = " << garadgetdata;
- channel->publish("garadget/" + QString(channel->topicPrefixList().first()) + "/set-config", garadgetdata);
-
- hardwareManager()->mqttProvider()->releaseChannel(channel);
- }
-}
-
-void IntegrationPluginGaradget::executeAction(ThingActionInfo *info)
-{
- Thing *thing = info->thing();
- Action action = info->action();
-
- qCDebug(dcGaradget) << "executeAction function" << (thing->thingClassId());
-
- if (m_closableStopActionTypeMap.contains(thing->thingClassId())) {
- qCDebug(dcGaradget) << "Publishing: m_closableStopActionTypeMap" << "how did I get here?";
- Thing *parentDev = myThings().findById(thing->parentId());
- MqttChannel *channel = m_mqttChannels.value(parentDev);
- if (!channel) {
- qCWarning(dcGaradget()) << "No mqtt channel for this thing.";
- return info->finish(Thing::ThingErrorHardwareNotAvailable);
- }
- ParamTypeId openingChannelParamTypeId = m_openingChannelParamTypeMap.value(thing->thingClassId());
- ParamTypeId closingChannelParamTypeId = m_closingChannelParamTypeMap.value(thing->thingClassId());
- if (action.actionTypeId() == m_closableOpenActionTypeMap.value(thing->thingClassId())) {
- qCDebug(dcGaradget) << "Publishing:" << channel->topicPrefixList().first() + "/sonoff/cmnd/" + thing->paramValue(closingChannelParamTypeId).toString() << "OFF";
- channel->publish(channel->topicPrefixList().first() + "/sonoff/cmnd/" + thing->paramValue(closingChannelParamTypeId).toString().toLower(), "OFF");
- qCDebug(dcGaradget) << "Publishing:" << channel->topicPrefixList().first() + "/sonoff/cmnd/" + thing->paramValue(openingChannelParamTypeId).toString() << "ON";
- channel->publish(channel->topicPrefixList().first() + "/sonoff/cmnd/" + thing->paramValue(openingChannelParamTypeId).toString().toLower(), "ON");
- } else if (action.actionTypeId() == m_closableCloseActionTypeMap.value(thing->thingClassId())) {
- qCDebug(dcGaradget) << "Publishing:" << channel->topicPrefixList().first() + "/sonoff/cmnd/" + thing->paramValue(openingChannelParamTypeId).toString() << "OFF";
- channel->publish(channel->topicPrefixList().first() + "/sonoff/cmnd/" + thing->paramValue(openingChannelParamTypeId).toString().toLower(), "OFF");
- qCDebug(dcGaradget) << "Publishing:" << channel->topicPrefixList().first() + "/sonoff/cmnd/" + thing->paramValue(closingChannelParamTypeId).toString() << "ON";
- channel->publish(channel->topicPrefixList().first() + "/sonoff/cmnd/" + thing->paramValue(closingChannelParamTypeId).toString().toLower(), "ON");
- } else { // Stop
- qCDebug(dcGaradget) << "Publishing:" << channel->topicPrefixList().first() + "/sonoff/cmnd/" + thing->paramValue(openingChannelParamTypeId).toString() << "OFF";
- channel->publish(channel->topicPrefixList().first() + "/sonoff/cmnd/" + thing->paramValue(openingChannelParamTypeId).toString().toLower(), "OFF");
- qCDebug(dcGaradget) << "Publishing:" << channel->topicPrefixList().first() + "/sonoff/cmnd/" + thing->paramValue(closingChannelParamTypeId).toString() << "OFF";
- channel->publish(channel->topicPrefixList().first() + "/sonoff/cmnd/" + thing->paramValue(closingChannelParamTypeId).toString().toLower(), "OFF");
- }
- return info->finish(Thing::ThingErrorNoError);
- }
-
- if (thing->thingClassId() == sonoff_basicThingClassId) {
- MqttChannel *channel = m_mqttChannels.value(thing);
- if (!channel) {
- qCWarning(dcGaradget()) << "No MQTT channel for this thing.";
- info->finish(Thing::ThingErrorHardwareNotAvailable);
- return;
- }
- qCDebug(dcGaradget) << "entered sonoff_basicThingClassId function" << (thing->thingClassId());
-// QString channelName = stateMaps.value(thing->thingClassId()).key(action.actionTypeId());
-// QByteArray payload = action.paramValue(action.actionTypeId()).toBool() ? "ON" : "OFF";
-// qCDebug(dcGaradget) << "Publishing:" << channel->topicPrefixList().first() + "/sonoff/cmnd/" + channelName << payload;
-// channel->publish(channel->topicPrefixList().first() + "/sonoff/cmnd/" + channelName, payload);
-// qCDebug(dcGaradget) << "Publishing:" << "garadget/" + channel->topicPrefixList().first() + "/command" << payload;
-// channel->publish("garadget/" + channel->topicPrefixList().first() + "/command", payload);
-// thing->setStateValue(action.actionTypeId(), action.paramValue(action.actionTypeId()));
-// info->finish(Thing::ThingErrorNoError);
-// return;
-
- if (action.actionTypeId() == sonoff_basicOpenActionTypeId) {
- qCDebug(dcGaradget) << "Publishing:" << "garadget/" + channel->topicPrefixList().first() + "/command" << "open";
- channel->publish("garadget/" + channel->topicPrefixList().first() + "/command", "open");
-// qCDebug(dcGaradget) << "OpenAction stuff:" << action.actionTypeId() << action.paramValue(action.actionTypeId());
-// qCDebug(dcGaradget) << "OpenMapAction stuff:" << action.paramValue(action.actionTypeId()) << stateOpeningMaps.value(thing->thingClassId()).key(action.actionTypeId());
-// thing->setStateValue(action.actionTypeId(), action.paramValue(action.actionTypeId()));
- info->finish(Thing::ThingErrorNoError);
- return;
- }
- if (action.actionTypeId() == sonoff_basicCloseActionTypeId) {
- qCDebug(dcGaradget) << "Publishing:" << "garadget/" + channel->topicPrefixList().first() + "/command" << "close";
- channel->publish("garadget/" + channel->topicPrefixList().first() + "/command", "close");
-// qCDebug(dcGaradget) << "CloseAction stuff:" << thing << thing->thingClassId() << thing->thingClassId();
-// qCDebug(dcGaradget) << "CloseAction newparameter" << thing->paramValue(stateStateMAPS) ;
-// thing->setStateValue(stateStateMAPS.value(thing->thingClassId()).key(action.actionTypeId()),"closed");
-// qCDebug(dcGaradget) << "CloseMapAction stuff:" << stateStateMAPS.value(thing->thingClassId()).key(action.actionTypeId());
-// thing->setStateValue(action.actionTypeId(), action.paramValue(action.actionTypeId()));
- info->finish(Thing::ThingErrorNoError);
- return;
- }
- if (action.actionTypeId() == sonoff_basicStopActionTypeId) {
- qCDebug(dcGaradget) << "Publishing:" << "garadget/" + channel->topicPrefixList().first() + "/command" << "stop";
- channel->publish("garadget/" + channel->topicPrefixList().first() + "/command", "stop");
-// qCDebug(dcGaradget) << "StopAction stuff:" << action.actionTypeId() << action.paramValue(action.actionTypeId());
-// qCDebug(dcGaradget) << "StopMapAction stuff:" << action.paramValue(action.actionTypeId()) << stateMovingMaps.value(thing->thingClassId()).key(action.actionTypeId());
-// thing->setStateValue(action.actionTypeId(), action.paramValue(action.actionTypeId()));
- info->finish(Thing::ThingErrorNoError);
- return;
- }
-
- }
- qCWarning(dcGaradget) << "Unhandled execute action call for device" << thing;
-}
-
-void IntegrationPluginGaradget::onClientConnected(MqttChannel *channel)
-{
- qCDebug(dcGaradget) << "Sonoff thing connected!";
- Thing *dev = m_mqttChannels.key(channel);
- dev->setStateValue(m_connectedStateTypeMap.value(dev->thingClassId()), true);
-
- foreach (Thing *child, myThings()) {
- if (child->parentId() == dev->id()) {
- child->setStateValue(m_connectedStateTypeMap.value(child->thingClassId()), true);
- }
- }
-}
-
-void IntegrationPluginGaradget::onClientDisconnected(MqttChannel *channel)
-{
- qCDebug(dcGaradget) << "Sonoff thing disconnected!";
- Thing *dev = m_mqttChannels.key(channel);
- dev->setStateValue(m_connectedStateTypeMap.value(dev->thingClassId()), false);
-
- foreach (Thing *child, myThings()) {
- if (child->parentId() == dev->id()) {
- child->setStateValue(m_connectedStateTypeMap.value(child->thingClassId()), false);
- }
- }
-}
-
-void IntegrationPluginGaradget::onPublishReceived(MqttChannel *channel, const QString &topic, const QByteArray &payload)
-{
- qCDebug(dcGaradget) << "Publish received from Sonoff thing:" << topic << qUtf8Printable(payload);
- Thing *thing = m_mqttChannels.key(channel);
- if (topic.startsWith(channel->topicPrefixList().first() + "/sonoff/POWER")) {
- QString channelName = topic.split("/").last();
-
- thing->setStateValue(stateMaps.value(thing->thingClassId()).value(channelName), payload == "ON");
-
- // Legacy (deprecated) connected things via params
- foreach (Thing *child, myThings().filterByParentId(thing->id())) {
- if (child->paramValue(m_channelParamTypeMap.value(child->thingClassId())).toString() != channelName) {
- continue;
- }
- if (m_powerStateTypeMap.contains(child->thingClassId())) {
- child->setStateValue(m_powerStateTypeMap.value(child->thingClassId()), payload == "ON");
- }
- }
- }
- if (topic.startsWith(channel->topicPrefixList().first() + "/sonoff/STATE")) {
- QJsonParseError error;
- QJsonDocument jsonDoc = QJsonDocument::fromJson(payload, &error);
- if (error.error != QJsonParseError::NoError) {
- qCWarning(dcGaradget) << "Cannot parse JSON from Garadget device" << error.errorString();
- return;
- }
- QVariantMap dataMap = jsonDoc.toVariant().toMap();
- thing->setStateValue(m_signalStrengthStateTypeMap.value(thing->thingClassId()), dataMap.value("Wifi").toMap().value("RSSI").toInt());
-
- if (m_brightnessStateTypeMap.contains(thing->thingClassId())) {
- thing->setStateValue(m_brightnessStateTypeMap.value(thing->thingClassId()), dataMap.value("Dimmer").toInt());
- }
-
- // Legacy (deprecated) connected things by params
- foreach (Thing *child, myThings().filterByParentId(thing->id())) {
- if (m_powerStateTypeMap.contains(child->thingClassId())) {
- QString childChannel = child->paramValue(m_channelParamTypeMap.value(child->thingClassId())).toString();
- QString valueString = jsonDoc.toVariant().toMap().value(childChannel).toString();
- child->setStateValue(m_powerStateTypeMap.value(child->thingClassId()), valueString == "ON");
- }
- child->setStateValue(m_signalStrengthStateTypeMap.value(child->thingClassId()), dataMap.value("Wifi").toMap().value("RSSI").toInt());
- }
- }
- if (topic.startsWith("garadget/" + channel->topicPrefixList().first() + "/status")) {
- qCDebug(dcGaradget) << "Garadget status received " << payload;
- QJsonParseError error;
- QJsonDocument jsonDoc = QJsonDocument::fromJson(payload, &error);
- if (error.error != QJsonParseError::NoError) {
- qCWarning(dcGaradget) << "Cannot parse JSON from Garadget device" << error.errorString();
- return;
- }
- QVariantMap dataMap = jsonDoc.toVariant().toMap();
-// thing->setStateValue(m_signalStrengthStateTypeMap.value(thing->thingClassId()), dataMap.value("Gstatus").toMap().value("status"));
- thing->setStateValue(m_stateStateTypeMap.value(thing->thingClassId()), dataMap.value("status").toMap().value("state"));
-
- qCDebug(dcGaradget) << "Datamap " << m_signalStrengthStateTypeMap.value(thing->thingClassId());
- qCDebug(dcGaradget) << "Garadget status decode " << jsonDoc;
- }
-}
diff --git a/garadget/integrationplugingaradget.cpp b/garadget/integrationplugingaradget.cpp
new file mode 100644
index 00000000..b5e66a9f
--- /dev/null
+++ b/garadget/integrationplugingaradget.cpp
@@ -0,0 +1,208 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea.
+* This project including source code and documentation is protected by
+* copyright law, and remains the property of nymea GmbH. All rights, including
+* reproduction, publication, editing and translation, are reserved. The use of
+* this project is subject to the terms of a license agreement to be concluded
+* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
+* under https://nymea.io/license
+*
+* GNU Lesser General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the
+* terms of the GNU Lesser General Public License as published by the Free
+* Software Foundation; version 3. This project is distributed in the hope that
+* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
+* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public License
+* along with this project. If not, see .
+*
+* For any further details and any questions please contact us under
+* contact@nymea.io or see our FAQ/Licensing Information on
+* https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "integrationplugingaradget.h"
+#include "plugininfo.h"
+
+#include
+#include
+#include
+#include
+
+#include "hardwaremanager.h"
+#include "network/networkaccessmanager.h"
+#include "network/mqtt/mqttprovider.h"
+#include "network/mqtt/mqttchannel.h"
+
+void IntegrationPluginGaradget::setupThing(ThingSetupInfo *info)
+{
+ Thing *thing = info->thing();
+
+// QHostAddress deviceAddress = QHostAddress(thing->paramValue(garadgetThingIpAddressParamTypeId).toString());
+ // ipaddress is defined here but not sure how to get rid of and still have the mqtt channel. Garadget only works with the broker.
+
+ // Note from Michael: So, how does one configure the garadget device to connect to the MQTT broker? Is there a webinterface
+ // where you go with the browser and configure nymea's address there? If so, we could automate that so that the user
+ // doesn't have to do that.
+ QHostAddress deviceAddress = QHostAddress("192.168.1.174");
+ if (deviceAddress.isNull()) {
+ qCWarning(dcGaradget) << "Not a valid IP address given for IP address parameter";
+ //: Error setting up thing
+ return info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("The given IP address is not valid."));
+ }
+
+ // Note from Michael: Does the clientId really need to be "garage"? Note that client ids must be unique on a single
+ // broker. So setting this to "garage" would prevent multiple garadgets from connecting to the same nymea instance.
+ // Better use something unique like the thingId if the garadget device supports it. Or, maybe, the user could configure
+ // it during setup using a paramType (like the ip address param stuff above).
+ MqttChannel *channel = hardwareManager()->mqttProvider()->createChannel("garage", deviceAddress );
+ if (!channel) {
+ qCWarning(dcGaradget) << "Failed to create MQTT channel.";
+ //: Error setting up thing
+ return info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error creating MQTT channel. Please check MQTT server settings."));
+ }
+
+ qCDebug(dcGaradget) << "initial setup instructions:" << deviceAddress.toString() << channel;
+
+ // Note from Michael: With other devices that use MQTT, normally we do a REST call to their webinterface just to configure
+ // nymea's IP on them with this code below. Could that work with the garadget too?
+/*
+ QUrl url(QString("http://%1/cm").arg(deviceAddress.toString()));
+ QUrlQuery query;
+ QMap configItems;
+ configItems.insert("MqttHost", channel->serverAddress().toString());
+ configItems.insert("MqttPort", QString::number(channel->serverPort()));
+ configItems.insert("MqttClient", channel->clientId());
+ configItems.insert("MqttUser", channel->username());
+ configItems.insert("MqttPassword", channel->password());
+ configItems.insert("Topic", "sonoff");
+ configItems.insert("FullTopic", channel->topicPrefixList().first() + "/%topic%/");
+
+ QStringList configList;
+ foreach (const QString &key, configItems.keys()) {
+ configList << key + ' ' + configItems.value(key);
+ }
+ QString fullCommand = "Backlog " + configList.join(';');
+ query.addQueryItem("cmnd", fullCommand.toUtf8().toPercentEncoding());
+
+ url.setQuery(query);
+
+ QNetworkRequest request(url);
+ QNetworkReply *reply = hardwareManager()->networkManager()->get(request);
+ connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater);
+ connect(reply, &QNetworkReply::finished, info, [this, info, channel, reply](){
+ if (reply->error() != QNetworkReply::NoError) {
+ qCDebug(dcTasmota) << "Sonoff thing setup call failed:" << reply->error() << reply->errorString() << reply->readAll();
+ hardwareManager()->mqttProvider()->releaseChannel(channel);
+ //: Error setting up thing
+ info->finish(Thing::ThingErrorSetupFailed, QT_TR_NOOP("Could not connect to Tasmota device."));
+ return;
+ }
+*/
+//BEE mod
+
+ m_mqttChannels.insert(thing, channel);
+ connect(channel, &MqttChannel::clientConnected, this, &IntegrationPluginGaradget::onClientConnected);
+ connect(channel, &MqttChannel::clientDisconnected, this, &IntegrationPluginGaradget::onClientDisconnected);
+ connect(channel, &MqttChannel::publishReceived, this, &IntegrationPluginGaradget::onPublishReceived);
+ qCDebug(dcGaradget) << "Garadget setup complete";
+
+// insert to reprogram client Garadget to new device/topic name
+ QJsonObject garadgetobj;
+ garadgetobj.insert("nme", QString(channel->topicPrefixList().first()));
+ QJsonDocument garadgetdoc(garadgetobj);
+ QByteArray garadgetdata = garadgetdoc.toJson(QJsonDocument::Compact);
+ QString jsonString(garadgetdata);
+ qCDebug(dcGaradget) << "Publishing:" << "garadget/" + channel->topicPrefixList().first() << garadgetdata;
+ channel->publish("garadget/" + channel->topicPrefixList().first() + "/set-config", garadgetdata);
+
+
+ info->finish(Thing::ThingErrorNoError);
+}
+
+void IntegrationPluginGaradget::thingRemoved(Thing *thing)
+{
+ qCDebug(dcGaradget) << "Device removed" << thing->name();
+ qCDebug(dcGaradget) << "Releasing MQTT channel";
+ MqttChannel* channel = m_mqttChannels.take(thing);
+ hardwareManager()->mqttProvider()->releaseChannel(channel);
+}
+
+void IntegrationPluginGaradget::executeAction(ThingActionInfo *info)
+{
+ Thing *thing = info->thing();
+ Action action = info->action();
+
+ qCDebug(dcGaradget) << "executeAction function" << (thing->thingClassId());
+
+ MqttChannel *channel = m_mqttChannels.value(info->thing());
+ if (!channel) {
+ qCWarning(dcGaradget()) << "No mqtt channel for this thing.";
+ return info->finish(Thing::ThingErrorHardwareNotAvailable);
+ }
+
+
+ if (action.actionTypeId() == garadgetOpenActionTypeId) {
+ qCDebug(dcGaradget) << "Publishing:" << "garadget/" + channel->topicPrefixList().first() + "/command" << "open";
+ channel->publish("garadget/" + channel->topicPrefixList().first() + "/command", "open");
+// qCDebug(dcGaradget) << "OpenAction stuff:" << action.actionTypeId() << action.paramValue(action.actionTypeId());
+// qCDebug(dcGaradget) << "OpenMapAction stuff:" << action.paramValue(action.actionTypeId()) << stateOpeningMaps.value(thing->thingClassId()).key(action.actionTypeId());
+// thing->setStateValue(action.actionTypeId(), action.paramValue(action.actionTypeId()));
+ info->finish(Thing::ThingErrorNoError);
+ return;
+ }
+ if (action.actionTypeId() == garadgetCloseActionTypeId) {
+ qCDebug(dcGaradget) << "Publishing:" << "garadget/" + channel->topicPrefixList().first() + "/command" << "close";
+ channel->publish("garadget/" + channel->topicPrefixList().first() + "/command", "close");
+// qCDebug(dcGaradget) << "CloseAction stuff:" << thing << thing->thingClassId() << thing->thingClassId();
+// qCDebug(dcGaradget) << "CloseAction newparameter" << thing->paramValue(stateStateMAPS) ;
+// thing->setStateValue(stateStateMAPS.value(thing->thingClassId()).key(action.actionTypeId()),"closed");
+// qCDebug(dcGaradget) << "CloseMapAction stuff:" << stateStateMAPS.value(thing->thingClassId()).key(action.actionTypeId());
+// thing->setStateValue(action.actionTypeId(), action.paramValue(action.actionTypeId()));
+ info->finish(Thing::ThingErrorNoError);
+ return;
+ }
+ if (action.actionTypeId() == garadgetStopActionTypeId) {
+ qCDebug(dcGaradget) << "Publishing:" << "garadget/" + channel->topicPrefixList().first() + "/command" << "stop";
+ channel->publish("garadget/" + channel->topicPrefixList().first() + "/command", "stop");
+// qCDebug(dcGaradget) << "StopAction stuff:" << action.actionTypeId() << action.paramValue(action.actionTypeId());
+// qCDebug(dcGaradget) << "StopMapAction stuff:" << action.paramValue(action.actionTypeId()) << stateMovingMaps.value(thing->thingClassId()).key(action.actionTypeId());
+// thing->setStateValue(action.actionTypeId(), action.paramValue(action.actionTypeId()));
+ info->finish(Thing::ThingErrorNoError);
+ return;
+ }
+
+ qCWarning(dcGaradget) << "Unhandled execute action call for garadget thing" << thing;
+}
+
+void IntegrationPluginGaradget::onClientConnected(MqttChannel *channel)
+{
+ qCDebug(dcGaradget) << "Garadget thing connected!";
+ Thing *dev = m_mqttChannels.key(channel);
+ dev->setStateValue(garadgetConnectedStateTypeId, true);
+}
+
+void IntegrationPluginGaradget::onClientDisconnected(MqttChannel *channel)
+{
+ qCDebug(dcGaradget) << "Garadget thing disconnected!";
+ Thing *dev = m_mqttChannels.key(channel);
+ dev->setStateValue(garadgetConnectedStateTypeId, false);
+}
+
+void IntegrationPluginGaradget::onPublishReceived(MqttChannel *channel, const QString &topic, const QByteArray &payload)
+{
+ qCDebug(dcGaradget) << "Publish received from garadget thing:" << topic << qUtf8Printable(payload);
+ Thing *thing = m_mqttChannels.key(channel);
+
+ // TODO: Fill in the "state" state with "open", "closed", "opening", "closing", "intermediate", dending on what we get from the garadget
+ if (topic.startsWith(channel->topicPrefixList().first() + "/sonoff/STATE")) {
+ thing->setStateValue(garadgetStateStateTypeId, "closed");
+ }
+}
diff --git a/garadget/integrationpluginGaradget.h b/garadget/integrationplugingaradget.h
similarity index 56%
rename from garadget/integrationpluginGaradget.h
rename to garadget/integrationplugingaradget.h
index f6ff6123..68302c76 100644
--- a/garadget/integrationpluginGaradget.h
+++ b/garadget/integrationplugingaradget.h
@@ -39,15 +39,14 @@ class IntegrationPluginGaradget: public IntegrationPlugin
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginGaradget.json")
+ Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationplugingaradget.json")
Q_INTERFACES(IntegrationPlugin)
public:
- explicit IntegrationPluginGaradget();
- ~IntegrationPluginGaradget();
+ explicit IntegrationPluginGaradget() = default;
+ ~IntegrationPluginGaradget() = default;
- void init() override;
void setupThing(ThingSetupInfo *info) override;
void thingRemoved(Thing *thing) override;
void executeAction(ThingActionInfo *info) override;
@@ -59,39 +58,6 @@ private slots:
private:
QHash m_mqttChannels;
-
- // Helpers for parent devices (the ones starting with sonoff)
- QHash m_ipAddressParamTypeMap;
- QHash > m_attachedDeviceParamTypeIdMap;
-
- // helpers from bee
- QHash m_stateParamTypeMap;
- QHash m_movingParamTypeMap;
- QHash m_percentageParamTypeMap;
- QHash m_closingOutputParamTypeMap;
- QHash m_openingOutputParamTypeMap;
-
- QHash m_stateStateTypeMap;
- QHash m_movingStateTypeMap;
- QHash m_percentageStateTypeMap;
- QHash m_closingOutputStateTypeMap;
- QHash m_openingOutputStateTypeMap;
-
- // Helpers for child devices (virtual ones, starting with Garadget)
- QHash m_channelParamTypeMap;
- QHash m_openingChannelParamTypeMap;
- QHash m_closingChannelParamTypeMap;
- QHash m_powerStateTypeMap;
-
- QHash m_closableOpenActionTypeMap;
- QHash m_closableCloseActionTypeMap;
- QHash m_closableStopActionTypeMap;
-
- // Helpers for both devices
- QHash m_connectedStateTypeMap;
- QHash m_signalStrengthStateTypeMap;
-
- QHash m_brightnessStateTypeMap;
};
#endif // INTEGRATIONPLUGINGARADGET_H
diff --git a/garadget/integrationpluginGaradget.json b/garadget/integrationplugingaradget.json
similarity index 98%
rename from garadget/integrationpluginGaradget.json
rename to garadget/integrationplugingaradget.json
index 60b780c7..4d3aa93d 100644
--- a/garadget/integrationpluginGaradget.json
+++ b/garadget/integrationplugingaradget.json
@@ -1,6 +1,6 @@
{
"name": "Garadget",
- "displayName": "Sonoff-Garadget",
+ "displayName": "Garadget",
"id": "476781af-ad41-423b-b9bb-f308f2aff339",
"vendors": [
{
@@ -9,7 +9,7 @@
"id": "22d59bee-79cc-4dea-b742-30ac6bdcf2c9",
"thingClasses": [
{
- "name": "sonoff_basic",
+ "name": "garadget",
"displayName": "Garadget",
"id": "e808b8ae-7608-41ce-8444-892f0648a4d3",
"setupMethod": "JustAdd",
diff --git a/nymea-plugins.pro b/nymea-plugins.pro
index a8f3990e..40fd2fd6 100644
--- a/nymea-plugins.pro
+++ b/nymea-plugins.pro
@@ -22,6 +22,7 @@ PLUGIN_DIRS = \
fastcom \
flowercare \
fronius \
+ garadget \
genericelements \
genericthings \
goecharger \