From df63d55197c1f33060e31719bb0c4bc75a5ca399 Mon Sep 17 00:00:00 2001 From: nymea Date: Thu, 9 May 2019 18:39:54 +0200 Subject: [PATCH 1/7] add ws2812fx plug-in --- nymea-plugins.pro | 2 + ws2812fx/devicepluginws2812fx.cpp | 313 +++++++++++++++++++++++++++++ ws2812fx/devicepluginws2812fx.h | 120 +++++++++++ ws2812fx/devicepluginws2812fx.json | 172 ++++++++++++++++ ws2812fx/ws2812fx.pro | 12 ++ 5 files changed, 619 insertions(+) create mode 100644 ws2812fx/devicepluginws2812fx.cpp create mode 100644 ws2812fx/devicepluginws2812fx.h create mode 100644 ws2812fx/devicepluginws2812fx.json create mode 100644 ws2812fx/ws2812fx.pro 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 \ From 0ba20c9c4e360b52577d23efe8bbd7ace0c49177 Mon Sep 17 00:00:00 2001 From: nymea Date: Sun, 26 May 2019 18:35:33 +0200 Subject: [PATCH 2/7] fixed commands, added async actions --- ws2812fx/devicepluginws2812fx.cpp | 283 ++++++++++++++++++++--------- ws2812fx/devicepluginws2812fx.h | 6 + ws2812fx/devicepluginws2812fx.json | 6 +- 3 files changed, 210 insertions(+), 85 deletions(-) diff --git a/ws2812fx/devicepluginws2812fx.cpp b/ws2812fx/devicepluginws2812fx.cpp index 9a6c146d..ff797f7d 100644 --- a/ws2812fx/devicepluginws2812fx.cpp +++ b/ws2812fx/devicepluginws2812fx.cpp @@ -46,6 +46,14 @@ DevicePluginWs2812fx ::DevicePluginWs2812fx () DeviceManager::DeviceSetupStatus DevicePluginWs2812fx::setupDevice(Device *device) { + if(!m_reconnectTimer) { + m_reconnectTimer = new QTimer(this); + m_reconnectTimer->setSingleShot(true); + m_reconnectTimer->setInterval(5000); + + connect(m_reconnectTimer, &QTimer::timeout, this, &DevicePluginWs2812fx::onReconnectTimer); + } + if (device->deviceClassId() == ws2812fxDeviceClassId) { QString interface = device->paramValue(ws2812fxDeviceSerialPortParamTypeId).toString(); @@ -55,9 +63,9 @@ DeviceManager::DeviceSetupStatus DevicePluginWs2812fx::setupDevice(Device *devic if(!serialPort) return DeviceManager::DeviceSetupStatusFailure; - serialPort->setBaudRate(11520); + serialPort->setBaudRate(115200); serialPort->setDataBits(QSerialPort::DataBits::Data8); - serialPort->setParity(QSerialPort::Parity::EvenParity); + serialPort->setParity(QSerialPort::Parity::NoParity); serialPort->setStopBits(QSerialPort::StopBits::OneStop); serialPort->setFlowControl(QSerialPort::FlowControl::NoFlowControl); @@ -70,6 +78,7 @@ DeviceManager::DeviceSetupStatus DevicePluginWs2812fx::setupDevice(Device *devic connect(serialPort, SIGNAL(readyRead()), this, SLOT(onReadyRead())); qCDebug(dcWs2812fx()) << "Setup successfully serial port" << interface; + device->setStateValue(ws2812fxConnectedStateTypeId, true); m_usedInterfaces.append(interface); m_serialPorts.insert(device, serialPort); } else { @@ -88,19 +97,14 @@ DeviceManager::DeviceError DevicePluginWs2812fx::discoverDevices(const DeviceCla 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); - } + + 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; @@ -117,12 +121,28 @@ DeviceManager::DeviceError DevicePluginWs2812fx::executeAction(Device *device, c if (!serialPort) return DeviceManager::DeviceErrorDeviceNotFound; QByteArray command; + if (action.actionTypeId() == ws2812fxPowerActionTypeId) { + command.append("b "); + if (action.param(ws2812fxPowerActionPowerParamTypeId).value().toBool()) { + command.append("30"); + } else { + command.append("0"); + } + command.append("\r\n"); + qDebug(dcWs2812fx()) << "Sending command" << command; + serialPort->write(command); + m_pendingActions.insert("brightness", action.id()); + return DeviceManager::DeviceErrorAsync; + } if (action.actionTypeId() == ws2812fxBrightnessActionTypeId) { command.append("b "); command.append(action.param(ws2812fxBrightnessActionBrightnessParamTypeId).value().toString()); + command.append("\r\n"); + qDebug(dcWs2812fx()) << "Sending command" << command; serialPort->write(command); + m_pendingActions.insert("brightness", action.id()); return DeviceManager::DeviceErrorAsync; } @@ -130,15 +150,24 @@ DeviceManager::DeviceError DevicePluginWs2812fx::executeAction(Device *device, c command.append("s "); command.append(action.param(ws2812fxSpeedActionSpeedParamTypeId).value().toString()); + command.append("\r\n"); + qDebug(dcWs2812fx()) << "Sending command" << command; serialPort->write(command); + m_pendingActions.insert("speed", action.id()); return DeviceManager::DeviceErrorAsync; } if (action.actionTypeId() == ws2812fxColorActionTypeId) { + QColor color; + color= action.param(ws2812fxColorActionColorParamTypeId).value().value(); command.append("c "); - command.append(action.param(ws2812fxSpeedActionSpeedParamTypeId).value().toString()); + command.append(QString(color.name()).remove("#")); + command.append("\r\n"); + qDebug(dcWs2812fx()) << "Sending command" << command; serialPort->write(command); + + m_pendingActions.insert("color", action.id()); return DeviceManager::DeviceErrorAsync; } @@ -146,10 +175,14 @@ DeviceManager::DeviceError DevicePluginWs2812fx::executeAction(Device *device, c // minValue 153, maxValue 500 QColor color; - color.setRgb(255, 255, ((action.param(ws2812fxColorActionColorParamTypeId).value().toInt()-153)/347.00)); + color.setRgb(255, 255, static_cast((255.00-(((action.param(ws2812fxColorTemperatureActionColorTemperatureParamTypeId).value().toDouble()-153.00)/347.00))*255.00))); + device->setStateValue(ws2812fxColorTemperatureStateTypeId, action.param(ws2812fxColorTemperatureActionColorTemperatureParamTypeId).value()); command.append("c "); - command.append(color.rgb()); + command.append(QString(color.name()).remove("#")); + command.append("\r\n"); + qDebug(dcWs2812fx()) << "Sending command" << command; serialPort->write(command); + m_pendingActions.insert("color", action.id()); return DeviceManager::DeviceErrorAsync; } @@ -158,123 +191,126 @@ DeviceManager::DeviceError DevicePluginWs2812fx::executeAction(Device *device, c QString effectMode = action.param(ws2812fxEffectModeActionEffectModeParamTypeId).value().toString(); command.append("m "); if (effectMode == "Static") { - command.append(static_cast(FX_MODE_STATIC)); + command.append(QString::number(FX_MODE_STATIC)); } else if (effectMode == "Blink") { - command.append(FX_MODE_BLINK); + command.append(QString::number(FX_MODE_BLINK)); } else if (effectMode == "Color Wipe") { - command.append(FX_MODE_COLOR_WIPE); + command.append(QString::number(FX_MODE_COLOR_WIPE)); } else if (effectMode == "Color Wipe Inverse") { - command.append(FX_MODE_COLOR_WIPE_INV); + command.append(QString::number(FX_MODE_COLOR_WIPE_INV)); } else if (effectMode == "Color Wipe Reverse") { - command.append(FX_MODE_COLOR_WIPE_REV); + command.append(QString::number(FX_MODE_COLOR_WIPE_REV)); } else if (effectMode == "Color Wipe Reverse Inverse") { - command.append(FX_MODE_COLOR_WIPE_REV_INV); + command.append(QString::number(FX_MODE_COLOR_WIPE_REV_INV)); } else if (effectMode == "Color Wipe Random") { - command.append(FX_MODE_COLOR_WIPE_RANDOM); + command.append(QString::number(FX_MODE_COLOR_WIPE_RANDOM)); } else if (effectMode == "Random Color") { - command.append(FX_MODE_RANDOM_COLOR); + command.append(QString::number(FX_MODE_RANDOM_COLOR)); } else if (effectMode == "Single Dynamic") { - command.append(FX_MODE_SINGLE_DYNAMIC); + command.append(QString::number(FX_MODE_SINGLE_DYNAMIC)); } else if (effectMode == "Multi Dynamic") { - command.append(FX_MODE_MULTI_DYNAMIC); + command.append(QString::number(FX_MODE_MULTI_DYNAMIC)); } else if (effectMode == "Rainbow") { - command.append(FX_MODE_RAINBOW); + command.append(QString::number(FX_MODE_RAINBOW)); } else if (effectMode == "Rainbow Cycle") { - command.append(FX_MODE_RAINBOW_CYCLE); + command.append(QString::number(FX_MODE_RAINBOW_CYCLE)); } else if (effectMode == "Scan") { - command.append(FX_MODE_SCAN); + command.append(QString::number(FX_MODE_SCAN)); } else if (effectMode == "Dual Scan") { - command.append(FX_MODE_DUAL_SCAN); + command.append(QString::number(FX_MODE_DUAL_SCAN)); } else if (effectMode == "Fade") { - command.append(FX_MODE_FADE); + command.append(QString::number(FX_MODE_FADE)); } else if (effectMode == "Theater Chase") { - command.append(FX_MODE_THEATER_CHASE); + command.append(QString::number(FX_MODE_THEATER_CHASE)); } else if (effectMode == "Theater Chase Rainbow") { - command.append(FX_MODE_THEATER_CHASE_RAINBOW); + command.append(QString::number(FX_MODE_THEATER_CHASE_RAINBOW)); } else if (effectMode == "Running Lights") { - command.append(FX_MODE_RUNNING_LIGHTS); + command.append(QString::number(FX_MODE_RUNNING_LIGHTS)); } else if (effectMode == "Twinkle") { - command.append(FX_MODE_TWINKLE); + command.append(QString::number(FX_MODE_TWINKLE)); } else if (effectMode == "Twinkle Random") { - command.append(FX_MODE_TWINKLE_RANDOM); + command.append(QString::number(FX_MODE_TWINKLE_RANDOM)); } else if (effectMode == "Twinkle Fade") { - command.append(FX_MODE_TWINKLE_FADE); + command.append(QString::number(FX_MODE_TWINKLE_FADE)); } else if (effectMode == "Twinkle Fade Random") { - command.append(FX_MODE_TWINKLE_FADE_RANDOM); + command.append(QString::number(FX_MODE_TWINKLE_FADE_RANDOM)); } else if (effectMode == "Sparkle") { - command.append(FX_MODE_SPARKLE); + command.append(QString::number(FX_MODE_SPARKLE)); } else if (effectMode == "Flash Sparkle") { - command.append(FX_MODE_FLASH_SPARKLE); + command.append(QString::number(FX_MODE_FLASH_SPARKLE)); } else if (effectMode == "Hyper Sparkle") { - command.append(FX_MODE_HYPER_SPARKLE); + command.append(QString::number(FX_MODE_HYPER_SPARKLE)); } else if (effectMode == "Strobe") { - command.append(FX_MODE_STROBE); + command.append(QString::number(FX_MODE_STROBE)); } else if (effectMode == "Strobe Rainbow") { - command.append(FX_MODE_STROBE_RAINBOW); + command.append(QString::number(FX_MODE_STROBE_RAINBOW)); } else if (effectMode == "Multi Strobe") { - command.append(FX_MODE_MULTI_STROBE); + command.append(QString::number(FX_MODE_MULTI_STROBE)); } else if (effectMode == "Blink Rainbow") { - command.append(FX_MODE_BLINK_RAINBOW); + command.append(QString::number(FX_MODE_BLINK_RAINBOW)); } else if (effectMode == "Chase White") { - command.append(FX_MODE_CHASE_WHITE); + command.append(QString::number(FX_MODE_CHASE_WHITE)); } else if (effectMode == "Chase Color") { - command.append(FX_MODE_CHASE_COLOR); + command.append(QString::number(FX_MODE_CHASE_COLOR)); } else if (effectMode == "Chase Random") { - command.append(FX_MODE_CHASE_RANDOM); + command.append(QString::number(FX_MODE_CHASE_RANDOM)); } else if (effectMode == "Chase Flash") { - command.append(FX_MODE_CHASE_FLASH); + command.append(QString::number(FX_MODE_CHASE_FLASH)); } else if (effectMode == "Chase Flash Random") { - command.append(FX_MODE_CHASE_FLASH_RANDOM); + command.append(QString::number(FX_MODE_CHASE_FLASH_RANDOM)); } else if (effectMode == "Chase Rainbow White") { - command.append(FX_MODE_CHASE_RAINBOW_WHITE); + command.append(QString::number(FX_MODE_CHASE_RAINBOW_WHITE)); } else if (effectMode == "Chase Blackout") { - command.append(FX_MODE_CHASE_BLACKOUT); + command.append(QString::number(FX_MODE_CHASE_BLACKOUT)); } else if (effectMode == "Chase Blackout Rainbow") { - command.append(FX_MODE_CHASE_BLACKOUT_RAINBOW); + command.append(QString::number(FX_MODE_CHASE_BLACKOUT_RAINBOW)); } else if (effectMode == "Color Sweep Random") { - command.append(FX_MODE_COLOR_SWEEP_RANDOM); + command.append(QString::number(FX_MODE_COLOR_SWEEP_RANDOM)); } else if (effectMode == "Running Color") { - command.append(FX_MODE_RUNNING_COLOR); + command.append(QString::number(FX_MODE_RUNNING_COLOR)); } else if (effectMode == "Running Red Blue") { - command.append(FX_MODE_RUNNING_RED_BLUE); + command.append(QString::number(FX_MODE_RUNNING_RED_BLUE)); } else if (effectMode == "Running Random") { - command.append(FX_MODE_RUNNING_RANDOM); + command.append(QString::number(FX_MODE_RUNNING_RANDOM)); }else if (effectMode == "Larson Scanner") { - command.append(FX_MODE_LARSON_SCANNER); + command.append(QString::number(FX_MODE_LARSON_SCANNER)); }else if (effectMode == "Comet") { - command.append(FX_MODE_COMET); + command.append(QString::number(FX_MODE_COMET)); }else if (effectMode == "Fireworks") { - command.append(FX_MODE_FIREWORKS); + command.append(QString::number(FX_MODE_FIREWORKS)); }else if (effectMode == "Fireworks Random") { - command.append(FX_MODE_FIREWORKS_RANDOM); + command.append(QString::number(FX_MODE_FIREWORKS_RANDOM)); }else if (effectMode == "Merry Christmas") { - command.append(FX_MODE_MERRY_CHRISTMAS); + command.append(QString::number(FX_MODE_MERRY_CHRISTMAS)); }else if (effectMode == "Fire Flicker") { - command.append(FX_MODE_FIRE_FLICKER); + command.append(QString::number(FX_MODE_FIRE_FLICKER)); }else if (effectMode == "Fire Flicker (soft)") { - command.append(FX_MODE_FIRE_FLICKER_SOFT); + command.append(QString::number(FX_MODE_FIRE_FLICKER_SOFT)); }else if (effectMode == "Fire Flicker (intense)") { - command.append(FX_MODE_FIRE_FLICKER_INTENSE); + command.append(QString::number(FX_MODE_FIRE_FLICKER_INTENSE)); }else if (effectMode == "Circus Combustus") { - command.append(FX_MODE_CIRCUS_COMBUSTUS); + command.append(QString::number(FX_MODE_CIRCUS_COMBUSTUS)); }else if (effectMode == "Halloween") { - command.append(FX_MODE_HALLOWEEN); + command.append(QString::number(FX_MODE_HALLOWEEN)); }else if (effectMode == "Bicolor Chase") { - command.append(FX_MODE_BICOLOR_CHASE); + command.append(QString::number(FX_MODE_BICOLOR_CHASE)); }else if (effectMode == "Tricolor Chase") { - command.append(FX_MODE_TRICOLOR_CHASE); + command.append(QString::number(FX_MODE_TRICOLOR_CHASE)); }else if (effectMode == "ICU") { - command.append(FX_MODE_ICU); + command.append(QString::number(FX_MODE_ICU)); + }else if (effectMode == "Custom 0") { + command.append(QString::number(FX_MODE_CUSTOM_0)); }else if (effectMode == "Custom 1") { - command.append(FX_MODE_CUSTOM_0); + command.append(QString::number(FX_MODE_CUSTOM_1)); }else if (effectMode == "Custom 2") { - command.append(FX_MODE_CUSTOM_1); + command.append(QString::number(FX_MODE_CUSTOM_2)); }else if (effectMode == "Custom 3") { - command.append(FX_MODE_CUSTOM_2); - }else if (effectMode == "Custom 4") { - command.append(FX_MODE_CUSTOM_3); + command.append(QString::number(FX_MODE_CUSTOM_3)); } + command.append("\r\n"); + qDebug(dcWs2812fx()) << "Sending command" << command; serialPort->write(command); + m_pendingActions.insert("mode", action.id()); return DeviceManager::DeviceErrorAsync; } return DeviceManager::DeviceErrorActionTypeNotFound; @@ -289,25 +325,108 @@ void DevicePluginWs2812fx::deviceRemoved(Device *device) m_usedInterfaces.removeAll(device->paramValue(ws2812fxDeviceSerialPortParamTypeId).toString()); QSerialPort *serialPort = m_serialPorts.take(device); + serialPort->flush(); serialPort->close(); serialPort->deleteLater(); } + + if (myDevices().empty()) { + m_reconnectTimer->stop(); + m_reconnectTimer->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); + while (serialPort->canReadLine()) { + data = serialPort->readLine(); + qDebug(dcWs2812fx()) << "Message received" << data; + + if (data.contains("mode")) { + if (m_pendingActions.contains("mode")) { + emit actionExecutionFinished(m_pendingActions.value("mode"), DeviceManager::DeviceErrorNoError); + } + QString mode = data.split('-').at(1); + mode.remove(0, 1); + mode.remove("\r\n"); + qDebug(dcWs2812fx()) << "set mode to:" << mode; + device->setStateValue(ws2812fxEffectModeStateTypeId, mode); + } + if (data.contains("brightness")) { + if (m_pendingActions.contains("brightness")) { + emit actionExecutionFinished(m_pendingActions.value("brightness"), DeviceManager::DeviceErrorNoError); + } + QString rawBrightness = data.split(':').at(1); + rawBrightness.remove(" "); + rawBrightness.remove("\r\n"); + int brightness = rawBrightness.toInt(); + + qDebug(dcWs2812fx()) << "set brightness to:" << brightness; + device->setStateValue(ws2812fxBrightnessStateTypeId, brightness); + if (brightness == 0) { + device->setStateValue(ws2812fxPowerStateTypeId, false); + } else { + device->setStateValue(ws2812fxPowerStateTypeId, true); + } + } + if (data.contains("speed")) { + if (m_pendingActions.contains("speed")) { + emit actionExecutionFinished(m_pendingActions.value("speed"), DeviceManager::DeviceErrorNoError); + } + QString rawSpeed = data.split(':').at(1); + rawSpeed.remove(" "); + rawSpeed.remove("\r\n"); + int speed = data.split(':').at(1).toInt(); + + qDebug(dcWs2812fx()) << "set speed to:" << speed; + device->setStateValue(ws2812fxSpeedStateTypeId, speed); + } + if (data.contains("color")) { + if (m_pendingActions.contains("color")) { + emit actionExecutionFinished(m_pendingActions.value("color"), DeviceManager::DeviceErrorNoError); + } + QString rawColor = data.split(':').at(1); + rawColor.remove(" "); + rawColor.remove("0x"); + rawColor.remove("\r\n"); + rawColor.prepend("#"); + qDebug(dcWs2812fx()) << "set color to:" << rawColor; + device->setStateValue(ws2812fxColorStateTypeId, rawColor); + } } - qDebug(dcWs2812fx()) << "Message received" << data; +} + +void DevicePluginWs2812fx::onReconnectTimer() +{ + foreach(Device *device, myDevices()) { + if (!device->stateValue(ws2812fxConnectedStateTypeId).toBool()) { + QSerialPort *serialPort = m_serialPorts.value(device); + if (serialPort) { + if (serialPort->open(QSerialPort::ReadWrite)) { + device->setStateValue(ws2812fxConnectedStateTypeId, true); + } else { + device->setStateValue(ws2812fxConnectedStateTypeId, false); + m_reconnectTimer->start(); + } + } + } + } + } void DevicePluginWs2812fx::onSerialError(QSerialPort::SerialPortError error) { - qCWarning(dcWs2812fx()) << "Serial Port error happened:" << error; + QSerialPort *serialPort = static_cast(sender()); + Device *device = m_serialPorts.key(serialPort); + + if (error != QSerialPort::NoError && serialPort->isOpen()) { + qCCritical(dcWs2812fx()) << "Serial port error:" << error << serialPort->errorString(); + m_reconnectTimer->start(); + serialPort->close(); + device->setStateValue(ws2812fxConnectedStateTypeId, false); + } } diff --git a/ws2812fx/devicepluginws2812fx.h b/ws2812fx/devicepluginws2812fx.h index db8b501f..e08eb5ed 100644 --- a/ws2812fx/devicepluginws2812fx.h +++ b/ws2812fx/devicepluginws2812fx.h @@ -87,6 +87,8 @@ #include "plugin/deviceplugin.h" #include "devicemanager.h" + +#include #include #include @@ -108,9 +110,13 @@ public: private: QHash m_serialPorts; QList m_usedInterfaces; + QHash m_pendingActions; + + QTimer *m_reconnectTimer = nullptr; private slots: void onReadyRead(); + void onReconnectTimer(); void onSerialError(QSerialPort::SerialPortError error); signals: diff --git a/ws2812fx/devicepluginws2812fx.json b/ws2812fx/devicepluginws2812fx.json index fd3c6c51..90624c35 100644 --- a/ws2812fx/devicepluginws2812fx.json +++ b/ws2812fx/devicepluginws2812fx.json @@ -21,7 +21,7 @@ "displayName": "Serial port", "type": "QString", "inputType": "TextLine", - "defaultValue": "ttyAMA0" + "defaultValue": "ttyAMC0" } ], "stateTypes": [ @@ -157,10 +157,10 @@ "Bicolor Chase", "Tricolor Chase", "ICU", + "Custom 0", "Custom 1", "Custom 2", - "Custom 3", - "Custom 4" + "Custom 3" ], "writable": true } From 1fa68fc3c3f70bd6ab00cefcb9a9a9cfb0892193 Mon Sep 17 00:00:00 2001 From: nymea Date: Tue, 25 Jun 2019 22:49:16 +0200 Subject: [PATCH 3/7] updated to new device api --- ws2812fx/devicepluginws2812fx.cpp | 92 +++++++++++++++---------------- ws2812fx/devicepluginws2812fx.h | 21 ++++--- 2 files changed, 57 insertions(+), 56 deletions(-) diff --git a/ws2812fx/devicepluginws2812fx.cpp b/ws2812fx/devicepluginws2812fx.cpp index ff797f7d..1989fd39 100644 --- a/ws2812fx/devicepluginws2812fx.cpp +++ b/ws2812fx/devicepluginws2812fx.cpp @@ -44,7 +44,7 @@ DevicePluginWs2812fx ::DevicePluginWs2812fx () { } -DeviceManager::DeviceSetupStatus DevicePluginWs2812fx::setupDevice(Device *device) +Device::DeviceSetupStatus DevicePluginWs2812fx::setupDevice(Device *device) { if(!m_reconnectTimer) { m_reconnectTimer = new QTimer(this); @@ -61,7 +61,7 @@ DeviceManager::DeviceSetupStatus DevicePluginWs2812fx::setupDevice(Device *devic QSerialPort *serialPort = new QSerialPort(interface, this); if(!serialPort) - return DeviceManager::DeviceSetupStatusFailure; + return Device::DeviceSetupStatusFailure; serialPort->setBaudRate(115200); serialPort->setDataBits(QSerialPort::DataBits::Data8); @@ -71,7 +71,8 @@ DeviceManager::DeviceSetupStatus DevicePluginWs2812fx::setupDevice(Device *devic if (!serialPort->open(QIODevice::ReadWrite)) { qCWarning(dcWs2812fx()) << "Could not open serial port" << interface << serialPort->errorString(); - return DeviceManager::DeviceSetupStatusFailure; + serialPort->deleteLater(); + return Device::DeviceSetupStatusFailure; } connect(serialPort, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onSerialError(QSerialPort::SerialPortError))); @@ -82,15 +83,15 @@ DeviceManager::DeviceSetupStatus DevicePluginWs2812fx::setupDevice(Device *devic m_usedInterfaces.append(interface); m_serialPorts.insert(device, serialPort); } else { - return DeviceManager::DeviceSetupStatusFailure; + return Device::DeviceSetupStatusFailure; } - return DeviceManager::DeviceSetupStatusSuccess; + return Device::DeviceSetupStatusSuccess; } - return DeviceManager::DeviceSetupStatusFailure; + return Device::DeviceSetupStatusFailure; } -DeviceManager::DeviceError DevicePluginWs2812fx::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) +Device::DeviceError DevicePluginWs2812fx::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) { Q_UNUSED(params) // Create the list of available serial interfaces @@ -101,25 +102,23 @@ DeviceManager::DeviceError DevicePluginWs2812fx::discoverDevices(const DeviceCla qCDebug(dcWs2812fx()) << "Found serial port:" << port.portName(); QString description = port.manufacturer() + " " + port.description(); DeviceDescriptor descriptor(deviceClassId, port.portName(), description); + foreach (Device *existingDevice, myDevices().filterByParam(ws2812fxDeviceSerialPortParamTypeId, port.portName())) { + descriptor.setDeviceId(existingDevice->id()); + } ParamList parameters; parameters.append(Param(ws2812fxDeviceSerialPortParamTypeId, port.portName())); descriptor.setParams(parameters); deviceDescriptors.append(descriptor); } emit devicesDiscovered(deviceClassId, deviceDescriptors); - return DeviceManager::DeviceErrorAsync; + return Device::DeviceErrorAsync; } -DeviceManager::DeviceError DevicePluginWs2812fx::executeAction(Device *device, const Action &action) +Device::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() == ws2812fxPowerActionTypeId) { command.append("b "); @@ -129,10 +128,7 @@ DeviceManager::DeviceError DevicePluginWs2812fx::executeAction(Device *device, c command.append("0"); } command.append("\r\n"); - qDebug(dcWs2812fx()) << "Sending command" << command; - serialPort->write(command); - m_pendingActions.insert("brightness", action.id()); - return DeviceManager::DeviceErrorAsync; + return sendCommand(device, action.id(), command, CommandType::Brightness); } if (action.actionTypeId() == ws2812fxBrightnessActionTypeId) { @@ -140,10 +136,7 @@ DeviceManager::DeviceError DevicePluginWs2812fx::executeAction(Device *device, c command.append("b "); command.append(action.param(ws2812fxBrightnessActionBrightnessParamTypeId).value().toString()); command.append("\r\n"); - qDebug(dcWs2812fx()) << "Sending command" << command; - serialPort->write(command); - m_pendingActions.insert("brightness", action.id()); - return DeviceManager::DeviceErrorAsync; + return sendCommand(device, action.id(), command, CommandType::Brightness); } if (action.actionTypeId() == ws2812fxSpeedActionTypeId) { @@ -151,10 +144,7 @@ DeviceManager::DeviceError DevicePluginWs2812fx::executeAction(Device *device, c command.append("s "); command.append(action.param(ws2812fxSpeedActionSpeedParamTypeId).value().toString()); command.append("\r\n"); - qDebug(dcWs2812fx()) << "Sending command" << command; - serialPort->write(command); - m_pendingActions.insert("speed", action.id()); - return DeviceManager::DeviceErrorAsync; + return sendCommand(device, action.id(), command, CommandType::Speed); } if (action.actionTypeId() == ws2812fxColorActionTypeId) { @@ -164,11 +154,7 @@ DeviceManager::DeviceError DevicePluginWs2812fx::executeAction(Device *device, c command.append("c "); command.append(QString(color.name()).remove("#")); command.append("\r\n"); - qDebug(dcWs2812fx()) << "Sending command" << command; - serialPort->write(command); - - m_pendingActions.insert("color", action.id()); - return DeviceManager::DeviceErrorAsync; + return sendCommand(device, action.id(), command, CommandType::Color); } if (action.actionTypeId() == ws2812fxColorTemperatureActionTypeId) { @@ -180,10 +166,7 @@ DeviceManager::DeviceError DevicePluginWs2812fx::executeAction(Device *device, c command.append("c "); command.append(QString(color.name()).remove("#")); command.append("\r\n"); - qDebug(dcWs2812fx()) << "Sending command" << command; - serialPort->write(command); - m_pendingActions.insert("color", action.id()); - return DeviceManager::DeviceErrorAsync; + return sendCommand(device, action.id(), command, CommandType::Color); } if (action.actionTypeId() == ws2812fxEffectModeActionTypeId) { @@ -308,14 +291,11 @@ DeviceManager::DeviceError DevicePluginWs2812fx::executeAction(Device *device, c command.append(QString::number(FX_MODE_CUSTOM_3)); } command.append("\r\n"); - qDebug(dcWs2812fx()) << "Sending command" << command; - serialPort->write(command); - m_pendingActions.insert("mode", action.id()); - return DeviceManager::DeviceErrorAsync; + return sendCommand(device, action.id(), command, CommandType::Mode); } - return DeviceManager::DeviceErrorActionTypeNotFound; + return Device::DeviceErrorActionTypeNotFound; } - return DeviceManager::DeviceErrorDeviceClassNotFound; + return Device::DeviceErrorDeviceClassNotFound; } @@ -347,8 +327,8 @@ void DevicePluginWs2812fx::onReadyRead() qDebug(dcWs2812fx()) << "Message received" << data; if (data.contains("mode")) { - if (m_pendingActions.contains("mode")) { - emit actionExecutionFinished(m_pendingActions.value("mode"), DeviceManager::DeviceErrorNoError); + if (m_pendingActions.contains(CommandType::Mode)) { + emit actionExecutionFinished(m_pendingActions.value(CommandType::Mode), Device::DeviceErrorNoError); } QString mode = data.split('-').at(1); mode.remove(0, 1); @@ -357,8 +337,8 @@ void DevicePluginWs2812fx::onReadyRead() device->setStateValue(ws2812fxEffectModeStateTypeId, mode); } if (data.contains("brightness")) { - if (m_pendingActions.contains("brightness")) { - emit actionExecutionFinished(m_pendingActions.value("brightness"), DeviceManager::DeviceErrorNoError); + if (m_pendingActions.contains(CommandType::Brightness)) { + emit actionExecutionFinished(m_pendingActions.value(CommandType::Brightness), Device::DeviceErrorNoError); } QString rawBrightness = data.split(':').at(1); rawBrightness.remove(" "); @@ -374,8 +354,8 @@ void DevicePluginWs2812fx::onReadyRead() } } if (data.contains("speed")) { - if (m_pendingActions.contains("speed")) { - emit actionExecutionFinished(m_pendingActions.value("speed"), DeviceManager::DeviceErrorNoError); + if (m_pendingActions.contains(CommandType::Speed)) { + emit actionExecutionFinished(m_pendingActions.value(CommandType::Speed), Device::DeviceErrorNoError); } QString rawSpeed = data.split(':').at(1); rawSpeed.remove(" "); @@ -386,8 +366,8 @@ void DevicePluginWs2812fx::onReadyRead() device->setStateValue(ws2812fxSpeedStateTypeId, speed); } if (data.contains("color")) { - if (m_pendingActions.contains("color")) { - emit actionExecutionFinished(m_pendingActions.value("color"), DeviceManager::DeviceErrorNoError); + if (m_pendingActions.contains(CommandType::Color)) { + emit actionExecutionFinished(m_pendingActions.value(CommandType::Color), Device::DeviceErrorNoError); } QString rawColor = data.split(':').at(1); rawColor.remove(" "); @@ -430,3 +410,17 @@ void DevicePluginWs2812fx::onSerialError(QSerialPort::SerialPortError error) device->setStateValue(ws2812fxConnectedStateTypeId, false); } } + +Device::DeviceError DevicePluginWs2812fx::sendCommand(Device* device, ActionId actionId, const QByteArray &command, CommandType commandType) +{ + qDebug(dcWs2812fx()) << "Sending command" << command; + QSerialPort *serialPort = m_serialPorts.value(device); + if (!serialPort) + return Device::DeviceErrorDeviceNotFound; + if (serialPort->write(command) != command.length()) { + qCWarning(dcWs2812fx) << "Error writing to serial port"; + return Device::DeviceErrorHardwareFailure; + } + m_pendingActions.insert(commandType, actionId); + return Device::DeviceErrorAsync; +} diff --git a/ws2812fx/devicepluginws2812fx.h b/ws2812fx/devicepluginws2812fx.h index e08eb5ed..159d6d90 100644 --- a/ws2812fx/devicepluginws2812fx.h +++ b/ws2812fx/devicepluginws2812fx.h @@ -85,8 +85,7 @@ #define FX_MODE_CUSTOM_2 58 #define FX_MODE_CUSTOM_3 59 -#include "plugin/deviceplugin.h" -#include "devicemanager.h" +#include "devices/deviceplugin.h" #include #include @@ -102,21 +101,29 @@ class DevicePluginWs2812fx : public DevicePlugin public: explicit DevicePluginWs2812fx(); - DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; + Device::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; + Device::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) override; + Device::DeviceError executeAction(Device *device, const Action &action) override; private: + enum CommandType { + Color, + Speed, + Brightness, + Mode + }; + QHash m_serialPorts; QList m_usedInterfaces; - QHash m_pendingActions; + QHash m_pendingActions; QTimer *m_reconnectTimer = nullptr; + Device::DeviceError sendCommand(Device *device, ActionId actionId, const QByteArray &command, CommandType commandType); private slots: void onReadyRead(); - void onReconnectTimer(); + void onReconnectTimer(); void onSerialError(QSerialPort::SerialPortError error); signals: From bcf7444f967cdd1af088f2976dff058c0fde7b04 Mon Sep 17 00:00:00 2001 From: nymea Date: Tue, 25 Jun 2019 22:56:41 +0200 Subject: [PATCH 4/7] fix merge error --- nymea-plugins.pro | 1 - 1 file changed, 1 deletion(-) diff --git a/nymea-plugins.pro b/nymea-plugins.pro index c3f6893f..b3ded9b2 100644 --- a/nymea-plugins.pro +++ b/nymea-plugins.pro @@ -44,7 +44,6 @@ PLUGIN_DIRS = \ unitec \ wakeonlan \ wemo \ - ws2812 \ ws2812fx \ From 7164d0b58cbb921dd8bada756f82f6ff9e555c31 Mon Sep 17 00:00:00 2001 From: nymea Date: Fri, 26 Jul 2019 09:25:08 +0200 Subject: [PATCH 5/7] added plug-in to debian folder --- debian/control | 15 +++++++++++++++ debian/nymea-plugin-ws2812fx.install.in | 1 + 2 files changed, 16 insertions(+) create mode 100644 debian/nymea-plugin-ws2812fx.install.in diff --git a/debian/control b/debian/control index 109179e7..b83c4a60 100644 --- a/debian/control +++ b/debian/control @@ -550,6 +550,21 @@ Description: nymea.io plugin for wemo This package will install the nymea.io plugin for wemo +Package: nymea-plugin-ws2812fx +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, + nymea-plugins-translations, +Description: nymea.io plugin for ws2812fx + The nymea daemon is a plugin based IoT (Internet of Things) server. The + server works like a translator for devices, things and services and + allows them to interact. + With the powerful rule engine you are able to connect any device available + in the system and create individual scenes and behaviors for your environment. + . + This package will install the nymea.io plugin for ws2812fx + + Package: nymea-plugin-tcpcommander Architecture: any Depends: ${shlibs:Depends}, diff --git a/debian/nymea-plugin-ws2812fx.install.in b/debian/nymea-plugin-ws2812fx.install.in new file mode 100644 index 00000000..8a70387a --- /dev/null +++ b/debian/nymea-plugin-ws2812fx.install.in @@ -0,0 +1 @@ +usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_devicepluginws2812fx.so From bf3a199aee152fdfea3aedd7d6f04db861caf73d Mon Sep 17 00:00:00 2001 From: nymea Date: Fri, 26 Jul 2019 17:03:06 +0200 Subject: [PATCH 6/7] added README-md --- ws2812fx/README.md | 7 +++++++ ws2812fx/devicepluginws2812fx.cpp | 16 ++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 ws2812fx/README.md diff --git a/ws2812fx/README.md b/ws2812fx/README.md new file mode 100644 index 00000000..b516a2eb --- /dev/null +++ b/ws2812fx/README.md @@ -0,0 +1,7 @@ +# WS2812FX + +Plug-In for the WS2812FX project, a WS2812 effect library for Arduino and ESP8266. +Flash your microcontroller with the provided "serial_control" example. Connect the microcontroller +over USB to the nymea device. + +See also: https://github.com/kitesurfer1404/WS2812FX diff --git a/ws2812fx/devicepluginws2812fx.cpp b/ws2812fx/devicepluginws2812fx.cpp index 1989fd39..e40fd5c1 100644 --- a/ws2812fx/devicepluginws2812fx.cpp +++ b/ws2812fx/devicepluginws2812fx.cpp @@ -46,14 +46,6 @@ DevicePluginWs2812fx ::DevicePluginWs2812fx () Device::DeviceSetupStatus DevicePluginWs2812fx::setupDevice(Device *device) { - if(!m_reconnectTimer) { - m_reconnectTimer = new QTimer(this); - m_reconnectTimer->setSingleShot(true); - m_reconnectTimer->setInterval(5000); - - connect(m_reconnectTimer, &QTimer::timeout, this, &DevicePluginWs2812fx::onReconnectTimer); - } - if (device->deviceClassId() == ws2812fxDeviceClassId) { QString interface = device->paramValue(ws2812fxDeviceSerialPortParamTypeId).toString(); @@ -82,6 +74,14 @@ Device::DeviceSetupStatus DevicePluginWs2812fx::setupDevice(Device *device) device->setStateValue(ws2812fxConnectedStateTypeId, true); m_usedInterfaces.append(interface); m_serialPorts.insert(device, serialPort); + + if(!m_reconnectTimer) { + m_reconnectTimer = new QTimer(this); + m_reconnectTimer->setSingleShot(true); + m_reconnectTimer->setInterval(5000); + + connect(m_reconnectTimer, &QTimer::timeout, this, &DevicePluginWs2812fx::onReconnectTimer); + } } else { return Device::DeviceSetupStatusFailure; } From 7ef0edd0eceb44d53861b64bd9beb7dba38aad04 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sun, 28 Jul 2019 01:08:17 +0200 Subject: [PATCH 7/7] add .ts file --- .../translations/5a3c8ca5-4ef7-47a3-bf3f-c257b9f11ef0-en_US.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 ws2812fx/translations/5a3c8ca5-4ef7-47a3-bf3f-c257b9f11ef0-en_US.ts diff --git a/ws2812fx/translations/5a3c8ca5-4ef7-47a3-bf3f-c257b9f11ef0-en_US.ts b/ws2812fx/translations/5a3c8ca5-4ef7-47a3-bf3f-c257b9f11ef0-en_US.ts new file mode 100644 index 00000000..dcd02922 --- /dev/null +++ b/ws2812fx/translations/5a3c8ca5-4ef7-47a3-bf3f-c257b9f11ef0-en_US.ts @@ -0,0 +1 @@ + \ No newline at end of file