diff --git a/doorbird/README.md b/doorbird/README.md
index ab687dc5..05134aea 100644
--- a/doorbird/README.md
+++ b/doorbird/README.md
@@ -2,13 +2,25 @@
This plugin integrates DoorBird video doorbells into nymea. All the communication between nymea and the DoorBird device happens locally and will work without internet connection.
-Currently supported features are:
+## Supported Things
-* Doorbell presses
-* Motion events
-* Enable/disable IR light
-* Switching door relays
+* All video doorbells
+ * Auto discovery
+ * Doorbell presses
+ * Motion events
+ * Enable/disable IR light
+ * Switching door relays
+ * No internet connection required
-The user must have the permission to act as DoorBird API-operator.
-You can check the permissions in the DoorBird app.
+## Requirements
+* The DoorBird device must be in the same local area network as nymea.
+* The router must not block avahi/zeroconf multicast messages.
+* TCP Sockets on port 80 must not be blocked by the router.
+* The user must have the permission to act as DoorBird API-operator.
+ * You can check the permissions in the DoorBird app.
+* The package "nymea-plugin-doorbird" must be installed.
+
+## More
+
+https://www.doorbird.com/
diff --git a/doorbird/deviceplugindoorbird.cpp b/doorbird/deviceplugindoorbird.cpp
deleted file mode 100644
index 70a7c42a..00000000
--- a/doorbird/deviceplugindoorbird.cpp
+++ /dev/null
@@ -1,306 +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 "deviceplugindoorbird.h"
-#include "plugininfo.h"
-
-#include "platform/platformzeroconfcontroller.h"
-#include "network/zeroconf/zeroconfservicebrowser.h"
-#include "network/zeroconf/zeroconfserviceentry.h"
-
-#include
-#include
-#include
-#include
-
-DevicePluginDoorbird::DevicePluginDoorbird()
-{
-}
-
-
-void DevicePluginDoorbird::discoverDevices(DeviceDiscoveryInfo *info)
-{
- if (info->deviceClassId() == doorBirdDeviceClassId) {
- ZeroConfServiceBrowser *serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_axis-video._tcp");
- connect(info, &QObject::destroyed, serviceBrowser, &QObject::deleteLater);
-
- QTimer::singleShot(5000, this, [this, info, serviceBrowser](){
- foreach (const ZeroConfServiceEntry serviceEntry, serviceBrowser->serviceEntries()) {
- if (serviceEntry.hostName().startsWith("bha-")) {
- qCDebug(dcDoorBird) << "Found DoorBird device, name: " << serviceEntry.name() << "\n host address:" << serviceEntry.hostAddress().toString() << "\n text:" << serviceEntry.txt() << serviceEntry.protocol() << serviceEntry.serviceType();
- DeviceDescriptor deviceDescriptor(doorBirdDeviceClassId, serviceEntry.name(), serviceEntry.hostAddress().toString());
- ParamList params;
- QString macAddress;
- if (serviceEntry.txt().length() == 0) {
- qCWarning(dcDoorBird()) << "Discovery failed, service entry missing";
- continue;
- }
-
- if (serviceEntry.txt().first().split("=").length() == 2) {
- macAddress = serviceEntry.txt().first().split("=").last();
- } else {
- qCWarning(dcDoorBird()) << "Could not parse MAC Address" << serviceEntry.txt().first();
- continue;
- }
- if (!myDevices().filterByParam(doorBirdDeviceSerialnumberParamTypeId, macAddress).isEmpty()) {
- Device *existingDevice = myDevices().filterByParam(doorBirdDeviceSerialnumberParamTypeId, macAddress).first();
- deviceDescriptor.setDeviceId(existingDevice->id());
- }
- params.append(Param(doorBirdDeviceSerialnumberParamTypeId, macAddress));
- params.append(Param(doorBirdDeviceAddressParamTypeId, serviceEntry.hostAddress().toString()));
- deviceDescriptor.setParams(params);
- info->addDeviceDescriptor(deviceDescriptor);
- }
- }
- serviceBrowser->deleteLater();
- info->finish(Device::DeviceErrorNoError);
- });
- return;
- } else {
- qCWarning(dcDoorBird()) << "Cannot discover for deviceClassId" << info->deviceClassId();
- info->finish(Device::DeviceErrorDeviceNotFound);
- }
-}
-
-
-void DevicePluginDoorbird::startPairing(DevicePairingInfo *info)
-{
- if (info->deviceClassId() == doorBirdDeviceClassId) {
- info->finish(Device::DeviceErrorNoError, QT_TR_NOOP("Please enter username and password for the DoorBird device"));
- return;
- } else {
- qCWarning(dcDoorBird()) << "StartPairing unhandled deviceClassId" << info->deviceClassId();
- info->finish(Device::DeviceErrorCreationMethodNotSupported);
- }
-}
-
-
-void DevicePluginDoorbird::confirmPairing(DevicePairingInfo *info, const QString &username, const QString &password)
-{
- if (info->deviceClassId() == doorBirdDeviceClassId) {
- QHostAddress address = QHostAddress(info->params().paramValue(doorBirdDeviceAddressParamTypeId).toString());
-
- Doorbird *doorbird = new Doorbird(address, this);
- connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected);
- connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent);
- connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent);
- connect(doorbird, &Doorbird::sessionIdReceived, this, &DevicePluginDoorbird::onSessionIdReceived);
- m_doorbirdConnections.insert(info->deviceId(), doorbird);
- m_pendingPairings.insert(doorbird, info);
- doorbird->getSession(username, password);
- connect(info, &DevicePairingInfo::aborted, this, [this, info]{
- if (m_pendingPairings.values().contains(info)) {
- Doorbird *doorbird = m_pendingPairings.key(info);
- m_pendingPairings.remove(doorbird);
- doorbird->deleteLater();
- }
- m_doorbirdConnections.remove(info->deviceId());
- });
-
- pluginStorage()->beginGroup(info->deviceId().toString());
- pluginStorage()->setValue("username", username);
- pluginStorage()->setValue("password", password);
- pluginStorage()->endGroup();
- } else {
- qCWarning(dcDoorBird()) << "Confirm pairing DeviceClassNotFound" << info->deviceClassId();
- info->finish(Device::DeviceErrorDeviceClassNotFound);
- }
-}
-
-
-void DevicePluginDoorbird::setupDevice(DeviceSetupInfo *info)
-{
- Device *device = info->device();
-
- if (device->deviceClassId() == doorBirdDeviceClassId) {
- QHostAddress address = QHostAddress(device->paramValue(doorBirdDeviceAddressParamTypeId).toString());
-
- if (m_doorbirdConnections.contains(device->id())) {
- info->finish(Device::DeviceErrorNoError);
- } else {
- pluginStorage()->beginGroup(device->id().toString());
- QString username = pluginStorage()->value("username").toString();
- QString password = pluginStorage()->value("password").toString();
- pluginStorage()->endGroup();
-
- qCDebug(dcDoorBird()) << "Device setup" << device->name() << username << password;
- Doorbird *doorbird = new Doorbird(address, this);
- connect(doorbird, &Doorbird::deviceConnected, this, &DevicePluginDoorbird::onDoorBirdConnected);
- connect(doorbird, &Doorbird::eventReveiced, this, &DevicePluginDoorbird::onDoorBirdEvent);
- connect(doorbird, &Doorbird::requestSent, this, &DevicePluginDoorbird::onDoorBirdRequestSent);
- connect(doorbird, &Doorbird::sessionIdReceived, this, &DevicePluginDoorbird::onSessionIdReceived);
- m_doorbirdConnections.insert(device->id(), doorbird);
- m_pendingDeviceSetups.insert(doorbird, info);
- doorbird->getSession(username, password);
- connect(info, &DeviceSetupInfo::aborted, this, [device, doorbird, this] {
- if (!doorbird) {
- doorbird->deleteLater();
- }
- m_doorbirdConnections.remove(device->id());
- m_pendingPairings.remove(doorbird);
- });
- }
- } else {
- qCWarning(dcDoorBird()) << "Unhandled device class" << info->device()->deviceClass();
- info->finish(Device::DeviceErrorDeviceClassNotFound);
- }
-}
-
-
-void DevicePluginDoorbird::postSetupDevice(Device *device)
-{
- if (device->deviceClassId() == doorBirdDeviceClassId) {
- device->setStateValue(doorBirdConnectedStateTypeId, true); //since we checked the connection in the deviceSetup
- Doorbird *doorbird = m_doorbirdConnections.value(device->id());
- doorbird->connectToEventMonitor();
- doorbird->infoRequest();
- doorbird->listFavorites();
- doorbird->listSchedules();
- }
-}
-
-
-void DevicePluginDoorbird::executeAction(DeviceActionInfo *info)
-{
- Device *device = info->device();
- Action action = info->action();
-
- if (device->deviceClassId() == doorBirdDeviceClassId) {
- Doorbird *doorbird = m_doorbirdConnections.value(device->id());
- if (!doorbird) {
- qCWarning(dcDoorBird()) << "Doorbird object not found" << device->name();
- info->finish(Device::DeviceErrorHardwareFailure);
- return;
- }
- if (action.actionTypeId() == doorBirdOpenDoorActionTypeId) {
- int number = action.param(doorBirdOpenDoorActionNumberParamTypeId).value().toInt();
- QUuid requestId = doorbird->openDoor(number);
- m_asyncActions.insert(requestId, info);
- connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
- return;
- } else if (action.actionTypeId() == doorBirdLightOnActionTypeId) {
- QUuid requestId = doorbird->lightOn();
- m_asyncActions.insert(requestId, info);
- connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
- return;
- } else if (action.actionTypeId() == doorBirdRestartActionTypeId) {
- QUuid requestId = doorbird->restart();
- m_asyncActions.insert(requestId, info);
- connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
- return;
- } else {
- qCWarning(dcDoorBird()) << "Unhandled ActionTypeId:" << action.actionTypeId();
- info->finish(Device::DeviceErrorActionTypeNotFound);
- }
- } else {
- qCWarning(dcDoorBird()) << "Execute action, unhandled device class" << device->deviceClass();
- info->finish(Device::DeviceErrorDeviceClassNotFound);
- }
-}
-
-void DevicePluginDoorbird::deviceRemoved(Device *device)
-{
- if (device->deviceClassId() == doorBirdDeviceClassId) {
- Doorbird *doorbirdConnection = m_doorbirdConnections.take(device->id());
- doorbirdConnection->deleteLater();
- }
-}
-
-void DevicePluginDoorbird::onDoorBirdConnected(bool status)
-{
- Doorbird *doorbird = static_cast(sender());
- Device *device = myDevices().findById(m_doorbirdConnections.key(doorbird));
- if (!device)
- return;
-
- device->setStateValue(doorBirdConnectedStateTypeId, status);
-}
-
-void DevicePluginDoorbird::onDoorBirdEvent(Doorbird::EventType eventType, bool status)
-{
- Doorbird *doorbird = static_cast(sender());
- Device *device = myDevices().findById(m_doorbirdConnections.key(doorbird));
- if (!device)
- return;
-
- switch (eventType) {
- case Doorbird::EventType::Rfid:
- break;
- case Doorbird::EventType::Input:
- break;
- case Doorbird::EventType::Motion:
- device->setStateValue(doorBirdIsPresentStateTypeId, status);
- if (status) {
- device->setStateValue(doorBirdLastSeenTimeStateTypeId, QDateTime::currentDateTime().toTime_t());
- }
- break;
- case Doorbird::EventType::Doorbell:
- if (status) {
- emit emitEvent(Event(doorBirdDoorbellPressedEventTypeId ,device->id()));
- }
- break;
- }
-}
-
-void DevicePluginDoorbird::onDoorBirdRequestSent(QUuid requestId, bool success)
-{
- Doorbird *doorbird = static_cast(sender());
-
- if (m_asyncActions.contains(requestId)) {
- DeviceActionInfo* actionInfo = m_asyncActions.take(requestId);
- actionInfo->finish(success ? Device::DeviceErrorNoError : Device::DeviceErrorInvalidParameter);
- }
-
- if (m_pendingPairings.contains(doorbird) && !success) {
- DevicePairingInfo *info = m_pendingPairings.take(doorbird);
- info->finish(Device::DeviceErrorAuthenticationFailure, tr("Wrong username or password"));
- }
-
- if (m_pendingDeviceSetups.contains(doorbird) && !success) {
- DeviceSetupInfo *info = m_pendingDeviceSetups.take(doorbird);
- info->finish(Device::DeviceErrorAuthenticationFailure, tr("Wrong username or password"));
- }
-}
-
-void DevicePluginDoorbird::onSessionIdReceived(const QString &sessionId)
-{
- Q_UNUSED(sessionId);
- Doorbird *doorbird = static_cast(sender());
-
- if (m_pendingPairings.contains(doorbird)) {
- DevicePairingInfo *info = m_pendingPairings.take(doorbird);
- info->finish(Device::DeviceErrorNoError);
- }
-
- if (m_pendingDeviceSetups.contains(doorbird)) {
- DeviceSetupInfo *info = m_pendingDeviceSetups.take(doorbird);
- info->finish(Device::DeviceErrorNoError);
- }
-}
diff --git a/doorbird/doorbird.cpp b/doorbird/doorbird.cpp
index a8bda046..74225d16 100644
--- a/doorbird/doorbird.cpp
+++ b/doorbird/doorbird.cpp
@@ -75,7 +75,7 @@ QUuid Doorbird::getSession(const QString &username, const QString &password)
reply->deleteLater();
if (reply->error() != QNetworkReply::NoError) {
- qCWarning(dcDoorBird) << "Error DoorBird device:" << reply->errorString();
+ qCWarning(dcDoorBird) << "Error DoorBird thing:" << reply->errorString();
emit requestSent(requestId, false);
return;
}
diff --git a/doorbird/doorbird.pro b/doorbird/doorbird.pro
index 55b1f7e0..99666af5 100644
--- a/doorbird/doorbird.pro
+++ b/doorbird/doorbird.pro
@@ -2,12 +2,12 @@ include(../plugins.pri)
QT += network
-TARGET = $$qtLibraryTarget(nymea_deviceplugindoorbird)
+TARGET = $$qtLibraryTarget(nymea_integrationplugindoorbird)
SOURCES += \
- deviceplugindoorbird.cpp \
+ integrationplugindoorbird.cpp \
doorbird.cpp \
HEADERS += \
- deviceplugindoorbird.h \
+ integrationplugindoorbird.h \
doorbird.h \
diff --git a/doorbird/integrationplugindoorbird.cpp b/doorbird/integrationplugindoorbird.cpp
new file mode 100644
index 00000000..85a5643a
--- /dev/null
+++ b/doorbird/integrationplugindoorbird.cpp
@@ -0,0 +1,306 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* 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 "integrationplugindoorbird.h"
+#include "plugininfo.h"
+
+#include "platform/platformzeroconfcontroller.h"
+#include "network/zeroconf/zeroconfservicebrowser.h"
+#include "network/zeroconf/zeroconfserviceentry.h"
+
+#include
+#include
+#include
+#include
+
+IntegrationPluginDoorbird::IntegrationPluginDoorbird()
+{
+}
+
+
+void IntegrationPluginDoorbird::discoverThings(ThingDiscoveryInfo *info)
+{
+ if (info->thingClassId() == doorBirdThingClassId) {
+ ZeroConfServiceBrowser *serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_axis-video._tcp");
+ connect(info, &QObject::destroyed, serviceBrowser, &QObject::deleteLater);
+
+ QTimer::singleShot(5000, this, [this, info, serviceBrowser](){
+ foreach (const ZeroConfServiceEntry serviceEntry, serviceBrowser->serviceEntries()) {
+ if (serviceEntry.hostName().startsWith("bha-")) {
+ qCDebug(dcDoorBird) << "Found DoorBird Thing, name: " << serviceEntry.name() << "\n host address:" << serviceEntry.hostAddress().toString() << "\n text:" << serviceEntry.txt() << serviceEntry.protocol() << serviceEntry.serviceType();
+ ThingDescriptor ThingDescriptor(doorBirdThingClassId, serviceEntry.name(), serviceEntry.hostAddress().toString());
+ ParamList params;
+ QString macAddress;
+ if (serviceEntry.txt().length() == 0) {
+ qCWarning(dcDoorBird()) << "Discovery failed, service entry missing";
+ continue;
+ }
+
+ if (serviceEntry.txt().first().split("=").length() == 2) {
+ macAddress = serviceEntry.txt().first().split("=").last();
+ } else {
+ qCWarning(dcDoorBird()) << "Could not parse MAC Address" << serviceEntry.txt().first();
+ continue;
+ }
+ if (!myThings().filterByParam(doorBirdThingSerialnumberParamTypeId, macAddress).isEmpty()) {
+ Thing *existingThing = myThings().filterByParam(doorBirdThingSerialnumberParamTypeId, macAddress).first();
+ ThingDescriptor.setThingId(existingThing->id());
+ }
+ params.append(Param(doorBirdThingSerialnumberParamTypeId, macAddress));
+ params.append(Param(doorBirdThingAddressParamTypeId, serviceEntry.hostAddress().toString()));
+ ThingDescriptor.setParams(params);
+ info->addThingDescriptor(ThingDescriptor);
+ }
+ }
+ serviceBrowser->deleteLater();
+ info->finish(Thing::ThingErrorNoError);
+ });
+ return;
+ } else {
+ qCWarning(dcDoorBird()) << "Cannot discover for ThingClassId" << info->thingClassId();
+ info->finish(Thing::ThingErrorThingNotFound);
+ }
+}
+
+
+void IntegrationPluginDoorbird::startPairing(ThingPairingInfo *info)
+{
+ if (info->thingClassId() == doorBirdThingClassId) {
+ info->finish(Thing::ThingErrorNoError, QT_TR_NOOP("Please enter username and password for the DoorBird Thing"));
+ return;
+ } else {
+ qCWarning(dcDoorBird()) << "StartPairing unhandled ThingClassId" << info->thingClassId();
+ info->finish(Thing::ThingErrorCreationMethodNotSupported);
+ }
+}
+
+
+void IntegrationPluginDoorbird::confirmPairing(ThingPairingInfo *info, const QString &username, const QString &password)
+{
+ if (info->thingClassId() == doorBirdThingClassId) {
+ QHostAddress address = QHostAddress(info->params().paramValue(doorBirdThingAddressParamTypeId).toString());
+
+ Doorbird *doorbird = new Doorbird(address, this);
+ connect(doorbird, &Doorbird::deviceConnected, this, &IntegrationPluginDoorbird::onDoorBirdConnected);
+ connect(doorbird, &Doorbird::eventReveiced, this, &IntegrationPluginDoorbird::onDoorBirdEvent);
+ connect(doorbird, &Doorbird::requestSent, this, &IntegrationPluginDoorbird::onDoorBirdRequestSent);
+ connect(doorbird, &Doorbird::sessionIdReceived, this, &IntegrationPluginDoorbird::onSessionIdReceived);
+ m_doorbirdConnections.insert(info->thingId(), doorbird);
+ m_pendingPairings.insert(doorbird, info);
+ doorbird->getSession(username, password);
+ connect(info, &ThingPairingInfo::aborted, this, [this, info]{
+ if (m_pendingPairings.values().contains(info)) {
+ Doorbird *doorbird = m_pendingPairings.key(info);
+ m_pendingPairings.remove(doorbird);
+ doorbird->deleteLater();
+ }
+ m_doorbirdConnections.remove(info->thingId());
+ });
+
+ pluginStorage()->beginGroup(info->thingId().toString());
+ pluginStorage()->setValue("username", username);
+ pluginStorage()->setValue("password", password);
+ pluginStorage()->endGroup();
+ } else {
+ qCWarning(dcDoorBird()) << "Confirm pairing ThingClassNotFound" << info->thingClassId();
+ info->finish(Thing::ThingErrorThingClassNotFound);
+ }
+}
+
+
+void IntegrationPluginDoorbird::setupThing(ThingSetupInfo *info)
+{
+ Thing *thing = info->thing();
+
+ if (thing->thingClassId() == doorBirdThingClassId) {
+ QHostAddress address = QHostAddress(thing->paramValue(doorBirdThingAddressParamTypeId).toString());
+
+ if (m_doorbirdConnections.contains(thing->id())) {
+ info->finish(Thing::ThingErrorNoError);
+ } else {
+ pluginStorage()->beginGroup(thing->id().toString());
+ QString username = pluginStorage()->value("username").toString();
+ QString password = pluginStorage()->value("password").toString();
+ pluginStorage()->endGroup();
+
+ qCDebug(dcDoorBird()) << "Thing setup" << thing->name() << username << password;
+ Doorbird *doorbird = new Doorbird(address, this);
+ connect(doorbird, &Doorbird::deviceConnected, this, &IntegrationPluginDoorbird::onDoorBirdConnected);
+ connect(doorbird, &Doorbird::eventReveiced, this, &IntegrationPluginDoorbird::onDoorBirdEvent);
+ connect(doorbird, &Doorbird::requestSent, this, &IntegrationPluginDoorbird::onDoorBirdRequestSent);
+ connect(doorbird, &Doorbird::sessionIdReceived, this, &IntegrationPluginDoorbird::onSessionIdReceived);
+ m_doorbirdConnections.insert(thing->id(), doorbird);
+ m_pendingThingSetups.insert(doorbird, info);
+ doorbird->getSession(username, password);
+ connect(info, &ThingSetupInfo::aborted, this, [thing, doorbird, this] {
+ if (!doorbird) {
+ doorbird->deleteLater();
+ }
+ m_doorbirdConnections.remove(thing->id());
+ m_pendingPairings.remove(doorbird);
+ });
+ }
+ } else {
+ qCWarning(dcDoorBird()) << "Unhandled Thing class" << info->thing()->thingClass();
+ info->finish(Thing::ThingErrorThingClassNotFound);
+ }
+}
+
+
+void IntegrationPluginDoorbird::postSetupThing(Thing *thing)
+{
+ if (thing->thingClassId() == doorBirdThingClassId) {
+ thing->setStateValue(doorBirdConnectedStateTypeId, true); //since we checked the connection in the ThingSetup
+ Doorbird *doorbird = m_doorbirdConnections.value(thing->id());
+ doorbird->connectToEventMonitor();
+ doorbird->infoRequest();
+ doorbird->listFavorites();
+ doorbird->listSchedules();
+ }
+}
+
+
+void IntegrationPluginDoorbird::executeAction(ThingActionInfo *info)
+{
+ Thing *thing = info->thing();
+ Action action = info->action();
+
+ if (thing->thingClassId() == doorBirdThingClassId) {
+ Doorbird *doorbird = m_doorbirdConnections.value(thing->id());
+ if (!doorbird) {
+ qCWarning(dcDoorBird()) << "Doorbird object not found" << thing->name();
+ info->finish(Thing::ThingErrorHardwareFailure);
+ return;
+ }
+ if (action.actionTypeId() == doorBirdOpenDoorActionTypeId) {
+ int number = action.param(doorBirdOpenDoorActionNumberParamTypeId).value().toInt();
+ QUuid requestId = doorbird->openDoor(number);
+ m_asyncActions.insert(requestId, info);
+ connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
+ return;
+ } else if (action.actionTypeId() == doorBirdLightOnActionTypeId) {
+ QUuid requestId = doorbird->lightOn();
+ m_asyncActions.insert(requestId, info);
+ connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
+ return;
+ } else if (action.actionTypeId() == doorBirdRestartActionTypeId) {
+ QUuid requestId = doorbird->restart();
+ m_asyncActions.insert(requestId, info);
+ connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
+ return;
+ } else {
+ qCWarning(dcDoorBird()) << "Unhandled ActionTypeId:" << action.actionTypeId();
+ info->finish(Thing::ThingErrorActionTypeNotFound);
+ }
+ } else {
+ qCWarning(dcDoorBird()) << "Execute action, unhandled Thing class" << thing->thingClass();
+ info->finish(Thing::ThingErrorThingClassNotFound);
+ }
+}
+
+void IntegrationPluginDoorbird::thingRemoved(Thing *thing)
+{
+ if (thing->thingClassId() == doorBirdThingClassId) {
+ Doorbird *doorbirdConnection = m_doorbirdConnections.take(thing->id());
+ doorbirdConnection->deleteLater();
+ }
+}
+
+void IntegrationPluginDoorbird::onDoorBirdConnected(bool status)
+{
+ Doorbird *doorbird = static_cast(sender());
+ Thing *thing = myThings().findById(m_doorbirdConnections.key(doorbird));
+ if (!thing)
+ return;
+
+ thing->setStateValue(doorBirdConnectedStateTypeId, status);
+}
+
+void IntegrationPluginDoorbird::onDoorBirdEvent(Doorbird::EventType eventType, bool status)
+{
+ Doorbird *doorbird = static_cast(sender());
+ Thing *thing = myThings().findById(m_doorbirdConnections.key(doorbird));
+ if (!thing)
+ return;
+
+ switch (eventType) {
+ case Doorbird::EventType::Rfid:
+ break;
+ case Doorbird::EventType::Input:
+ break;
+ case Doorbird::EventType::Motion:
+ thing->setStateValue(doorBirdIsPresentStateTypeId, status);
+ if (status) {
+ thing->setStateValue(doorBirdLastSeenTimeStateTypeId, QDateTime::currentDateTime().toTime_t());
+ }
+ break;
+ case Doorbird::EventType::Doorbell:
+ if (status) {
+ emit emitEvent(Event(doorBirdDoorbellPressedEventTypeId ,thing->id()));
+ }
+ break;
+ }
+}
+
+void IntegrationPluginDoorbird::onDoorBirdRequestSent(QUuid requestId, bool success)
+{
+ Doorbird *doorbird = static_cast(sender());
+
+ if (m_asyncActions.contains(requestId)) {
+ ThingActionInfo* actionInfo = m_asyncActions.take(requestId);
+ actionInfo->finish(success ? Thing::ThingErrorNoError : Thing::ThingErrorInvalidParameter);
+ }
+
+ if (m_pendingPairings.contains(doorbird) && !success) {
+ ThingPairingInfo *info = m_pendingPairings.take(doorbird);
+ info->finish(Thing::ThingErrorAuthenticationFailure, tr("Wrong username or password"));
+ }
+
+ if (m_pendingThingSetups.contains(doorbird) && !success) {
+ ThingSetupInfo *info = m_pendingThingSetups.take(doorbird);
+ info->finish(Thing::ThingErrorAuthenticationFailure, tr("Wrong username or password"));
+ }
+}
+
+void IntegrationPluginDoorbird::onSessionIdReceived(const QString &sessionId)
+{
+ Q_UNUSED(sessionId);
+ Doorbird *doorbird = static_cast(sender());
+
+ if (m_pendingPairings.contains(doorbird)) {
+ ThingPairingInfo *info = m_pendingPairings.take(doorbird);
+ info->finish(Thing::ThingErrorNoError);
+ }
+
+ if (m_pendingThingSetups.contains(doorbird)) {
+ ThingSetupInfo *info = m_pendingThingSetups.take(doorbird);
+ info->finish(Thing::ThingErrorNoError);
+ }
+}
diff --git a/doorbird/deviceplugindoorbird.h b/doorbird/integrationplugindoorbird.h
similarity index 64%
rename from doorbird/deviceplugindoorbird.h
rename to doorbird/integrationplugindoorbird.h
index 594decb0..3168785d 100644
--- a/doorbird/deviceplugindoorbird.h
+++ b/doorbird/integrationplugindoorbird.h
@@ -28,44 +28,43 @@
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-#ifndef DEVICEPLUGINDOORBIRD_H
-#define DEVICEPLUGINDOORBIRD_H
+#ifndef INTEGRATIONPLUGINDOORBIRD_H
+#define INTEGRATIONPLUGINDOORBIRD_H
#include
-#include "devices/deviceplugin.h"
-#include "devices/devicemanager.h"
+#include "integrations/integrationplugin.h"
#include "doorbird.h"
class QNetworkAccessManager;
class QNetworkReply;
-class DevicePluginDoorbird: public DevicePlugin
+class IntegrationPluginDoorbird: public IntegrationPlugin
{
Q_OBJECT
- Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "deviceplugindoorbird.json")
- Q_INTERFACES(DevicePlugin)
+ Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationplugindoorbird.json")
+ Q_INTERFACES(IntegrationPlugin)
public:
- explicit DevicePluginDoorbird();
+ explicit IntegrationPluginDoorbird();
- void discoverDevices(DeviceDiscoveryInfo *info) override;
- void setupDevice(DeviceSetupInfo *info) override;
- void postSetupDevice(Device *device) override;
- void executeAction(DeviceActionInfo *info) override;
+ void discoverThings(ThingDiscoveryInfo *info) override;
+ void setupThing(ThingSetupInfo *info) override;
+ void postSetupThing(Thing *thing) override;
+ void executeAction(ThingActionInfo *info) override;
- void startPairing(DevicePairingInfo *info) override;
- void confirmPairing(DevicePairingInfo *info, const QString &username, const QString &secret) override;
+ void startPairing(ThingPairingInfo *info) override;
+ void confirmPairing(ThingPairingInfo *info, const QString &username, const QString &secret) override;
- void deviceRemoved(Device *device)override;
+ void thingRemoved(Thing *thing)override;
private:
- QHash m_doorbirdConnections;
- QHash m_pendingPairings;
- QHash m_pendingDeviceSetups;
+ QHash m_doorbirdConnections;
+ QHash m_pendingPairings;
+ QHash m_pendingThingSetups;
- QHash m_asyncActions;
+ QHash m_asyncActions;
private slots:
void onDoorBirdConnected(bool status);
@@ -74,4 +73,4 @@ private slots:
void onSessionIdReceived(const QString &sessionId);
};
-#endif // DEVICEPLUGINDOORBIRD_H
+#endif // INTEGRATIONPLUGINDOORBIRD_H
diff --git a/doorbird/deviceplugindoorbird.json b/doorbird/integrationplugindoorbird.json
similarity index 99%
rename from doorbird/deviceplugindoorbird.json
rename to doorbird/integrationplugindoorbird.json
index a5e348f7..ac31c717 100644
--- a/doorbird/deviceplugindoorbird.json
+++ b/doorbird/integrationplugindoorbird.json
@@ -7,7 +7,7 @@
"name": "doorBird",
"displayName": "DoorBird",
"id": "2da07435-571e-4956-a387-6caa51d6e845",
- "deviceClasses": [
+ "thingClasses": [
{
"id": "0485eb61-2a22-42ba-9dd2-a5961485bf08",
"name": "doorBird",