added some more bit shifting

This commit is contained in:
Boernsman 2020-01-03 10:19:52 +01:00 committed by bernhard.trinnes
parent d84e0face7
commit 6af09273e1
11 changed files with 1428 additions and 2 deletions

16
debian/control vendored
View File

@ -400,6 +400,21 @@ Description: nymea.io plugin for lgsmarttv
This package will install the nymea.io plugin for lgsmarttv
Package: nymea-plugin-lifx
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
nymea-plugins-translations,
Description: nymea.io plugin for lifx
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 lifx
Package: nymea-plugin-mailnotification
Architecture: any
Depends: ${shlibs:Depends},
@ -981,6 +996,7 @@ Depends: nymea-plugin-anel,
nymea-plugin-genericthings,
nymea-plugin-kodi,
nymea-plugin-lgsmarttv,
nymea-plugin-lifx,
nymea-plugin-mailnotification,
nymea-plugin-texasinstruments,
nymea-plugin-nanoleaf,

1
debian/nymea-plugin-lifx.install.in vendored Normal file
View File

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

3
lifx/README.md Normal file
View File

@ -0,0 +1,3 @@
# Lifx
This plug-in implements the LAN API for Lifx devices

View File

@ -0,0 +1,220 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
* 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 "devicepluginlifx.h"
#include "devices/device.h"
#include "types/param.h"
#include "plugininfo.h"
#include <QDebug>
#include <QColor>
#include <QRgb>
DevicePluginLifx::DevicePluginLifx()
{
}
void DevicePluginLifx::init()
{
m_connectedStateTypeIds.insert(colorBulbDeviceClassId, colorBulbConnectedStateTypeId);
m_connectedStateTypeIds.insert(dimmableBulbDeviceClassId, dimmableBulbConnectedStateTypeId);
m_powerStateTypeIds.insert(colorBulbDeviceClassId, colorBulbPowerStateTypeId);
m_powerStateTypeIds.insert(dimmableBulbDeviceClassId, dimmableBulbPowerStateTypeId);
m_brightnessStateTypeIds.insert(colorBulbDeviceClassId, colorBulbBrightnessStateTypeId);
m_brightnessStateTypeIds.insert(dimmableBulbDeviceClassId, dimmableBulbBrightnessStateTypeId);
}
void DevicePluginLifx::discoverDevices(DeviceDiscoveryInfo *info)
{
if (!m_lifxConnection) {
m_lifxConnection = new Lifx(this);
m_lifxConnection->enable();
}
if (info->deviceClassId() == colorBulbDeviceClassId) {
}
}
void DevicePluginLifx::setupDevice(DeviceSetupInfo *info)
{
Device *device = info->device();
if (!m_lifxConnection) {
m_lifxConnection = new Lifx(this);
m_lifxConnection->enable();
}
if (device->deviceClassId() == colorBulbDeviceClassId) {
info->finish(Device::DeviceErrorNoError);
}
}
void DevicePluginLifx::postSetupDevice(Device *device)
{
connect(device, &Device::nameChanged, this, &DevicePluginLifx::onDeviceNameChanged);
if (!m_pluginTimer) {
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(60);
connect(m_pluginTimer, &PluginTimer::timeout, this, [this]() {
});
}
m_pluginTimer->timeout();
}
void DevicePluginLifx::executeAction(DeviceActionInfo *info)
{
Device *device = info->device();
Action action = info->action();
if (!m_lifxConnection)
return info->finish(Device::DeviceErrorHardwareFailure);
if (device->deviceClassId() == colorBulbDeviceClassId) {
if (action.actionTypeId() == colorBulbPowerActionTypeId) {
bool power = action.param(colorBulbPowerActionPowerParamTypeId).value().toBool();
int requestId = m_lifxConnection->setPower(power);
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
m_asyncActions.insert(requestId, info);
} else if (action.actionTypeId() == colorBulbBrightnessActionTypeId) {
if (!device->stateValue(colorBulbPowerStateTypeId).toBool())
m_lifxConnection->setPower(true);
if (m_pendingBrightnessAction.contains(device->id())) {
//Scrap old info and insert new one
m_pendingBrightnessAction.insert(device->id(), info);
} else {
m_pendingBrightnessAction.insert(device->id(), info);
QTimer::singleShot(500, this, [info, this]{
int brightness = info->action().param(colorBulbBrightnessActionBrightnessParamTypeId).value().toInt();
m_pendingBrightnessAction.remove(info->device()->id());
int requestId = m_lifxConnection->setBrightness(brightness);
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
m_asyncActions.insert(requestId, info);
});
}
} else if (action.actionTypeId() == colorBulbColorActionColorParamTypeId) {
QRgb color = QColor(action.param(colorBulbColorActionColorParamTypeId).value().toString()).rgba();
if (!device->stateValue(colorBulbPowerStateTypeId).toBool())
m_lifxConnection->setPower(true);
int requestId = m_lifxConnection->setColor(color);
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
m_asyncActions.insert(requestId, info);
} else if (action.actionTypeId() == colorBulbColorTemperatureActionTypeId) {
int colorTemperature = 6500 - (action.param(colorBulbColorTemperatureActionColorTemperatureParamTypeId).value().toUInt() * -11.12);
if (!device->stateValue(colorBulbPowerStateTypeId).toBool())
m_lifxConnection->setPower(true);
int requestId = m_lifxConnection->setColorTemperature(colorTemperature);
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
m_asyncActions.insert(requestId, info);
} else {
qCWarning(dcLifx()) << "Unhandled action";
}
} else if (device->deviceClassId() == dimmableBulbDeviceClassId) {
if (action.actionTypeId() == dimmableBulbPowerActionTypeId) {
bool power = action.param(dimmableBulbPowerActionPowerParamTypeId).value().toBool();
int requestId = m_lifxConnection->setPower(power);
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
} else if (action.actionTypeId() == dimmableBulbBrightnessActionTypeId) {
int brightness = action.param(dimmableBulbBrightnessActionBrightnessParamTypeId).value().toInt();
if (!device->stateValue(dimmableBulbPowerStateTypeId).toBool())
m_lifxConnection->setPower(true);
int requestId = m_lifxConnection->setBrightness(brightness);
connect(info, &DeviceActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
m_asyncActions.insert(requestId, info);
} else {
qCWarning(dcLifx()) << "Unhandled action";
}
} else {
qCWarning(dcLifx()) << "Unhandled device class";
}
}
void DevicePluginLifx::deviceRemoved(Device *device)
{
Q_UNUSED(device)
if (myDevices().isEmpty()) {
m_lifxConnection->deleteLater();
m_lifxConnection = nullptr;
}
}
void DevicePluginLifx::onDeviceNameChanged()
{
Device *device = static_cast<Device*>(sender());
Q_UNUSED(device)
}
void DevicePluginLifx::onConnectionChanged(bool connected)
{
Q_UNUSED(connected)
// device->setStateValue(m_connectedStateTypeIds.value(device->deviceClassId()), connected);
}
void DevicePluginLifx::onRequestExecuted(int requestId, bool success)
{
if (m_asyncActions.contains(requestId)) {
DeviceActionInfo *info = m_asyncActions.take(requestId);
if (success) {
info->finish(Device::DeviceErrorNoError);
} else {
info->finish(Device::DeviceErrorHardwareFailure);
}
}
}
/*void DevicePluginLifx::onPowerNotificationReceived(bool status)
{
Q_UNUSED(status)
Lifx *Lifx = static_cast<Lifx *>(sender());
Device * device = myDevices().findById(m_LifxConnections.key(Lifx));
if(!device)
return;
device->setStateValue(m_powerStateTypeIds.value(device->deviceClassId()), status);
}
void DevicePluginLifx::onBrightnessNotificationReceived(int percentage)
{
Q_UNUSED(percentage)
Lifx *lifx = static_cast<Lifx *>(sender());
Device * device = myDevices().findById(m_lifxConnections.key(lifx));
if(!device)
return;
device->setStateValue(m_brightnessStateTypeIds.value(device->deviceClassId()), percentage);
}*/

View File

@ -0,0 +1,78 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
* 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 DEVICEPLUGINLIFX_H
#define DEVICEPLUGINLIFX_H
#include "devices/deviceplugin.h"
#include "plugintimer.h"
#include "lifx.h"
#include <QTimer>
class DevicePluginLifx : public DevicePlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "devicepluginlifx.json")
Q_INTERFACES(DevicePlugin)
public:
explicit DevicePluginLifx();
void init() override;
void discoverDevices(DeviceDiscoveryInfo *info) override;
void setupDevice(DeviceSetupInfo *info) override;
void postSetupDevice(Device *device) override;
void executeAction(DeviceActionInfo *info) override;
void deviceRemoved(Device *device) override;
private:
PluginTimer *m_pluginTimer = nullptr;
QHash<int, DeviceActionInfo *> m_asyncActions;
Lifx *m_lifxConnection;
QHash<DeviceClassId, StateTypeId> m_connectedStateTypeIds;
QHash<DeviceClassId, StateTypeId> m_powerStateTypeIds;
QHash<DeviceClassId, StateTypeId> m_brightnessStateTypeIds;
QHash<DeviceId, DeviceActionInfo *> m_pendingBrightnessAction;
private slots:
void onDeviceNameChanged();
void onConnectionChanged(bool connected);
void onRequestExecuted(int requestId, bool success);
/*void onPowerNotificationReceived(bool status);
void onBrightnessNotificationReceived(int percentage);
void onColorTemperatureNotificationReceived(int kelvin);
void onRgbNotificationReceived(QRgb rgbColor);
void onNameNotificationReceived(const QString &name);*/
};
#endif // DEVICEPLUGINLIFX_H

