Merge PR #502: New plugin: Garadget

This commit is contained in:
Jenkins nymea 2021-12-15 11:53:09 +01:00
commit cfb6fbf2e1
11 changed files with 915 additions and 0 deletions

16
debian/control vendored
View File

@ -344,6 +344,22 @@ Description: nymea.io plugin for eq-3
This package will install the nymea.io plugin for eq-3
Package: nymea-plugin-garadget
Architecture: any
Multi-Arch: same
Section: libs
Depends: ${shlibs:Depends},
${misc:Depends},
Description: nymea.io plugin for Garadget
The nymea daemon is a plugin based IoT (Internet of Things) server. The
server works like a translator for devices, things and services and
allows them to interact.
With the powerful rule engine you are able to connect any device available
in the system and create individual scenes and behaviors for your environment.
.
This package will install the nymea.io plugin for Garadget Garage Door Opener
Package: nymea-plugin-genericelements
Architecture: any
Depends: ${shlibs:Depends},

View File

@ -0,0 +1 @@
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationplugingaradget.so

55
garadget/README.md Normal file
View File

@ -0,0 +1,55 @@
The nymea plugin for Garadget Garage Door Opener requires Garadget version 1.20 or later
nymea supports the Garadget device via the mqtt only mode using the nymea internal MQTT broker. External MQTT broker is not supported.
Make sure nymeas MQTT broker is enabled in System Settings -> MQTT broker and create a policy (Client ID, username and password) for the garadget device to log in.
Note: The garadget must be configured with the MQTT mode only! otherwise the Particle operation will probably conflict.
See the (https://www.garadget.com/setup-instructions/) for garadget general setup and (https://community.garadget.com/t/mqtt-support/3226/5) for MQTT instructions
Garadget Initial Configuration:
Put your device into listening mode: press and hold “M” button for about 3 seconds until LED starts blinking dark blue.
Connect any WiFi enabled device to PHOTON-XXXX access point.
Open http://192.168.0.1/ in the browser
Confirmed in settings that your Garadget is v1.20 or later.
at a minimum set the following:
select your SSID
enter SSID password
select Only MQTT
enter nymead Broker IP:
enter nymead Broker Port:
enter nymead Broker User ID: (if needed)
enter nymead Broker Password: (if needed)
enter Device Topic ID: (this must be unique across all garadget devices and contain NO /s)
select Save & Connect (The device will reconnect to your WiFi network via dhcp)
nymea configuration:
assuming you have installed the garadget plugin:
select garadget plugin from the ADD things page or Configure things page.
select Garadget (there will be an Internal MQTT client and MQTT client - Ignore them)
Name the thing with your choice of names
Thing Parameter -> enter the Device Topic ID: you entered in the Garadget device above.
nymea operation:
on the Garadget window, the up icon, stop icon, and down icon cause the device to activate the garage door.
on the Garadget detail window (uppre righthand corner), you can tune the Garadget configuration for:
Refection Threshold
Button Press Time
Door Moving Time. (you should adjust to the time it takes your door to open to prevent garadget indicating stopped unnecessarily)
on the Configure Things page for Garadget, you can tune the Garadget configuration for:
sensor scan interval
multi button press delay (garadget manual labels this consecutive button presses delay)
when changed it takes a couple seconds for Garadget to respond and update the values shown in the nymea window.
notes:
DECKO Garage Door opener requires a ~ 3.3 Volt zener diode in series of the connection between the Garadget and the DECKO
Garadget manual indicates the range of mtt is 1000 to 12000 ms but testing on v1.24 shows it currently only accepts 5000 to 60000 ms (nymea will request other values but Garadget may reject)
The plugin will show connected as soon as the Garadget connects to the broker.
The plugin will detect if the device is commanded to change broker connection or topic name and therefore set state to disconnected.
The plugin may take 1 minute to show disconnects (power down or breakage).
Issues: Garadget operating a DECKO garage door opener (may not be issue with other garage door openers)
the Garadget can get confused on the correct relay actions to take if you hit "stop" and then either "open" or "close" when operating a DECKO
It is best to be in direct view of the door if you hit "stop" (the plugin image will be halfway up) to be sure you know where the door will go next.
This confusion is an issue of the Garadget device and not of nymea-plugin.
If nymead reboots rapidly, Garadget may not detect and show disconnected. In this case You may need to push the reset button on the Garadget

12
garadget/garadget.pro Normal file
View File

@ -0,0 +1,12 @@
include(../plugins.pri)
QT += network
PKGCONFIG += nymea-mqtt
SOURCES += \
integrationplugingaradget.cpp
HEADERS += \
integrationplugingaradget.h

128
garadget/garadget.svg Normal file
View File

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="Ebene_1"
data-name="Ebene 1"
viewBox="0 0 482.32801 240.97508"
version="1.1"
sodipodi:docname="frontlogo.svg"
inkscape:export-filename="D:\github\docs\_media\logo-blue.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
width="482.328"
height="240.97508"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata37">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Zeichenfläche 1</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1027"
id="namedview35"
showgrid="false"
inkscape:zoom="1.4214414"
inkscape:cx="452.13125"
inkscape:cy="190.01553"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="Ebene_1"
height="1"
showguides="true"
inkscape:guide-bbox="true">
<sodipodi:guide
position="234.26924,297.58525"
orientation="0,1"
id="guide6233"
inkscape:locked="false" />
<sodipodi:guide
position="233.56573,165.32514"
orientation="1,0"
id="guide6235"
inkscape:locked="false" />
</sodipodi:namedview>
<defs
id="defs12">
<style
id="style10">.cls-1{fill:#010101;}</style>
</defs>
<title
id="title14">Zeichenfläche 1</title>
<polygon
class="cls-1"
points="44.42,115.07 54.16,124.8 129.62,49.35 205.07,124.8 214.81,115.07 129.62,29.87 "
id="polygon16"
transform="matrix(0.85895992,0,0,0.85895992,122.48759,-25.657133)"
style="fill:#1fa3ec;fill-opacity:1" />
<path
class="cls-1"
d="m 233.81738,51.649254 a 45.181292,45.181292 0 0 0 -16.0969,87.407766 v -13.03901 a 33.327645,33.327645 0 0 1 10.18726,-62.025496 v 82.365666 h 11.82788 V 63.992514 a 33.327645,33.327645 0 0 1 10.18726,62.025496 v 12.99606 a 45.181292,45.181292 0 0 0 -16.1055,-87.364816 z"
id="path18"
inkscape:connector-curvature="0"
style="fill:#1fa3ec;fill-opacity:1;stroke-width:0.85895991" />
<polygon
class="cls-1"
points="860.75,74.18 860.75,60.41 772.33,60.41 772.33,74.18 809.65,74.18 809.65,178.31 823.42,178.31 823.42,74.18 "
id="polygon20"
style="fill:#000000;fill-opacity:1"
transform="matrix(0.7,0,0,0.7,-187.838,115.35308)" />
<polygon
class="cls-1"
points="356.75,74.18 356.75,60.41 268.34,60.41 268.34,74.18 305.66,74.18 305.66,178.31 319.43,178.31 319.43,74.18 "
id="polygon22"
style="fill:#000000;fill-opacity:1"
transform="matrix(0.7,0,0,0.7,-187.838,115.35308)" />
<path
class="cls-1"
d="m 118.839,240.17008 h 10.696 c -8.673,-17.759 -30.695,-66.353 -30.695,-82.53 H 88.746 c 0,16.177 -22.015,64.771 -30.688,82.53 h 10.689 c 2.576,-5.418 7.098,-15.113 11.837,-26.18 h 26.418 c 4.76,11.067 9.261,20.762 11.837,26.18 z m -34.223,-35.819 c 3.409,-8.4 6.678,-17.024 9.177,-24.899 2.499,7.875 5.775,16.534 9.184,24.899 z"
id="path24"
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:1;stroke-width:0.69999999" />
<path
class="cls-1"
d="m 471.632,240.17008 h 10.696 c -8.666,-17.759 -30.695,-66.353 -30.695,-82.53 h -10.094 c 0,16.177 -22.015,64.771 -30.688,82.53 h 10.689 c 2.583,-5.418 7.098,-15.113 11.837,-26.18 h 26.418 c 4.767,11.067 9.261,20.762 11.837,26.18 z m -34.223,-35.819 c 3.409,-8.4 6.678,-17.024 9.177,-24.899 2.499,7.875 5.775,16.534 9.184,24.899 z"
id="path26"
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:1;stroke-width:0.69999999" />
<path
class="cls-1"
d="m 315.287,167.27908 c 14.343,0 26.019,14.189 26.019,31.626 0,17.437 -11.676,31.626 -26.019,31.626 -14.343,0 -26.019,-14.189 -26.019,-31.626 0,-17.437 11.669,-31.626 26.019,-31.626 m 0,-9.639 c -19.698,0 -35.658,18.473 -35.658,41.3 0,22.827 15.96,41.3 35.658,41.3 19.698,0 35.658,-18.473 35.658,-41.265 0,-22.792 -15.967,-41.265 -35.658,-41.265 z"
id="path28"
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:1;stroke-width:0.69999999" />
<path
class="cls-1"
d="m 161.462,240.97508 a 25.368,25.368 0 0 1 -25.256,-25.417 h 9.639 a 15.617,15.617 0 1 0 31.234,0 16.002,16.002 0 0 0 -4.347,-10.927 c -2.8,-2.94 -6.3,-4.403 -11.795,-4.9 -6.3,-0.56 -11.165,-2.744 -14.805,-6.671 a 21.371,21.371 0 0 1 -5.6,-14.357 20.944,20.944 0 1 1 41.888,0 h -9.653 a 11.305,11.305 0 1 0 -22.61,0 11.585,11.585 0 0 0 3.052,7.805 c 1.995,2.156 4.641,3.276 8.582,3.619 4.9,0.441 12.11,1.736 17.927,7.861 a 25.746,25.746 0 0 1 7,17.563 25.368,25.368 0 0 1 -25.256,25.424 z"
id="path30"
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:1;stroke-width:0.69999999" />
<path
class="cls-1"
d="m 265.51,157.69608 v 0 -0.056 h -9.667 v 0.259 c -0.301,3.206 -7.917,11.543 -21.896,21.469 -15.533,-11.025 -21.609,-18.83 -21.896,-21.469 v -0.259 h -9.632 v 0.056 0 c 0,0.119 0,0.238 0,0.357 v 82.117 h 9.632 v -66.213 q 7.056,6.937 19.201,15.281 l 2.716,1.827 2.702,-1.848 q 12.138,-8.302 19.173,-15.246 v 66.199 h 9.632 v -82.117 c 0.007,-0.105 0.035,-0.231 0.035,-0.357 z"
id="path32"
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:1;stroke-width:0.69999999" />
</svg>

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -0,0 +1,266 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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 "integrations/thing.h"
#include "plugininfo.h"
#include <QJsonDocument>
#include "network/mqtt/mqttprovider.h"
#include <mqttclient.h>
void IntegrationPluginGaradget::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
pluginStorage()->beginGroup(thing->id().toString());
pluginStorage()->setValue("lastWillAvailable", false);
pluginStorage()->endGroup();
MqttClient *client = nullptr;
client = hardwareManager()->mqttProvider()->createInternalClient(thing->id().toString());
m_mqttClients.insert(thing, client);
connect(client, &MqttClient::connected, this, [this, thing](){
subscribe(thing);
});
connect(client, &MqttClient::subscribeResult, info, [info](quint16 /*packetId*/, const Mqtt::SubscribeReturnCodes returnCodes){
info->finish(returnCodes.first() == Mqtt::SubscribeReturnCodeFailure ? Thing::ThingErrorHardwareFailure : Thing::ThingErrorNoError);
});
connect(client, &MqttClient::publishReceived, this, &IntegrationPluginGaradget::publishReceived);
// In case we're already connected, manually call subscribe now
if (client->isConnected()) {
subscribe(thing);
}
}
void IntegrationPluginGaradget::postSetupThing(Thing *thing)
{
if (!m_pluginTimer) {
int updatetime = 30;
int lwtupdatetime = 300 / updatetime;
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(updatetime);
connect(m_pluginTimer, &PluginTimer::timeout, this, [=](){
m_statuscounter[thing] += 1;
foreach (Thing *thing, myThings()) {
pluginStorage()->beginGroup(thing->id().toString());
bool lastWillAvailable = pluginStorage()->value("lastWillAvailable").toBool();
pluginStorage()->endGroup();
if ((lastWillAvailable == false) && (m_lastActivityTimeStamps[thing].msecsTo(QDateTime::currentDateTime()) > 2000 * updatetime) && (thing->stateValue(garadgetConnectedStateTypeId).toBool() == true)) {
qCDebug(dcGaradget) << "disconnect device" << thing->paramValue(garadgetThingDeviceNameParamTypeId).toString();
thing->setStateValue(garadgetConnectedStateTypeId, false);
}
if ( ((lastWillAvailable == false) && (thing->stateValue(garadgetConnectedStateTypeId).toBool() == true)) || m_statuscounter[thing] > lwtupdatetime) {
m_mqttClients.value(thing)->publish("garadget/" + thing->paramValue(garadgetThingDeviceNameParamTypeId).toString() + "/command", "get-status");
}
}
if (m_statuscounter[thing] > lwtupdatetime) {
m_statuscounter[thing] = 1;
}
});
connect(thing, &Thing::settingChanged, this, [=](const ParamTypeId &settingTypeId){
foreach (Thing *thing, myThings()) {
QJsonObject garadgetobj;
if ((thing->stateValue(garadgetConnectedStateTypeId).toBool() == true) && (settingTypeId == garadgetSettingsRdtParamTypeId)){
garadgetobj.insert("rdt", thing->setting(garadgetSettingsRdtParamTypeId).toInt());
garadgetobj.insert("rlp", thing->setting(garadgetSettingsRlpParamTypeId).toInt());
garadgetobj.insert("rlt",thing->setting(garadgetSettingsRltParamTypeId).toInt());
garadgetobj.insert("mtt", thing->setting(garadgetSettingsMttParamTypeId).toInt());
QJsonDocument garadgetdoc(garadgetobj);
QByteArray garadgetdata = garadgetdoc.toJson(QJsonDocument::Compact);
QString jsonDoc(garadgetdata);
qCDebug(dcGaradget()) << "Changing Configuration" << garadgetdata;
m_mqttClients.value(thing)->publish("garadget/" + thing->paramValue(garadgetThingDeviceNameParamTypeId).toString() + "/set-config", garadgetdata);
}
}
});
}
}
void IntegrationPluginGaradget::thingRemoved(Thing *thing)
{
qCDebug(dcGaradget) << "device " << thing->paramValue(garadgetThingDeviceNameParamTypeId).toString() << "Removed";
m_mqttClients.take(thing)->deleteLater();
if (m_pluginTimer && myThings().isEmpty()) {
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
m_pluginTimer = nullptr;
}
}
void IntegrationPluginGaradget::executeAction(ThingActionInfo *info)
{
Thing *thing = info->thing();
Action action = info->action();
QString name = "garadget/" + thing->paramValue(garadgetThingDeviceNameParamTypeId).toString();
MqttClient *client = m_mqttClients.value(thing);
if (!client) {
qCWarning(dcGaradget) << "No valid MQTT client for thing" << thing->name();
return info->finish(Thing::ThingErrorThingNotFound);
}
QString act = "";
QByteArray actarray;
if (action.actionTypeId() == garadgetOpenActionTypeId) {
act = "open";
}
if (action.actionTypeId() == garadgetCloseActionTypeId) {
act = "close";
}
if (action.actionTypeId() == garadgetStopActionTypeId) {
act = "stop";
}
if (act != "" ) {
name = name + "/command";
}
QString conftype = "";
int actint = 0;
if (action.actionTypeId() == garadgetSrtActionTypeId) {
if (action.paramValue(garadgetSrtActionSrtParamTypeId).toInt() > -1) {
actint = action.paramValue( garadgetSrtActionSrtParamTypeId).toInt();
conftype = "srt";
} else {
name = name + "/command";
act = "get-config";
}
}
if (conftype != "") {
name = name + "/set-config";
QJsonObject garadgetobj;
garadgetobj.insert(conftype, actint);
QJsonDocument garadgetdoc(garadgetobj);
QByteArray garadgetdata = garadgetdoc.toJson(QJsonDocument::Compact);
QString jsonDoc(garadgetdata);
act = garadgetdata;
}
if (act != "" ) {
actarray = act.toUtf8();
qCDebug(dcGaradget) << "Publishing:" << name << act;
quint16 packetId = client->publish(name, actarray, Mqtt::QoS1, false);
connect(client, &MqttClient::published, info, [info, packetId](quint16 packetIdResult){
if (packetId == packetIdResult) {
info->finish(Thing::ThingErrorNoError);
}
});
}
info->finish(Thing::ThingErrorNoError);
return;
}
void IntegrationPluginGaradget::subscribe(Thing *thing)
{
MqttClient *client = m_mqttClients.value(thing);
if (!client) {
// Device might have been removed
return;
}
client->subscribe("garadget/" + thing->paramValue(garadgetThingDeviceNameParamTypeId).toString() + "/#");
}
void IntegrationPluginGaradget::publishReceived(const QString &topic, const QByteArray &payload, bool retained)
{
MqttClient* client = static_cast<MqttClient*>(sender());
Thing *thing = m_mqttClients.key(client);
if (!thing) {
qCWarning(dcGaradget) << "Received a publish message from a client but don't have a matching thing" << retained;
return;
}
if (topic.endsWith("/status")) {
if (thing->stateValue(garadgetConnectedStateTypeId) == false) {
qCDebug(dcGaradget) << "Setting" << thing->paramValue(garadgetThingDeviceNameParamTypeId).toString() << "to Online" ;
thing->setStateValue(garadgetConnectedStateTypeId, true);
}
m_lastActivityTimeStamps[thing] = QDateTime::currentDateTime();
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(payload, &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(dcGaradget) << "Cannot parse JSON from Garadget device" << error.errorString();
return;
}
QJsonObject jo = jsonDoc.object();
thing->setStateValue(garadgetSignalStrengthStateTypeId, (90 + jo.value(QString("signal")).toInt()) * 2.4 );
thing->setStateValue(garadgetSensorlevelStateTypeId, jo.value(QString("sensor")).toInt());
thing->setStateValue(garadgetBrightlevelStateTypeId, jo.value(QString("bright")).toInt());
if (jo.value(QString("status")).toString().contains(QString("stopped"))) {
thing->setStateValue(garadgetStateStateTypeId, "intermediate");
qCDebug(dcGaradget) << thing->paramValue(garadgetThingDeviceNameParamTypeId).toString() << "is" << jo.value(QString("status")).toString() ;
} else {
thing->setStateValue(garadgetStateStateTypeId, jo.value(QString("status")).toString());
}
}
if (topic.endsWith("/config")) {
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(payload, &error);
if (error.error != QJsonParseError::NoError) {
qCWarning(dcGaradget) << "Cannot parse JSON from Garadget device" << error.errorString();
return;
}
QJsonObject jo = jsonDoc.object();
thing->setStateValue(garadgetSrtStateTypeId,jo.value(QString("srt")).toInt());
thing->setSettingValue(garadgetSettingsRltParamTypeId,jo.value(QString("rlt")).toInt());
thing->setSettingValue(garadgetSettingsMttParamTypeId,jo.value(QString("mtt")).toInt());
thing->setSettingValue(garadgetSettingsRdtParamTypeId,jo.value(QString("rdt")).toInt());
thing->setSettingValue(garadgetSettingsRlpParamTypeId,jo.value(QString("rlp")).toInt());
qCDebug(dcGaradget) << thing->paramValue(garadgetThingDeviceNameParamTypeId).toString() << "System Configuration" << "srt =" << thing->stateValue(garadgetSrtStateTypeId).toInt() << "rlt =" << thing->setting(garadgetSettingsRltParamTypeId).toInt()<< "mtt =" << thing->setting(garadgetSettingsMttParamTypeId).toInt() << "rdt =" << thing->setting(garadgetSettingsRdtParamTypeId).toUInt() << "rlp =" << thing->setting(garadgetSettingsRlpParamTypeId).toUInt();
}
if (topic.endsWith("/set-config")){
if ( (payload.contains("mqip")) or (payload.contains("mqpt")) or (payload.contains("nme")) ) {
thing->setStateValue(garadgetConnectedStateTypeId, false);
qCDebug(dcGaradget) << thing->paramValue(garadgetThingDeviceNameParamTypeId).toString() << "Detected change of Broker msg - set connected to false";
}
}
if (topic.endsWith("/LWT")){
if (payload.contains("Online") or payload.contains("Offline")) {
qCDebug(dcGaradget()) << "Setting support for LWT";
pluginStorage()->beginGroup(thing->id().toString());
pluginStorage()->setValue("lastWillAvailable", true);
pluginStorage()->endGroup();
}
if (payload.contains("Online")) {
if (thing->stateValue(garadgetConnectedStateTypeId) == false) {
qCDebug(dcGaradget) << "Setting" << thing->paramValue(garadgetThingDeviceNameParamTypeId).toString() << "to Online" ;
thing->setStateValue(garadgetConnectedStateTypeId, true);
}
}
if (payload.contains("Offline")) {
if (thing->stateValue(garadgetConnectedStateTypeId) == true) {
qCDebug(dcGaradget) << "Setting" << thing->paramValue(garadgetThingDeviceNameParamTypeId).toString() << "to Offline" ;
thing->setStateValue(garadgetConnectedStateTypeId, false);
}
}
}
}

View File

@ -0,0 +1,75 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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 <https://www.gnu.org/licenses/>.
*
* 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
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef INTEGRATIONPLUGINGARADGET_H
#define INTEGRATIONPLUGINGARADGET_H
#include "plugintimer.h"
#include "integrations/integrationplugin.h"
#include "network/networkaccessmanager.h"
#include <QHash>
#include <QDebug>
#include <QTimer>
class MqttClient;
class IntegrationPluginGaradget: public IntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationplugingaradget.json")
Q_INTERFACES(IntegrationPlugin)
public:
explicit IntegrationPluginGaradget() = default;
~IntegrationPluginGaradget() = default;
void setupThing(ThingSetupInfo *info) override;
void thingRemoved(Thing *thing) override;
void executeAction(ThingActionInfo *info) override;
void postSetupThing(Thing *thing) override;
private:
QHash<Thing*, MqttClient*> m_mqttClients;
PluginTimer *m_pluginTimer = nullptr;
QHash<Thing*, QDateTime> m_lastActivityTimeStamps;
QHash<Thing*, int> m_statuscounter;
private slots:
void subscribe(Thing *thing);
void publishReceived(const QString &topic, const QByteArray &payload, bool retained);
};
#endif // INTEGRATIONPLUGINGARADGET_H

