From 5cb4e1407a659a12167fda1cbba2d731de04727b Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sun, 6 Jan 2019 21:03:32 +0100 Subject: [PATCH] New Plugin: Boblight --- boblight/bobchannel.cpp | 89 +++++ boblight/bobchannel.h | 66 ++++ boblight/bobclient.cpp | 181 +++++++++++ boblight/bobclient.h | 79 +++++ boblight/boblight.pro | 20 ++ boblight/devicepluginboblight.cpp | 306 ++++++++++++++++++ boblight/devicepluginboblight.h | 68 ++++ boblight/devicepluginboblight.json | 138 ++++++++ ...71bea-1362-4cc6-888f-2ebe80bad46a-en_US.ts | 140 ++++++++ debian/control | 20 +- debian/nymea-plugin-boblight.install.in | 1 + nymea-plugins.pro | 1 + 12 files changed, 1108 insertions(+), 1 deletion(-) create mode 100644 boblight/bobchannel.cpp create mode 100644 boblight/bobchannel.h create mode 100644 boblight/bobclient.cpp create mode 100644 boblight/bobclient.h create mode 100644 boblight/boblight.pro create mode 100644 boblight/devicepluginboblight.cpp create mode 100644 boblight/devicepluginboblight.h create mode 100644 boblight/devicepluginboblight.json create mode 100644 boblight/translations/d5271bea-1362-4cc6-888f-2ebe80bad46a-en_US.ts create mode 100644 debian/nymea-plugin-boblight.install.in diff --git a/boblight/bobchannel.cpp b/boblight/bobchannel.cpp new file mode 100644 index 00000000..497bf43a --- /dev/null +++ b/boblight/bobchannel.cpp @@ -0,0 +1,89 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "bobchannel.h" + +BobChannel::BobChannel(const int &id, QObject *parent) : + QObject(parent), + m_id(id) +{ + m_animation = new QPropertyAnimation(this, "finalColor", this); + m_animation->setDuration(500); + m_animation->setEasingCurve(QEasingCurve::InOutQuad); +} + +int BobChannel::id() const +{ + return m_id; +} + +QColor BobChannel::color() const +{ + return m_color; +} + +void BobChannel::setColor(const QColor &color) +{ + m_color = color; + emit colorChanged(); + + if (m_animation->state() == QPropertyAnimation::Running) { + m_animation->stop(); + } + + m_animation->setStartValue(m_finalColor); + m_animation->setEndValue(color); + m_animation->start(); +} + +bool BobChannel::power() const +{ + return m_power; +} + +void BobChannel::setPower(bool power) +{ + if (power != m_power) { + m_power = power; + emit powerChanged(); + + if (m_animation->state() == QPropertyAnimation::Running) { + m_animation->stop(); + } + + QColor target = m_color; + target.setAlpha(target.alpha() * (m_power ? 1 : 0)); + m_animation->setStartValue(m_finalColor); + m_animation->setEndValue(target); + m_animation->start(); + } +} + +QColor BobChannel::finalColor() const +{ + return m_finalColor; +} + +void BobChannel::setFinalColor(const QColor &color) +{ + m_finalColor = color; + emit finalColorChanged(); +} + diff --git a/boblight/bobchannel.h b/boblight/bobchannel.h new file mode 100644 index 00000000..e3262ad4 --- /dev/null +++ b/boblight/bobchannel.h @@ -0,0 +1,66 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef BOBCHANNEL_H +#define BOBCHANNEL_H + +#include +#include +#include + +class BobChannel : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool power READ power WRITE setPower NOTIFY powerChanged) + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + + // don't directly write to this, the propertyAnimation requires a writable property tho... + Q_PROPERTY(QColor finalColor READ finalColor WRITE setFinalColor NOTIFY finalColorChanged) + +public: + explicit BobChannel(const int &id, QObject *parent = 0); + + int id() const; + + QColor color() const; + void setColor(const QColor &color); + + bool power() const; + void setPower(bool power); + + QColor finalColor() const; + void setFinalColor(const QColor &color); + +private: + QPropertyAnimation *m_animation; + int m_id; + bool m_power = false; + QColor m_color = Qt::white; + QColor m_finalColor = Qt::black; + +signals: + void colorChanged(); + void brightnessChanged(); + void finalColorChanged(); + void powerChanged(); + +}; + +#endif // BOBCHANNEL_H diff --git a/boblight/bobclient.cpp b/boblight/bobclient.cpp new file mode 100644 index 00000000..d6560e01 --- /dev/null +++ b/boblight/bobclient.cpp @@ -0,0 +1,181 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * Copyright (C) 2014 Michael Zanetti * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "bobclient.h" +#include "extern-plugininfo.h" + +#include "libboblight/boblight.h" + +#include +#include + +BobClient::BobClient(const QString &host, const int &port, QObject *parent) : + QObject(parent), + m_host(host), + m_port(port), + m_connected(false) +{ + m_syncTimer = new QTimer(this); + m_syncTimer->setSingleShot(false); + m_syncTimer->setInterval(50); + + connect(m_syncTimer, SIGNAL(timeout()), this, SLOT(sync())); +} + +BobClient::~BobClient() +{ + if (m_boblight) { + boblight_destroy(m_boblight); + } +} + +bool BobClient::connectToBoblight() +{ + if (connected()) { + return true; + } + m_boblight = boblight_init(); + + //try to connect, if we can't then bitch to stderr and destroy boblight + if (!boblight_connect(m_boblight, m_host.toLatin1().data(), m_port, 1000000)) { + qCWarning(dcBoblight) << "Failed to connect:" << boblight_geterror(m_boblight); + boblight_destroy(m_boblight); + m_boblight = nullptr; + setConnected(false); + return false; + } + + qCDebug(dcBoblight) << "Connected to boblightd successfully."; + boblight_setpriority(m_boblight, m_priority); + for (int i = 0; i < lightsCount(); ++i) { + BobChannel *channel = new BobChannel(i, this); + channel->setColor(QColor(255,255,255,0)); + connect(channel, SIGNAL(colorChanged()), this, SLOT(sync())); + m_channels.insert(i, channel); + } + setConnected(true); + return true; +} + +bool BobClient::connected() +{ + return m_connected; +} + +void BobClient::setPriority(int priority) +{ + m_priority = priority; + if (connected()) { + qCDebug(dcBoblight) << "setting priority to" << priority << boblight_setpriority(m_boblight, priority); + } + emit priorityChanged(priority); +} + +void BobClient::setPower(int channel, bool power) +{ + qCDebug(dcBoblight()) << "BobClient: setPower" << channel << power; + m_channels.value(channel)->setPower(power); + emit powerChanged(channel, power); +} + +BobChannel *BobClient::getChannel(const int &id) +{ + foreach (BobChannel *channel, m_channels) { + if (channel->id() == id) + return channel; + } + return 0; +} + +void BobClient::setColor(int channel, QColor color) +{ + if (channel == -1) { + for (int i = 0; i < lightsCount(); ++i) { + setColor(i, color); + } + } else { + BobChannel *c = getChannel(channel); + if (c) { + c->setColor(color); + qCDebug(dcBoblight) << "set channel" << channel << "to color" << color; + emit colorChanged(channel, color); + } + } +} + +void BobClient::setBrightness(int channel, int brightness) +{ + QColor color = m_channels.value(channel)->color(); + color.setAlpha(qRound(brightness * 255.0 / 100)); + m_channels.value(channel)->setColor(color); + emit brightnessChanged(channel, brightness); + + if (brightness > 0) { + m_channels.value(channel)->setPower(true); + emit powerChanged(channel, true); + } +} + +void BobClient::sync() +{ + if (!m_connected) + return; + + foreach (BobChannel *channel, m_channels) { + int rgb[3]; + rgb[0] = channel->finalColor().red() * channel->finalColor().alphaF(); + rgb[1] = channel->finalColor().green() * channel->finalColor().alphaF(); + rgb[2] = channel->finalColor().blue() * channel->finalColor().alphaF(); + boblight_addpixel(m_boblight, channel->id(), rgb); + } + + if (!boblight_sendrgb(m_boblight, 1, NULL)) { + qCWarning(dcBoblight) << "Boblight connection error:" << boblight_geterror(m_boblight); + boblight_destroy(m_boblight); + qDeleteAll(m_channels); + m_channels.clear(); + setConnected(false); + } +} + +void BobClient::setConnected(bool connected) +{ + m_connected = connected; + emit connectionChanged(); + + // if disconnected, delete all channels + if (!connected) { + m_syncTimer->stop(); + qDeleteAll(m_channels); + } else { + m_syncTimer->start(); + } +} + +int BobClient::lightsCount() +{ + return boblight_getnrlights(m_boblight); +} + +QColor BobClient::currentColor(const int &channel) +{ + return getChannel(channel)->color(); +} diff --git a/boblight/bobclient.h b/boblight/bobclient.h new file mode 100644 index 00000000..dd323deb --- /dev/null +++ b/boblight/bobclient.h @@ -0,0 +1,79 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * Copyright (C) 2014 Michael Zanetti * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef BOBCLIENT_H +#define BOBCLIENT_H + +#include +#include +#include +#include +#include + +#include + +class BobClient : public QObject +{ + Q_OBJECT +public: + explicit BobClient(const QString &host = "127.0.0.1", const int &port = 19333, QObject *parent = 0); + ~BobClient(); + + bool connectToBoblight(); + bool connected(); + + int lightsCount(); + QColor currentColor(const int &channel); + + void setPriority(int priority); + + void setPower(int channel, bool power); + void setColor(int channel, QColor color); + void setBrightness(int channel, int brightness); + +private: + void *m_boblight = nullptr; + + QTimer *m_syncTimer; + QString m_host; + int m_port; + bool m_connected; + int m_priority = 128; + + QMap m_colors; + QMap m_channels; + + BobChannel *getChannel(const int &id); + + +private slots: + void sync(); + void setConnected(bool connected); + +signals: + void connectionChanged(); + void powerChanged(int channel, bool power); + void brightnessChanged(int channel, int brightness); + void colorChanged(int channel, const QColor &color); + void priorityChanged(int priority); +}; + +#endif // BOBCLIENT_H diff --git a/boblight/boblight.pro b/boblight/boblight.pro new file mode 100644 index 00000000..1d67db69 --- /dev/null +++ b/boblight/boblight.pro @@ -0,0 +1,20 @@ +include(/usr/include/nymea/plugin.pri) + +QT += dbus bluetooth concurrent + +CONFIG += c++11 + +TARGET = $$qtLibraryTarget(nymea_devicepluginboblight) +LIBS += -lboblight + +SOURCES += \ + devicepluginboblight.cpp \ + bobclient.cpp \ + bobchannel.cpp + +HEADERS += \ + devicepluginboblight.h \ + bobclient.h \ + bobchannel.h + + diff --git a/boblight/devicepluginboblight.cpp b/boblight/devicepluginboblight.cpp new file mode 100644 index 00000000..45c8c430 --- /dev/null +++ b/boblight/devicepluginboblight.cpp @@ -0,0 +1,306 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * Copyright (C) 2014 Michael Zanetti * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*! + \page boblight.html + \title Boblight + + \ingroup plugins + \ingroup network + + This plugin allows to communicate with a \l{https://code.google.com/p/boblight/}{boblight} server + running on localhost:19333. If a boblight server is running ,the configured light devices from the server will + appear automatically in guh. + + \chapter Plugin properties + Following JSON file contains the definition and the description of all available \l{DeviceClass}{DeviceClasses} + and \l{Vendor}{Vendors} of this \l{DevicePlugin}. + + Each \l{DeviceClass} has a list of \l{ParamType}{paramTypes}, \l{ActionType}{actionTypes}, \l{StateType}{stateTypes} + and \l{EventType}{eventTypes}. The \l{DeviceClass::CreateMethod}{createMethods} parameter describes how the \l{Device} + will be created in the system. A device can have more than one \l{DeviceClass::CreateMethod}{CreateMethod}. + The \l{DeviceClass::SetupMethod}{setupMethod} describes the setup method of the \l{Device}. + The detailed implementation of each \l{DeviceClass} can be found in the source code. + + \note If a \l{StateType} has the parameter \tt{"writable": {...}}, an \l{ActionType} with the same uuid and \l{ParamType}{ParamTypes} + will be created automatically. + + \quotefile plugins/deviceplugins/boblight/devicepluginboblight.json +*/ + +#include "devicepluginboblight.h" + +#include "plugin/device.h" +#include "devicemanager.h" + +#include "bobclient.h" +#include "plugininfo.h" +#include "plugintimer.h" + +#include +#include +#include + +DevicePluginBoblight::DevicePluginBoblight() +{ +} + +void DevicePluginBoblight::init() +{ + m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(15); + connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginBoblight::guhTimer); +} + +void DevicePluginBoblight::deviceRemoved(Device *device) +{ + if (device->deviceClassId() == boblightServerDeviceClassId) { + BobClient *client = m_bobClients.take(device->id()); + client->deleteLater(); + } +} + +void DevicePluginBoblight::startMonitoringAutoDevices() +{ + m_canCreateAutoDevices = true; + qCDebug(dcBoblight()) << "Populating auto devices" << myDevices().count(); + QHash parentDevices; + QHash deviceIds; + foreach (Device *device, myDevices()) { + deviceIds.insert(device->id(), device); + if (device->deviceClassId() == boblightServerDeviceClassId) { + qWarning() << "Device" << device->id() << "is bridge"; + if (!parentDevices.contains(device->id())) { + parentDevices[device->id()] = 0; + } + } else if (device->deviceClassId() == boblightDeviceClassId) { + qWarning() << "Device" << device->id() << "is child to bridge" << device->parentId(); + parentDevices[device->parentId()] += 1; + } + } + qWarning() << "have bridge devices:" << parentDevices.count(); + QList descriptors; + foreach (const DeviceId &id, parentDevices.keys()) { + if (parentDevices.value(id) < deviceIds.value(id)->paramValue(boblightServerDeviceChannelsParamTypeId).toInt()) { + for (int i = parentDevices.value(id); i < deviceIds.value(id)->paramValue(boblightServerDeviceChannelsParamTypeId).toInt(); i++) { + DeviceDescriptor descriptor(boblightDeviceClassId, deviceIds.value(id)->name() + " " + QString::number(i + 1), QString(), id); + descriptor.setParams(ParamList() << Param(boblightDeviceChannelParamTypeId, i)); + qCDebug(dcBoblight()) << "Adding new boblight channel" << i + 1; + descriptors.append(descriptor); + } + } + } + if (!descriptors.isEmpty()) { + emit autoDevicesAppeared(boblightDeviceClassId, descriptors); + } +} + +void DevicePluginBoblight::guhTimer() +{ + foreach (BobClient *client, m_bobClients) { + if (!client->connected()) { + client->connectToBoblight(); + } + } +} + +void DevicePluginBoblight::onPowerChanged(int channel, bool power) +{ + qCDebug(dcBoblight()) << "power changed" << channel << power; + BobClient *sndr = dynamic_cast(sender()); + foreach (Device* device, myDevices()) { + if (m_bobClients.value(device->parentId()) == sndr && device->paramValue(boblightDeviceChannelParamTypeId).toInt() == channel) { + qCWarning(dcBoblight()) << "setting state power" << power; + device->setStateValue(boblightPowerStateTypeId, power); + } + } +} + +void DevicePluginBoblight::onBrightnessChanged(int channel, int brightness) +{ + BobClient *sndr = dynamic_cast(sender()); + foreach (Device* device, myDevices()) { + if (m_bobClients.value(device->parentId()) == sndr && device->paramValue(boblightDeviceChannelParamTypeId).toInt() == channel) { + device->setStateValue(boblightBrightnessStateTypeId, brightness); + } + } +} + +void DevicePluginBoblight::onColorChanged(int channel, const QColor &color) +{ + BobClient *sndr = dynamic_cast(sender()); + foreach (Device* device, myDevices()) { + if (m_bobClients.value(device->parentId()) == sndr && device->paramValue(boblightDeviceChannelParamTypeId).toInt() == channel) { + device->setStateValue(boblightColorStateTypeId, color); + } + } +} + +void DevicePluginBoblight::onPriorityChanged(int priority) +{ + BobClient *sndr = dynamic_cast(sender()); + foreach (Device* device, myDevices()) { + if (m_bobClients.value(device->id()) == sndr) { + device->setStateValue(boblightServerPriorityStateTypeId, priority); + } + } +} + +QColor DevicePluginBoblight::tempToRgb(int temp) +{ + // 153 cold: 0.839216, 1, 0.827451 + // 500 warm: 0.870588, 1, 0.266667 + + // => 0 : 214,255,212 + // 100 : 222,255,67 + + // r => 0 : 214 = 100 : 222 + // => temp : (x-214) = 100 : (255 - 214) + // => x = temp * (255-214) / 100 + // r = x + 214 + + int red = temp * 41 / 100 + 214; + + int green = 255; + + // b => 0 : 212 = 100 : 67 + // => temp : (212 - x) = 100 : (212 - 145) + // => x = temp * 145 / 100 + // g = 212 - x + + int blue = 212 - temp * 145 / 100; + + qWarning() << "temp:" << temp << "rgb" << red << green << blue; + return QColor(red, green, blue); +} + +DeviceManager::DeviceSetupStatus DevicePluginBoblight::setupDevice(Device *device) +{ + if (device->deviceClassId() == boblightServerDeviceClassId) { + + BobClient *bobClient = new BobClient(device->paramValue(boblightServerDeviceHostAddressParamTypeId).toString(), device->paramValue(boblightServerDevicePortParamTypeId).toInt(), this); + bool connected = bobClient->connectToBoblight(); + if (!connected) { + qCWarning(dcBoblight()) << "Error connecting to boblight..."; + } else { + qCDebug(dcBoblight()) << "Connected to boblight"; + } + bobClient->setPriority(device->stateValue(boblightServerPriorityStateTypeId).toInt()); + device->setStateValue(boblightServerConnectedStateTypeId, connected); + m_bobClients.insert(device->id(), bobClient); + connect(bobClient, &BobClient::connectionChanged, this, &DevicePluginBoblight::onConnectionChanged); + connect(bobClient, &BobClient::powerChanged, this, &DevicePluginBoblight::onPowerChanged); + connect(bobClient, &BobClient::brightnessChanged, this, &DevicePluginBoblight::onBrightnessChanged); + connect(bobClient, &BobClient::colorChanged, this, &DevicePluginBoblight::onColorChanged); + connect(bobClient, &BobClient::priorityChanged, this, &DevicePluginBoblight::onPriorityChanged); + } else if (device->deviceClassId() == boblightDeviceClassId) { + BobClient *bobClient = m_bobClients.value(device->parentId()); + device->setStateValue(boblightConnectedStateTypeId, bobClient->connected()); + m_bobClients.insert(device->id(), bobClient); + } + + return DeviceManager::DeviceSetupStatusSuccess; +} + +void DevicePluginBoblight::postSetupDevice(Device *device) +{ + if (device->deviceClassId() == boblightServerDeviceClassId && m_canCreateAutoDevices) { + startMonitoringAutoDevices(); + } + if (device->deviceClassId() == boblightDeviceClassId) { + BobClient *bobClient = m_bobClients.value(device->parentId()); + if (bobClient && bobClient->connected()) { + device->setStateValue(boblightConnectedStateTypeId, bobClient->connected()); + + QColor color = device->stateValue(boblightColorStateTypeId).value(); + int brightness = device->stateValue(boblightBrightnessStateTypeId).toInt(); + bool power = device->stateValue(boblightPowerStateTypeId).toBool(); + + bobClient->setColor(device->paramValue(boblightDeviceChannelParamTypeId).toInt(), color); + bobClient->setBrightness(device->paramValue(boblightDeviceChannelParamTypeId).toInt(), brightness); + bobClient->setPower(device->paramValue(boblightDeviceChannelParamTypeId).toInt(), power); + + } + } +} + +DeviceManager::DeviceError DevicePluginBoblight::executeAction(Device *device, const Action &action) +{ + if (!device->setupComplete()) { + return DeviceManager::DeviceErrorHardwareNotAvailable; + } + qCDebug(dcBoblight()) << "Execute action for boblight" << action.params(); + if (device->deviceClassId() == boblightServerDeviceClassId) { + BobClient *bobClient = m_bobClients.value(device->id()); + if (!bobClient || !bobClient->connected()) { + qCWarning(dcBoblight()) << "Boblight on" << device->paramValue(boblightServerDeviceHostAddressParamTypeId).toString() << "not connected"; + return DeviceManager::DeviceErrorHardwareNotAvailable; + } + + if (action.actionTypeId() == boblightServerPriorityActionTypeId) { + bobClient->setPriority(action.param(boblightServerPriorityActionPriorityParamTypeId).value().toInt()); + return DeviceManager::DeviceErrorNoError; + } + qCWarning(dcBoblight()) << "Unhandled action" << action.actionTypeId() << "for BoblightServer device" << device; + return DeviceManager::DeviceErrorActionTypeNotFound; + } + + if (device->deviceClassId() == boblightDeviceClassId) { + BobClient *bobClient = m_bobClients.value(device->parentId()); + if (!bobClient || !bobClient->connected()) { + qCWarning(dcBoblight()) << "Boblight not connected"; + return DeviceManager::DeviceErrorHardwareNotAvailable; + } + + if (action.actionTypeId() == boblightPowerActionTypeId) { + bobClient->setPower(device->paramValue(boblightDeviceChannelParamTypeId).toInt(), action.param(boblightPowerActionPowerParamTypeId).value().toBool()); + return DeviceManager::DeviceErrorNoError; + } + if (action.actionTypeId() == boblightColorActionTypeId) { + bobClient->setColor(device->paramValue(boblightDeviceChannelParamTypeId).toInt(), action.param(boblightColorActionColorParamTypeId).value().value()); + return DeviceManager::DeviceErrorNoError; + } + if (action.actionTypeId() == boblightBrightnessActionTypeId) { + bobClient->setBrightness(device->paramValue(boblightDeviceChannelParamTypeId).toInt(), action.param(boblightBrightnessActionBrightnessParamTypeId).value().toInt()); + return DeviceManager::DeviceErrorNoError; + } + if (action.actionTypeId() == boblightColorTemperatureActionTypeId) { + bobClient->setColor(device->paramValue(boblightDeviceChannelParamTypeId).toInt(), tempToRgb(action.param(boblightColorTemperatureActionColorTemperatureParamTypeId).value().toInt())); + return DeviceManager::DeviceErrorNoError; + } + return DeviceManager::DeviceErrorActionTypeNotFound; + } + return DeviceManager::DeviceErrorDeviceClassNotFound; +} + +void DevicePluginBoblight::onConnectionChanged() +{ + BobClient *bobClient = static_cast(sender()); + qCDebug(dcBoblight()) << "Connection changed. BobClient:" << bobClient << bobClient->connected() << m_bobClients.keys(bobClient); + foreach (const DeviceId &deviceId, m_bobClients.keys(bobClient)) { + foreach (Device *device, myDevices()) { + if (device->id() == deviceId || device->parentId() == deviceId) { + device->setStateValue(boblightConnectedStateTypeId, bobClient->connected()); + break; + } + } + } +} + diff --git a/boblight/devicepluginboblight.h b/boblight/devicepluginboblight.h new file mode 100644 index 00000000..e394dbaa --- /dev/null +++ b/boblight/devicepluginboblight.h @@ -0,0 +1,68 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef DEVICEPLUGINBOBLIGHT_H +#define DEVICEPLUGINBOBLIGHT_H + +#include "plugin/deviceplugin.h" +#include "bobclient.h" + +class BobClient; +class PluginTimer; + +class DevicePluginBoblight : public DevicePlugin +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "devicepluginboblight.json") + Q_INTERFACES(DevicePlugin) + +public: + explicit DevicePluginBoblight(); + + void init() override; + + DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; + void postSetupDevice(Device *device) override; + void deviceRemoved(Device *device) override; + + void startMonitoringAutoDevices() override; + + DeviceManager::DeviceError executeAction(Device *device, const Action &action) override; + +private slots: + void onConnectionChanged(); + void guhTimer(); + + void onPowerChanged(int channel, bool power); + void onBrightnessChanged(int channel, int brightness); + void onColorChanged(int channel, const QColor &color); + void onPriorityChanged(int priority); + +private: + QColor tempToRgb(int temp); +private: + PluginTimer *m_pluginTimer = nullptr; + + QHash m_bobClients; + bool m_canCreateAutoDevices = false; +}; + +#endif // DEVICEPLUGINBOBLIGHT_H diff --git a/boblight/devicepluginboblight.json b/boblight/devicepluginboblight.json new file mode 100644 index 00000000..37ef152b --- /dev/null +++ b/boblight/devicepluginboblight.json @@ -0,0 +1,138 @@ +{ + "id": "d5271bea-1362-4cc6-888f-2ebe80bad46a", + "name": "Boblight", + "displayName": "Boblight", + "vendors": [ + { + "id": "f0c9dd91-c2b0-4cd0-b161-a17fee9d2303", + "name": "boblight", + "displayName": "Boblight", + "deviceClasses": [ + { + "id": "f267a7f4-ed75-4026-9b97-98884d7f4399", + "name": "boblightServer", + "displayName": "Boblight server", + "createMethods": ["user"], + "interfaces": ["gateway", "connectable"], + "paramTypes": [ + { + "id": "de82ea8c-2f1e-4b93-b85a-f6a0b7f87e4a", + "name": "hostAddress", + "displayName": "Host Address", + "type" : "QString", + "inputType": "IPv4Address", + "defaultValue": "127.0.0.1" + }, + { + "id": "8cbe5ef8-6b45-441e-9051-08d48f3948da", + "name": "port", + "displayName": "Port", + "type" : "int", + "defaultValue": 19333 + }, + { + "id": "277f2458-d932-4a6e-a7bb-58814ab99663", + "name": "channels", + "displayName": "Channels", + "type": "int", + "defaultValue": 1 + } + ], + "stateTypes": [ + { + "id": "638fb9ec-4797-4ef6-a9b6-d935f1c49e17", + "name": "connected", + "displayName": "connected", + "displayNameEvent": "Connected changed", + "defaultValue": false, + "type": "bool" + }, + { + "id": "60d345e8-757c-4bc2-a96b-31121fc84356", + "name": "priority", + "displayName": "Priority", + "displayNameEvent": "Priority changed", + "displayNameAction": "Set priority", + "type": "int", + "defaultValue": 128, + "minValue": 0, + "maxValue": 256, + "writable": true + } + + ] + }, + { + "id": "05347200-416e-4b75-b4e3-6f913a2a7e76", + "name": "boblight", + "displayName": "Boblight", + "createMethods": ["auto"], + "interfaces": ["colorlight", "connectable"], + "paramTypes": [ + { + "id": "7b5b784d-d623-4a2e-b081-9be84b1ce1a8", + "name": "channel", + "displayName": "Channel", + "type": "int", + "defaultValue": -1 + } + ], + "stateTypes": [ + { + "id": "bb40f1bd-62b9-485e-86a1-b0c820a93b8a", + "name": "connected", + "displayName": "connected", + "defaultValue": false, + "displayNameEvent": "Connected changed", + "type": "bool" + }, + { + "id": "95aec7b5-247a-42a2-8748-273b034b988c", + "name": "power", + "displayName": "Power", + "defaultValue": false, + "type": "bool", + "displayNameEvent": "Power changed", + "displayNameAction": "Set power", + "writable": true + }, + { + "id": "0a92eab5-233c-4081-840b-15578091365c", + "name": "brightness", + "displayName": "Brightness", + "defaultValue": 100, + "type": "int", + "displayNameEvent": "Brightness changed", + "displayNameAction": "Set brightness", + "writable": true, + "minValue": 0, + "maxValue": 100 + }, + { + "id": "b6f24e6f-d2a8-4f22-b40f-3a0e38bdabe0", + "name": "colorTemperature", + "displayName": "Color Temperature", + "defaultValue": 0, + "type": "int", + "displayNameEvent": "Color Temperature changed", + "displayNameAction": "Set color temperature", + "writable": true, + "minValue": 0, + "maxValue": 100 + }, + { + "id": "a213d2d1-bd29-4a16-8459-520aa919ae67", + "name": "color", + "displayName": "Color", + "defaultValue": "#ffffff", + "type": "QColor", + "displayNameEvent": "Color changed", + "displayNameAction": "Set color", + "writable": true + } + ] + } + ] + } + ] +} diff --git a/boblight/translations/d5271bea-1362-4cc6-888f-2ebe80bad46a-en_US.ts b/boblight/translations/d5271bea-1362-4cc6-888f-2ebe80bad46a-en_US.ts new file mode 100644 index 00000000..38e3e205 --- /dev/null +++ b/boblight/translations/d5271bea-1362-4cc6-888f-2ebe80bad46a-en_US.ts @@ -0,0 +1,140 @@ + + + + + Boblight + + Boblight + The name of the plugin Boblight (d5271bea-1362-4cc6-888f-2ebe80bad46a) +---------- +The name of the vendor (f0c9dd91-c2b0-4cd0-b161-a17fee9d2303) +---------- +The name of the DeviceClass (05347200-416e-4b75-b4e3-6f913a2a7e76) + + + + Boblight server + The name of the DeviceClass (f267a7f4-ed75-4026-9b97-98884d7f4399) + + + + Host Address + The name of the paramType (de82ea8c-2f1e-4b93-b85a-f6a0b7f87e4a) of boblightServer + + + + Port + The name of the paramType (8cbe5ef8-6b45-441e-9051-08d48f3948da) of boblightServer + + + + Channels + The name of the paramType (277f2458-d932-4a6e-a7bb-58814ab99663) of boblightServer + + + + Connected changed + The name of the autocreated EventType (638fb9ec-4797-4ef6-a9b6-d935f1c49e17) +---------- +The name of the autocreated EventType (bb40f1bd-62b9-485e-86a1-b0c820a93b8a) + + + + connected + The name of the ParamType of the autocreated EventType (638fb9ec-4797-4ef6-a9b6-d935f1c49e17) of DeviceClass boblightServer +---------- +The name of the ParamType of the autocreated EventType (bb40f1bd-62b9-485e-86a1-b0c820a93b8a) of DeviceClass boblight + + + + Priority changed + The name of the autocreated EventType (60d345e8-757c-4bc2-a96b-31121fc84356) + + + + Priority + The name of the ParamType of the autocreated EventType (60d345e8-757c-4bc2-a96b-31121fc84356) of DeviceClass boblightServer +---------- +The name of the autocreated ParamType of the writable StateType (60d345e8-757c-4bc2-a96b-31121fc84356) of DeviceClass boblightServer + + + + Set priority + The name of the autocreated ActionType (60d345e8-757c-4bc2-a96b-31121fc84356) + + + + Channel + The name of the paramType (7b5b784d-d623-4a2e-b081-9be84b1ce1a8) of boblight + + + + Power changed + The name of the autocreated EventType (95aec7b5-247a-42a2-8748-273b034b988c) + + + + Power + The name of the ParamType of the autocreated EventType (95aec7b5-247a-42a2-8748-273b034b988c) of DeviceClass boblight +---------- +The name of the autocreated ParamType of the writable StateType (95aec7b5-247a-42a2-8748-273b034b988c) of DeviceClass boblight + + + + Set power + The name of the autocreated ActionType (95aec7b5-247a-42a2-8748-273b034b988c) + + + + Brightness changed + The name of the autocreated EventType (0a92eab5-233c-4081-840b-15578091365c) + + + + Brightness + The name of the ParamType of the autocreated EventType (0a92eab5-233c-4081-840b-15578091365c) of DeviceClass boblight +---------- +The name of the autocreated ParamType of the writable StateType (0a92eab5-233c-4081-840b-15578091365c) of DeviceClass boblight + + + + Set brightness + The name of the autocreated ActionType (0a92eab5-233c-4081-840b-15578091365c) + + + + Color Temperature changed + The name of the autocreated EventType (b6f24e6f-d2a8-4f22-b40f-3a0e38bdabe0) + + + + Color Temperature + The name of the ParamType of the autocreated EventType (b6f24e6f-d2a8-4f22-b40f-3a0e38bdabe0) of DeviceClass boblight +---------- +The name of the autocreated ParamType of the writable StateType (b6f24e6f-d2a8-4f22-b40f-3a0e38bdabe0) of DeviceClass boblight + + + + Set color temperature + The name of the autocreated ActionType (b6f24e6f-d2a8-4f22-b40f-3a0e38bdabe0) + + + + Color changed + The name of the autocreated EventType (a213d2d1-bd29-4a16-8459-520aa919ae67) + + + + Color + The name of the ParamType of the autocreated EventType (a213d2d1-bd29-4a16-8459-520aa919ae67) of DeviceClass boblight +---------- +The name of the autocreated ParamType of the writable StateType (a213d2d1-bd29-4a16-8459-520aa919ae67) of DeviceClass boblight + + + + Set color + The name of the autocreated ActionType (a213d2d1-bd29-4a16-8459-520aa919ae67) + + + + diff --git a/debian/control b/debian/control index 0122a4d6..dd6df1d8 100644 --- a/debian/control +++ b/debian/control @@ -45,6 +45,23 @@ Description: nymea.io plugin for awattar This package will install the nymea.io plugin for awattar +Package: nymea-plugin-boblight +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, + nymea-plugins-translations, +Description: nymea.io plugin for boblight + 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 boblight. Boblight allows + controlling LEDs via home-brew controllers. See https://github.com/arvydas/boblight + for informations on boblight. + + Package: nymea-plugin-commandlauncher Architecture: any Depends: ${shlibs:Depends}, @@ -700,7 +717,8 @@ Description: Plugins for nymea IoT server - the default plugin collection Package: nymea-plugins-maker Section: libs Architecture: all -Depends: nymea-plugin-commandlauncher, +Depends: nymea-plugin-boblight, + nymea-plugin-commandlauncher, nymea-plugin-udpcommander, nymea-plugin-tcpcommander, nymea-plugin-httpcommander, diff --git a/debian/nymea-plugin-boblight.install.in b/debian/nymea-plugin-boblight.install.in new file mode 100644 index 00000000..88d9b8bb --- /dev/null +++ b/debian/nymea-plugin-boblight.install.in @@ -0,0 +1 @@ +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_devicepluginboblight.so diff --git a/nymea-plugins.pro b/nymea-plugins.pro index 6ccdf0ee..96c9ee27 100644 --- a/nymea-plugins.pro +++ b/nymea-plugins.pro @@ -3,6 +3,7 @@ TEMPLATE = subdirs PLUGIN_DIRS = \ avahimonitor \ awattar \ + boblight \ commandlauncher \ conrad \ datetime \