View File

@ -0,0 +1,192 @@
{
"displayName": "LIFX",
"name": "Lifx",
"id": "4e00ee30-79e2-447b-8dcc-c34470f41992",
"vendors": [
{
"name": "lifx",
"displayName": "LIFX",
"id": "e5e48c0d-cff7-4c0f-983e-d23bd3e4ba87",
"deviceClasses": [
{
"id": "12907c9c-e7f0-47f2-bd58-39d52ffdf24e",
"name": "colorBulb",
"displayName": "Color",
"createMethods": ["user", "discovery"],
"interfaces": ["colorlight", "connectable"],
"paramTypes": [
{
"id": "fd1c4817-5111-433a-b5b9-fd9f49d4975c",
"name": "host",
"displayName": "Host address",
"type" : "QString",
"inputType": "IPv4Address",
"readOnly": true
},
{
"id": "44c13745-300c-491f-b617-3a8d53472998",
"name": "port",
"displayName": "Port",
"type" : "int",
"readOnly": true
},
{
"id": "976ecea0-ac25-47d4-9dc5-362962ddb6c0",
"name": "id",
"displayName": "Id",
"type" : "QString",
"readOnly": true
}
],
"stateTypes": [
{
"id": "dc4c1640-90f3-4fe0-af9b-db7fa105f18a",
"name": "connected",
"displayName": "Reachable",
"displayNameEvent": "Reachable changed",
"defaultValue": false,
"type": "bool"
},
{
"id": "12de3f8f-2454-4057-aa12-9290296fdbdd",
"name": "power",
"displayName": "Power",
"displayNameEvent": "Power changed",
"displayNameAction": "Set power",
"type": "bool",
"defaultValue": false,
"writable": true
},
{
"id": "dd7d7e70-5552-4531-8789-2d0f750488be",
"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": "a47d8164-5023-4ffb-8298-73293e93e7f6",
"name": "color",
"displayName": "Color",
"displayNameEvent": "Color changed",
"displayNameAction": "Set color",
"type": "QColor",
"defaultValue": "#000000",
"writable": true
},
{
"id": "8bd20350-0e79-45dc-b68a-84da99356863",
"name": "brightness",
"displayName": "Brightness",
"displayNameEvent": "Brightness changed",
"displayNameAction": "Set brigtness",
"type": "int",
"unit": "Percentage",
"defaultValue": 0,
"minValue": 0,
"maxValue": 100,
"writable": true
},
{
"id": "65f88396-2958-480e-b0be-c4695400a343",
"name": "effect",
"displayName": "effect",
"displayNameEvent": "effect changed",
"displayNameAction": "Set effect",
"type": "QString",
"defaultValue": "none",
"possibleValues": [
"none",
"color loop"
],
"writable": true
}
]
},
{
"id": "a5b02af8-7c97-4a78-9c78-bafee7407b5e",
"name": "dimmableBulb",
"displayName": "Day and Dusk",
"createMethods": ["user", "discovery"],
"interfaces": ["colortemperaturelight", "connectable"],
"paramTypes": [
{
"id": "cc0a765b-a753-4e07-a6e5-47e9272c4346",
"name": "host",
"displayName": "Host address",
"type" : "QString",
"inputType": "IPv4Address",
"readOnly": true
},
{
"id": "d233d9bf-6662-414d-92f6-dd3e267051b5",
"name": "port",
"displayName": "Port",
"type" : "int",
"readOnly": true
},
{
"id": "f157a97b-3fe5-4d9e-b5e3-5636f80d46ed",
"name": "id",
"displayName": "Id",
"type" : "QString",
"readOnly": true
}
],
"stateTypes": [
{
"id": "d33f98ef-5e0f-464c-afed-88b95cc701cd",
"name": "connected",
"displayName": "Reachable",
"displayNameEvent": "Reachable changed",
"defaultValue": false,
"type": "bool"
},
{
"id": "9e1344ea-cd05-4dd8-8948-8d2f5e00e1b0",
"name": "power",
"displayName": "Power",
"displayNameEvent": "Power changed",
"displayNameAction": "Set power",
"type": "bool",
"defaultValue": false,
"writable": true
},
{
"id": "a0a1bdcc-2761-4d90-85d1-5ce887546611",
"name": "brightness",
"displayName": "Brightness",
"displayNameEvent": "Brightness changed",
"displayNameAction": "Set brigtness",
"type": "int",
"unit": "Percentage",
"defaultValue": 0,
"minValue": 0,
"maxValue": 100,
"writable": true
},
{
"id": "95797dee-b836-4047-98d5-afbbce4f8c42",
"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
}
]
}
]
}
]
}