View File

@ -0,0 +1,163 @@
{
"name": "garadget",
"displayName": "Garadget",
"id": "476781af-ad41-423b-b9bb-f308f2aff339",
"vendors": [
{
"name": "Garadget",
"displayName": "Garadget",
"id": "22d59bee-79cc-4dea-b742-30ac6bdcf2c9",
"thingClasses": [
{
"name": "garadget",
"displayName": "Garadget",
"id": "e808b8ae-7608-41ce-8444-892f0648a4d3",
"setupMethod": "JustAdd",
"createMethods": ["User"],
"interfaces": ["statefulgaragedoor", "wirelessconnectable"],
"paramTypes": [
{
"id": "54a11a17-fc37-4316-891f-001c55e38220",
"name":"deviceName",
"displayName": "deviceName",
"type": "QString",
"defaultValue": ""
}
],
"settingsTypes": [
{
"id": "13ad28d6-15e5-4e20-862b-51062344b576",
"name": "rdt",
"displayName": "sensor scan interval in mS 200-60,000",
"type": "uint",
"defaultValue": 1000
},
{
"id": "6be83c99-cbf0-4d1d-b838-697e442ebb43",
"name": "rlp",
"displayName": "multi button press delay mS 10-5,000",
"type": "uint",
"defaultValue": 1000
},
{
"id": "c38e89db-b259-4fa0-9f20-03fe3b8a7514" ,
"name": "rlt",
"displayName": "Button Press Time in 10-2000 ms",
"type": "int",
"defaultValue": 300
},
{
"id": "acda9268-4663-46d1-a409-231d648e6fc8" ,
"name": "mtt",
"displayName": "Door Moving Time 5000-60000 ms",
"type": "int",
"defaultValue": 10
}
],
"stateTypes": [
{
"id": "a3d7e6eb-82d0-47ee-b95f-4dde931eb7e2",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "174509b5-fc3e-4f03-8c93-8e044f0a2ce0" ,
"name": "state",
"displayName": "State",
"displayNameEvent": "State changed",
"type": "QString",
"possibleValues": ["open", "closed", "opening", "closing", "intermediate"],
"defaultValue": "closed"
},
{
"id": "024f178c-a920-42d4-887f-1c90a96d5eb3",
"name": "signalStrength",
"displayName": "WIFI Signal Level",
"displayNameEvent": "WIFI Signal Level changed",
"type": "uint",
"unit": "Percentage",
"minValue": 0,
"maxValue": 100,
"defaultValue": 0
},
{
"id": "4aaeefbd-46d9-4111-b262-a001a47ecb22",
"name": "sensorlevel",
"displayName": "Lazer Sensor Level",
"displayNameEvent": "Lazer Sensor Level changed",
"type": "int",
"suggestLogging": true,
"defaultValue": 0
},
{
"id": "bd7fece8-3ff6-421a-bb5e-80323beb8d8d",
"name": "brightlevel",
"displayName": "Ambient Brightness Level",
"displayNameEvent": "Ambient Brightness changed",
"type": "int",
"suggestLogging": true,
"defaultValue": 0
},
{
"id": "656a181e-5c06-4bb6-8c5d-7921db07bef6" ,
"name": "srt",
"displayName": "Reflection Threshold 0-80",
"displayNameEvent": "Reflection Threshold changed",
"displayNameAction": "Set Reflection Threshold value",
"type": "int",
"defaultValue": 25,
"writable": true
}
],
"actionTypes": [
{
"id": "ae3b1c67-7219-4768-a1c7-55c3b9a610cb" ,
"name": "open",
"displayName": "Open"
},
{
"id": "56a9e131-b65e-4622-9a9b-f5b42d0021ef" ,
"name": "close",
"displayName": "Close"
},
{
"id": "12ea84c1-0650-4ac1-a02c-de95965def92" ,
"name": "stop",
"displayName": "Stop"
}
],
"eventTypes": [
{
"id": "a42983a9-9194-458d-9e67-fc4d7ce27e40",
"name": "triggered",
"displayName": "Publish received",
"paramTypes": [
{
"id": "5dfb6ce9-095b-4476-ac94-c7c35653de1f",
"name": "topic",
"displayName": "Topic",
"type": "QString"
},
{
"id": "7573d3c5-a867-4123-a7f9-65eb35eac233",
"name": "data",
"displayName": "Payload",
"type": "QString"
}
]
}
]
}
]
}
]
}

