cloud actions do now work
parent
8907fb7b47
commit
5e40675829
|
|
@ -1,9 +1,18 @@
|
|||
# Lifx
|
||||
|
||||
This plug-in implements the LAN API for Lifx devices
|
||||
This plug-in integrates LIFX lights to nymea.
|
||||
|
||||
## Supported Things
|
||||
|
||||
* All LIFX lights
|
||||
|
||||
## Requirements
|
||||
|
||||
* LIFX cloud access token.
|
||||
** Get the token from https://cloud.lifx.com/settings
|
||||
* Internet connection
|
||||
* The package 'nymea-plugin-lifx' must be installed.
|
||||
|
||||
## More
|
||||
|
||||
https://www.lifx.com/
|
||||
|
|
|
|||
|
|
@ -63,52 +63,45 @@ void IntegrationPluginLifx::init()
|
|||
m_brightnessStateTypeIds.insert(colorBulbThingClassId, colorBulbBrightnessStateTypeId);
|
||||
m_brightnessStateTypeIds.insert(dimmableBulbThingClassId, dimmableBulbBrightnessStateTypeId);
|
||||
|
||||
|
||||
m_colorTemperatureStateTypeIds.insert(colorBulbThingClassId, colorBulbColorTemperatureStateTypeId);
|
||||
m_colorTemperatureStateTypeIds.insert(dimmableBulbThingClassId, dimmableBulbColorTemperatureStateTypeId);
|
||||
|
||||
m_hostAddressParamTypeIds.insert(colorBulbThingClassId, colorBulbThingHostParamTypeId);
|
||||
m_hostAddressParamTypeIds.insert(dimmableBulbThingClassId, dimmableBulbThingHostParamTypeId);
|
||||
|
||||
m_portParamTypeIds.insert(colorBulbThingClassId, colorBulbThingPortParamTypeId);
|
||||
m_portParamTypeIds.insert(dimmableBulbThingClassId, dimmableBulbThingPortParamTypeId);
|
||||
|
||||
m_idParamTypeIds.insert(colorBulbThingClassId, colorBulbThingIdParamTypeId);
|
||||
m_idParamTypeIds.insert(dimmableBulbThingClassId, dimmableBulbThingIdParamTypeId);
|
||||
|
||||
m_serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser("_hap._tcp"); // discovers all homekit devices
|
||||
|
||||
QFile file;
|
||||
file.setFileName("/tmp/products.json");
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qCWarning(dcLifx()) << "Could not open products file" << file.errorString() << "file name:" << file.fileName();
|
||||
} else {
|
||||
QJsonDocument productsJson = QJsonDocument::fromJson(file.readAll());
|
||||
file.close();
|
||||
|
||||
if (!productsJson.isArray()) {
|
||||
qCWarning(dcLifx()) << "Products JSON is not a valid array";
|
||||
} else {
|
||||
QJsonArray productsArray = productsJson.array().first().toObject().value("products").toArray();
|
||||
foreach (QJsonValue value, productsArray) {
|
||||
QJsonObject object = value.toObject();
|
||||
Lifx::LifxProduct product;
|
||||
product.pid = object["pid"].toInt();
|
||||
product.name = object["name"].toString();
|
||||
qCDebug(dcLifx()) << "Lifx product JSON, found product. PID:" << product.pid << "Name" << product.name;
|
||||
QJsonObject features = object["features"].toObject();
|
||||
product.color = features["color"].toBool();
|
||||
product.infrared = features["infrared"].toBool();
|
||||
product.matrix = features["matrix"].toBool();
|
||||
product.multizone = features["multizone"].toBool();
|
||||
product.minColorTemperature = features["temperature_range"].toArray().first().toInt();
|
||||
product.maxColorTemperature = features["temperature_range"].toArray().last().toInt();
|
||||
product.chain = features["chain"].toBool();
|
||||
m_lifxProducts.insert(product.pid, product);
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO for LAN connection, get id and device features
|
||||
// QFile file;
|
||||
// file.setFileName("/tmp/products.json");
|
||||
// if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
// qCWarning(dcLifx()) << "Could not open products file" << file.errorString() << "file name:" << file.fileName();
|
||||
// } else {
|
||||
// QJsonDocument productsJson = QJsonDocument::fromJson(file.readAll());
|
||||
// file.close();
|
||||
|
||||
// if (!productsJson.isArray()) {
|
||||
// qCWarning(dcLifx()) << "Products JSON is not a valid array";
|
||||
// } else {
|
||||
// QJsonArray productsArray = productsJson.array().first().toObject().value("products").toArray();
|
||||
// foreach (QJsonValue value, productsArray) {
|
||||
// QJsonObject object = value.toObject();
|
||||
// LifxLan::LifxProduct product;
|
||||
// product.pid = object["pid"].toInt();
|
||||
// product.name = object["name"].toString();
|
||||
// qCDebug(dcLifx()) << "Lifx product JSON, found product. PID:" << product.pid << "Name" << product.name;
|
||||
// QJsonObject features = object["features"].toObject();
|
||||
// product.color = features["color"].toBool();
|
||||
// product.infrared = features["infrared"].toBool();
|
||||
// product.matrix = features["matrix"].toBool();
|
||||
// product.multizone = features["multizone"].toBool();
|
||||
// product.minColorTemperature = features["temperature_range"].toArray().first().toInt();
|
||||
// product.maxColorTemperature = features["temperature_range"].toArray().last().toInt();
|
||||
// product.chain = features["chain"].toBool();
|
||||
// m_lifxProducts.insert(product.pid, product);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
m_networkManager = hardwareManager()->networkManager();
|
||||
}
|
||||
|
||||
|
|
@ -156,6 +149,7 @@ void IntegrationPluginLifx::confirmPairing(ThingPairingInfo *info, const QString
|
|||
|
||||
void IntegrationPluginLifx::discoverThings(ThingDiscoveryInfo *info)
|
||||
{
|
||||
// NOTE: the LAN API is not yet finished, to enable LAN discovery add "discovery" to the createMethods
|
||||
if ((info->thingClassId() == colorBulbThingClassId) || (info->thingClassId() == dimmableBulbThingClassId)) {
|
||||
QHash<QString, ThingDescriptor> descriptors;
|
||||
foreach (const ZeroConfServiceEntry avahiEntry, m_serviceBrowser->serviceEntries()) {
|
||||
|
|
@ -203,15 +197,20 @@ void IntegrationPluginLifx::setupThing(ThingSetupInfo *info)
|
|||
Thing *thing = info->thing();
|
||||
|
||||
if (thing->thingClassId() == colorBulbThingClassId || thing->thingClassId() == dimmableBulbThingClassId) {
|
||||
Lifx *lifx = new Lifx(QHostAddress(thing->paramValue(m_hostAddressParamTypeIds.value(thing->thingClassId())).toString()),
|
||||
thing->paramValue(m_portParamTypeIds.value(thing->thingClassId())).toInt(), this);
|
||||
if(lifx->enable()) {
|
||||
m_lifxConnections.insert(thing, lifx);
|
||||
//TODO async setup
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
} else {
|
||||
lifx->deleteLater();
|
||||
if (thing->parentId().isNull()) {
|
||||
// Lifx LAN
|
||||
//LifxLan *lifx = new LifxLan(, this);
|
||||
//if(lifx->enable()) {
|
||||
// m_lifxLanConnections.insert(thing, lifx);
|
||||
//TODO async setup for LAN devices
|
||||
// info->finish(Thing::ThingErrorNoError);
|
||||
//} else {
|
||||
// lifx->deleteLater();
|
||||
info->finish(Thing::ThingErrorSetupFailed);
|
||||
//}
|
||||
} else {
|
||||
// Lifx Cloud
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
} else if (thing->thingClassId() == lifxAccountThingClassId) {
|
||||
|
||||
|
|
@ -250,8 +249,9 @@ void IntegrationPluginLifx::postSetupThing(Thing *thing)
|
|||
if (!m_pluginTimer) {
|
||||
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(60);
|
||||
connect(m_pluginTimer, &PluginTimer::timeout, this, [this]() {
|
||||
foreach (Lifx *lifx, m_lifxConnections) {
|
||||
foreach (LifxLan *lifx, m_lifxLanConnections) {
|
||||
Q_UNUSED(lifx)
|
||||
//TODO update LAN device states
|
||||
}
|
||||
|
||||
foreach (LifxCloud *lifx, m_lifxCloudConnections) {
|
||||
|
|
@ -271,11 +271,11 @@ void IntegrationPluginLifx::executeAction(ThingActionInfo *info)
|
|||
Thing *thing = info->thing();
|
||||
Action action = info->action();
|
||||
bool cloudDevice = false;
|
||||
Lifx *lifx;
|
||||
LifxLan *lifx;
|
||||
LifxCloud *lifxCloud;
|
||||
|
||||
if (m_lifxConnections.contains(thing)) {
|
||||
lifx = m_lifxConnections.value(thing);
|
||||
if (m_lifxLanConnections.contains(thing)) {
|
||||
lifx = m_lifxLanConnections.value(thing);
|
||||
} else if (m_lifxCloudConnections.contains(myThings().findById(thing->parentId()))) {
|
||||
lifxCloud = m_lifxCloudConnections.value(myThings().findById(thing->parentId()));
|
||||
cloudDevice = true;
|
||||
|
|
@ -299,9 +299,13 @@ void IntegrationPluginLifx::executeAction(ThingActionInfo *info)
|
|||
|
||||
} else if (action.actionTypeId() == colorBulbBrightnessActionTypeId) {
|
||||
|
||||
if (!thing->stateValue(colorBulbPowerStateTypeId).toBool())
|
||||
lifx->setPower(true);
|
||||
|
||||
if (!thing->stateValue(colorBulbPowerStateTypeId).toBool()){
|
||||
if (cloudDevice) {
|
||||
lifxCloud->setPower(lightId, true);
|
||||
} else {
|
||||
lifx->setPower(true);
|
||||
}
|
||||
}
|
||||
int brightness = info->action().param(colorBulbBrightnessActionBrightnessParamTypeId).value().toInt();
|
||||
int requestId;
|
||||
if (cloudDevice) {
|
||||
|
|
@ -313,8 +317,13 @@ void IntegrationPluginLifx::executeAction(ThingActionInfo *info)
|
|||
m_asyncActions.insert(requestId, info);
|
||||
} else if (action.actionTypeId() == colorBulbColorActionColorParamTypeId) {
|
||||
QRgb color = QColor(action.param(colorBulbColorActionColorParamTypeId).value().toString()).rgba();
|
||||
if (!thing->stateValue(colorBulbPowerStateTypeId).toBool())
|
||||
lifx->setPower(true);
|
||||
if (!thing->stateValue(colorBulbPowerStateTypeId).toBool()){
|
||||
if (cloudDevice) {
|
||||
lifxCloud->setPower(lightId, true);
|
||||
} else {
|
||||
lifx->setPower(true);
|
||||
}
|
||||
}
|
||||
int requestId;
|
||||
if (cloudDevice) {
|
||||
requestId = lifxCloud->setColor(lightId, color);
|
||||
|
|
@ -325,8 +334,13 @@ void IntegrationPluginLifx::executeAction(ThingActionInfo *info)
|
|||
m_asyncActions.insert(requestId, info);
|
||||
} else if (action.actionTypeId() == colorBulbColorTemperatureActionTypeId) {
|
||||
int colorTemperature = 6500 - (action.param(colorBulbColorTemperatureActionColorTemperatureParamTypeId).value().toUInt() * -11.12);
|
||||
if (!thing->stateValue(colorBulbPowerStateTypeId).toBool())
|
||||
lifx->setPower(true);
|
||||
if (!thing->stateValue(colorBulbPowerStateTypeId).toBool()){
|
||||
if (cloudDevice) {
|
||||
lifxCloud->setPower(lightId, true);
|
||||
} else {
|
||||
lifx->setPower(true);
|
||||
}
|
||||
}
|
||||
int requestId;
|
||||
if (cloudDevice) {
|
||||
requestId = lifxCloud->setColorTemperature(lightId, colorTemperature);
|
||||
|
|
@ -335,6 +349,40 @@ void IntegrationPluginLifx::executeAction(ThingActionInfo *info)
|
|||
}
|
||||
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
||||
m_asyncActions.insert(requestId, info);
|
||||
} else if (action.actionTypeId() == colorBulbEffectStateTypeId) {
|
||||
if (!thing->stateValue(colorBulbPowerStateTypeId).toBool()){
|
||||
if (cloudDevice) {
|
||||
lifxCloud->setPower(lightId, true);
|
||||
} else {
|
||||
lifx->setPower(true);
|
||||
}
|
||||
}
|
||||
QString effectString = action.param(colorBulbColorTemperatureActionColorTemperatureParamTypeId).value().toString();
|
||||
int requestId;
|
||||
LifxCloud::Effect effect;
|
||||
if (effectString == "None") {
|
||||
effect = LifxCloud::EffectNone;
|
||||
} else if (effectString == "Breathe") {
|
||||
effect = LifxCloud::EffectBreathe;
|
||||
} else if (effectString == "Move") {
|
||||
effect = LifxCloud::EffectMove;
|
||||
} else if (effectString == "Morph") {
|
||||
effect = LifxCloud::EffectMove;
|
||||
} else if (effectString == "Flame") {
|
||||
effect = LifxCloud::EffectMove;
|
||||
} else if (effectString == "Pulse") {
|
||||
effect = LifxCloud::EffectMove;
|
||||
}
|
||||
if (cloudDevice) {
|
||||
QColor color = QColor(thing->stateValue(colorBulbColorStateTypeId).toString());
|
||||
requestId = lifxCloud->setEffect(lightId, effect, color);
|
||||
} else {
|
||||
qCWarning(dcLifx()) << "LAN devices are not yet supported";
|
||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
||||
m_asyncActions.insert(requestId, info);
|
||||
} else {
|
||||
Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8());
|
||||
}
|
||||
|
|
@ -351,8 +399,13 @@ void IntegrationPluginLifx::executeAction(ThingActionInfo *info)
|
|||
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
||||
} else if (action.actionTypeId() == dimmableBulbBrightnessActionTypeId) {
|
||||
int brightness = action.param(dimmableBulbBrightnessActionBrightnessParamTypeId).value().toInt();
|
||||
if (!thing->stateValue(dimmableBulbPowerStateTypeId).toBool())
|
||||
lifx->setPower(true);
|
||||
if (!thing->stateValue(colorBulbPowerStateTypeId).toBool()){
|
||||
if (cloudDevice) {
|
||||
lifxCloud->setPower(lightId, true);
|
||||
} else {
|
||||
lifx->setPower(true);
|
||||
}
|
||||
}
|
||||
int requestId;
|
||||
if (cloudDevice) {
|
||||
requestId = lifxCloud->setBrightnesss(lightId, brightness);
|
||||
|
|
@ -361,6 +414,39 @@ void IntegrationPluginLifx::executeAction(ThingActionInfo *info)
|
|||
}
|
||||
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
||||
m_asyncActions.insert(requestId, info);
|
||||
} else if (action.actionTypeId() == dimmableBulbEffectStateTypeId) {
|
||||
if (!thing->stateValue(colorBulbPowerStateTypeId).toBool()){
|
||||
if (cloudDevice) {
|
||||
lifxCloud->setPower(lightId, true);
|
||||
} else {
|
||||
lifx->setPower(true);
|
||||
}
|
||||
}
|
||||
QString effectString = action.param(dimmableBulbColorTemperatureActionColorTemperatureParamTypeId).value().toString();
|
||||
int requestId;
|
||||
LifxCloud::Effect effect;
|
||||
if (effectString == "None") {
|
||||
effect = LifxCloud::EffectNone;
|
||||
} else if (effectString == "Breathe") {
|
||||
effect = LifxCloud::EffectBreathe;
|
||||
} else if (effectString == "Move") {
|
||||
effect = LifxCloud::EffectMove;
|
||||
} else if (effectString == "Morph") {
|
||||
effect = LifxCloud::EffectMove;
|
||||
} else if (effectString == "Flame") {
|
||||
effect = LifxCloud::EffectMove;
|
||||
} else if (effectString == "Pulse") {
|
||||
effect = LifxCloud::EffectMove;
|
||||
}
|
||||
if (cloudDevice) {
|
||||
requestId = lifxCloud->setEffect(lightId, effect, QColor("0xffffff"));
|
||||
} else {
|
||||
qCWarning(dcLifx()) << "LAN devices are not yet supported";
|
||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
connect(info, &ThingActionInfo::aborted, this, [requestId, this] {m_asyncActions.remove(requestId);});
|
||||
m_asyncActions.insert(requestId, info);
|
||||
} else {
|
||||
Q_ASSERT_X(false, "executeAction", QString("Unhandled actionTypeId: %1").arg(action.actionTypeId().toString()).toUtf8());
|
||||
}
|
||||
|
|
@ -372,8 +458,8 @@ void IntegrationPluginLifx::executeAction(ThingActionInfo *info)
|
|||
void IntegrationPluginLifx::thingRemoved(Thing *thing)
|
||||
{
|
||||
if (thing->thingClassId() == colorBulbThingClassId || thing->thingClassId() == dimmableBulbThingClassId) {
|
||||
if (m_lifxConnections.contains(thing))
|
||||
m_lifxConnections.take(thing)->deleteLater();
|
||||
if (m_lifxLanConnections.contains(thing))
|
||||
m_lifxLanConnections.take(thing)->deleteLater();
|
||||
} else if (thing->thingClassId() == lifxAccountThingClassId) {
|
||||
if (m_lifxCloudConnections.contains(thing))
|
||||
m_lifxCloudConnections.take(thing)->deleteLater();
|
||||
|
|
@ -412,17 +498,17 @@ void IntegrationPluginLifx::executeBrowserItem(BrowserActionInfo *info)
|
|||
connect(info, &BrowserActionInfo::aborted, this, [requestId, this] {m_asyncBrowserItem.remove(requestId);});
|
||||
}
|
||||
|
||||
void IntegrationPluginLifx::onConnectionChanged(bool connected)
|
||||
void IntegrationPluginLifx::onLifxLanConnectionChanged(bool connected)
|
||||
{
|
||||
Q_UNUSED(connected)
|
||||
Lifx *lifx = static_cast<Lifx *>(sender());
|
||||
Thing *thing = m_lifxConnections.key(lifx);
|
||||
LifxLan *lifx = static_cast<LifxLan *>(sender());
|
||||
Thing *thing = m_lifxLanConnections.key(lifx);
|
||||
if (!thing)
|
||||
return;
|
||||
thing->setStateValue(m_connectedStateTypeIds.value(thing->thingClassId()), connected);
|
||||
}
|
||||
|
||||
void IntegrationPluginLifx::onRequestExecuted(int requestId, bool success)
|
||||
void IntegrationPluginLifx::onLifxLanRequestExecuted(int requestId, bool success)
|
||||
{
|
||||
if (m_asyncActions.contains(requestId)) {
|
||||
ThingActionInfo *info = m_asyncActions.take(requestId);
|
||||
|
|
@ -492,8 +578,8 @@ void IntegrationPluginLifx::onLifxCloudLightsListReceived(const QList<LifxCloud:
|
|||
ThingDescriptor thingDescriptor(thingClassId, light.product.name, light.location.name, parentThing->id());
|
||||
foreach (Thing * thing, myThings().filterByParam(m_idParamTypeIds.value(thingClassId), light.id)) {
|
||||
thing->setStateValue(m_connectedStateTypeIds.value(thingClassId), light.connected);
|
||||
thing->setStateValue(m_brightnessStateTypeIds.value(thingClassId), light.brightness);
|
||||
thing->setStateValue(m_colorTemperatureStateTypeIds.value(thingClassId), light.colorTemperature);
|
||||
thing->setStateValue(m_brightnessStateTypeIds.value(thingClassId), light.brightness*100.00);
|
||||
thing->setStateValue(m_colorTemperatureStateTypeIds.value(thingClassId), light.colorTemperature); //TODO Kelvin to mired
|
||||
thing->setStateValue(m_powerStateTypeIds.value(thingClassId), light.power);
|
||||
if (thingClassId == colorBulbThingClassId) {
|
||||
thing->setStateValue(colorBulbColorStateTypeId, light.color);
|
||||
|
|
@ -537,7 +623,6 @@ void IntegrationPluginLifx::onLifxCloudRequestExecuted(int requestId, bool succe
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void IntegrationPluginLifx::onLifxCloudScenesListReceived(const QList<LifxCloud::Scene> &scenes)
|
||||
{
|
||||
LifxCloud *lifxCloud = static_cast<LifxCloud *>(sender());
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "plugintimer.h"
|
||||
#include "lifx.h"
|
||||
#include "lifxlan.h"
|
||||
#include "lifxcloud.h"
|
||||
|
||||
#include "network/networkaccessmanager.h"
|
||||
|
|
@ -71,7 +71,7 @@ private:
|
|||
PluginTimer *m_pluginTimer = nullptr;
|
||||
QHash<LifxCloud *, ThingSetupInfo *> m_asyncCloudSetups;
|
||||
QHash<int, ThingActionInfo *> m_asyncActions;
|
||||
QHash<Thing *, Lifx *> m_lifxConnections;
|
||||
QHash<Thing *, LifxLan *> m_lifxLanConnections;
|
||||
QHash<Thing *, LifxCloud *> m_lifxCloudConnections;
|
||||
QHash<LifxCloud *, BrowseResult *> m_asyncBrowseResults;
|
||||
QHash<int, BrowserActionInfo *> m_asyncBrowserItem;
|
||||
|
|
@ -87,11 +87,11 @@ private:
|
|||
QHash<ThingClassId, ParamTypeId> m_idParamTypeIds;
|
||||
|
||||
QHash<ThingId, ThingActionInfo *> m_pendingBrightnessAction;
|
||||
QHash<int, Lifx::LifxProduct> m_lifxProducts;
|
||||
QHash<int, LifxLan::LifxProduct> m_lifxProducts;
|
||||
|
||||
private slots:
|
||||
void onConnectionChanged(bool connected);
|
||||
void onRequestExecuted(int requestId, bool success);
|
||||
void onLifxLanConnectionChanged(bool connected);
|
||||
void onLifxLanRequestExecuted(int requestId, bool success);
|
||||
|
||||
void onLifxCloudConnectionChanged(bool connected);
|
||||
void onLifxCloudAuthenticationChanged(bool authenticated);
|
||||
|
|
|
|||
|
|
@ -51,23 +51,9 @@
|
|||
"id": "12907c9c-e7f0-47f2-bd58-39d52ffdf24e",
|
||||
"name": "colorBulb",
|
||||
"displayName": "Color",
|
||||
"createMethods": ["auto", "discovery"],
|
||||
"createMethods": ["auto"],
|
||||
"interfaces": ["colorlight", "connectable"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "fd1c4817-5111-433a-b5b9-fd9f49d4975c",
|
||||
"name": "host",
|
||||
"displayName": "Host address",
|
||||
"type" : "QString",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": "44c13745-300c-491f-b617-3a8d53472998",
|
||||
"name": "port",
|
||||
"displayName": "Port",
|
||||
"type" : "int",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": "976ecea0-ac25-47d4-9dc5-362962ddb6c0",
|
||||
"name": "id",
|
||||
|
|
@ -139,10 +125,14 @@
|
|||
"displayNameEvent": "Effect changed",
|
||||
"displayNameAction": "Set effect",
|
||||
"type": "QString",
|
||||
"defaultValue": "none",
|
||||
"defaultValue": "None",
|
||||
"possibleValues": [
|
||||
"none",
|
||||
"color loop"
|
||||
"None",
|
||||
"Breathe",
|
||||
"Move",
|
||||
"Morph",
|
||||
"Flame",
|
||||
"Pulse"
|
||||
],
|
||||
"writable": true
|
||||
}
|
||||
|
|
@ -152,23 +142,9 @@
|
|||
"id": "a5b02af8-7c97-4a78-9c78-bafee7407b5e",
|
||||
"name": "dimmableBulb",
|
||||
"displayName": "Day and Dusk",
|
||||
"createMethods": ["auto", "discovery"],
|
||||
"createMethods": ["auto"],
|
||||
"interfaces": ["colortemperaturelight", "connectable"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "cc0a765b-a753-4e07-a6e5-47e9272c4346",
|
||||
"name": "host",
|
||||
"displayName": "Host address",
|
||||
"type" : "QString",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": "d233d9bf-6662-414d-92f6-dd3e267051b5",
|
||||
"name": "port",
|
||||
"displayName": "Port",
|
||||
"type" : "int",
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"id": "f157a97b-3fe5-4d9e-b5e3-5636f80d46ed",
|
||||
"name": "id",
|
||||
|
|
@ -221,6 +197,24 @@
|
|||
"minValue": 153,
|
||||
"maxValue": 500,
|
||||
"writable": true
|
||||
},
|
||||
{
|
||||
"id": "be47c474-eca1-479e-9393-68281a43d72a",
|
||||
"name": "effect",
|
||||
"displayName": "Effect",
|
||||
"displayNameEvent": "Effect changed",
|
||||
"displayNameAction": "Set effect",
|
||||
"type": "QString",
|
||||
"defaultValue": "None",
|
||||
"possibleValues": [
|
||||
"None",
|
||||
"Breathe",
|
||||
"Move",
|
||||
"Morph",
|
||||
"Flame",
|
||||
"Pulse"
|
||||
],
|
||||
"writable": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
include(../plugins.pri)
|
||||
|
||||
QT += network
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginlifx.cpp \
|
||||
lifx.cpp \
|
||||
lifxcloud.cpp \
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginlifx.h \
|
||||
lifx.h \
|
||||
lifxcloud.h \
|
||||
|
||||
|
|
@ -74,21 +74,9 @@ void LifxCloud::listLights()
|
|||
QNetworkReply *reply = m_networkManager->get(request);
|
||||
connect(reply, &QNetworkReply::finished, &QNetworkReply::deleteLater);
|
||||
connect(reply, &QNetworkReply::finished, this, [reply, this] {
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
|
||||
// check HTTP status code
|
||||
if (status > 207) {
|
||||
qCWarning(dcLifx()) << "Error get lights list" << status << reply->errorString();
|
||||
if(!checkHttpStatusCode(reply)) {
|
||||
return;
|
||||
}
|
||||
if (!m_authenticated) {
|
||||
m_authenticated = true;
|
||||
emit authenticationChanged(true);
|
||||
}
|
||||
if (!m_connected) {
|
||||
m_connected = true;
|
||||
emit authenticationChanged(true);
|
||||
}
|
||||
QByteArray rawData = reply->readAll();
|
||||
|
||||
QJsonDocument data; QJsonParseError error;
|
||||
|
|
@ -110,6 +98,11 @@ void LifxCloud::listLights()
|
|||
Light light;
|
||||
light.id = object["id"].toString().toUtf8();
|
||||
light.uuid = object["uuid"].toString().toUtf8();
|
||||
if (object["power"].toString() == "on") {
|
||||
light.power = true;
|
||||
} else {
|
||||
light.power = false;
|
||||
}
|
||||
light.label = object["label"].toString();
|
||||
light.connected = object["connected"].toBool();
|
||||
light.brightness = object["brightness"].toDouble();
|
||||
|
|
@ -162,21 +155,9 @@ void LifxCloud::listScenes()
|
|||
QNetworkReply *reply = m_networkManager->get(request);
|
||||
connect(reply, &QNetworkReply::finished, &QNetworkReply::deleteLater);
|
||||
connect(reply, &QNetworkReply::finished, this, [reply, this] {
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
|
||||
// check HTTP status code
|
||||
if (status != 200) {
|
||||
qCWarning(dcLifx()) << "Error get scene list" << status << reply->errorString();
|
||||
if(!checkHttpStatusCode(reply)) {
|
||||
return;
|
||||
}
|
||||
if (!m_authenticated) {
|
||||
m_authenticated = true;
|
||||
emit authenticationChanged(true);
|
||||
}
|
||||
if (!m_connected) {
|
||||
m_connected = true;
|
||||
emit authenticationChanged(true);
|
||||
}
|
||||
QByteArray rawData = reply->readAll();
|
||||
qCDebug(dcLifx()) << "Got list scenes reply" << rawData;
|
||||
QJsonDocument data; QJsonParseError error;
|
||||
|
|
@ -202,27 +183,27 @@ void LifxCloud::listScenes()
|
|||
|
||||
int LifxCloud::setPower(const QString &lightId, bool power, int duration)
|
||||
{
|
||||
return setState(lightId, StatePower, power, duration);
|
||||
return setState("id:"+lightId, StatePower, power, duration);
|
||||
}
|
||||
|
||||
int LifxCloud::setBrightnesss(const QString &lightId, int brightness, int duration)
|
||||
{
|
||||
return setState(lightId, StateBrightness, brightness/100.00, duration);
|
||||
return setState("id:"+lightId, StateBrightness, brightness/100.00, duration);
|
||||
}
|
||||
|
||||
int LifxCloud::setColor(const QString &lightId, QColor color, int duration)
|
||||
{
|
||||
return setState(lightId, StateColor, color.name(), duration);
|
||||
return setState("id:"+lightId, StateColor, color.name(), duration);
|
||||
}
|
||||
|
||||
int LifxCloud::setColorTemperature(const QString &selector, int kelvin, int duration)
|
||||
int LifxCloud::setColorTemperature(const QString &lightId, int kelvin, int duration)
|
||||
{
|
||||
return setState(selector, StateColorTemperature, kelvin, duration);
|
||||
return setState("id:"+lightId, StateColorTemperature, kelvin, duration);
|
||||
}
|
||||
|
||||
int LifxCloud::setInfrared(const QString &lightId, int infrared, int duration)
|
||||
{
|
||||
return setState(lightId, StateColor, infrared/100.00, duration);
|
||||
return setState("id:"+lightId, StateColor, infrared/100.00, duration);
|
||||
}
|
||||
|
||||
int LifxCloud::activateScene(const QString &sceneId)
|
||||
|
|
@ -240,34 +221,59 @@ int LifxCloud::activateScene(const QString &sceneId)
|
|||
QNetworkReply *reply = m_networkManager->put(request, "");
|
||||
connect(reply, &QNetworkReply::finished, &QNetworkReply::deleteLater);
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
// check HTTP status code
|
||||
if (status == 401 || status == 403) {
|
||||
if (m_authenticated) {
|
||||
m_authenticated = false;
|
||||
emit authenticationChanged(false);
|
||||
}
|
||||
}
|
||||
if (status > 207) {
|
||||
qCWarning(dcLifx()) << "Error activate Scene" << status << reply->errorString();
|
||||
emit requestExecuted(requestId, false);
|
||||
return;
|
||||
}
|
||||
if (!m_authenticated) {
|
||||
m_authenticated = true;
|
||||
emit authenticationChanged(true);
|
||||
}
|
||||
if (!m_connected) {
|
||||
m_connected = true;
|
||||
emit authenticationChanged(true);
|
||||
}
|
||||
emit requestExecuted(requestId, true);
|
||||
emit requestExecuted(requestId, checkHttpStatusCode(reply));
|
||||
QByteArray rawData = reply->readAll();
|
||||
qCDebug(dcLifx()) << "Got activate scene reply" << rawData;
|
||||
});
|
||||
return requestId;
|
||||
}
|
||||
|
||||
int LifxCloud::setEffect(const QString &lightId, LifxCloud::Effect effect, QColor color)
|
||||
{
|
||||
if (m_authorizationToken.isEmpty()) {
|
||||
qCWarning(dcLifx()) << "Authorization token is not set";
|
||||
return -1;
|
||||
}
|
||||
int requestId = qrand();
|
||||
QNetworkRequest request;
|
||||
QJsonObject payload;
|
||||
switch (effect) {
|
||||
case LifxCloud::EffectNone:
|
||||
request.setUrl(QUrl(QString("https://api.lifx.com/v1/lights/id:%1/effects/off").arg(lightId)));
|
||||
break;
|
||||
case LifxCloud::EffectBreathe:
|
||||
request.setUrl(QUrl(QString("https://api.lifx.com/v1/lights/id:%1/effects/breathe").arg(lightId)));
|
||||
payload["color"] = color.name();
|
||||
break;
|
||||
case LifxCloud::EffectMove:
|
||||
request.setUrl(QUrl(QString("https://api.lifx.com/v1/lights/id:%1/effects/move").arg(lightId)));
|
||||
break;
|
||||
case LifxCloud::EffectMorph:
|
||||
request.setUrl(QUrl(QString("https://api.lifx.com/v1/lights/id:%1/effects/morph").arg(lightId)));
|
||||
break;
|
||||
case LifxCloud::EffectFlame:
|
||||
request.setUrl(QUrl(QString("https://api.lifx.com/v1/lights/id:%1/effects/flame").arg(lightId)));
|
||||
break;
|
||||
case LifxCloud::EffectPulse:
|
||||
request.setUrl(QUrl(QString("https://api.lifx.com/v1/lights/id:%1/effects/pulse").arg(lightId)));
|
||||
payload["color"] = color.name();
|
||||
break;
|
||||
}
|
||||
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Authorization","Bearer "+m_authorizationToken);
|
||||
QJsonDocument doc;
|
||||
doc.setObject(payload);
|
||||
QNetworkReply *reply = m_networkManager->put(request, doc.toJson());
|
||||
connect(reply, &QNetworkReply::finished, &QNetworkReply::deleteLater);
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
|
||||
QByteArray rawData = reply->readAll();
|
||||
qCDebug(dcLifx()) << "Got set state reply" << rawData;
|
||||
emit requestExecuted(requestId, checkHttpStatusCode(reply));
|
||||
});
|
||||
return requestId;
|
||||
}
|
||||
|
||||
int LifxCloud::setState(const QString &selector, State state, QVariant stateValue, int duration)
|
||||
{
|
||||
if (m_authorizationToken.isEmpty()) {
|
||||
|
|
@ -275,7 +281,6 @@ int LifxCloud::setState(const QString &selector, State state, QVariant stateValu
|
|||
return -1;
|
||||
}
|
||||
int requestId = qrand();
|
||||
|
||||
QNetworkRequest request;
|
||||
request.setUrl(QUrl(QString("https://api.lifx.com/v1/lights/%1/state").arg(selector)));
|
||||
request.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/json");
|
||||
|
|
@ -287,45 +292,77 @@ int LifxCloud::setState(const QString &selector, State state, QVariant stateValu
|
|||
switch (state) {
|
||||
case StatePower:
|
||||
if (stateValue.toBool())
|
||||
payload["power"] = "ON";
|
||||
payload["power"] = "on";
|
||||
else
|
||||
payload["power"] = "OFF";
|
||||
payload["power"] = "off";
|
||||
|
||||
qCDebug(dcLifx()) << "Set state power" << stateValue.toBool();
|
||||
break;
|
||||
case StateBrightness:
|
||||
payload["brightness"] = stateValue.toDouble();
|
||||
qCDebug(dcLifx()) << "Set state brightness" << stateValue;
|
||||
break;
|
||||
case StateColor:
|
||||
payload["color"] = stateValue.toString();
|
||||
qCDebug(dcLifx()) << "Set state color" << stateValue;
|
||||
break;
|
||||
case StateColorTemperature:
|
||||
payload["color"] = "kelvin:"+stateValue.toString();
|
||||
qCDebug(dcLifx()) << "Set state color" << stateValue;
|
||||
break;
|
||||
case StateInfrared:
|
||||
payload["infrared"] = stateValue.toDouble();
|
||||
qCDebug(dcLifx()) << "Set state infrared" << stateValue;
|
||||
}
|
||||
|
||||
doc.setObject(payload);
|
||||
QNetworkReply *reply = m_networkManager->post(request, doc.toJson());
|
||||
qCDebug(dcLifx()) << "Set state request" << request.url() << doc.toJson();
|
||||
QNetworkReply *reply = m_networkManager->put(request, doc.toJson());
|
||||
connect(reply, &QNetworkReply::finished, &QNetworkReply::deleteLater);
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] {
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
// check HTTP status code
|
||||
if (status > 207) {
|
||||
qCWarning(dcLifx()) << "Error get scene list" << status << reply->errorString();
|
||||
emit requestExecuted(requestId, false);
|
||||
return;
|
||||
}
|
||||
if (!m_authenticated) {
|
||||
m_authenticated = true;
|
||||
emit authenticationChanged(true);
|
||||
}
|
||||
if (!m_connected) {
|
||||
m_connected = true;
|
||||
emit authenticationChanged(true);
|
||||
}
|
||||
connect(reply, &QNetworkReply::finished, this, [requestId, duration,reply, this] {
|
||||
|
||||
QByteArray rawData = reply->readAll();
|
||||
qCDebug(dcLifx()) << "Got set state reply" << rawData;
|
||||
emit requestExecuted(requestId, true);
|
||||
if (checkHttpStatusCode(reply)) {
|
||||
emit requestExecuted(requestId, true);
|
||||
QTimer::singleShot(duration*1000+500, this, [=] {listLights();});
|
||||
} else {
|
||||
emit requestExecuted(requestId, false);
|
||||
}
|
||||
});
|
||||
return requestId;
|
||||
}
|
||||
|
||||
bool LifxCloud::checkHttpStatusCode(QNetworkReply *reply)
|
||||
{
|
||||
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qCWarning(dcLifx()) << "Request error:" << status << reply->errorString();
|
||||
if (m_connected) {
|
||||
m_connected = false;
|
||||
emit connectionChanged(false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// check HTTP status code
|
||||
if (status == 401 || status == 403) {
|
||||
if (m_authenticated) {
|
||||
m_authenticated = false;
|
||||
emit authenticationChanged(false);
|
||||
}
|
||||
}
|
||||
if (status > 207) {
|
||||
qCWarning(dcLifx()) << "Error get scene list" << status;
|
||||
return false;
|
||||
}
|
||||
if (!m_authenticated) {
|
||||
m_authenticated = true;
|
||||
emit authenticationChanged(true);
|
||||
}
|
||||
if (!m_connected) {
|
||||
m_connected = true;
|
||||
emit connectionChanged(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@ public:
|
|||
StateColorTemperature,
|
||||
StateInfrared
|
||||
};
|
||||
|
||||
enum Effect {
|
||||
EffectNone,
|
||||
EffectBreathe,
|
||||
EffectMove,
|
||||
EffectMorph,
|
||||
EffectFlame,
|
||||
EffectPulse
|
||||
};
|
||||
|
||||
struct Group {
|
||||
QByteArray id;
|
||||
QString name;
|
||||
|
|
@ -101,19 +111,22 @@ public:
|
|||
|
||||
void listLights();
|
||||
void listScenes();
|
||||
int setPower(const QString &lightId, bool power, int duration = 3);
|
||||
int setBrightnesss(const QString &lightId, int brightness, int duration = 3);
|
||||
int setColor(const QString &selector, QColor color, int duration = 3);
|
||||
int setColorTemperature(const QString &selector, int kelvin, int duration = 3);
|
||||
int setInfrared(const QString &lightId, int infrared, int duration = 3);
|
||||
int setPower(const QString &lightId, bool power, int duration = 5);
|
||||
int setBrightnesss(const QString &lightId, int brightness, int duration = 5);
|
||||
int setColor(const QString &lightId, QColor color, int duration = 5);
|
||||
int setColorTemperature(const QString &lightId, int kelvin, int duration = 5);
|
||||
int setInfrared(const QString &lightId, int infrared, int duration = 5);
|
||||
|
||||
int activateScene(const QString &sceneId);
|
||||
|
||||
int setEffect(const QString &lightId, Effect effect, QColor color);
|
||||
|
||||
private:
|
||||
NetworkAccessManager *m_networkManager = nullptr;
|
||||
QByteArray m_authorizationToken;
|
||||
|
||||
int setState(const QString &lightId, State state, QVariant stateValue, int duration);
|
||||
bool checkHttpStatusCode(QNetworkReply *reply);
|
||||
bool m_authenticated = false;
|
||||
bool m_connected = false;
|
||||
signals:
|
||||
|
|
|
|||
|
|
@ -29,20 +29,16 @@
|
|||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
|
||||
#include "lifx.h"
|
||||
#include "lifxlan.h"
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
#include <QColor>
|
||||
|
||||
|
||||
Lifx::Lifx(const QHostAddress &address, quint16 port, QObject *parent) :
|
||||
LifxLan::LifxLan(const QHostAddress &address, quint16 port, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_host(address),
|
||||
m_port(port)
|
||||
{
|
||||
m_reconnectTimer = new QTimer(this);
|
||||
m_reconnectTimer->setSingleShot(true);
|
||||
connect(m_reconnectTimer, &QTimer::timeout, this, &Lifx::onReconnectTimer);
|
||||
m_clientId = qrand();
|
||||
|
||||
m_socket = new QUdpSocket(this);
|
||||
|
|
@ -51,7 +47,7 @@ Lifx::Lifx(const QHostAddress &address, quint16 port, QObject *parent) :
|
|||
m_socket->setSocketOption(QAbstractSocket::MulticastLoopbackOption, QVariant(1));
|
||||
}
|
||||
|
||||
Lifx::~Lifx()
|
||||
LifxLan::~LifxLan()
|
||||
{
|
||||
if (m_socket) {
|
||||
m_socket->waitForBytesWritten(1000);
|
||||
|
|
@ -59,7 +55,7 @@ Lifx::~Lifx()
|
|||
}
|
||||
}
|
||||
|
||||
bool Lifx::enable()
|
||||
bool LifxLan::enable()
|
||||
{
|
||||
// Bind udp socket and join multicast group
|
||||
if(!m_socket->bind(QHostAddress::AnyIPv4, m_port, QUdpSocket::ShareAddress)){
|
||||
|
|
@ -75,21 +71,21 @@ bool Lifx::enable()
|
|||
m_socket = nullptr;
|
||||
return false;
|
||||
}
|
||||
connect(m_socket, &QUdpSocket::readyRead, this, &Lifx::onReadyRead);
|
||||
connect(m_socket, &QUdpSocket::readyRead, this, &LifxLan::onReadyRead);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Lifx::setHostAddress(const QHostAddress &address)
|
||||
void LifxLan::setHostAddress(const QHostAddress &address)
|
||||
{
|
||||
m_host = address;
|
||||
}
|
||||
|
||||
void Lifx::setPort(quint16 port)
|
||||
void LifxLan::setPort(quint16 port)
|
||||
{
|
||||
m_port = port;
|
||||
}
|
||||
|
||||
int Lifx::setColorTemperature(uint mirad, uint msFadeTime)
|
||||
int LifxLan::setColorTemperature(uint mirad, uint msFadeTime)
|
||||
{
|
||||
Q_UNUSED(mirad)
|
||||
Q_UNUSED(msFadeTime)
|
||||
|
|
@ -99,59 +95,48 @@ int Lifx::setColorTemperature(uint mirad, uint msFadeTime)
|
|||
return requestId;
|
||||
}
|
||||
|
||||
int Lifx::setColor(QColor color, uint msFadeTime)
|
||||
int LifxLan::setColor(QColor color, uint msFadeTime)
|
||||
{
|
||||
Q_UNUSED(color)
|
||||
Q_UNUSED(msFadeTime)
|
||||
int requestId = qrand();
|
||||
Message message;
|
||||
//TODO create LAN message
|
||||
sendMessage(message);
|
||||
return requestId;
|
||||
}
|
||||
|
||||
int Lifx::setBrightness(uint percentage, uint msFadeTime)
|
||||
int LifxLan::setBrightness(uint percentage, uint msFadeTime)
|
||||
{
|
||||
Q_UNUSED(percentage)
|
||||
Q_UNUSED(msFadeTime)
|
||||
int requestId = qrand();
|
||||
Message message;
|
||||
sendMessage(message);
|
||||
//TODO create LAN message
|
||||
return requestId;
|
||||
}
|
||||
|
||||
int Lifx::setPower(bool power, uint msFadeTime)
|
||||
int LifxLan::setPower(bool power, uint msFadeTime)
|
||||
{
|
||||
Q_UNUSED(power)
|
||||
Q_UNUSED(msFadeTime)
|
||||
int requestId = qrand();
|
||||
Message message;
|
||||
sendMessage(message);
|
||||
//TODO create LAN message
|
||||
return requestId;
|
||||
}
|
||||
|
||||
int Lifx::flash()
|
||||
{
|
||||
int requestId = qrand();
|
||||
|
||||
return requestId;
|
||||
}
|
||||
|
||||
int Lifx::flash15s()
|
||||
{
|
||||
int requestId = qrand();
|
||||
|
||||
return requestId;
|
||||
}
|
||||
|
||||
void Lifx::sendMessage(const Lifx::Message &message)
|
||||
void LifxLan::sendMessage(const LifxLan::Message &message)
|
||||
{
|
||||
QByteArray header;
|
||||
// -- FRAME --
|
||||
// Protocol number: must be 1024 (decimal)
|
||||
quint16 protocol = 1024;
|
||||
protocol |= (0x0001 << 4); //Message includes a target address: must be one (1)
|
||||
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)
|
||||
protocol &= ~(0x0003); // Message origin indicator: must be zero (0)
|
||||
header.append(protocol >> 8);
|
||||
header.append(protocol & 0xff);
|
||||
|
||||
|
|
@ -188,15 +173,12 @@ void Lifx::sendMessage(const Lifx::Message &message)
|
|||
header.append(2, '0');
|
||||
|
||||
QByteArray fullMessage;
|
||||
//message.append(header);
|
||||
//message.append(payload);
|
||||
//message.append(message.length());
|
||||
fullMessage = QByteArray::fromHex("0x310000340000000000000000000000000000000000000000000000000000000066000000005555FFFFFFFFAC0D00040000");
|
||||
std::reverse(fullMessage.begin(), fullMessage.end());
|
||||
//fullMessage = QByteArray::fromHex("0x310000340000000000000000000000000000000000000000000000000000000066000000005555FFFFFFFFAC0D00040000"); // test message - set all lights green
|
||||
//std::reverse(fullMessage.begin(), fullMessage.end());
|
||||
m_socket->writeDatagram(fullMessage, m_host, m_port);
|
||||
}
|
||||
|
||||
void Lifx::onStateChanged(QAbstractSocket::SocketState state)
|
||||
void LifxLan::onStateChanged(QAbstractSocket::SocketState state)
|
||||
{
|
||||
switch (state) {
|
||||
case QAbstractSocket::SocketState::ConnectedState:
|
||||
|
|
@ -212,13 +194,8 @@ void Lifx::onStateChanged(QAbstractSocket::SocketState state)
|
|||
}
|
||||
}
|
||||
|
||||
void Lifx::onReadyRead()
|
||||
void LifxLan::onReadyRead()
|
||||
{
|
||||
QByteArray data = m_socket->readAll();
|
||||
qCDebug(dcLifx()) << "Message received" << data;
|
||||
}
|
||||
|
||||
void Lifx::onReconnectTimer()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -28,8 +28,8 @@
|
|||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef LIFX_H
|
||||
#define LIFX_H
|
||||
#ifndef LIFXLAN_H
|
||||
#define LIFXLAN_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
#include <QColor>
|
||||
|
||||
class Lifx : public QObject
|
||||
class LifxLan : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
|
@ -122,8 +122,8 @@ public:
|
|||
bool chain;
|
||||
};
|
||||
|
||||
explicit Lifx(const QHostAddress &address, quint16 port = 56700, QObject *parent = nullptr);
|
||||
~Lifx();
|
||||
explicit LifxLan(const QHostAddress &address, quint16 port = 56700, QObject *parent = nullptr);
|
||||
~LifxLan();
|
||||
bool enable();
|
||||
void setHostAddress(const QHostAddress &address);
|
||||
void setPort(quint16 port);
|
||||
|
|
@ -132,8 +132,6 @@ public:
|
|||
int setColor(QColor color, uint msFadeTime = 500);
|
||||
int setBrightness(uint percentage, uint msFadeTime = 500);
|
||||
int setPower(bool power, uint msFadeTime = 500);
|
||||
int flash();
|
||||
int flash15s();
|
||||
|
||||
private:
|
||||
quint32 m_clientId = 0;
|
||||
|
|
@ -148,19 +146,9 @@ private:
|
|||
private slots:
|
||||
void onStateChanged(QAbstractSocket::SocketState state);
|
||||
void onReadyRead();
|
||||
void onReconnectTimer();
|
||||
|
||||
signals:
|
||||
void connectionChanged(bool connected);
|
||||
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
|
||||
#endif // LIFXLAN_H
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
"tagline": "Control LIFX light bulbs.",
|
||||
"icon": "lifx.png",
|
||||
"stability": "consumer",
|
||||
"offline": true,
|
||||
"offline": false,
|
||||
"technologies": [
|
||||
"network"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="de">
|
||||
<context>
|
||||
<name>IntegrationPluginLifx</name>
|
||||
<message>
|
||||
<source>LIFX server is not reachable.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This token is invalid.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Lifx</name>
|
||||
<message>
|
||||
|
|
@ -68,18 +79,6 @@ The name of the EventType ({dd7d7e70-5552-4531-8789-2d0f750488be}) of ThingClass
|
|||
<extracomment>The name of the ThingClass ({a5b02af8-7c97-4a78-9c78-bafee7407b5e})</extracomment>
|
||||
<translation>Tag und Sonnenaufgang</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host address</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: dimmableBulb, Type: thing, ID: {cc0a765b-a753-4e07-a6e5-47e9272c4346})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: colorBulb, Type: thing, ID: {fd1c4817-5111-433a-b5b9-fd9f49d4975c})</extracomment>
|
||||
<translation>Adresse</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Id</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: colorBulb, Type: thing, ID: {976ecea0-ac25-47d4-9dc5-362962ddb6c0})</extracomment>
|
||||
<translation>ID</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>LIFX</source>
|
||||
<extracomment>The name of the vendor ({e5e48c0d-cff7-4c0f-983e-d23bd3e4ba87})
|
||||
|
|
@ -87,13 +86,6 @@ The name of the ParamType (ThingClass: colorBulb, Type: thing, ID: {fd1c4817-511
|
|||
The name of the plugin Lifx ({4e00ee30-79e2-447b-8dcc-c34470f41992})</extracomment>
|
||||
<translation>LIFX</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Port</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: dimmableBulb, Type: thing, ID: {d233d9bf-6662-414d-92f6-dd3e267051b5})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: colorBulb, Type: thing, ID: {44c13745-300c-491f-b617-3a8d53472998})</extracomment>
|
||||
<translation>Port</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: dimmableBulb, ActionType: power, ID: {9e1344ea-cd05-4dd8-8948-8d2f5e00e1b0})
|
||||
|
|
@ -148,7 +140,9 @@ The name of the ActionType ({dd7d7e70-5552-4531-8789-2d0f750488be}) of ThingClas
|
|||
</message>
|
||||
<message>
|
||||
<source>Set effect</source>
|
||||
<extracomment>The name of the ActionType ({65f88396-2958-480e-b0be-c4695400a343}) of ThingClass colorBulb</extracomment>
|
||||
<extracomment>The name of the ActionType ({be47c474-eca1-479e-9393-68281a43d72a}) of ThingClass dimmableBulb
|
||||
----------
|
||||
The name of the ActionType ({65f88396-2958-480e-b0be-c4695400a343}) of ThingClass colorBulb</extracomment>
|
||||
<translation>Setze Effekt</translation>
|
||||
</message>
|
||||
<message>
|
||||
|
|
@ -160,7 +154,13 @@ The name of the ActionType ({12de3f8f-2454-4057-aa12-9290296fdbdd}) of ThingClas
|
|||
</message>
|
||||
<message>
|
||||
<source>Effect</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: colorBulb, ActionType: effect, ID: {65f88396-2958-480e-b0be-c4695400a343})
|
||||
<extracomment>The name of the ParamType (ThingClass: dimmableBulb, ActionType: effect, ID: {be47c474-eca1-479e-9393-68281a43d72a})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: dimmableBulb, EventType: effect, ID: {be47c474-eca1-479e-9393-68281a43d72a})
|
||||
----------
|
||||
The name of the StateType ({be47c474-eca1-479e-9393-68281a43d72a}) of ThingClass dimmableBulb
|
||||
----------
|
||||
The name of the ParamType (ThingClass: colorBulb, ActionType: effect, ID: {65f88396-2958-480e-b0be-c4695400a343})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: colorBulb, EventType: effect, ID: {65f88396-2958-480e-b0be-c4695400a343})
|
||||
----------
|
||||
|
|
@ -169,12 +169,16 @@ The name of the StateType ({65f88396-2958-480e-b0be-c4695400a343}) of ThingClass
|
|||
</message>
|
||||
<message>
|
||||
<source>Effect changed</source>
|
||||
<extracomment>The name of the EventType ({65f88396-2958-480e-b0be-c4695400a343}) of ThingClass colorBulb</extracomment>
|
||||
<extracomment>The name of the EventType ({be47c474-eca1-479e-9393-68281a43d72a}) of ThingClass dimmableBulb
|
||||
----------
|
||||
The name of the EventType ({65f88396-2958-480e-b0be-c4695400a343}) of ThingClass colorBulb</extracomment>
|
||||
<translation>Effekt geändert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ID</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: dimmableBulb, Type: thing, ID: {f157a97b-3fe5-4d9e-b5e3-5636f80d46ed})</extracomment>
|
||||
<extracomment>The name of the ParamType (ThingClass: dimmableBulb, Type: thing, ID: {f157a97b-3fe5-4d9e-b5e3-5636f80d46ed})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: colorBulb, Type: thing, ID: {976ecea0-ac25-47d4-9dc5-362962ddb6c0})</extracomment>
|
||||
<translation>ID</translation>
|
||||
</message>
|
||||
<message>
|
||||
|
|
@ -184,5 +188,46 @@ The name of the StateType ({65f88396-2958-480e-b0be-c4695400a343}) of ThingClass
|
|||
The name of the ActionType ({8bd20350-0e79-45dc-b68a-84da99356863}) of ThingClass colorBulb</extracomment>
|
||||
<translation>Setze Helligkeit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connected</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: lifxAccount, EventType: connected, ID: {3e7b358b-d7de-4db4-8a3a-b9860eae186f})
|
||||
----------
|
||||
The name of the StateType ({3e7b358b-d7de-4db4-8a3a-b9860eae186f}) of ThingClass lifxAccount</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connected changed</source>
|
||||
<extracomment>The name of the EventType ({3e7b358b-d7de-4db4-8a3a-b9860eae186f}) of ThingClass lifxAccount</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>LIFX cloud account</source>
|
||||
<extracomment>The name of the ThingClass ({387c87f6-3e5b-4d6a-ba4d-372d0efad79f})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logged in</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: lifxAccount, EventType: loggedIn, ID: {0db34069-5de0-4233-baec-27f039228524})
|
||||
----------
|
||||
The name of the StateType ({0db34069-5de0-4233-baec-27f039228524}) of ThingClass lifxAccount</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logged in changed</source>
|
||||
<extracomment>The name of the EventType ({0db34069-5de0-4233-baec-27f039228524}) of ThingClass lifxAccount</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>User name</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: lifxAccount, EventType: userDisplayName, ID: {554afd9b-a2ec-4d28-9065-2b9ab3a9e3b2})
|
||||
----------
|
||||
The name of the StateType ({554afd9b-a2ec-4d28-9065-2b9ab3a9e3b2}) of ThingClass lifxAccount</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>User name changed</source>
|
||||
<extracomment>The name of the EventType ({554afd9b-a2ec-4d28-9065-2b9ab3a9e3b2}) of ThingClass lifxAccount</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1">
|
||||
<context>
|
||||
<name>IntegrationPluginLifx</name>
|
||||
<message>
|
||||
<source>LIFX server is not reachable.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This token is invalid.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Lifx</name>
|
||||
<message>
|
||||
|
|
@ -68,18 +79,6 @@ The name of the EventType ({dd7d7e70-5552-4531-8789-2d0f750488be}) of ThingClass
|
|||
<extracomment>The name of the ThingClass ({a5b02af8-7c97-4a78-9c78-bafee7407b5e})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host address</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: dimmableBulb, Type: thing, ID: {cc0a765b-a753-4e07-a6e5-47e9272c4346})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: colorBulb, Type: thing, ID: {fd1c4817-5111-433a-b5b9-fd9f49d4975c})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Id</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: colorBulb, Type: thing, 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})
|
||||
|
|
@ -87,13 +86,6 @@ The name of the ParamType (ThingClass: colorBulb, Type: thing, ID: {fd1c4817-511
|
|||
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 (ThingClass: dimmableBulb, Type: thing, ID: {d233d9bf-6662-414d-92f6-dd3e267051b5})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: colorBulb, Type: thing, ID: {44c13745-300c-491f-b617-3a8d53472998})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Power</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: dimmableBulb, ActionType: power, ID: {9e1344ea-cd05-4dd8-8948-8d2f5e00e1b0})
|
||||
|
|
@ -148,7 +140,9 @@ The name of the ActionType ({dd7d7e70-5552-4531-8789-2d0f750488be}) of ThingClas
|
|||
</message>
|
||||
<message>
|
||||
<source>Set effect</source>
|
||||
<extracomment>The name of the ActionType ({65f88396-2958-480e-b0be-c4695400a343}) of ThingClass colorBulb</extracomment>
|
||||
<extracomment>The name of the ActionType ({be47c474-eca1-479e-9393-68281a43d72a}) of ThingClass dimmableBulb
|
||||
----------
|
||||
The name of the ActionType ({65f88396-2958-480e-b0be-c4695400a343}) of ThingClass colorBulb</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
|
|
@ -160,7 +154,13 @@ The name of the ActionType ({12de3f8f-2454-4057-aa12-9290296fdbdd}) of ThingClas
|
|||
</message>
|
||||
<message>
|
||||
<source>Effect</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: colorBulb, ActionType: effect, ID: {65f88396-2958-480e-b0be-c4695400a343})
|
||||
<extracomment>The name of the ParamType (ThingClass: dimmableBulb, ActionType: effect, ID: {be47c474-eca1-479e-9393-68281a43d72a})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: dimmableBulb, EventType: effect, ID: {be47c474-eca1-479e-9393-68281a43d72a})
|
||||
----------
|
||||
The name of the StateType ({be47c474-eca1-479e-9393-68281a43d72a}) of ThingClass dimmableBulb
|
||||
----------
|
||||
The name of the ParamType (ThingClass: colorBulb, ActionType: effect, ID: {65f88396-2958-480e-b0be-c4695400a343})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: colorBulb, EventType: effect, ID: {65f88396-2958-480e-b0be-c4695400a343})
|
||||
----------
|
||||
|
|
@ -169,12 +169,16 @@ The name of the StateType ({65f88396-2958-480e-b0be-c4695400a343}) of ThingClass
|
|||
</message>
|
||||
<message>
|
||||
<source>Effect changed</source>
|
||||
<extracomment>The name of the EventType ({65f88396-2958-480e-b0be-c4695400a343}) of ThingClass colorBulb</extracomment>
|
||||
<extracomment>The name of the EventType ({be47c474-eca1-479e-9393-68281a43d72a}) of ThingClass dimmableBulb
|
||||
----------
|
||||
The name of the EventType ({65f88396-2958-480e-b0be-c4695400a343}) of ThingClass colorBulb</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ID</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: dimmableBulb, Type: thing, ID: {f157a97b-3fe5-4d9e-b5e3-5636f80d46ed})</extracomment>
|
||||
<extracomment>The name of the ParamType (ThingClass: dimmableBulb, Type: thing, ID: {f157a97b-3fe5-4d9e-b5e3-5636f80d46ed})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: colorBulb, Type: thing, ID: {976ecea0-ac25-47d4-9dc5-362962ddb6c0})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
|
|
@ -184,5 +188,46 @@ The name of the StateType ({65f88396-2958-480e-b0be-c4695400a343}) of ThingClass
|
|||
The name of the ActionType ({8bd20350-0e79-45dc-b68a-84da99356863}) of ThingClass colorBulb</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connected</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: lifxAccount, EventType: connected, ID: {3e7b358b-d7de-4db4-8a3a-b9860eae186f})
|
||||
----------
|
||||
The name of the StateType ({3e7b358b-d7de-4db4-8a3a-b9860eae186f}) of ThingClass lifxAccount</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connected changed</source>
|
||||
<extracomment>The name of the EventType ({3e7b358b-d7de-4db4-8a3a-b9860eae186f}) of ThingClass lifxAccount</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>LIFX cloud account</source>
|
||||
<extracomment>The name of the ThingClass ({387c87f6-3e5b-4d6a-ba4d-372d0efad79f})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logged in</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: lifxAccount, EventType: loggedIn, ID: {0db34069-5de0-4233-baec-27f039228524})
|
||||
----------
|
||||
The name of the StateType ({0db34069-5de0-4233-baec-27f039228524}) of ThingClass lifxAccount</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logged in changed</source>
|
||||
<extracomment>The name of the EventType ({0db34069-5de0-4233-baec-27f039228524}) of ThingClass lifxAccount</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>User name</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: lifxAccount, EventType: userDisplayName, ID: {554afd9b-a2ec-4d28-9065-2b9ab3a9e3b2})
|
||||
----------
|
||||
The name of the StateType ({554afd9b-a2ec-4d28-9065-2b9ab3a9e3b2}) of ThingClass lifxAccount</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>User name changed</source>
|
||||
<extracomment>The name of the EventType ({554afd9b-a2ec-4d28-9065-2b9ab3a9e3b2}) of ThingClass lifxAccount</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
|||
Loading…
Reference in New Issue