View File

@ -0,0 +1,207 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
* 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 "lifx.h"
#include "extern-plugininfo.h"
#include <QColor>
#include <QRandomGenerator>
Lifx::Lifx(QObject *parent) :
QObject(parent)
{
m_reconnectTimer = new QTimer(this);
m_reconnectTimer->setSingleShot(true);
connect(m_reconnectTimer, &QTimer::timeout, this, &Lifx::onReconnectTimer);
}
Lifx::~Lifx()
{
if (m_socket) {
m_socket->waitForBytesWritten(1000);
m_socket->close();
}
}
bool Lifx::enable()
{
// Clean up
if (m_socket) {
delete m_socket;
m_socket = nullptr;
}
// Bind udp socket and join multicast group
m_socket = new QUdpSocket(this);
m_port = 56700;
m_host = QHostAddress("239.255.255.250");
m_socket->setSocketOption(QAbstractSocket::MulticastTtlOption,QVariant(1));
m_socket->setSocketOption(QAbstractSocket::MulticastLoopbackOption,QVariant(1));
if(!m_socket->bind(QHostAddress::AnyIPv4, m_port, QUdpSocket::ShareAddress)){
qCWarning(dcLifx()) << "could not bind to port" << m_port;
delete m_socket;
m_socket = nullptr;
return false;
}
if(!m_socket->joinMulticastGroup(m_host)){
qCWarning(dcLifx()) << "could not join multicast group" << m_host;
delete m_socket;
m_socket = nullptr;
return false;
}
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
connect(m_socket, &QUdpSocket::readyRead, this, &Lifx::onReadyRead);
return true;
}
void Lifx::discoverDevices()
{
Message message;
sendMessage(message);
}
int Lifx::setColorTemperature(int mirad, int msFadeTime)
{
Q_UNUSED(mirad)
Q_UNUSED(msFadeTime)
int requestId = static_cast<int>(QRandomGenerator::global()->generate());
return requestId;
}
int Lifx::setColor(QColor color, int msFadeTime)
{
Q_UNUSED(color)
Q_UNUSED(msFadeTime)
int requestId = static_cast<int>(QRandomGenerator::global()->generate());
return requestId;
}
int Lifx::setBrightness(int percentage, int msFadeTime)
{
Q_UNUSED(percentage)
Q_UNUSED(msFadeTime)
int requestId = static_cast<int>(QRandomGenerator::global()->generate());
Message message;
sendMessage(message);
return requestId;
}
int Lifx::setPower(bool power, int msFadeTime)
{
Q_UNUSED(power)
Q_UNUSED(msFadeTime)
int requestId = static_cast<int>(QRandomGenerator::global()->generate());
return requestId;
}
int Lifx::flash()
{
int requestId = static_cast<int>(QRandomGenerator::global()->generate());
return requestId;
}
int Lifx::flash15s()
{
int requestId = static_cast<int>(QRandomGenerator::global()->generate());
return requestId;
}
void Lifx::sendMessage(const Lifx::Message &message)
{
QByteArray data;
// -- FRAME --
// Protocol number: must be 1024 (decimal)
quint16 protocol = 1024;
protocol |= (0x0001 << 4); //Message includes a target address: must be one (1)
protocol |= (message.frame.Tagged << 5); // Determines usage of the Frame Address target field
protocol &= ~(0x0003); // Message origin indicator: must be zero (0)
data.append(protocol >> 8);
data.append(protocol & 0xff);
//Source identifier: unique value set by the client, used by responses
data.append("nyma");
// -- FRAME ADDRESS --
//Target - frame address starts with 64 bits
//ADD RESERVED SECTION a reserved section of 48 bits (6 bytes)
data.append(6, '0');
//ADD ACK and RES
//ADD SEQUENCE NUMBER 1Byte
data.append(m_sequenceNumber + 1);
//ADD MESSAGE TYPE
//ADD SIZE
data.append(((static_cast<uint16_t>(data.length()+1) & 0xff00) >> 8));
data.append((static_cast<uint16_t>(data.length()+1) & 0x00ff));
//Finally another reserved field of 16 bits (2 bytes).
data.append(2, '0');
data = QByteArray::fromHex("0x310000340000000000000000000000000000000000000000000000000000000066000000005555FFFFFFFFAC0D00040000");
m_socket->writeDatagram(data, m_host, m_port);
Q_UNUSED(message)
}
void Lifx::onStateChanged(QAbstractSocket::SocketState state)
{
switch (state) {
case QAbstractSocket::SocketState::ConnectedState:
emit connectionChanged(true);
break;
case QAbstractSocket::SocketState::UnconnectedState:
m_reconnectTimer->start(10 * 1000);
emit connectionChanged(false);
break;
default:
emit connectionChanged(false);
break;
}
}
void Lifx::onReadyRead()
{
QByteArray data = m_socket->readAll();
qCDebug(dcLifx()) << "Message received" << data;
}
void Lifx::onReconnectTimer()
{
}