14
garadget/meta.json Normal file
View File

@ -0,0 +1,14 @@
{
"title": "Garadget",
"tagline": "Garadget",
"icon": "garadget.svg",
"stability": "community",
"offline": true,
"technologies": [
"network",
"mqtt"
],
"categories": [
"lock"
]
}

View File

@ -0,0 +1,184 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>garadget</name>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="59"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="62"/>
<source>Ambient Brightness Level</source>
<extracomment>The name of the ParamType (ThingClass: garadget, EventType: brightlevel, ID: {bd7fece8-3ff6-421a-bb5e-80323beb8d8d})
----------
The name of the StateType ({bd7fece8-3ff6-421a-bb5e-80323beb8d8d}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="65"/>
<source>Ambient Brightness changed</source>
<extracomment>The name of the EventType ({bd7fece8-3ff6-421a-bb5e-80323beb8d8d}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="68"/>
<source>Button Press Time in 10-2000 ms</source>
<extracomment>The name of the ParamType (ThingClass: garadget, Type: settings, ID: {c38e89db-b259-4fa0-9f20-03fe3b8a7514})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="71"/>
<source>Close</source>
<extracomment>The name of the ActionType ({56a9e131-b65e-4622-9a9b-f5b42d0021ef}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="74"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="77"/>
<source>Connected</source>
<extracomment>The name of the ParamType (ThingClass: garadget, EventType: connected, ID: {a3d7e6eb-82d0-47ee-b95f-4dde931eb7e2})
----------
The name of the StateType ({a3d7e6eb-82d0-47ee-b95f-4dde931eb7e2}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="80"/>
<source>Connected changed</source>
<extracomment>The name of the EventType ({a3d7e6eb-82d0-47ee-b95f-4dde931eb7e2}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="83"/>
<source>Door Moving Time 5000-60000 ms</source>
<extracomment>The name of the ParamType (ThingClass: garadget, Type: settings, ID: {acda9268-4663-46d1-a409-231d648e6fc8})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="86"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="89"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="92"/>
<source>Garadget</source>
<extracomment>The name of the ThingClass ({e808b8ae-7608-41ce-8444-892f0648a4d3})
----------
The name of the vendor ({22d59bee-79cc-4dea-b742-30ac6bdcf2c9})
----------
The name of the plugin garadget ({476781af-ad41-423b-b9bb-f308f2aff339})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="95"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="98"/>
<source>Lazer Sensor Level</source>
<extracomment>The name of the ParamType (ThingClass: garadget, EventType: sensorlevel, ID: {4aaeefbd-46d9-4111-b262-a001a47ecb22})
----------
The name of the StateType ({4aaeefbd-46d9-4111-b262-a001a47ecb22}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="101"/>
<source>Lazer Sensor Level changed</source>
<extracomment>The name of the EventType ({4aaeefbd-46d9-4111-b262-a001a47ecb22}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="104"/>
<source>Open</source>
<extracomment>The name of the ActionType ({ae3b1c67-7219-4768-a1c7-55c3b9a610cb}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="107"/>
<source>Payload</source>
<extracomment>The name of the ParamType (ThingClass: garadget, EventType: triggered, ID: {7573d3c5-a867-4123-a7f9-65eb35eac233})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="110"/>
<source>Publish received</source>
<extracomment>The name of the EventType ({a42983a9-9194-458d-9e67-fc4d7ce27e40}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="113"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="116"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="119"/>
<source>Reflection Threshold 0-80</source>
<extracomment>The name of the ParamType (ThingClass: garadget, ActionType: srt, ID: {656a181e-5c06-4bb6-8c5d-7921db07bef6})
----------
The name of the ParamType (ThingClass: garadget, EventType: srt, ID: {656a181e-5c06-4bb6-8c5d-7921db07bef6})
----------
The name of the StateType ({656a181e-5c06-4bb6-8c5d-7921db07bef6}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="122"/>
<source>Reflection Threshold changed</source>
<extracomment>The name of the EventType ({656a181e-5c06-4bb6-8c5d-7921db07bef6}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="125"/>
<source>Set Reflection Threshold value</source>
<extracomment>The name of the ActionType ({656a181e-5c06-4bb6-8c5d-7921db07bef6}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="128"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="131"/>
<source>State</source>
<extracomment>The name of the ParamType (ThingClass: garadget, EventType: state, ID: {174509b5-fc3e-4f03-8c93-8e044f0a2ce0})
----------
The name of the StateType ({174509b5-fc3e-4f03-8c93-8e044f0a2ce0}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="134"/>
<source>State changed</source>
<extracomment>The name of the EventType ({174509b5-fc3e-4f03-8c93-8e044f0a2ce0}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="137"/>
<source>Stop</source>
<extracomment>The name of the ActionType ({12ea84c1-0650-4ac1-a02c-de95965def92}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="140"/>
<source>Topic</source>
<extracomment>The name of the ParamType (ThingClass: garadget, EventType: triggered, ID: {5dfb6ce9-095b-4476-ac94-c7c35653de1f})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="143"/>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="146"/>
<source>WIFI Signal Level</source>
<extracomment>The name of the ParamType (ThingClass: garadget, EventType: signalStrength, ID: {024f178c-a920-42d4-887f-1c90a96d5eb3})
----------
The name of the StateType ({024f178c-a920-42d4-887f-1c90a96d5eb3}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="149"/>
<source>WIFI Signal Level changed</source>
<extracomment>The name of the EventType ({024f178c-a920-42d4-887f-1c90a96d5eb3}) of ThingClass garadget</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="152"/>
<source>deviceName</source>
<extracomment>The name of the ParamType (ThingClass: garadget, Type: thing, ID: {54a11a17-fc37-4316-891f-001c55e38220})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="155"/>
<source>multi button press delay mS 10-5,000</source>
<extracomment>The name of the ParamType (ThingClass: garadget, Type: settings, ID: {6be83c99-cbf0-4d1d-b838-697e442ebb43})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-Desktop-Debug/garadget/plugininfo.h" line="158"/>
<source>sensor scan interval in mS 200-60,000</source>
<extracomment>The name of the ParamType (ThingClass: garadget, Type: settings, ID: {13ad28d6-15e5-4e20-862b-51062344b576})</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -22,6 +22,7 @@ PLUGIN_DIRS = \
fastcom \
flowercare \
fronius \
garadget \
genericelements \
genericthings \
goecharger \