mirror of
https://github.com/nymea/nymea-plugins.git
synced 2026-07-18 00:43:48 +02:00
devices to things
This commit is contained in:
parent
50d05f7d61
commit
05b9b9dfaa
286
lukeroberts/integrationpluginlukeroberts.cpp
Normal file
286
lukeroberts/integrationpluginlukeroberts.cpp
Normal file
@ -0,0 +1,286 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 "integrationpluginlukeroberts.h"
|
||||
#include "plugininfo.h"
|
||||
#include "hardware/bluetoothlowenergy/bluetoothlowenergymanager.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QRgb>
|
||||
|
||||
IntegrationPluginLukeRoberts::IntegrationPluginLukeRoberts()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IntegrationPluginLukeRoberts::init()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void IntegrationPluginLukeRoberts::discoverThings(ThingDiscoveryInfo *info)
|
||||
{
|
||||
if (!hardwareManager()->bluetoothLowEnergyManager()->available())
|
||||
return info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("Bluetooth is not available on this system."));
|
||||
|
||||
if (!hardwareManager()->bluetoothLowEnergyManager()->enabled())
|
||||
return info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("Bluetooth is disabled. Please enable Bluetooth and try again."));
|
||||
|
||||
BluetoothDiscoveryReply *reply = hardwareManager()->bluetoothLowEnergyManager()->discoverDevices();
|
||||
connect(reply, &BluetoothDiscoveryReply::finished, reply, &BluetoothDiscoveryReply::deleteLater);
|
||||
|
||||
connect(reply, &BluetoothDiscoveryReply::finished, info, [this, info, reply](){
|
||||
|
||||
if (reply->error() != BluetoothDiscoveryReply::BluetoothDiscoveryReplyErrorNoError) {
|
||||
qCWarning(dcLukeRoberts()) << "Bluetooth discovery error:" << reply->error();
|
||||
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("An error happened during Bluetooth discovery."));
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (const QBluetoothDeviceInfo &deviceInfo, reply->discoveredDevices()) {
|
||||
if (deviceInfo.serviceUuids().contains(customControlServiceUuid)) {
|
||||
ThingDescriptor descriptor(modelFThingClassId, "Model F", deviceInfo.name() + " (" + deviceInfo.address().toString() + ")");
|
||||
ParamList params;
|
||||
|
||||
foreach (Thing *existingThing, myThings()) {
|
||||
if (existingThing->paramValue(modelFThingMacParamTypeId).toString() == deviceInfo.address().toString()) {
|
||||
descriptor.setThingId(existingThing->id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
params.append(Param(modelFThingMacParamTypeId, deviceInfo.address().toString()));
|
||||
descriptor.setParams(params);
|
||||
info->addThingDescriptor(descriptor);
|
||||
}
|
||||
}
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void IntegrationPluginLukeRoberts::setupThing(ThingSetupInfo *info)
|
||||
{
|
||||
Thing *thing = info->thing();
|
||||
|
||||
qCDebug(dcLukeRoberts()) << "Setup device" << thing->name() << thing->params();
|
||||
|
||||
QBluetoothAddress address = QBluetoothAddress(thing->paramValue(modelFThingMacParamTypeId).toString());
|
||||
QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo(address, thing->name(), 0);
|
||||
|
||||
BluetoothLowEnergyDevice *bluetoothDevice = hardwareManager()->bluetoothLowEnergyManager()->registerDevice(deviceInfo, QLowEnergyController::RandomAddress);
|
||||
|
||||
LukeRoberts *lamp = new LukeRoberts(bluetoothDevice, this);
|
||||
connect(lamp, &LukeRoberts::connectedChanged, this, &IntegrationPluginLukeRoberts::onConnectedChanged);
|
||||
connect(lamp, &LukeRoberts::deviceInformationChanged, this, &IntegrationPluginLukeRoberts::onDeviceInformationChanged);
|
||||
|
||||
m_lamps.insert(lamp, thing);
|
||||
|
||||
connect(lamp, &LukeRoberts::deviceInitializationFinished, info, [this, info, lamp](bool success){
|
||||
Thing *thing = info->thing();
|
||||
|
||||
if (!thing->setupComplete()) {
|
||||
if (success) {
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
} else {
|
||||
m_lamps.take(lamp);
|
||||
|
||||
hardwareManager()->bluetoothLowEnergyManager()->unregisterDevice(lamp->bluetoothDevice());
|
||||
lamp->deleteLater();
|
||||
|
||||
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Error connecting to lamp."));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
lamp->bluetoothDevice()->connectDevice();
|
||||
}
|
||||
|
||||
void IntegrationPluginLukeRoberts::postSetupThing(Thing *thing)
|
||||
{
|
||||
Q_UNUSED(thing)
|
||||
|
||||
if (!m_reconnectTimer) {
|
||||
m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
|
||||
connect(m_reconnectTimer, &PluginTimer::timeout, this, &IntegrationPluginLukeRoberts::onReconnectTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IntegrationPluginLukeRoberts::executeAction(ThingActionInfo *info)
|
||||
{
|
||||
Thing *thing = info->thing();
|
||||
Action action = info->action();
|
||||
|
||||
QPointer<LukeRoberts> lamp = m_lamps.key(thing);
|
||||
if (lamp.isNull())
|
||||
return info->finish(Thing::ThingErrorHardwareFailure);
|
||||
|
||||
if (!lamp->bluetoothDevice()->connected()) {
|
||||
return info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
}
|
||||
|
||||
if (action.actionTypeId() == modelFPowerActionTypeId) {
|
||||
bool power = action.param(modelFPowerActionPowerParamTypeId).value().toBool();
|
||||
if (!power) {
|
||||
lamp->selectScene(0); //Scene 0 is the off scene
|
||||
} else {
|
||||
lamp->selectScene(0xff); // Scene 0xff is the default scene
|
||||
}
|
||||
|
||||
} else if (action.actionTypeId() == modelFBrightnessActionTypeId) {
|
||||
int brightness = action.param(modelFBrightnessActionBrightnessParamTypeId).value().toInt();
|
||||
lamp->modifyBrightness(brightness);
|
||||
|
||||
} else if (action.actionTypeId() == modelFColorActionTypeId) {
|
||||
QColor rgb = QColor::fromRgb(QRgb(action.param(modelFColorActionColorParamTypeId).value().toInt()));
|
||||
lamp->setImmediateLight(0, rgb.saturation(), rgb.hue(), rgb.lightness());
|
||||
|
||||
} else if (action.actionTypeId() == modelFColorTemperatureActionTypeId) {
|
||||
int kelvin = action.param(modelFColorTemperatureActionColorTemperatureParamTypeId).value().toInt();
|
||||
lamp->modifyColorTemperature(kelvin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IntegrationPluginLukeRoberts::thingRemoved(Thing *thing)
|
||||
{
|
||||
if (!m_lamps.values().contains(thing))
|
||||
return;
|
||||
|
||||
LukeRoberts *lamp = m_lamps.key(thing);
|
||||
m_lamps.take(lamp);
|
||||
|
||||
hardwareManager()->bluetoothLowEnergyManager()->unregisterDevice(lamp->bluetoothDevice());
|
||||
lamp->deleteLater();
|
||||
|
||||
if (myThings().isEmpty()) {
|
||||
hardwareManager()->pluginTimerManager()->unregisterTimer(m_reconnectTimer);
|
||||
m_reconnectTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginLukeRoberts::browseThing(BrowseResult *result)
|
||||
{
|
||||
LukeRoberts *lamp = m_lamps.key(result->thing());
|
||||
if (!lamp) {
|
||||
result->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
qDebug(dcLukeRoberts()) << "Browse thing called";
|
||||
m_pendingBrowseResults.insert(lamp, result);
|
||||
lamp->getSceneList();
|
||||
}
|
||||
|
||||
void IntegrationPluginLukeRoberts::browserItem(BrowserItemResult *result)
|
||||
{
|
||||
LukeRoberts *lamp = m_lamps.key(result->thing());
|
||||
if (!lamp) {
|
||||
result->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
qDebug(dcLukeRoberts()) << "Browse item called";
|
||||
|
||||
}
|
||||
|
||||
void IntegrationPluginLukeRoberts::executeBrowserItem(BrowserActionInfo *info)
|
||||
{
|
||||
LukeRoberts *lamp = m_lamps.key(info->thing());
|
||||
if (!lamp) {
|
||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
lamp->selectScene(info->browserAction().itemId().toInt());
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
void IntegrationPluginLukeRoberts::executeBrowserItemAction(BrowserItemActionInfo *info)
|
||||
{
|
||||
LukeRoberts *lamp = m_lamps.key(info->thing());
|
||||
if (!lamp) {
|
||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginLukeRoberts::onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value)
|
||||
{
|
||||
Q_UNUSED(paramTypeId)
|
||||
Q_UNUSED(value)
|
||||
}
|
||||
|
||||
|
||||
void IntegrationPluginLukeRoberts::onReconnectTimeout()
|
||||
{
|
||||
foreach (LukeRoberts *lamp, m_lamps.keys()) {
|
||||
if (!lamp->bluetoothDevice()->connected()) {
|
||||
lamp->bluetoothDevice()->connectDevice();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginLukeRoberts::onConnectedChanged(bool connected)
|
||||
{
|
||||
LukeRoberts *lamp = static_cast<LukeRoberts *>(sender());
|
||||
Thing *thing = m_lamps.value(lamp);
|
||||
thing->setStateValue(modelFConnectedStateTypeId, connected);
|
||||
}
|
||||
|
||||
void IntegrationPluginLukeRoberts::onDeviceInformationChanged(const QString &firmwareRevision, const QString &hardwareRevision, const QString &softwareRevision)
|
||||
{
|
||||
LukeRoberts *lamp = static_cast<LukeRoberts *>(sender());
|
||||
Thing *thing = m_lamps.value(lamp);
|
||||
|
||||
qDebug(dcLukeRoberts()) << thing->name() << "Firmware" << firmwareRevision << "Hardware" << hardwareRevision << "Software" << softwareRevision;
|
||||
//thing->setStateValue(modelFFirmwareRevisionStateTypeId, firmwareRevision);
|
||||
//thing->setStateValue(modelFardwareRevisionStateTypeId, hardwareRevision);
|
||||
//thing->setStateValue(modelFSoftwareRevisionStateTypeId, softwareRevision);
|
||||
}
|
||||
|
||||
void IntegrationPluginLukeRoberts::onSceneListReceived(QList<LukeRoberts::Scene> scenes)
|
||||
{
|
||||
LukeRoberts *lamp = static_cast<LukeRoberts *>(sender());
|
||||
if (m_pendingBrowseResults.contains(lamp)) {
|
||||
BrowseResult *result = m_pendingBrowseResults.value(lamp);
|
||||
foreach (LukeRoberts::Scene scene, scenes) {
|
||||
BrowserItem item;
|
||||
item.setId(QString::number(scene.id));
|
||||
item.setDisplayName(scene.name);
|
||||
item.setBrowsable(false);
|
||||
item.setExecutable(true);
|
||||
item.setIcon(BrowserItem::BrowserIconApplication);
|
||||
result->addItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginLukeRoberts::onStatusCodeReceived(LukeRoberts::StatusCodes statusCode)
|
||||
{
|
||||
qDebug(dcLukeRoberts()) << "Status code received" << statusCode;
|
||||
}
|
||||
82
lukeroberts/integrationpluginlukeroberts.h
Normal file
82
lukeroberts/integrationpluginlukeroberts.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* 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 Licene 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 INTEGRATIONPLUGINLUKEROBERTS_H
|
||||
#define INTEGRATIONPLUGINLUKEROBERTS_H
|
||||
|
||||
#include "plugintimer.h"
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "hardware/bluetoothlowenergy/bluetoothlowenergydevice.h"
|
||||
|
||||
#include "lukeroberts.h"
|
||||
|
||||
class IntegrationPluginLukeRoberts : public IntegrationPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginlukeroberts.json")
|
||||
Q_INTERFACES(IntegrationPlugin)
|
||||
|
||||
public:
|
||||
explicit IntegrationPluginLukeRoberts();
|
||||
|
||||
void init() override;
|
||||
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||
void setupThing(ThingSetupInfo *info) override;
|
||||
void postSetupThing(Thing *thing) override;
|
||||
void executeAction(ThingActionInfo *info) override;
|
||||
|
||||
void thingRemoved(Thing *thing) override;
|
||||
|
||||
void browseThing(BrowseResult *result) override;
|
||||
void browserItem(BrowserItemResult *result) override;
|
||||
void executeBrowserItem(BrowserActionInfo *info) override;
|
||||
void executeBrowserItemAction(BrowserItemActionInfo *info) override;
|
||||
private:
|
||||
QHash<LukeRoberts *, Thing *> m_lamps;
|
||||
PluginTimer *m_reconnectTimer = nullptr;
|
||||
bool m_autoSymbolMode = true;
|
||||
|
||||
QHash<LukeRoberts *, BrowseResult *> m_pendingBrowseResults;
|
||||
QHash<int, BrowserActionInfo*> m_pendingBrowserActions;
|
||||
QHash<int, BrowserItemActionInfo*> m_pendingBrowserItemActions;
|
||||
|
||||
private slots:
|
||||
void onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value);
|
||||
void onReconnectTimeout();
|
||||
|
||||
void onConnectedChanged(bool connected);
|
||||
void onStatusCodeReceived(LukeRoberts::StatusCodes statusCode);
|
||||
void onDeviceInformationChanged(const QString &firmwareRevision, const QString &hardwareRevision, const QString &softwareRevision);
|
||||
|
||||
void onSceneListReceived(QList<LukeRoberts::Scene> scenes);
|
||||
};
|
||||
|
||||
#endif // INTEGRATIONPLUGINLUKEROBERTS_H
|
||||
98
lukeroberts/integrationpluginlukeroberts.json
Normal file
98
lukeroberts/integrationpluginlukeroberts.json
Normal file
@ -0,0 +1,98 @@
|
||||
{
|
||||
"displayName": "Luke Roberts",
|
||||
"id": "40f368ee-1815-46fd-9d74-4b8e5b5f21e7",
|
||||
"name": "LukeRoberts",
|
||||
"vendors": [
|
||||
{
|
||||
"displayName": "Luke Roberts",
|
||||
"name": "LukeRoberts",
|
||||
"id": "4e942850-9553-493c-8a4a-5a468e124099",
|
||||
"thingClasses": [
|
||||
{
|
||||
"id": "5de74ba9-4a46-4235-94b4-8aefc1e2b27f",
|
||||
"name": "modelF",
|
||||
"displayName": "Model F",
|
||||
"createMethods": ["discovery"],
|
||||
"interfaces": ["colorlight", "connectable"],
|
||||
"browsable": true,
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "5cde31de-8c5d-4c10-890e-1dd3b5efcad1",
|
||||
"name": "mac",
|
||||
"displayName": "Mac address",
|
||||
"type": "QString",
|
||||
"inputType": "MacAddress"
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "09b9e571-74a8-4d47-a432-ae9743915d8d",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"id": "ac3a55e1-48af-402d-b9ef-6020d4a1cb4f",
|
||||
"name": "power",
|
||||
"displayName": "power",
|
||||
"displayNameEvent": "power changed",
|
||||
"displayNameAction": "Set power",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"writable": true
|
||||
},
|
||||
{
|
||||
"id": "ce156b88-b142-4516-8110-5fe044ed0ba8",
|
||||
"name": "colorTemperature",
|
||||
"displayName": "color temperature",
|
||||
"displayNameEvent": "color temperature changed",
|
||||
"displayNameAction": "Set color temperature",
|
||||
"type": "int",
|
||||
"unit": "Mired",
|
||||
"defaultValue": 170,
|
||||
"minValue": 153,
|
||||
"maxValue": 500,
|
||||
"writable": true
|
||||
},
|
||||
{
|
||||
"id": "01844169-43de-42df-9908-f015bb3ea7c2",
|
||||
"name": "color",
|
||||
"displayName": "color",
|
||||
"displayNameEvent": "color changed",
|
||||
"displayNameAction": "Set color",
|
||||
"type": "QColor",
|
||||
"defaultValue": "#000000",
|
||||
"writable": true
|
||||
},
|
||||
{
|
||||
"id": "70c92741-9c7f-47df-85c1-bdd05cef90b6",
|
||||
"name": "brightness",
|
||||
"displayName": "brightness",
|
||||
"displayNameEvent": "brightness changed",
|
||||
"displayNameAction": "Set brigtness",
|
||||
"type": "int",
|
||||
"unit": "Percentage",
|
||||
"defaultValue": 0,
|
||||
"minValue": 0,
|
||||
"maxValue": 100,
|
||||
"writable": true
|
||||
}
|
||||
],
|
||||
"actionTypes": [
|
||||
],
|
||||
"eventTypes": [
|
||||
],
|
||||
"browserItemActionTypes": [
|
||||
{
|
||||
"id": "51407fb3-9966-43bf-b3d4-98e1fe6588ec",
|
||||
"name": "updateScenes",
|
||||
"displayName": "Update scenes"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user