View File

@ -0,0 +1,151 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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
* This project may also contain libraries licensed under the open source software license GNU GPL v.3.
* 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 LIFX_H
#define LIFX_H
#include <QObject>
#include <QTimer>
#include <QHostAddress>
#include <QUdpSocket>
#include "network/networkaccessmanager.h"
#include "devices/device.h"
#include <QColor>
class Lifx : public QObject
{
Q_OBJECT
public:
#pragma pack(push, 1)
typedef struct {
/* frame */
uint16_t size;
uint16_t protocol:12;
uint8_t addressable:1;
uint8_t tagged:1;
uint8_t origin:2;
uint32_t source;
/* frame address */
uint8_t target[8];
uint8_t reserved[6];
uint8_t res_required:1;
uint8_t ack_required:1;
uint8_t :6;
uint8_t sequence;
/* protocol header */
uint64_t :64;
uint16_t type;
uint16_t :16;
/* variable length payload follows */
} ProtocolHeader_t;
#pragma pack(pop)
struct Frame {
//quint16 Size; //Size of entire message in bytes including this field
//quint16 Protocol; //Protocol number: must be 1024 (decimal)
//bool Addressable; //Message includes a target address: must be one (1)
bool Tagged; //Determines usage of the Frame Address target field
//quint8 Origin; //Message origin indicator: must be zero (0)
quint32 Source; //Source identifier: unique value set by the client, used by responses
};
struct FrameAddress {
quint64 Target; //6 byte device address (MAC address) or zero (0) means all devices. The last two bytes should be 0 bytes.
bool ResponseRequired; //Response message required
bool AckRequired; //Acknowledgement message required
quint8 Sequence; //Wrap around message sequence number
};
struct ProtocolHeader {
quint16 Type; //Message type determines the payload being used
};
struct Message {
Frame frame;
FrameAddress frameAddress;
ProtocolHeader protocolHeader;
QByteArray payload;
};
enum LightMessages {
Get = 101,
SetColor = 102,
SetWaveform = 103,
SetWaveformOptional = 119,
State = 107,
GetPower = 116,
SetPower = 117,
StatePower = 118,
GetInfrared = 120,
StateInfrared = 121,
SetInfrared = 122
};
explicit Lifx(QObject *parent = nullptr);
~Lifx();
bool enable();
void discoverDevices();
int setColorTemperature(int kelvin, int msFadeTime=500);
int setColor(QColor color, int msFadeTime = 500);
int setBrightness(int percentage, int msFadeTime = 500);
int setPower(bool power, int msFadeTime = 500);
int flash();
int flash15s();
private:
QTimer *m_reconnectTimer = nullptr;
QUdpSocket *m_socket = nullptr;
QHostAddress m_host;
quint16 m_port;
quint8 m_sequenceNumber = 0;
void sendMessage(const Message &message);
private slots:
void onStateChanged(QAbstractSocket::SocketState state);
void onReadyRead();
void onReconnectTimer();
signals:
void connectionChanged(bool connected);
void devicesDiscovered(QHostAddress address, int port);
//void requestExecuted(int requestId, bool success);
//void errorReceived(int code, const QString &message);
//void powerNotificationReceived(bool status);
//void brightnessNotificationReceived(int percentage);
//void colorTemperatureNotificationReceived(int kelvin);
//void rgbNotificationReceived(QRgb rgbColor);
//void hueNotificationReceived(int hueColor);
//void nameNotificationReceived(const QString &name);
//void saturationNotificationReceived(int percentage);
};
#endif // LIFX_H

