diff --git a/nymea-plugins.pro b/nymea-plugins.pro index 8985227c..c3f6893f 100644 --- a/nymea-plugins.pro +++ b/nymea-plugins.pro @@ -44,6 +44,8 @@ PLUGIN_DIRS = \ unitec \ wakeonlan \ wemo \ + ws2812 \ + ws2812fx \ message(============================================) diff --git a/ws2812fx/devicepluginws2812fx.cpp b/ws2812fx/devicepluginws2812fx.cpp new file mode 100644 index 00000000..9a6c146d --- /dev/null +++ b/ws2812fx/devicepluginws2812fx.cpp @@ -0,0 +1,313 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Bernhard Trinnes * + * * + * This file is part of nymea. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 library; If not, see * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*! + \page ws2812fx.html + \title WS2812FX Control + \brief Plug-In to control WS2812FX over USB + + \ingroup plugins + \ingroup nymea-plugins + + \chapter Plugin properties + Following JSON file contains the definition and the description of all available \l{DeviceClass}{DeviceClasses} + and \l{Vendor}{Vendors} of this \l{DevicePlugin}. + + For more details how to read this JSON file please check out the documentation for \l{The plugin JSON File}. + + \quotefile plugins/deviceplugins/ws2812fx/devicepluginws2812fx.json +*/ +#include +#include "devicepluginws2812fx.h" +#include "plugininfo.h" + +DevicePluginWs2812fx ::DevicePluginWs2812fx () +{ +} + +DeviceManager::DeviceSetupStatus DevicePluginWs2812fx::setupDevice(Device *device) +{ + if (device->deviceClassId() == ws2812fxDeviceClassId) { + QString interface = device->paramValue(ws2812fxDeviceSerialPortParamTypeId).toString(); + + if (!m_usedInterfaces.contains(interface)) { + + QSerialPort *serialPort = new QSerialPort(interface, this); + if(!serialPort) + return DeviceManager::DeviceSetupStatusFailure; + + serialPort->setBaudRate(11520); + serialPort->setDataBits(QSerialPort::DataBits::Data8); + serialPort->setParity(QSerialPort::Parity::EvenParity); + serialPort->setStopBits(QSerialPort::StopBits::OneStop); + serialPort->setFlowControl(QSerialPort::FlowControl::NoFlowControl); + + if (!serialPort->open(QIODevice::ReadWrite)) { + qCWarning(dcWs2812fx()) << "Could not open serial port" << interface << serialPort->errorString(); + return DeviceManager::DeviceSetupStatusFailure; + } + + connect(serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onSerialError(QSerialPort::SerialPortError))); + connect(serialPort, SIGNAL(readyRead()), this, SLOT(onReadyRead())); + + qCDebug(dcWs2812fx()) << "Setup successfully serial port" << interface; + m_usedInterfaces.append(interface); + m_serialPorts.insert(device, serialPort); + } else { + return DeviceManager::DeviceSetupStatusFailure; + } + return DeviceManager::DeviceSetupStatusSuccess; + } + return DeviceManager::DeviceSetupStatusFailure; +} + + +DeviceManager::DeviceError DevicePluginWs2812fx::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) +{ + Q_UNUSED(params) + // Create the list of available serial interfaces + QList deviceDescriptors; + + Q_FOREACH(QSerialPortInfo port, QSerialPortInfo::availablePorts()) { + if (m_usedInterfaces.contains(port.portName())){ + //device already in use + qCDebug(dcWs2812fx()) << "Found serial port that is already used:" << port.portName(); + } else { + //Serial port is not yet used, create now a new one + qCDebug(dcWs2812fx()) << "Found serial port:" << port.portName(); + QString description = port.manufacturer() + " " + port.description(); + DeviceDescriptor descriptor(deviceClassId, port.portName(), description); + ParamList parameters; + parameters.append(Param(ws2812fxDeviceSerialPortParamTypeId, port.portName())); + descriptor.setParams(parameters); + deviceDescriptors.append(descriptor); + } + } + emit devicesDiscovered(deviceClassId, deviceDescriptors); + return DeviceManager::DeviceErrorAsync; +} + + +DeviceManager::DeviceError DevicePluginWs2812fx::executeAction(Device *device, const Action &action) +{ + qCDebug(dcWs2812fx) << "Execute action" << action.actionTypeId() << action.params(); + + if (device->deviceClassId() == ws2812fxDeviceClassId ) { + + QSerialPort *serialPort = m_serialPorts.value(device); + if (!serialPort) + return DeviceManager::DeviceErrorDeviceNotFound; + QByteArray command; + + if (action.actionTypeId() == ws2812fxBrightnessActionTypeId) { + + command.append("b "); + command.append(action.param(ws2812fxBrightnessActionBrightnessParamTypeId).value().toString()); + serialPort->write(command); + return DeviceManager::DeviceErrorAsync; + } + + if (action.actionTypeId() == ws2812fxSpeedActionTypeId) { + + command.append("s "); + command.append(action.param(ws2812fxSpeedActionSpeedParamTypeId).value().toString()); + serialPort->write(command); + return DeviceManager::DeviceErrorAsync; + } + + if (action.actionTypeId() == ws2812fxColorActionTypeId) { + + command.append("c "); + command.append(action.param(ws2812fxSpeedActionSpeedParamTypeId).value().toString()); + serialPort->write(command); + return DeviceManager::DeviceErrorAsync; + } + + if (action.actionTypeId() == ws2812fxColorTemperatureActionTypeId) { + + // minValue 153, maxValue 500 + QColor color; + color.setRgb(255, 255, ((action.param(ws2812fxColorActionColorParamTypeId).value().toInt()-153)/347.00)); + command.append("c "); + command.append(color.rgb()); + serialPort->write(command); + return DeviceManager::DeviceErrorAsync; + } + + if (action.actionTypeId() == ws2812fxEffectModeActionTypeId) { + + QString effectMode = action.param(ws2812fxEffectModeActionEffectModeParamTypeId).value().toString(); + command.append("m "); + if (effectMode == "Static") { + command.append(static_cast(FX_MODE_STATIC)); + } else if (effectMode == "Blink") { + command.append(FX_MODE_BLINK); + } else if (effectMode == "Color Wipe") { + command.append(FX_MODE_COLOR_WIPE); + } else if (effectMode == "Color Wipe Inverse") { + command.append(FX_MODE_COLOR_WIPE_INV); + } else if (effectMode == "Color Wipe Reverse") { + command.append(FX_MODE_COLOR_WIPE_REV); + } else if (effectMode == "Color Wipe Reverse Inverse") { + command.append(FX_MODE_COLOR_WIPE_REV_INV); + } else if (effectMode == "Color Wipe Random") { + command.append(FX_MODE_COLOR_WIPE_RANDOM); + } else if (effectMode == "Random Color") { + command.append(FX_MODE_RANDOM_COLOR); + } else if (effectMode == "Single Dynamic") { + command.append(FX_MODE_SINGLE_DYNAMIC); + } else if (effectMode == "Multi Dynamic") { + command.append(FX_MODE_MULTI_DYNAMIC); + } else if (effectMode == "Rainbow") { + command.append(FX_MODE_RAINBOW); + } else if (effectMode == "Rainbow Cycle") { + command.append(FX_MODE_RAINBOW_CYCLE); + } else if (effectMode == "Scan") { + command.append(FX_MODE_SCAN); + } else if (effectMode == "Dual Scan") { + command.append(FX_MODE_DUAL_SCAN); + } else if (effectMode == "Fade") { + command.append(FX_MODE_FADE); + } else if (effectMode == "Theater Chase") { + command.append(FX_MODE_THEATER_CHASE); + } else if (effectMode == "Theater Chase Rainbow") { + command.append(FX_MODE_THEATER_CHASE_RAINBOW); + } else if (effectMode == "Running Lights") { + command.append(FX_MODE_RUNNING_LIGHTS); + } else if (effectMode == "Twinkle") { + command.append(FX_MODE_TWINKLE); + } else if (effectMode == "Twinkle Random") { + command.append(FX_MODE_TWINKLE_RANDOM); + } else if (effectMode == "Twinkle Fade") { + command.append(FX_MODE_TWINKLE_FADE); + } else if (effectMode == "Twinkle Fade Random") { + command.append(FX_MODE_TWINKLE_FADE_RANDOM); + } else if (effectMode == "Sparkle") { + command.append(FX_MODE_SPARKLE); + } else if (effectMode == "Flash Sparkle") { + command.append(FX_MODE_FLASH_SPARKLE); + } else if (effectMode == "Hyper Sparkle") { + command.append(FX_MODE_HYPER_SPARKLE); + } else if (effectMode == "Strobe") { + command.append(FX_MODE_STROBE); + } else if (effectMode == "Strobe Rainbow") { + command.append(FX_MODE_STROBE_RAINBOW); + } else if (effectMode == "Multi Strobe") { + command.append(FX_MODE_MULTI_STROBE); + } else if (effectMode == "Blink Rainbow") { + command.append(FX_MODE_BLINK_RAINBOW); + } else if (effectMode == "Chase White") { + command.append(FX_MODE_CHASE_WHITE); + } else if (effectMode == "Chase Color") { + command.append(FX_MODE_CHASE_COLOR); + } else if (effectMode == "Chase Random") { + command.append(FX_MODE_CHASE_RANDOM); + } else if (effectMode == "Chase Flash") { + command.append(FX_MODE_CHASE_FLASH); + } else if (effectMode == "Chase Flash Random") { + command.append(FX_MODE_CHASE_FLASH_RANDOM); + } else if (effectMode == "Chase Rainbow White") { + command.append(FX_MODE_CHASE_RAINBOW_WHITE); + } else if (effectMode == "Chase Blackout") { + command.append(FX_MODE_CHASE_BLACKOUT); + } else if (effectMode == "Chase Blackout Rainbow") { + command.append(FX_MODE_CHASE_BLACKOUT_RAINBOW); + } else if (effectMode == "Color Sweep Random") { + command.append(FX_MODE_COLOR_SWEEP_RANDOM); + } else if (effectMode == "Running Color") { + command.append(FX_MODE_RUNNING_COLOR); + } else if (effectMode == "Running Red Blue") { + command.append(FX_MODE_RUNNING_RED_BLUE); + } else if (effectMode == "Running Random") { + command.append(FX_MODE_RUNNING_RANDOM); + }else if (effectMode == "Larson Scanner") { + command.append(FX_MODE_LARSON_SCANNER); + }else if (effectMode == "Comet") { + command.append(FX_MODE_COMET); + }else if (effectMode == "Fireworks") { + command.append(FX_MODE_FIREWORKS); + }else if (effectMode == "Fireworks Random") { + command.append(FX_MODE_FIREWORKS_RANDOM); + }else if (effectMode == "Merry Christmas") { + command.append(FX_MODE_MERRY_CHRISTMAS); + }else if (effectMode == "Fire Flicker") { + command.append(FX_MODE_FIRE_FLICKER); + }else if (effectMode == "Fire Flicker (soft)") { + command.append(FX_MODE_FIRE_FLICKER_SOFT); + }else if (effectMode == "Fire Flicker (intense)") { + command.append(FX_MODE_FIRE_FLICKER_INTENSE); + }else if (effectMode == "Circus Combustus") { + command.append(FX_MODE_CIRCUS_COMBUSTUS); + }else if (effectMode == "Halloween") { + command.append(FX_MODE_HALLOWEEN); + }else if (effectMode == "Bicolor Chase") { + command.append(FX_MODE_BICOLOR_CHASE); + }else if (effectMode == "Tricolor Chase") { + command.append(FX_MODE_TRICOLOR_CHASE); + }else if (effectMode == "ICU") { + command.append(FX_MODE_ICU); + }else if (effectMode == "Custom 1") { + command.append(FX_MODE_CUSTOM_0); + }else if (effectMode == "Custom 2") { + command.append(FX_MODE_CUSTOM_1); + }else if (effectMode == "Custom 3") { + command.append(FX_MODE_CUSTOM_2); + }else if (effectMode == "Custom 4") { + command.append(FX_MODE_CUSTOM_3); + } + serialPort->write(command); + return DeviceManager::DeviceErrorAsync; + } + return DeviceManager::DeviceErrorActionTypeNotFound; + } + return DeviceManager::DeviceErrorDeviceClassNotFound; +} + + +void DevicePluginWs2812fx::deviceRemoved(Device *device) +{ + if (device->deviceClassId() == ws2812fxDeviceClassId) { + + m_usedInterfaces.removeAll(device->paramValue(ws2812fxDeviceSerialPortParamTypeId).toString()); + QSerialPort *serialPort = m_serialPorts.take(device); + serialPort->close(); + serialPort->deleteLater(); + } +} + +void DevicePluginWs2812fx::onReadyRead() +{ + QSerialPort *serialPort = static_cast(sender()); + Device *device = m_serialPorts.key(serialPort); + Q_UNUSED(device); + + QByteArray data; + while (!serialPort->atEnd()) { + data = serialPort->read(100); + } + qDebug(dcWs2812fx()) << "Message received" << data; +} + +void DevicePluginWs2812fx::onSerialError(QSerialPort::SerialPortError error) +{ + qCWarning(dcWs2812fx()) << "Serial Port error happened:" << error; +} diff --git a/ws2812fx/devicepluginws2812fx.h b/ws2812fx/devicepluginws2812fx.h new file mode 100644 index 00000000..db8b501f --- /dev/null +++ b/ws2812fx/devicepluginws2812fx.h @@ -0,0 +1,120 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Bernhard Trinnes * + * * + * This file is part of nymea. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 library; If not, see * + * . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef DEVICEPLUGINWS2812FX_H +#define DEVICEPLUGINWS2812FX_H + +#define FX_MODE_STATIC 0 +#define FX_MODE_BLINK 1 +#define FX_MODE_BREATH 2 +#define FX_MODE_COLOR_WIPE 3 +#define FX_MODE_COLOR_WIPE_INV 4 +#define FX_MODE_COLOR_WIPE_REV 5 +#define FX_MODE_COLOR_WIPE_REV_INV 6 +#define FX_MODE_COLOR_WIPE_RANDOM 7 +#define FX_MODE_RANDOM_COLOR 8 +#define FX_MODE_SINGLE_DYNAMIC 9 +#define FX_MODE_MULTI_DYNAMIC 10 +#define FX_MODE_RAINBOW 11 +#define FX_MODE_RAINBOW_CYCLE 12 +#define FX_MODE_SCAN 13 +#define FX_MODE_DUAL_SCAN 14 +#define FX_MODE_FADE 15 +#define FX_MODE_THEATER_CHASE 16 +#define FX_MODE_THEATER_CHASE_RAINBOW 17 +#define FX_MODE_RUNNING_LIGHTS 18 +#define FX_MODE_TWINKLE 19 +#define FX_MODE_TWINKLE_RANDOM 20 +#define FX_MODE_TWINKLE_FADE 21 +#define FX_MODE_TWINKLE_FADE_RANDOM 22 +#define FX_MODE_SPARKLE 23 +#define FX_MODE_FLASH_SPARKLE 24 +#define FX_MODE_HYPER_SPARKLE 25 +#define FX_MODE_STROBE 26 +#define FX_MODE_STROBE_RAINBOW 27 +#define FX_MODE_MULTI_STROBE 28 +#define FX_MODE_BLINK_RAINBOW 29 +#define FX_MODE_CHASE_WHITE 30 +#define FX_MODE_CHASE_COLOR 31 +#define FX_MODE_CHASE_RANDOM 32 +#define FX_MODE_CHASE_RAINBOW 33 +#define FX_MODE_CHASE_FLASH 34 +#define FX_MODE_CHASE_FLASH_RANDOM 35 +#define FX_MODE_CHASE_RAINBOW_WHITE 36 +#define FX_MODE_CHASE_BLACKOUT 37 +#define FX_MODE_CHASE_BLACKOUT_RAINBOW 38 +#define FX_MODE_COLOR_SWEEP_RANDOM 39 +#define FX_MODE_RUNNING_COLOR 40 +#define FX_MODE_RUNNING_RED_BLUE 41 +#define FX_MODE_RUNNING_RANDOM 42 +#define FX_MODE_LARSON_SCANNER 43 +#define FX_MODE_COMET 44 +#define FX_MODE_FIREWORKS 45 +#define FX_MODE_FIREWORKS_RANDOM 46 +#define FX_MODE_MERRY_CHRISTMAS 47 +#define FX_MODE_FIRE_FLICKER 48 +#define FX_MODE_FIRE_FLICKER_SOFT 49 +#define FX_MODE_FIRE_FLICKER_INTENSE 50 +#define FX_MODE_CIRCUS_COMBUSTUS 51 +#define FX_MODE_HALLOWEEN 52 +#define FX_MODE_BICOLOR_CHASE 53 +#define FX_MODE_TRICOLOR_CHASE 54 +#define FX_MODE_ICU 55 +#define FX_MODE_CUSTOM 56 // keep this for backward compatiblity +#define FX_MODE_CUSTOM_0 56 // custom modes need to go at the end +#define FX_MODE_CUSTOM_1 57 +#define FX_MODE_CUSTOM_2 58 +#define FX_MODE_CUSTOM_3 59 + +#include "plugin/deviceplugin.h" +#include "devicemanager.h" +#include +#include + +class DevicePluginWs2812fx : public DevicePlugin +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "io.nymea.DevicePlugin" FILE "devicepluginws2812fx.json") + Q_INTERFACES(DevicePlugin) + +public: + explicit DevicePluginWs2812fx(); + + DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; + void deviceRemoved(Device *device) override; + DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override; + DeviceManager::DeviceError executeAction(Device *device, const Action &action) override; + +private: + QHash m_serialPorts; + QList m_usedInterfaces; + +private slots: + void onReadyRead(); + void onSerialError(QSerialPort::SerialPortError error); + +signals: + +}; + +#endif // DEVICEPLUGINWS2812FX_H diff --git a/ws2812fx/devicepluginws2812fx.json b/ws2812fx/devicepluginws2812fx.json new file mode 100644 index 00000000..fd3c6c51 --- /dev/null +++ b/ws2812fx/devicepluginws2812fx.json @@ -0,0 +1,172 @@ +{ + "displayName": "WS2812FX", + "name": "ws2812fx", + "id": "5a3c8ca5-4ef7-47a3-bf3f-c257b9f11ef0", + "vendors": [ + { + "name": "nymea", + "displayName": "nymea", + "id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6", + "deviceClasses": [ + { + "id": "24364e36-b199-4e35-b468-c44da58c009c", + "name": "ws2812fx", + "displayName": "WS2812FX", + "createMethods": ["user", "discovery"], + "interfaces": ["colorlight", "connectable"], + "paramTypes": [ + { + "id": "ed49f7d8-ab18-4c37-9b80-1004b75dcb91", + "name": "serialPort", + "displayName": "Serial port", + "type": "QString", + "inputType": "TextLine", + "defaultValue": "ttyAMA0" + } + ], + "stateTypes": [ + { + "id": "ee2c35ca-4236-43aa-aa7c-a5639c6dcf86", + "name": "connected", + "displayName": "reachable", + "displayNameEvent": "reachable changed", + "defaultValue": false, + "type": "bool" + }, + { + "id": "00db76b4-86b3-4a3f-b4e8-ceded6891282", + "name": "power", + "displayName": "power", + "displayNameEvent": "power changed", + "displayNameAction": "Set power", + "type": "bool", + "defaultValue": false, + "writable": true + }, + { + "id": "3de39d75-a775-43f1-b439-0fe326b4ba51", + "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": "8490bab0-1fdc-4acc-81e4-e7cc91d9ce1d", + "name": "color", + "displayName": "color", + "displayNameEvent": "color changed", + "displayNameAction": "Set color", + "type": "QColor", + "defaultValue": "#000000", + "writable": true + }, + { + "id": "05f2a002-6ce5-4811-bd79-44f15e981f5a", + "name": "brightness", + "displayName": "brightness", + "displayNameEvent": "brightness changed", + "displayNameAction": "Set brigtness", + "type": "int", + "unit": "Percentage", + "defaultValue": 0, + "minValue": 0, + "maxValue": 100, + "writable": true + }, + { + "id": "f1a37e73-1154-4f05-9444-d07566723c5a", + "name": "speed", + "displayName": "speed", + "displayNameEvent": "speed changed", + "displayNameAction": "Set speed", + "type": "int", + "unit": "Percentage", + "defaultValue": 0, + "minValue": 0, + "maxValue": 100, + "writable": true + }, + { + "id": "ebfb4bc6-b1dc-4a5c-a495-077cba4fec1a", + "name": "effectMode", + "displayName": "Effect mode", + "displayNameEvent": "Effect mode changed", + "displayNameAction": "Set effect mode", + "type": "QString", + "defaultValue": "Static", + "possibleValues": [ + "Static", + "Blink", + "Breath", + "Color Wipe", + "Color Wipe Inverse", + "Color Wipe Reverse", + "Color Wipe Reverse Inverse", + "Color Wipe Random ", + "Random Color", + "Single Dynamic", + "Multi Dynamic", + "Rainbow", + "Rainbow Cycle", + "Scan", + "Dual Scan", + "Fade", + "Theater Chase", + "Theater Chase Rainbow", + "Running Lights", + "Twinkle", + "Twinkle Random", + "Twinkle Fade", + "Twinkle Fade Random", + "Sparkle", + "Flash Sparkle", + "Hyper Sparkle", + "Strobe", + "Strobe Rainbow", + "Multi Strobe", + "Blink Rainbow", + "Chase White", + "Chase Color", + "Chase Random", + "Chase Rainbow", + "Chase Flash", + "Chase Flash Random", + "Chase Rainbow White", + "Chase Blackout", + "Chase Blackout Rainbow", + "Color Sweep Random", + "Running Color", + "Running Red Blue", + "Running Random", + "Larson Scanner", + "Comet", + "Fireworks", + "Fireworks Random", + "Merry Christmas", + "Fire Flicker", + "Fire Flicker (soft)", + "Fire Flicker (intense)", + "Circus Combustus", + "Halloween", + "Bicolor Chase", + "Tricolor Chase", + "ICU", + "Custom 1", + "Custom 2", + "Custom 3", + "Custom 4" + ], + "writable": true + } + ] + } + ] + } + ] +} diff --git a/ws2812fx/ws2812fx.pro b/ws2812fx/ws2812fx.pro new file mode 100644 index 00000000..3fe77d5b --- /dev/null +++ b/ws2812fx/ws2812fx.pro @@ -0,0 +1,12 @@ +include(../plugins.pri) + +QT += serialport + +TARGET = $$qtLibraryTarget(nymea_devicepluginws2812fx) + +SOURCES += \ + devicepluginws2812fx.cpp \ + + +HEADERS += \ + devicepluginws2812fx.h \