diff --git a/ws2812fx/integrationpluginws2812fx.cpp b/ws2812fx/integrationpluginws2812fx.cpp index 71c02f8d..cc405fcf 100644 --- a/ws2812fx/integrationpluginws2812fx.cpp +++ b/ws2812fx/integrationpluginws2812fx.cpp @@ -34,54 +34,93 @@ #include "integrationpluginws2812fx.h" #include "plugininfo.h" +#include "platform/platformzeroconfcontroller.h" +#include "network/zeroconf/zeroconfservicebrowser.h" #include "nymealightserialinterface.h" +#include "nymealighttcpinterface.h" IntegrationPluginWs2812fx ::IntegrationPluginWs2812fx () { } +void IntegrationPluginWs2812fx::init() +{ + m_serviceBrowser = hardwareManager()->zeroConfController()->createServiceBrowser(); + connect(m_serviceBrowser, &ZeroConfServiceBrowser::serviceEntryAdded, this, [=] (const ZeroConfServiceEntry &entry){ + qCDebug(dcWs2812fx()) << "mDNS service added" << entry; + foreach (Thing *thing, myThings().filterByThingClassId(nymeaLightThingClassId)) { + Q_UNUSED(thing) //TODO auto address update + if (entry.txt().contains("nymea-light")) { + } + } + }); +} + void IntegrationPluginWs2812fx::setupThing(ThingSetupInfo *info) { Thing *thing = info->thing(); + qCDebug(dcWs2812fx()) << "Setup thing" << thing->name(); - if (thing->thingClassId() == nymeaLightSerialThingClassId) { - QString interface = thing->paramValue(nymeaLightSerialThingSerialPortParamTypeId).toString(); + if (thing->thingClassId() == nymeaLightThingClassId) { + + QString interface = thing->paramValue(nymeaLightThingAddressParamTypeId).toString(); + NymeaLight *light = nullptr; + if (thing->paramValue(nymeaLightThingConnectionTypeParamTypeId).toString() == "Serial") { + + if (m_usedInterfaces.contains(interface)) { + info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("This serial port is already in use.")); + return; + } + + NymeaLightSerialInterface *lightInterface = new NymeaLightSerialInterface(interface, thing); + light = new NymeaLight(lightInterface, this); + lightInterface->setParent(light); + m_usedInterfaces.append(interface); + + info->finish(Thing::ThingErrorNoError); + } else if (thing->paramValue(nymeaLightThingConnectionTypeParamTypeId).toString() == "Network") { + if (m_usedInterfaces.contains(interface)) { + m_usedInterfaces.removeAll(interface); + qCDebug(dcWs2812fx()) << "Setup after reconfiguration, cleaning up ..."; + } + + if (QHostAddress(interface).isNull()) { + info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("Address not valid")); + return; + } + + NymeaLightTcpInterface *lightInterface = new NymeaLightTcpInterface(QHostAddress(interface), thing); + light = new NymeaLight(lightInterface, this); + lightInterface->setParent(light); + m_usedInterfaces.append(interface); - if (m_usedInterfaces.contains(interface)) { - info->finish(Thing::ThingErrorHardwareNotAvailable, QT_TR_NOOP("This serial port is already in use.")); - return; } - - NymeaLightSerialInterface *lightInterface = new NymeaLightSerialInterface(interface, thing); - NymeaLight *light = new NymeaLight(lightInterface, this); - lightInterface->setParent(light); - m_usedInterfaces.append(interface); m_lights.insert(thing, light); - connect(light, &NymeaLight::availableChanged, thing, [=](bool available){ qCDebug(dcWs2812fx()) << thing << "available changed" << available; - thing->setStateValue(nymeaLightSerialConnectedStateTypeId, available); + thing->setStateValue(nymeaLightConnectedStateTypeId, available); if (available) { // Set the light to the current states - light->setPower(thing->stateValue(nymeaLightSerialPowerStateTypeId).toBool()); - light->setBrightness(thing->stateValue(nymeaLightSerialBrightnessStateTypeId).toUInt()); - light->setColor(thing->stateValue(nymeaLightSerialColorStateTypeId).value()); - light->setEffect(thing->stateValue(nymeaLightSerialEffectModeStateTypeId).toUInt()); - light->setSpeed(thing->stateValue(nymeaLightSerialSpeedStateTypeId).toUInt()); + light->setPower(thing->stateValue(nymeaLightPowerStateTypeId).toBool()); + light->setBrightness(thing->stateValue(nymeaLightBrightnessStateTypeId).toUInt()); + light->setColor(thing->stateValue(nymeaLightColorStateTypeId).value()); + light->setEffect(thing->stateValue(nymeaLightEffectModeStateTypeId).toUInt()); + light->setSpeed(thing->stateValue(nymeaLightSpeedStateTypeId).toUInt()); } }); - - - info->finish(Thing::ThingErrorNoError); + } else { + qCWarning(dcWs2812fx()) << "ThingClass not supported" << thing->thingClassId(); + return info->finish(Thing::ThingErrorThingClassNotFound); } } void IntegrationPluginWs2812fx::postSetupThing(Thing *thing) { - if (thing->thingClassId() == nymeaLightSerialThingClassId) { + qCDebug(dcWs2812fx()) << "Post setup thing" << thing; + if (thing->thingClassId() == nymeaLightThingClassId) { NymeaLight *light = m_lights.value(thing); light->enable(); } @@ -96,14 +135,31 @@ void IntegrationPluginWs2812fx::discoverThings(ThingDiscoveryInfo *info) qCDebug(dcWs2812fx()) << "Found serial port:" << port.portName(); QString description = port.systemLocation() + " " + port.manufacturer() + " " + port.description(); ThingDescriptor descriptor(info->thingClassId(), QT_TR_NOOP("Nymea light"), description); - foreach (Thing *existingThing, myThings().filterByParam(nymeaLightSerialThingSerialPortParamTypeId, port.systemLocation())) { + foreach (Thing *existingThing, myThings().filterByParam(nymeaLightThingAddressParamTypeId, port.systemLocation())) { descriptor.setThingId(existingThing->id()); } ParamList parameters; - parameters.append(Param(nymeaLightSerialThingSerialPortParamTypeId, port.systemLocation())); + parameters.append(Param(nymeaLightThingConnectionTypeParamTypeId, "Serial")); + parameters.append(Param(nymeaLightThingSerialnumberParamTypeId, port.serialNumber())); + parameters.append(Param(nymeaLightThingAddressParamTypeId, port.systemLocation())); descriptor.setParams(parameters); info->addThingDescriptor(descriptor); } + + Q_FOREACH (const ZeroConfServiceEntry &service, m_serviceBrowser->serviceEntries()) { + qCDebug(dcWs2812fx()) << "mDNS service entry:" << service; + if (service.txt().contains("nymea-light")) { + ThingDescriptor descriptor(info->thingClassId(), service.name(), service.hostAddress().toString()); + + ParamList parameters; + parameters.append(Param(nymeaLightThingConnectionTypeParamTypeId, "Network")); + parameters.append(Param(nymeaLightThingSerialnumberParamTypeId, "")); //TODO fixme + parameters.append(Param(nymeaLightThingAddressParamTypeId, service.hostAddress().toString())); + descriptor.setParams(parameters); + info->addThingDescriptor(descriptor); + info->addThingDescriptor(descriptor); + } + } info->finish(Thing::ThingErrorNoError); } @@ -118,8 +174,8 @@ void IntegrationPluginWs2812fx::executeAction(ThingActionInfo *info) return; } - if (action.actionTypeId() == nymeaLightSerialPowerActionTypeId) { - bool power = action.param(nymeaLightSerialPowerActionPowerParamTypeId).value().toBool(); + if (action.actionTypeId() == nymeaLightPowerActionTypeId) { + bool power = action.param(nymeaLightPowerActionPowerParamTypeId).value().toBool(); qCDebug(dcWs2812fx()) << "Set power" << power; NymeaLightInterfaceReply *reply = light->setPower(power, 500); @@ -131,11 +187,11 @@ void IntegrationPluginWs2812fx::executeAction(ThingActionInfo *info) } qCDebug(dcWs2812fx()) << "Set power finished successfully" << power; - thing->setStateValue(nymeaLightSerialPowerStateTypeId, power); + thing->setStateValue(nymeaLightPowerStateTypeId, power); info->finish(Thing::ThingErrorNoError); }); - } else if (action.actionTypeId() == nymeaLightSerialColorActionTypeId) { - QColor color = action.param(nymeaLightSerialColorActionColorParamTypeId).value().value(); + } else if (action.actionTypeId() == nymeaLightColorActionTypeId) { + QColor color = action.param(nymeaLightColorActionColorParamTypeId).value().value(); qCDebug(dcWs2812fx()) << "Set color to" << color.name(QColor::HexRgb); NymeaLightInterfaceReply *reply = light->setColor(color); connect(info, &ThingActionInfo::aborted, reply, &NymeaLightInterfaceReply::finished); @@ -145,12 +201,12 @@ void IntegrationPluginWs2812fx::executeAction(ThingActionInfo *info) return; } qCDebug(dcWs2812fx()) << "Set color finished successfully" << color.name(QColor::HexRgb); - thing->setStateValue(nymeaLightSerialColorStateTypeId, color); + thing->setStateValue(nymeaLightColorStateTypeId, color); info->finish(Thing::ThingErrorNoError); }); - } else if (action.actionTypeId() == nymeaLightSerialColorTemperatureActionTypeId) { + } else if (action.actionTypeId() == nymeaLightColorTemperatureActionTypeId) { // minValue 153, maxValue 500 - uint colorTemperature = action.param(nymeaLightSerialColorTemperatureActionColorTemperatureParamTypeId).value().toDouble(); + uint colorTemperature = action.param(nymeaLightColorTemperatureActionColorTemperatureParamTypeId).value().toDouble(); QColor color; color.setRgb(255, 255, qRound((255.00 - (((colorTemperature - 153.00) / 347.00)) * 255.00))); @@ -164,11 +220,11 @@ void IntegrationPluginWs2812fx::executeAction(ThingActionInfo *info) } qCDebug(dcWs2812fx()) << "Set color temperature finished successfully" << colorTemperature; - thing->setStateValue(nymeaLightSerialColorTemperatureStateTypeId, colorTemperature); + thing->setStateValue(nymeaLightColorTemperatureStateTypeId, colorTemperature); info->finish(Thing::ThingErrorNoError); }); - } else if (action.actionTypeId() == nymeaLightSerialBrightnessActionTypeId) { - quint8 brightnessPercentage = action.param(nymeaLightSerialBrightnessActionBrightnessParamTypeId).value().toUInt(); + } else if (action.actionTypeId() == nymeaLightBrightnessActionTypeId) { + quint8 brightnessPercentage = action.param(nymeaLightBrightnessActionBrightnessParamTypeId).value().toUInt(); quint8 brightness = qRound(255.0 * brightnessPercentage / 100); qCDebug(dcWs2812fx()) << "Set brightness to" << brightnessPercentage << brightness; NymeaLightInterfaceReply *reply = light->setBrightness(brightness, 1000); @@ -180,11 +236,11 @@ void IntegrationPluginWs2812fx::executeAction(ThingActionInfo *info) } qCDebug(dcWs2812fx()) << "Set brightness finished successfully" << brightness; - thing->setStateValue(nymeaLightSerialBrightnessStateTypeId, brightnessPercentage); + thing->setStateValue(nymeaLightBrightnessStateTypeId, brightnessPercentage); info->finish(Thing::ThingErrorNoError); }); - } else if (action.actionTypeId() == nymeaLightSerialSpeedActionTypeId) { - quint16 speedPercentage = action.param(nymeaLightSerialSpeedActionSpeedParamTypeId).value().toUInt(); + } else if (action.actionTypeId() == nymeaLightSpeedActionTypeId) { + quint16 speedPercentage = action.param(nymeaLightSpeedActionSpeedParamTypeId).value().toUInt(); quint16 speed = 2000 - (speedPercentage * 20); qCDebug(dcWs2812fx()) << "Set speed" << speedPercentage << "%" << speed << "ms"; @@ -197,11 +253,11 @@ void IntegrationPluginWs2812fx::executeAction(ThingActionInfo *info) } qCDebug(dcWs2812fx()) << "Set speed finished successfully" << speedPercentage << "%" << speed << "ms"; - thing->setStateValue(nymeaLightSerialSpeedStateTypeId, speedPercentage); + thing->setStateValue(nymeaLightSpeedStateTypeId, speedPercentage); info->finish(Thing::ThingErrorNoError); }); - } else if (action.actionTypeId() == nymeaLightSerialEffectModeActionTypeId) { - QString effectMode = action.param(nymeaLightSerialEffectModeActionEffectModeParamTypeId).value().toString(); + } else if (action.actionTypeId() == nymeaLightEffectModeActionTypeId) { + QString effectMode = action.param(nymeaLightEffectModeActionEffectModeParamTypeId).value().toString(); quint8 mode = FX_MODE_STATIC; if (effectMode == "Static") { mode = FX_MODE_STATIC; @@ -331,7 +387,7 @@ void IntegrationPluginWs2812fx::executeAction(ThingActionInfo *info) } qCDebug(dcWs2812fx()) << "Set mode finished successfully" << effectMode << mode; - thing->setStateValue(nymeaLightSerialEffectModeStateTypeId, effectMode); + thing->setStateValue(nymeaLightEffectModeStateTypeId, effectMode); info->finish(Thing::ThingErrorNoError); }); } @@ -340,10 +396,10 @@ void IntegrationPluginWs2812fx::executeAction(ThingActionInfo *info) void IntegrationPluginWs2812fx::thingRemoved(Thing *thing) { - if (thing->thingClassId() == nymeaLightSerialThingClassId) { - m_usedInterfaces.removeAll(thing->paramValue(nymeaLightSerialThingSerialPortParamTypeId).toString()); + qCDebug(dcWs2812fx()) << "Thing removed" << thing; + if (thing->thingClassId() == nymeaLightThingClassId) { + m_usedInterfaces.removeAll(thing->paramValue(nymeaLightThingAddressParamTypeId).toString()); NymeaLight *light = m_lights.take(thing); light->deleteLater(); } } - diff --git a/ws2812fx/integrationpluginws2812fx.h b/ws2812fx/integrationpluginws2812fx.h index 29ccd6ac..65ab9d38 100644 --- a/ws2812fx/integrationpluginws2812fx.h +++ b/ws2812fx/integrationpluginws2812fx.h @@ -95,6 +95,8 @@ #include "integrations/integrationplugin.h" #include "nymealight.h" +#include "network/zeroconf/zeroconfservicebrowser.h" +#include "network/zeroconf/zeroconfserviceentry.h" #include #include @@ -110,6 +112,7 @@ class IntegrationPluginWs2812fx : public IntegrationPlugin public: explicit IntegrationPluginWs2812fx(); + void init() override; void setupThing(ThingSetupInfo *info) override; void postSetupThing(Thing *thing) override; void thingRemoved(Thing *thing) override; @@ -120,6 +123,8 @@ private: QHash m_lights; QList m_usedInterfaces; + ZeroConfServiceBrowser *m_serviceBrowser = nullptr; + private slots: signals: diff --git a/ws2812fx/integrationpluginws2812fx.json b/ws2812fx/integrationpluginws2812fx.json index 794d31b7..9b0ae15b 100644 --- a/ws2812fx/integrationpluginws2812fx.json +++ b/ws2812fx/integrationpluginws2812fx.json @@ -10,18 +10,37 @@ "thingClasses": [ { "id": "24364e36-b199-4e35-b468-c44da58c009c", - "name": "nymeaLightSerial", - "displayName": "Serial nymea light", + "name": "nymeaLight", + "displayName": "nymea light", "createMethods": ["user", "discovery"], "interfaces": ["colorlight", "connectable"], "paramTypes": [ { - "id": "ed49f7d8-ab18-4c37-9b80-1004b75dcb91", - "name": "serialPort", - "displayName": "Serial port", + "id": "a02dcbf9-c1d8-4dc3-9fb6-92ea75e0539d", + "name": "connectionType", + "displayName": "Connection type", "type": "QString", - "inputType": "TextLine", - "defaultValue": "/dev/ttyAMC0" + "allowedValues": [ + "Serial", + "Network" + ], + "defaultValue": "Serial", + "readOnly": true + }, + { + "id": "7faf014a-a13d-4c41-9c12-d4427313e2c2", + "name": "serialnumber", + "displayName": "Serial number", + "type": "QString", + "defaultValue": "", + "readOnly": true + }, + { + "id": "ed49f7d8-ab18-4c37-9b80-1004b75dcb91", + "name": "address", + "displayName": "Serial port or network address", + "type": "QString", + "defaultValue": "" } ], "stateTypes": [ diff --git a/ws2812fx/ws2812fx.pro b/ws2812fx/ws2812fx.pro index 33f5bbd8..d4221843 100644 --- a/ws2812fx/ws2812fx.pro +++ b/ws2812fx/ws2812fx.pro @@ -1,17 +1,21 @@ include(../plugins.pri) -QT += serialport +QT += \ + serialport \ + network TARGET = $$qtLibraryTarget(nymea_integrationpluginws2812fx) SOURCES += \ integrationpluginws2812fx.cpp \ nymealight.cpp \ - nymealightserialinterface.cpp + nymealightserialinterface.cpp \ + nymealighttcpinterface.cpp HEADERS += \ integrationpluginws2812fx.h \ nymealight.h \ nymealightinterface.h \ - nymealightserialinterface.h + nymealightserialinterface.h \ + nymealighttcpinterface.h