View File

@ -1,9 +1,9 @@
include(../plugins.pri)
QT += network
TARGET = $$qtLibraryTarget(nymea_devicepluginlifx)
QT += network
SOURCES += \
devicepluginlifx.cpp \
lifx.cpp \

373
lifx/products.json Normal file
View File

@ -0,0 +1,373 @@
[
{
"vid": 1,
"name": "LIFX",
"products": [
{
"pid": 1,
"name": "Original 1000",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 3,
"name": "Color 650",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 10,
"name": "White 800 (Low Voltage)",
"features": {
"color": false,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2700, 6500],
"chain": false
}
},
{
"pid": 11,
"name": "White 800 (High Voltage)",
"features": {
"color": false,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2700, 6500],
"chain": false
}
},
{
"pid": 18,
"name": "White 900 BR30 (Low Voltage)",
"features": {
"color": false,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2700, 6500],
"chain": false
}
},
{
"pid": 20,
"name": "Color 1000 BR30",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 22,
"name": "Color 1000",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 27,
"name": "LIFX A19",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 28,
"name": "LIFX BR30",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 29,
"name": "LIFX+ A19",
"features": {
"color": true,
"infrared": true,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 30,
"name": "LIFX+ BR30",
"features": {
"color": true,
"infrared": true,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 31,
"name": "LIFX Z",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": true,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 32,
"name": "LIFX Z 2",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": true,
"temperature_range": [2500, 9000],
"chain": false,
"min_ext_mz_firmware": 1532997580,
"min_ext_mz_firmware_components": [2, 77]
}
},
{
"pid": 36,
"name": "LIFX Downlight",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 37,
"name": "LIFX Downlight",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 38,
"name": "LIFX Beam",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": true,
"temperature_range": [2500, 9000],
"chain": false,
"min_ext_mz_firmware": 1532997580,
"min_ext_mz_firmware_components": [2, 77]
}
},
{
"pid": 43,
"name": "LIFX A19",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 44,
"name": "LIFX BR30",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 45,
"name": "LIFX+ A19",
"features": {
"color": true,
"infrared": true,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 46,
"name": "LIFX+ BR30",
"features": {
"color": true,
"infrared": true,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 49,
"name": "LIFX Mini",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 50,
"name": "LIFX Mini Day and Dusk",
"features": {
"color": false,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [1500, 4000],
"chain": false
}
},
{
"pid": 51,
"name": "LIFX Mini White",
"features": {
"color": false,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2700, 2700],
"chain": false
}
},
{
"pid": 52,
"name": "LIFX GU10",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 55,
"name": "LIFX Tile",
"features": {
"color": true,
"infrared": false,
"matrix": true,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": true
}
},
{
"pid": 57,
"name": "LIFX Candle",
"features": {
"color": true,
"infrared": false,
"matrix": true,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 59,
"name": "LIFX Mini Color",
"features": {
"color": true,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
},
{
"pid": 60,
"name": "LIFX Mini Day and Dusk",
"features": {
"color": false,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [1500, 4000],
"chain": false
}
},
{
"pid": 61,
"name": "LIFX Mini White",
"features": {
"color": false,
"infrared": false,
"matrix": false,
"multizone": false,
"temperature_range": [2700, 2700],
"chain": false
}
},
{
"pid": 68,
"name": "LIFX Candle",
"features": {
"color": true,
"infrared": false,
"matrix": true,
"multizone": false,
"temperature_range": [2500, 9000],
"chain": false
}
}
]
}
]

View File

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>Lifx</name>
<message>
<source>Brightness</source>
<extracomment>The name of the ParamType (DeviceClass: dimmableBulb, ActionType: brightness, ID: {a0a1bdcc-2761-4d90-85d1-5ce887546611})
----------
The name of the ParamType (DeviceClass: dimmableBulb, EventType: brightness, ID: {a0a1bdcc-2761-4d90-85d1-5ce887546611})
----------
The name of the StateType ({a0a1bdcc-2761-4d90-85d1-5ce887546611}) of DeviceClass dimmableBulb
----------
The name of the ParamType (DeviceClass: colorBulb, ActionType: brightness, ID: {8bd20350-0e79-45dc-b68a-84da99356863})
----------
The name of the ParamType (DeviceClass: colorBulb, EventType: brightness, ID: {8bd20350-0e79-45dc-b68a-84da99356863})
----------
The name of the StateType ({8bd20350-0e79-45dc-b68a-84da99356863}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Brightness changed</source>
<extracomment>The name of the EventType ({a0a1bdcc-2761-4d90-85d1-5ce887546611}) of DeviceClass dimmableBulb
----------
The name of the EventType ({8bd20350-0e79-45dc-b68a-84da99356863}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Color</source>
<extracomment>The name of the ParamType (DeviceClass: colorBulb, ActionType: color, ID: {a47d8164-5023-4ffb-8298-73293e93e7f6})
----------
The name of the ParamType (DeviceClass: colorBulb, EventType: color, ID: {a47d8164-5023-4ffb-8298-73293e93e7f6})
----------
The name of the StateType ({a47d8164-5023-4ffb-8298-73293e93e7f6}) of DeviceClass colorBulb
----------
The name of the DeviceClass ({12907c9c-e7f0-47f2-bd58-39d52ffdf24e})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Color changed</source>
<extracomment>The name of the EventType ({a47d8164-5023-4ffb-8298-73293e93e7f6}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Color temperature</source>
<extracomment>The name of the ParamType (DeviceClass: dimmableBulb, ActionType: colorTemperature, ID: {95797dee-b836-4047-98d5-afbbce4f8c42})
----------
The name of the ParamType (DeviceClass: dimmableBulb, EventType: colorTemperature, ID: {95797dee-b836-4047-98d5-afbbce4f8c42})
----------
The name of the StateType ({95797dee-b836-4047-98d5-afbbce4f8c42}) of DeviceClass dimmableBulb
----------
The name of the ParamType (DeviceClass: colorBulb, ActionType: colorTemperature, ID: {dd7d7e70-5552-4531-8789-2d0f750488be})
----------
The name of the ParamType (DeviceClass: colorBulb, EventType: colorTemperature, ID: {dd7d7e70-5552-4531-8789-2d0f750488be})
----------
The name of the StateType ({dd7d7e70-5552-4531-8789-2d0f750488be}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Color temperature changed</source>
<extracomment>The name of the EventType ({95797dee-b836-4047-98d5-afbbce4f8c42}) of DeviceClass dimmableBulb
----------
The name of the EventType ({dd7d7e70-5552-4531-8789-2d0f750488be}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Day and Dusk</source>
<extracomment>The name of the DeviceClass ({a5b02af8-7c97-4a78-9c78-bafee7407b5e})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Host address</source>
<extracomment>The name of the ParamType (DeviceClass: dimmableBulb, Type: device, ID: {cc0a765b-a753-4e07-a6e5-47e9272c4346})
----------
The name of the ParamType (DeviceClass: colorBulb, Type: device, ID: {fd1c4817-5111-433a-b5b9-fd9f49d4975c})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Id</source>
<extracomment>The name of the ParamType (DeviceClass: dimmableBulb, Type: device, ID: {f157a97b-3fe5-4d9e-b5e3-5636f80d46ed})
----------
The name of the ParamType (DeviceClass: colorBulb, Type: device, ID: {976ecea0-ac25-47d4-9dc5-362962ddb6c0})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>LIFX</source>
<extracomment>The name of the vendor ({e5e48c0d-cff7-4c0f-983e-d23bd3e4ba87})
----------
The name of the plugin Lifx ({4e00ee30-79e2-447b-8dcc-c34470f41992})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Port</source>
<extracomment>The name of the ParamType (DeviceClass: dimmableBulb, Type: device, ID: {d233d9bf-6662-414d-92f6-dd3e267051b5})
----------
The name of the ParamType (DeviceClass: colorBulb, Type: device, ID: {44c13745-300c-491f-b617-3a8d53472998})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power</source>
<extracomment>The name of the ParamType (DeviceClass: dimmableBulb, ActionType: power, ID: {9e1344ea-cd05-4dd8-8948-8d2f5e00e1b0})
----------
The name of the ParamType (DeviceClass: dimmableBulb, EventType: power, ID: {9e1344ea-cd05-4dd8-8948-8d2f5e00e1b0})
----------
The name of the StateType ({9e1344ea-cd05-4dd8-8948-8d2f5e00e1b0}) of DeviceClass dimmableBulb
----------
The name of the ParamType (DeviceClass: colorBulb, ActionType: power, ID: {12de3f8f-2454-4057-aa12-9290296fdbdd})
----------
The name of the ParamType (DeviceClass: colorBulb, EventType: power, ID: {12de3f8f-2454-4057-aa12-9290296fdbdd})
----------
The name of the StateType ({12de3f8f-2454-4057-aa12-9290296fdbdd}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Power changed</source>
<extracomment>The name of the EventType ({9e1344ea-cd05-4dd8-8948-8d2f5e00e1b0}) of DeviceClass dimmableBulb
----------
The name of the EventType ({12de3f8f-2454-4057-aa12-9290296fdbdd}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reachable</source>
<extracomment>The name of the ParamType (DeviceClass: dimmableBulb, EventType: connected, ID: {d33f98ef-5e0f-464c-afed-88b95cc701cd})
----------
The name of the StateType ({d33f98ef-5e0f-464c-afed-88b95cc701cd}) of DeviceClass dimmableBulb
----------
The name of the ParamType (DeviceClass: colorBulb, EventType: connected, ID: {dc4c1640-90f3-4fe0-af9b-db7fa105f18a})
----------
The name of the StateType ({dc4c1640-90f3-4fe0-af9b-db7fa105f18a}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reachable changed</source>
<extracomment>The name of the EventType ({d33f98ef-5e0f-464c-afed-88b95cc701cd}) of DeviceClass dimmableBulb
----------
The name of the EventType ({dc4c1640-90f3-4fe0-af9b-db7fa105f18a}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Set brigtness</source>
<extracomment>The name of the ActionType ({a0a1bdcc-2761-4d90-85d1-5ce887546611}) of DeviceClass dimmableBulb
----------
The name of the ActionType ({8bd20350-0e79-45dc-b68a-84da99356863}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Set color</source>
<extracomment>The name of the ActionType ({a47d8164-5023-4ffb-8298-73293e93e7f6}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Set color temperature</source>
<extracomment>The name of the ActionType ({95797dee-b836-4047-98d5-afbbce4f8c42}) of DeviceClass dimmableBulb
----------
The name of the ActionType ({dd7d7e70-5552-4531-8789-2d0f750488be}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Set effect</source>
<extracomment>The name of the ActionType ({65f88396-2958-480e-b0be-c4695400a343}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>Set power</source>
<extracomment>The name of the ActionType ({9e1344ea-cd05-4dd8-8948-8d2f5e00e1b0}) of DeviceClass dimmableBulb
----------
The name of the ActionType ({12de3f8f-2454-4057-aa12-9290296fdbdd}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>effect</source>
<extracomment>The name of the ParamType (DeviceClass: colorBulb, ActionType: effect, ID: {65f88396-2958-480e-b0be-c4695400a343})
----------
The name of the ParamType (DeviceClass: colorBulb, EventType: effect, ID: {65f88396-2958-480e-b0be-c4695400a343})
----------
The name of the StateType ({65f88396-2958-480e-b0be-c4695400a343}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>effect changed</source>
<extracomment>The name of the EventType ({65f88396-2958-480e-b0be-c4695400a343}) of DeviceClass colorBulb</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
</TS>