diff --git a/.azure.yml b/.azure.yml
index bb6f0c163..c0ae0d4fb 100644
--- a/.azure.yml
+++ b/.azure.yml
@@ -87,7 +87,6 @@ jobs:
python -m pip install aqtinstall
python -m aqt install -O c:\Qt 5.15.0 windows desktop win64_msvc2019_64
displayName: 'Install Qt 5.15.0'
-
# build process
- bash: ./.ci/ci_build.sh
env:
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index f0d5e0ae5..6bd2346eb 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -106,7 +106,7 @@
"type": "shell",
"command": "${workspaceFolder}/build/bin/hyperiond -d",
"windows": {
- "command": "${workspaceFolder}/build/bin/Debug/hyperiond -d -c"
+ "command": "${workspaceFolder}/build/bin/Debug/hyperiond"
},
"group": "build"
},
@@ -115,7 +115,7 @@
"type": "shell",
"command": "${workspaceFolder}/build/bin/hyperiond -d",
"windows": {
- "command": "${workspaceFolder}/build/bin/Release/hyperiond -d -c"
+ "command": "${workspaceFolder}/build/bin/Release/hyperiond"
},
"group": "build"
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 569a6a831..eb1b5fda5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,8 +13,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- An option to reset (delete) the database for the commandline has been added (#820)
- Improve language selection usability (#812)
- readded V4L2 Input method from old Hyperion (#825)
-- Windows: Start Hyperion with a console window `hyperiond -c` (Or new start menu entry) (#860)
-
### Changed
- Updated dependency rpi_ws281x to latest upstream (#820)
- Updated websocket-extensions (#826)
diff --git a/CompileHowto.md b/CompileHowto.md
index 04f3ecd89..8289e86af 100644
--- a/CompileHowto.md
+++ b/CompileHowto.md
@@ -40,7 +40,7 @@ wget -qN https://raw.github.com/hyperion-project/hyperion.ng/master/bin/scripts/
```
sudo apt-get update
-sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxcb-util0-dev libxcb-randr0-dev libxrandr-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libturbojpeg0-dev libqt5sql5-sqlite libssl-dev zlib1g-dev
+sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libturbojpeg0-dev libqt5sql5-sqlite libssl-dev zlib1g-dev
```
**on RPI you need the videocore IV headers**
@@ -82,7 +82,6 @@ We assume a 64bit Windows 7 or higher. Install the following
- Open a console window and execute `pip install aqtinstall`.
- Now we can download Qt to _C:\Qt_ `mkdir c:\Qt && aqt install -O c:\Qt 5.15.0 windows desktop win64_msvc2019_64`
- [CMake (Windows win64-x64 Installer)](https://cmake.org/download/) (Check: Add to PATH)
-- [Win64 OpenSSL v1.1.1g](https://slproweb.com/products/Win32OpenSSL.html) ([direct link](https://slproweb.com/download/Win64OpenSSL-1_1_1g.exe))
- [Visual Studio 2019 Build Tools](https://go.microsoft.com/fwlink/?linkid=840931) ([direct link](https://aka.ms/vs/16/release/vs_buildtools.exe))
- Select C++ Buildtools
- On the right, just select `MSVC v142 VS 2019 C++ x64/x86-Buildtools` and latest `Windows 10 SDK`. Everything else is not needed.
diff --git a/CrossCompileHowto.md b/CrossCompileHowto.md
index e17f13d6a..ac71d5746 100644
--- a/CrossCompileHowto.md
+++ b/CrossCompileHowto.md
@@ -4,14 +4,14 @@ Use a clean Raspbian Stretch Lite (on target) and Ubuntu 18/19 (on host) to exec
## On the Target system (here Raspberry Pi)
Install required additional packages.
```
-sudo apt-get install qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxcb-util0-dev libxcb-randr0-dev libxrandr-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libturbojpeg0-dev libqt5sql5-sqlite aptitude qt5-default rsync libssl-dev zlib1g-dev
+sudo apt-get install qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libturbojpeg0-dev libqt5sql5-sqlite aptitude qt5-default rsync libssl-dev zlib1g-dev
```
## On the Host system (here Ubuntu)
Update the Ubuntu environment to the latest stage and install required additional packages.
```
sudo apt-get update
sudo apt-get upgrade
-sudo apt-get -qq -y install git rsync cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxcb-util0-dev libxcb-randr0-dev libxrandr-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libturbojpeg0-dev libqt5sql5-sqlite libssl-dev zlib1g-dev
+sudo apt-get -qq -y install git rsync cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libjpeg-dev libturbojpeg0-dev libqt5sql5-sqlite libssl-dev zlib1g-dev
```
Refine the target IP or hostname, plus userID as required and set-up cross-compilation environment:
diff --git a/README.md b/README.md
index e5065dad6..8d2749e69 100644
--- a/README.md
+++ b/README.md
@@ -48,9 +48,6 @@ Covers these topics (WorkInProgress)
[![Visit Documentation](https://img.shields.io/website?down_message=offline&label=Documentation%20%20&up_message=online&url=https%3A%2F%2Fdocs.hyperion-project.org)](https://docs.hyperion-project.org)
-## Changelog
-Released and unreleased changes at [Changelog.md](CHANGELOG.md)
-
## Building
See [CompileHowto](CompileHowto.md) and [CrossCompileHowto](CrossCompileHowto.md).
diff --git a/assets/webconfig/i18n/cs.json b/assets/webconfig/i18n/cs.json
index 96c269e32..f5e776351 100644
--- a/assets/webconfig/i18n/cs.json
+++ b/assets/webconfig/i18n/cs.json
@@ -316,13 +316,13 @@
"wiz_hue_failure_connection": "Časový limit: Stiskněte tlačítko Bridge v průběhu 30 sekund",
"wiz_hue_failure_user": "Uživatel nebyl nalezen, vytvořte nový pomocí tlačítka níže nebo zadejte platné ID uživatele a stiskněte symbol „znovu načíst“.",
"wiz_hue_press_link": "Prosím stiskněte tlačítko odkazu na Hue Bridge.",
- "wiz_hue_ids_disabled": "Deaktivováno",
- "wiz_hue_ids_entire": "Celý obrázek",
"wiz_hue_noids": "Tento Hue Bridge nemá žárovky/lampy, předtím je spárujte s aplikací Hue Apps",
- "wiz_hue_pos": "Poloha",
"wiz_hue_searchb": "Hledání v Bridge ...",
"wiz_hue_blinkblue": "Nechte ID $1 svítit modře",
- "wiz_hue_ident": "Identifikovat",
+ "wiz_hue_disabled": "Deaktivováno",
+ "wiz_hue_entire": "Celý obrázek",
+ "wiz_pos": "Poloha",
+ "wiz_identify": "Identifikovat",
"wiz_cc_title": "Průvodce kalibrací barev",
"wiz_cc_intro1": "Tento průvodce vás provede kalibrací LED diod. Používáte-li Kodi, mohou být kalibrační obrázky a videa odesílány přímo na kodi bez dalších úkolů na vaší straně. Pokud tomu tak není, musíte tyto soubory sami stáhnout a použít je, pokud si to průvodce přeje.",
"wiz_cc_kwebs": "Kodi webový server (IP:Port)",
diff --git a/assets/webconfig/i18n/de.json b/assets/webconfig/i18n/de.json
index ee803ee27..f8f832d1f 100644
--- a/assets/webconfig/i18n/de.json
+++ b/assets/webconfig/i18n/de.json
@@ -355,9 +355,9 @@
"InfoDialog_iswitch_title": "Hyperion switcher",
"InfoDialog_iswitch_text": "Sollte in deinem lokalen Netzwerk Hyperion mehr als einmal laufen, kannst du hier zwischen den Web Konfigurationen hin und her schalten. Wähle dazu die Instanz unten aus und switche!",
"wiz_wizavail": "Assistent verfügbar",
- "wiz_guideyou": "Der $1 wird dich durch die Konfiguration leiten, drücke dazu einfach den Button!",
+ "wiz_guideyou": "Der $1 wird Dich durch die Konfiguration leiten, drücke dazu einfach den Button!",
"wiz_rgb_title": "RGB Byte Reihenfolge Assistent",
- "wiz_rgb_intro1": "Dieser Assisent wird dir dabei helfen die richtige Byte Reihenfolge für deine leds zu finden. Klicke auf Fortfahren um zu beginnen.",
+ "wiz_rgb_intro1": "Dieser Assisent wird Dir dabei helfen die richtige Byte Reihenfolge für deine leds zu finden. Klicke auf Fortfahren um zu beginnen.",
"wiz_rgb_intro2": "Wann benötigt man diesen Assistenten? Zur Erstkonfiguration oder wenn deine LEDs zb rot leuchten sollten, sie aber blau oder grün sind.",
"wiz_rgb_expl": "Der Farbpunkt ändert alle x Sekunden die Farbe (rot, grün), zur selben Zeit ändern deine LEDs die Farbe ebenfalls. Beantworte die Fragen unten, um deine RGB Byte Reihenfolge zu überprüfen/korrigieren.",
"wiz_rgb_switchevery": "Ändere Farbe alle...",
@@ -365,9 +365,9 @@
"wiz_rgb_qrend": "...rot ist?",
"wiz_rgb_qgend": "...grün ist?",
"wiz_hue_title": "Philips Hue Assistent",
- "wiz_hue_intro1": "Dieser Assistent hilft dir bei der Konfiguration von Hyperion für Philips Hue. Zu den Funktionen zählen ein automatisches finden der Hue Bridge, einen neuen Benutzer erstellen, die einzelnen Lampen unterschiedlichen Bereichen im Bild zuzuordnen und weitere Einstellungen von Hyperion automatisch anzupassen. Kurz gesagt: Komplette Einrichtung mit ein paar Klicks.",
+ "wiz_hue_intro1": "Dieser Assistent hilft Dir bei der Konfiguration von Hyperion für Philips Hue. Zu den Funktionen zählen ein automatisches finden der Hue Bridge, einen neuen Benutzer erstellen, die einzelnen Lampen unterschiedlichen Bereichen im Bild zuzuordnen und weitere Einstellungen von Hyperion automatisch anzupassen. Kurz gesagt: Komplette Einrichtung mit ein paar Klicks.",
"wiz_hue_desc1": "Es wird automatisch nach der Hue Bridge gesucht, solltest sie nicht gefunden werden, gebe die IP an und drücke den \"neu laden\" Button. Danach benötigst du eine gültige Benutzer ID, diese kann auch erstellt werden.",
- "wiz_hue_desc2": "Nun kannst du auswählen, welche der Lampen (IDs) hinzugefügt werden sollen. Mit der Position wählst du aus, wo die jeweilige Lampe \"im Bild\" sitzen soll. Deaktivierte Lampen werden nicht hinzugefügt. Als Hilfe zur Identifizierung kannst du sie mit einem Klick auf den rechten Button kurz aufleuchten lassen.",
+ "wiz_hue_desc2": "Nun kannst Du auswählen, welche der Lampen (IDs) hinzugefügt werden sollen. Mit der Position wählst Du aus, wo die jeweilige Lampe \"im Bild\" sitzen soll. Deaktivierte Lampen werden nicht hinzugefügt. Als Hilfe zur Identifizierung kannst Du sie mit einem Klick auf den rechten Button kurz aufleuchten lassen.",
"wiz_hue_ip": "Hue Bridge IP:",
"wiz_hue_username": "Benutzer ID:",
"wiz_hue_clientkey": "Clientkey:",
@@ -376,13 +376,9 @@
"wiz_hue_failure_connection": "Zeitüberschreitung. Bitte drücke die Taste auf deiner Hue Bridge rechtzeitig",
"wiz_hue_failure_user": "Benutzer ID wurde nicht gefunden, erstelle eine neue, indem du auf den nachfolgenden Button klickst, oder gib eine bereits registrierte an und klicke dann auf das \"neu laden\" Symbol.",
"wiz_hue_press_link": "Bitte \"Link\" Taste auf der Hue Bridge drücken.",
- "wiz_hue_ids_disabled": "Deaktiviert",
- "wiz_hue_ids_entire": "Ganzes Bild",
"wiz_hue_noids": "Diese Hue Bridge hat keine verbundenen Lampen, bitte verbinde diese zuerst mit deiner Hue Bridge (Nutze die Hue Apps dafür)",
- "wiz_hue_pos": "Position/Status",
"wiz_hue_searchb": "Suche nach Hue Bridge...",
"wiz_hue_blinkblue": "Lasse ID $1 blau aufleuchten",
- "wiz_hue_ident": "Identifiziere",
"wiz_hue_e_create_user": "Neuen Benutzer und Clientkey erstellen",
"wiz_hue_e_clientkey_needed": "Für die Verwendung der Entertainment API, ist ein zum Usernamen passender Clientkey erforderlich. Bitte einen vorhandenen eingeben oder über die Schaltflächen unten einen neuen erstellen.",
"wiz_hue_e_use_groupid": "Gruppen ID $1 verwenden",
@@ -396,6 +392,16 @@
"wiz_hue_e_desc2": "Nun kannst du die Entertainment Gruppe auswählen, welche die Lampen zur Verwendung mit Hyperion beinhaltet.",
"wiz_hue_e_desc3": "Nun kannst du auswählen, mit welcher Position die jeweilige Lampe \"im Bild\" sitzen soll. Eine Vorauswahl der Position, wurde Anhand der konfigurierten Positionen der Lampen in der Entertainment Gruppe gewählt. Dies ist nur eine Empfehlung und kann beliebig angepasst werden. Als Hilfe zur Identifizierung kannst du sie mit einem Klick auf den rechten Button kurz aufleuchten lassen und die Auswahl zu verbessern.",
"wiz_hue_e_use_group": "Gruppe verwenden",
+ "wiz_yeelight_title": "Yeelight Assistent",
+ "wiz_yeelight_intro1": "Dieser Assistent hilft Dir bei der Konfiguration von Hyperion für Yeelight. Zu den Funktionen zählen ein automatisches finden der Yeelights, die einzelnen Lampen unterschiedlichen Bereichen im Bild zuzuordnen und weitere Einstellungen von Hyperion automatisch anzupassen. Kurz gesagt: Komplette Einrichtung mit ein paar Klicks.",
+ "wiz_yeelight_desc2": "Nun kannst Du auswählen, welche der Lampen hinzugefügt werden sollen. Mit der Position wählst Du aus, wo die jeweilige Lampe \"im Bild\" sitzen soll. Deaktivierte Lampen werden nicht hinzugefügt. Als Hilfe zur Identifizierung kannst Du sie mit einem Klick auf den rechten Button kurz aufleuchten lassen.",
+ "wiz_yeelight_noLights": "Es wurden keine Yeelights gefunden! Bitte verbinde die Yeelights mit dem Netzwerk oder konfiguriere sie manuell.",
+ "wiz_yeelight_unsupported" : "Nicht Unterstützt",
+ "wiz_ids_disabled": "Deaktiviert",
+ "wiz_ids_entire": "Ganzes Bild",
+ "wiz_pos": "Position/Status",
+ "wiz_identify" : "Identifiziere",
+ "wiz_identify_light": "Identifiziere $1",
"wiz_cc_title": "Farbkalibrierungs Assistent",
"wiz_cc_intro1": "Der Assistent wird dich durch die Kalibrierung deiner LEDs leiten. Sofern du Kodi nutzt, können die Bilder und Testvideos direkt an Kodi geschickt werden. Andernfalls musst du das Material selbst herunterladen und anwenden.",
"wiz_cc_kwebs": "Kodi Webserver (IP:Port)",
@@ -438,7 +444,8 @@
"edt_dev_spec_orbIds_title": "Orb ID(s)",
"edt_dev_spec_useOrbSmoothing_title": "Nutze Orb Glättung",
"edt_dev_spec_targetIp_title": "Ziel IP",
- "edt_dev_spec_targetIpHost_title": "Ziel IP/hostname",
+ "edt_dev_spec_targetIpHost_title": "Ziel IP/Rechnername",
+ "edt_dev_spec_networkDeviceName_title" : "Gerätename im Netzwerk",
"edt_dev_spec_outputPath_title": "Ausgabepfad",
"edt_dev_spec_delayAfterConnect_title": "Verzögerung nach Verbindung",
"edt_dev_spec_FCsetConfig_title": "Wende fadecandy Konfiguration an",
@@ -451,20 +458,33 @@
"edt_dev_spec_username_title": "Benutzername",
"edt_dev_spec_lightid_title": "Lampen ID(s)",
"edt_dev_spec_lightid_itemtitle": "ID",
+ "edt_dev_spec_lights_title" : "Lampe(n)",
+ "edt_dev_spec_lights_itemtitle" : "Lampe",
+ "edt_dev_spec_lights_name" : "Name",
"edt_dev_spec_transistionTime_title": "Übergangszeit",
"edt_dev_spec_blackLightsTimeout_title": "Signal Erkennung Timeout bei schwarz",
+ "edt_dev_spec_transistionTimeExtra_title" : "Extra Übergangszeit bei Schwarz",
+ "edt_dev_spec_transeffect_title" : "Übergangseffekt",
+ "edt_conf_enum_transeffect_smooth" : "Gleichmäßig",
+ "edt_conf_enum_transeffect_sudden" : "Sofort",
+ "edt_dev_spec_debugLevel_title" : "Debug Stufe",
+ "edt_conf_enum_dl_nodebug" : "Keine Debugausgabe",
+ "edt_conf_enum_dl_verbose1" : "Stufe 1",
+ "edt_conf_enum_dl_verbose2" : "Stufe 2",
+ "edt_conf_enum_dl_verbose3" : "Stufe 3",
"edt_dev_spec_brightnessThreshold_title": "Signal Erkennung Helligkeitsminimum",
"edt_dev_spec_switchOffOnBlack_title": "Aus bei schwarz",
+ "edt_dev_spec_switchOffOnbelowMinBrightness_title" : "Aus bei Minimum",
"edt_dev_spec_brightnessFactor_title": "Helligkeitsfaktor",
- "edt_dev_spec_brightnessMin_title": "Helligkeit minimum",
- "edt_dev_spec_brightnessMax_title": "Helligkeit maximum",
+ "edt_dev_spec_brightnessMin_title": "Helligkeitsminimum",
+ "edt_dev_spec_brightnessMax_title": "Helligkeitsmaximum",
"edt_dev_spec_sslReadTimeout_title" : "Streamer lese Timeout",
"edt_dev_spec_sslHSTimeoutMin_title" : "Streamer Handshake minimum Timeout",
"edt_dev_spec_sslHSTimeoutMax_title" : "Streamer Handshake maximum Timeout",
"edt_dev_spec_verbose_title": "Logge alle Hue Commandos",
"edt_dev_spec_debugStreamer_title": "Streamer Debugging",
"edt_dev_spec_debugLevel_title": "Streamer Verbindung Debug Stufe",
- "edt_dev_spec_restoreOriginalState_title" : "Lampen Originalzustand wiederherstellen",
+ "edt_dev_spec_restoreOriginalState_title" : "Bei Deaktivierung, Lampen Originalzustand wiederherstellen",
"edt_dev_spec_useEntertainmentAPI_title": "Hue Entertainment API verwenden",
"edt_dev_spec_ledType_title": "LED typ",
"edt_dev_spec_uid_title": "UID",
@@ -511,6 +531,7 @@
"edt_conf_enum_brg": "BRG",
"edt_conf_enum_gbr": "GBR",
"edt_conf_enum_grb": "GRB",
+ "edt_conf_enum_hsv" : "HSV",
"edt_conf_enum_linear": "Linear",
"edt_conf_enum_PAL": "PAL",
"edt_conf_enum_NTSC": "NTSC",
diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json
index 018279d1e..e34c61dad 100644
--- a/assets/webconfig/i18n/en.json
+++ b/assets/webconfig/i18n/en.json
@@ -376,13 +376,9 @@
"wiz_hue_failure_connection" : "Timeout: Please press the bridge button within the period of 30 seconds",
"wiz_hue_failure_user" : "User not found, create a new one with the button below or input a valid user id and press the \"reload\" symbol.",
"wiz_hue_press_link" : "Please press link button on the Hue Bridge.",
- "wiz_hue_ids_disabled" : "Deactivated",
- "wiz_hue_ids_entire" : "Whole picture",
"wiz_hue_noids" : "This Hue bridge has no bulbs/stripes, please pair them before with the Hue Apps",
- "wiz_hue_pos": "Position/State",
"wiz_hue_searchb": "Searching for bridge...",
"wiz_hue_blinkblue": "Let ID $1 light up blue",
- "wiz_hue_ident" : "Identify",
"wiz_hue_e_create_user" : "Create new User and clientkey",
"wiz_hue_e_clientkey_needed": "A clientkey that matches the username is required to use the entertainment API. Please enter an existing one or use the button below to create a new one.",
"wiz_hue_e_use_groupid": "Use group ID $1",
@@ -396,6 +392,16 @@
"wiz_hue_e_desc2" : "Now choose your entertainment group, which has all your lights inside for use with Hyperion.",
"wiz_hue_e_desc3": "Now you can choose in which position the respective lamp should be \"in the picture\". A preselection of the position was made based on the configured positions of the lights in the entertainment group. This is just a recommendation and can be customized as desired. You can therefore highlight them briefly by clicking on the right button to improve the selection.",
"wiz_hue_e_use_group" : "Use group",
+ "wiz_yeelight_title" : "Yeelight Wizard",
+ "wiz_yeelight_intro1" : "This wizards configures Hyperion for the Yeelight system. Features are the Yeelighs' auto detection, setting each light to a specific position on your picture or disable it and tune the Hyperion settings automatically! So in short: All you need are some clicks and you are done!",
+ "wiz_yeelight_desc2" : "Now choose which lamps should be added. The position assigns the lamp to a specific position on your \"picture\". Disabled lamps won't be added. To identify single lamps press the button on the right.",
+ "wiz_yeelight_noLights": "No Yeelights found! Please get the lights connected to the network or configure them mannually.",
+ "wiz_yeelight_unsupported" : "Unsupported",
+ "wiz_pos": "Position/State",
+ "wiz_ids_disabled" : "Deactivated",
+ "wiz_ids_entire" : "Whole picture",
+ "wiz_identify" : "Identify",
+ "wiz_identify_light": "Identify $1",
"wiz_cc_title" : "Colour calibration wizard",
"wiz_cc_intro1" : "This wizard will guide you through your led calibration. If you are using Kodi, the calibration pictures and videos can be sent directly to it without further actions on your side. If not, you will need to download these files yourself and display them when the wizard needs you to adjust the setting.",
"wiz_cc_kwebs" : "Kodi webserver (IP:Port)",
@@ -438,7 +444,9 @@
"edt_dev_spec_orbIds_title" : "Orb ID(s)",
"edt_dev_spec_useOrbSmoothing_title" : "Use orb smoothing",
"edt_dev_spec_targetIp_title" : "Target IP",
- "edt_dev_spec_targetIpHost_title" : "Target IP/hostname",
+ "edt_dev_spec_targetIpHost_title" : "Target IP/Hostname",
+ "edt_dev_spec_networkDeviceName_title" : "Network devicename",
+ "edt_dev_spec_networkDevicePort_title" : "Port",
"edt_dev_spec_outputPath_title" : "Output path",
"edt_dev_spec_delayAfterConnect_title" : "Delay after connect",
"edt_dev_spec_FCsetConfig_title" : "Set fadecandy configuration",
@@ -451,10 +459,23 @@
"edt_dev_spec_username_title" : "Username",
"edt_dev_spec_lightid_title" : "Light ID(s)",
"edt_dev_spec_lightid_itemtitle" : "ID",
+ "edt_dev_spec_lights_title" : "Light(s)",
+ "edt_dev_spec_lights_itemtitle" : "Light",
+ "edt_dev_spec_lights_name" : "Name",
"edt_dev_spec_transistionTime_title" : "Transition time",
"edt_dev_spec_blackLightsTimeout_title": "Signal detection timeout on black",
+ "edt_dev_spec_transistionTimeExtra_title" : "Extra time darkness",
+ "edt_dev_spec_transeffect_title" : "Transition effect",
+ "edt_conf_enum_transeffect_smooth" : "Smooth",
+ "edt_conf_enum_transeffect_sudden" : "Sudden",
+ "edt_dev_spec_debugLevel_title" : "Debug level",
+ "edt_conf_enum_dl_nodebug" : "No Debug output",
+ "edt_conf_enum_dl_verbose1" : "Verbosity level 1",
+ "edt_conf_enum_dl_verbose2" : "Verbosity level 2",
+ "edt_conf_enum_dl_verbose3" : "Verbosity level 3",
"edt_dev_spec_brightnessThreshold_title": "Signal detection brightness minimum",
"edt_dev_spec_switchOffOnBlack_title" : "Switch off on black",
+ "edt_dev_spec_switchOffOnbelowMinBrightness_title" : "Switch-off, below minimum",
"edt_dev_spec_brightnessFactor_title" : "Brightness factor",
"edt_dev_spec_brightnessMin_title": "Brightness minimum",
"edt_dev_spec_brightnessMax_title": "Brightness maximum",
@@ -464,7 +485,7 @@
"edt_dev_spec_verbose_title": "Log all Hue commands",
"edt_dev_spec_debugStreamer_title": "Streamer Debug",
"edt_dev_spec_debugLevel_title": "Streamer Connection Debug Level",
- "edt_dev_spec_restoreOriginalState_title" : "Restore lights' original state",
+ "edt_dev_spec_restoreOriginalState_title" : "Restore lights' original state when disabled",
"edt_dev_spec_useEntertainmentAPI_title": "Use Hue Entertainment API",
"edt_dev_spec_ledType_title" : "LED Type",
"edt_dev_spec_uid_title" : "UID",
@@ -512,6 +533,7 @@
"edt_conf_enum_brg" : "BRG",
"edt_conf_enum_gbr" : "GBR",
"edt_conf_enum_grb" : "GRB",
+ "edt_conf_enum_hsv" : "HSV",
"edt_conf_enum_linear" : "Linear",
"edt_conf_enum_PAL" : "PAL",
"edt_conf_enum_NTSC" : "NTSC",
diff --git a/assets/webconfig/i18n/es.json b/assets/webconfig/i18n/es.json
index cf9475b5f..e463d8048 100644
--- a/assets/webconfig/i18n/es.json
+++ b/assets/webconfig/i18n/es.json
@@ -316,13 +316,14 @@
"wiz_hue_failure_connection": "El tiempo de conexión expiró. Por favor, pulsa el botón a tiempo.",
"wiz_hue_failure_user": "Usuario no encontrado, crea uno nuevo debajo o introduce un ID de usuario válido",
"wiz_hue_press_link": "Por favor, presione el botón de enlace en el Puente de Matiz.",
- "wiz_hue_ids_disabled": "Desactivado",
- "wiz_hue_ids_entire": "Imagen completa",
"wiz_hue_noids": "Este puente de Matiz no tiene bombillas/tiras, por favor, emparéjalos antes con las aplicaciones de Hue",
- "wiz_hue_pos": "Posición/Estado",
"wiz_hue_searchb": "Buscando el puente...",
"wiz_hue_blinkblue": "Permite a ID $1 encender el azul",
"wiz_hue_ident": "Identificar",
+ "wiz_ids_disabled": "Desactivado",
+ "wiz_ids_entire": "Imagen completa",
+ "wiz_pos": "Posición/Estado",
+ "wiz_identify": "Identificar",
"wiz_cc_title": "Asistente de calibración de color",
"wiz_cc_intro1": "Este asistente te guiará a través de la calibración led. Si estás utilizando Kodi, las imágenes de calibración y los videos se pueden enviar directamente a kodi sin más tareas de tu lado. Si no, necesitas descargar estos archivos tú mismo y aplicarlos, si el asistente lo desea.",
"wiz_cc_kwebs": "Servidor web Kodi (IP:PUERTO)",
diff --git a/assets/webconfig/i18n/it.json b/assets/webconfig/i18n/it.json
index 70275db2e..c9ee39c8c 100644
--- a/assets/webconfig/i18n/it.json
+++ b/assets/webconfig/i18n/it.json
@@ -316,13 +316,13 @@
"wiz_hue_failure_connection": "Timeout: premi il bottone del bridge entro il periodo di 30 secondi",
"wiz_hue_failure_user": "Utente non trovato, creane uno nuovo qui sotto o inserisci un id utente valido e premi il simbolo di \"ricarica\".",
"wiz_hue_press_link": "Premi il bottone di collegamento sull'Hue Bridge.",
- "wiz_hue_ids_disabled": "Disattiva",
- "wiz_hue_ids_entire": "Immagine intera",
"wiz_hue_noids": "questo Hue bridge non ha lampadine/strisce, prima associale con l'Hue App",
- "wiz_hue_pos": "Posizione/Stato",
"wiz_hue_searchb": "Cercando il bridge...",
"wiz_hue_blinkblue": "ID $1 si illumina di blu",
- "wiz_hue_ident": "Identifica",
+ "wiz_ids_disabled": "Disattiva",
+ "wiz_ids_entire": "Immagine intera",
+ "wiz_pos": "Posizione/Stato",
+ "wiz_identify" : "Identifica",
"wiz_cc_title": "Assistente calibrazione colore",
"wiz_cc_intro1": "Questo assistente ti guiderà attraverso la calibrazione dei tuoi led. Se stai usando Kodi, le immagini e i video di calibrazione possono essere mandati direttamente a Kodi senza altro lavoro da parte tua. Altrimenti devi scaricare questi file e applicarli tu stesso quando l'assistente necessita di regolare le impostazioni.",
"wiz_cc_kwebs": "Webserver Kodi (IP:Porta)",
diff --git a/assets/webconfig/i18n/sv.json b/assets/webconfig/i18n/sv.json
index 5aa03e29e..ba75868ab 100644
--- a/assets/webconfig/i18n/sv.json
+++ b/assets/webconfig/i18n/sv.json
@@ -316,13 +316,13 @@
"wiz_hue_failure_connection": "Timeout: Tryck på bryggknappen inom 30 sekunder",
"wiz_hue_failure_user": "Användaren hittades inte, skapa en ny med knappen nedan eller mata in ett giltigt användar-ID och tryck på \"ladda om\"",
"wiz_hue_press_link": "Tryck på länkknappen på HUE-bryggan.",
- "wiz_hue_ids_disabled": "Inaktiverad",
- "wiz_hue_ids_entire": "Hela bilden",
"wiz_hue_noids": "Denna Hue-brygga har inga LED-lampor/-tejp, vänligen koppla ihop dem med HUE-appen innan",
- "wiz_hue_pos": "Position/Läge",
"wiz_hue_searchb": "Letar efter brygga...",
"wiz_hue_blinkblue": "Låt ID $1 lysa blått",
- "wiz_hue_ident": "Identifiera",
+ "wiz_ids_disabled": "Inaktiverad",
+ "wiz_ids_entire": "Hela bilden",
+ "wiz_pos": "Position/Läge",
+ "wiz_identify": "Identifiera",
"wiz_cc_title": "Färgkalibreringsguiden",
"wiz_cc_intro1": "Den här guiden leder dig igenom din LED-kalibrering. Om du använder Kodi kan kalibreringsbilder och videoklipp skickas direkt utan ytterligare åtgärder från din sida. Om inte, måste du ladda ner dessa filer själv och visa dem när guiden vill justera inställningen.",
"wiz_cc_kwebs": "Kodi webbserver (IP:Port)",
diff --git a/assets/webconfig/js/content_leds.js b/assets/webconfig/js/content_leds.js
old mode 100755
new mode 100644
index 5d3109140..5db3676f9
--- a/assets/webconfig/js/content_leds.js
+++ b/assets/webconfig/js/content_leds.js
@@ -489,7 +489,7 @@ $(document).ready(function() {
$("#leddevices").off().on("change", function() {
var generalOptions = window.serverSchema.properties.device;
- // Modified schema entry "hardwareLedCount" in generalOptions to minimum LedCount
+ // Modified schema entry "hardwareLedCount" in generalOptions to minimum LedCount
var ledType = $(this).val();
//philipshueentertainment backward fix
@@ -535,6 +535,20 @@ $(document).ready(function() {
});
$("#root_specificOptions_useEntertainmentAPI").trigger("change");
}
+/*
+ else if(ledType == "wled") {
+ var ledWizardType = (this.checked) ? "wled" : ledType;
+ var data = { type: ledWizardType };
+ var wled_title = 'wiz_wled_title';
+ changeWizard(data, wled_title, startWizardWLED);
+ }
+*/
+ else if(ledType == "yeelight") {
+ var ledWizardType = (this.checked) ? "yeelight" : ledType;
+ var data = { type: ledWizardType };
+ var yeelight_title = 'wiz_yeelight_title';
+ changeWizard(data, yeelight_title, startWizardYeelight);
+ }
function changeWizard(data, hint, fn) {
$('#btn_wiz_holder').html("")
@@ -551,7 +565,7 @@ $(document).ready(function() {
var devRPiSPI = ['apa102', 'apa104', 'ws2801', 'lpd6803', 'lpd8806', 'p9813', 'sk6812spi', 'sk6822spi', 'ws2812spi'];
var devRPiPWM = ['ws281x'];
var devRPiGPIO = ['piblaster'];
- var devNET = ['atmoorb', 'fadecandy', 'philipshue', 'nanoleaf', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udph801', 'udpraw'];
+ var devNET = ['atmoorb', 'fadecandy', 'philipshue', 'nanoleaf', 'tinkerforge', 'tpm2net', 'udpe131', 'udpartnet', 'udph801', 'udpraw', 'wled', 'yeelight'];
var devUSB = ['adalight', 'dmx', 'atmo', 'hyperionusbasp', 'lightpack', 'multilightpack', 'paintpack', 'rawhid', 'sedu', 'tpm2', 'karate'];
var optArr = [[]];
diff --git a/assets/webconfig/js/hyperion.js b/assets/webconfig/js/hyperion.js
index 79c6fc548..94cab0096 100644
--- a/assets/webconfig/js/hyperion.js
+++ b/assets/webconfig/js/hyperion.js
@@ -118,15 +118,19 @@ function initWebSocket()
var response = JSON.parse(event.data);
var success = response.success;
var cmd = response.command;
+ var tan = response.tan
if (success || typeof(success) == "undefined")
{
$(window.hyperion).trigger({type:"cmd-"+cmd, response:response});
}
else
{
- var error = response.hasOwnProperty("error")? response.error : "unknown";
- $(window.hyperion).trigger({type:"error",reason:error});
- console.log("[window.websocket::onmessage] ",error)
+ // skip tan -1 error handling
+ if(tan != -1){
+ var error = response.hasOwnProperty("error")? response.error : "unknown";
+ $(window.hyperion).trigger({type:"error",reason:error});
+ console.log("[window.websocket::onmessage] ",error)
+ }
}
}
catch(exception_error)
@@ -165,6 +169,53 @@ function sendToHyperion(command, subcommand, msg)
window.websocket.send('{"command":"'+command+'", "tan":'+window.wsTan+subcommand+msg+'}');
}
+// Send a json message to Hyperion and wait for a matching response
+// A response matches, when command(+subcommand) of request and response is the same
+// command: The string command
+// subcommand: The optional string subcommand
+// data: The json data as Object
+// tan: The optional tan, default 1. If the tan is -1, we skip global response error handling
+// Returns data of response or false if timeout
+async function sendAsyncToHyperion (command, subcommand, data, tan = 1) {
+ let obj = { command, tan }
+ if (subcommand) {Object.assign(obj, {subcommand})}
+ if (data) { Object.assign(obj, data) }
+
+ //if (process.env.DEV || sstore.getters['common/getDebugState']) console.log('SENDAS', obj)
+ return __sendAsync(obj)
+}
+
+// Send a json message to Hyperion and wait for a matching response
+// A response matches, when command(+subcommand) of request and response is the same
+// Returns data of response or false if timeout
+async function __sendAsync (data) {
+ return new Promise((resolve, reject) => {
+ let cmd = data.command
+ let subc = data.subcommand
+ let tan = data.tan;
+ if (subc)
+ cmd = `${cmd}-${subc}`
+
+ let func = (e) => {
+ let rdata;
+ try {
+ rdata = JSON.parse(e.data)
+ } catch (error) {
+ console.error("[window.websocket::onmessage] ",error)
+ resolve(false)
+ }
+ if (rdata.command == cmd && rdata.tan == tan) {
+ window.websocket.removeEventListener('message', func)
+ resolve(rdata)
+ }
+ }
+ // after 7 sec we resolve false
+ setTimeout(() => { window.websocket.removeEventListener('message', func); resolve(false) }, 7000)
+ window.websocket.addEventListener('message', func)
+ window.websocket.send(JSON.stringify(data) + '\n')
+ })
+}
+
// -----------------------------------------------------------
// wrapped server commands
@@ -396,3 +447,25 @@ function requestAdjustment(type, value, complete)
else
sendToHyperion("adjustment", "", '"adjustment": {"'+type+'": '+value+'}');
}
+
+async function requestLedDeviceDiscovery(type)
+{
+ let data = { ledDeviceType: type };
+
+ return sendAsyncToHyperion("leddevice", "discover", data, Math.floor(Math.random() * 1000) );
+}
+
+async function requestLedDeviceProperties(type, params)
+{
+ let data = { ledDeviceType: type, params: params };
+
+ return sendAsyncToHyperion("leddevice", "getProperties", data, Math.floor(Math.random() * 1000));
+}
+
+function requestLedDeviceIdentification(type, params)
+{
+ sendToHyperion("leddevice", "identify", '"ledDeviceType": "'+type+'","params": '+JSON.stringify(params)+'');
+
+ //let data = {ledDeviceType: type, params: params};
+ //sendToHyperion("leddevice", "identify", data );
+}
diff --git a/assets/webconfig/js/wizard.js b/assets/webconfig/js/wizard.js
index b019b5811..f7a6f33ac 100644
--- a/assets/webconfig/js/wizard.js
+++ b/assets/webconfig/js/wizard.js
@@ -514,7 +514,66 @@ function beginWizardCC()
$('#btn_wizard_colorcalibration').off().on('click', startWizardCC);
-//hue wizard
+// Layout positions
+var lightPosTop = {hmin: 0.15, hmax: 0.85, vmin: 0 , vmax: 0.2 };
+var lightPosTopLeft = {hmin: 0 , hmax: 0.15, vmin: 0 , vmax: 0.15};
+var lightPosTopRight = {hmin: 0.85, hmax: 1.0 , vmin: 0 , vmax: 0.15};
+var lightPosBottom = {hmin: 0.15, hmax: 0.85, vmin: 0.8 , vmax: 1.0 };
+var lightPosBottomLeft = {hmin: 0 , hmax: 0.15, vmin: 0.85, vmax: 1.0 };
+var lightPosBottomRight = {hmin: 0.85, hmax: 1.0 , vmin: 0.85, vmax: 1.0 };
+var lightPosLeft = {hmin: 0 , hmax: 0.15, vmin: 0.15, vmax: 0.85};
+var lightPosLeftTop = {hmin: 0 , hmax: 0.15, vmin: 0 , vmax: 0.5 };
+var lightPosLeftMiddle = {hmin: 0 , hmax: 0.15, vmin: 0.25, vmax: 0.75};
+var lightPosLeftBottom = {hmin: 0 , hmax: 0.15, vmin: 0.5 , vmax: 1.0 };
+var lightPosRight = {hmin: 0.85, hmax: 1.0 , vmin: 0.15, vmax: 0.85};
+var lightPosRightTop = {hmin: 0.85, hmax: 1.0 , vmin: 0 , vmax: 0.5 };
+var lightPosRightMiddle = {hmin: 0.85, hmax: 1.0 , vmin: 0.25, vmax: 0.75};
+var lightPosRightBottom = {hmin: 0.85, hmax: 1.0 , vmin: 0.5 , vmax: 1.0 };
+var lightPosEntire = {hmin: 0.0 , hmax: 1.0 , vmin: 0.0 , vmax: 1.0 };
+
+function assignLightPos(id, pos, name)
+{
+ var i = null;
+
+ if(pos === "top")
+ i = lightPosTop;
+ else if(pos === "topleft")
+ i = lightPosTopLeft;
+ else if(pos === "topright")
+ i = lightPosTopRight;
+ else if(pos === "bottom")
+ i = lightPosBottom;
+ else if(pos === "bottomleft")
+ i = lightPosBottomLeft;
+ else if(pos === "bottomright")
+ i = lightPosBottomRight;
+ else if(pos === "left")
+ i = lightPosLeft;
+ else if(pos === "lefttop")
+ i = lightPosLeftTop;
+ else if(pos === "leftmiddle")
+ i = lightPosLeftMiddle;
+ else if(pos === "leftbottom")
+ i = lightPosLeftBottom;
+ else if(pos === "right")
+ i = lightPosRight;
+ else if(pos === "righttop")
+ i = lightPosRightTop;
+ else if(pos === "rightmiddle")
+ i = lightPosRightMiddle;
+ else if(pos === "rightbottom")
+ i = lightPosRightBottom;
+ else
+ i = lightPosEntire;
+
+ i.name = name;
+ return i;
+}
+
+//****************************
+// Wizard Philips Hue
+//****************************
+
var hueIPs = [];
var hueIPsinc = 0;
var lightIDs = null;
@@ -522,22 +581,6 @@ var groupIDs = null;
var lightLocation = [];
var groupLights = [];
var groupLightsLocations = [];
-
-var huePosTop = {hmin: 0.15, hmax: 0.85, vmin: 0 , vmax: 0.2 };
-var huePosTopLeft = {hmin: 0 , hmax: 0.15, vmin: 0 , vmax: 0.15};
-var huePosTopRight = {hmin: 0.85, hmax: 1.0 , vmin: 0 , vmax: 0.15};
-var huePosBottom = {hmin: 0.15, hmax: 0.85, vmin: 0.8 , vmax: 1.0 };
-var huePosBottomLeft = {hmin: 0 , hmax: 0.15, vmin: 0.85, vmax: 1.0 };
-var huePosBottomRight = {hmin: 0.85, hmax: 1.0 , vmin: 0.85, vmax: 1.0 };
-var huePosLeft = {hmin: 0 , hmax: 0.15, vmin: 0.15, vmax: 0.85};
-var huePosLeftTop = {hmin: 0 , hmax: 0.15, vmin: 0 , vmax: 0.5 };
-var huePosLeftMiddle = {hmin: 0 , hmax: 0.15, vmin: 0.25, vmax: 0.75};
-var huePosLeftBottom = {hmin: 0 , hmax: 0.15, vmin: 0.5 , vmax: 1.0 };
-var huePosRight = {hmin: 0.85, hmax: 1.0 , vmin: 0.15, vmax: 0.85};
-var huePosRightTop = {hmin: 0.85, hmax: 1.0 , vmin: 0 , vmax: 0.5 };
-var huePosRightMiddle = {hmin: 0.85, hmax: 1.0 , vmin: 0.25, vmax: 0.75};
-var huePosRightBottom = {hmin: 0.85, hmax: 1.0 , vmin: 0.5 , vmax: 1.0 };
-var huePosEntire = {hmin: 0.0 , hmax: 1.0 , vmin: 0.0 , vmax: 1.0 };
var hueType = "philipshue";
function startWizardPhilipsHue(e)
@@ -585,7 +628,7 @@ function startWizardPhilipsHue(e)
$('#wizp2_body').append('
'+$.i18n('wiz_hue_desc2')+'
');
}
createTable("lidsh", "lidsb", "hue_ids_t");
- $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lightid_title'),$.i18n('wiz_hue_pos'),$.i18n('wiz_hue_ident')], true));
+ $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lightid_title'),$.i18n('wiz_pos'),$.i18n('wiz_identify')], true));
$('#wizp2_footer').html(' '+$.i18n('general_btn_save')+' '+$.i18n('general_btn_cancel')+' ');
$('#wizp3_body').html(''+$.i18n('wiz_hue_press_link')+' ');
@@ -684,45 +727,6 @@ function checkUserResult(reply, usr) {
}
};
-function assignHuePos(id, pos)
-{
- var i = null;
-
- if(pos == "top")
- i = huePosTop;
- else if(pos == "topleft")
- i = huePosTopLeft;
- else if(pos == "topright")
- i = huePosTopRight;
- else if(pos == "bottom")
- i = huePosBottom;
- else if(pos == "bottomleft")
- i = huePosBottomLeft;
- else if(pos == "bottomright")
- i = huePosBottomRight;
- else if(pos == "left")
- i = huePosLeft;
- else if(pos == "lefttop")
- i = huePosLeftTop;
- else if(pos == "leftmiddle")
- i = huePosLeftMiddle;
- else if(pos == "leftbottom")
- i = huePosLeftBottom;
- else if(pos == "right")
- i = huePosRight;
- else if(pos == "righttop")
- i = huePosRightTop;
- else if(pos == "rightmiddle")
- i = huePosRightMiddle;
- else if(pos == "rightbottom")
- i = huePosRightBottom;
- else
- i = huePosEntire;
-
- i.name = lightIDs[id].name;
- return i;
-}
-
function identHueId(id, off, oState)
{
if(off !== true)
@@ -751,6 +755,72 @@ function useGroupId(id)
get_hue_lights();
}
+async function discover_hue_bridges(){
+
+ const res = await requestLedDeviceDiscovery ('philipshue');
+
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+ const r = res.info
+
+ // Process devices returned by discovery
+ console.log(r);
+
+ if(r.devices.length == 0)
+ $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
+ else
+ {
+ for(const device of r.devices)
+ {
+ console.log("Device:", device);
+
+ var ip = device.hostname + ":" + device.port;
+ console.log("Host:", ip);
+
+ hueIPs.push({internalipaddress : ip});
+ }
+ var usr = $('#user').val();
+ if(usr != "") {
+ checkHueBridge(checkUserResult, usr);
+ } else {
+ checkHueBridge(checkBridgeResult);
+ }
+ }
+ }
+}
+
+async function getProperties_hue_bridge(hostAddress, username, resourceFilter){
+
+ let params = { host: hostAddress, user: username, filter: resourceFilter};
+
+ const res = await requestLedDeviceProperties ('philipshue', params);
+
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+ const r = res.info
+
+ // Process properties returned
+ console.log(r);
+ }
+}
+
+function identify_hue_device(hostAddress, username, id){
+
+ console.log("identify_hue_device");
+
+ let params = { host: hostAddress, user: username, lightId: id };
+
+ const res = requestLedDeviceIdentification ("philipshue", params);
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+ const r = res.info
+ console.log(r);
+ }
+}
+
function getHueIPs(){
$('#wiz_hue_ipstate').html($.i18n('wiz_hue_searchb'));
$.ajax({
@@ -795,7 +865,8 @@ function beginWizardHue()
//check if ip is empty/reachable/search for bridge
if(eV("output") == "")
{
- getHueIPs();
+ //getHueIPs();
+ discover_hue_bridges();
}
else
{
@@ -810,8 +881,13 @@ function beginWizardHue()
}
$('#retry_bridge').off().on('click', function(){
- if($('#ip').val()!="") hueIPs.unshift({internalipaddress : $('#ip').val()});
- hueIPsinc = 0;
+ if($('#ip').val()!="")
+ {
+ hueIPs.unshift({internalipaddress : $('#ip').val()})
+ hueIPsinc = 0;
+ }
+ else discover_hue_bridges();
+
var usr = $('#user').val();
if(usr != "") {
checkHueBridge(checkUserResult, usr);
@@ -843,7 +919,7 @@ function beginWizardHue()
if($('#hue_'+key).val() != "disabled")
{
finalLightIds.push(key);
- var idx_content = assignHuePos(key, $('#hue_'+key).val());
+ var idx_content = assignLightPos(key, $('#hue_'+key).val(), lightIDs[key].name);
hueLedConfig.push(JSON.parse(JSON.stringify(idx_content)));
}
}
@@ -860,7 +936,9 @@ function beginWizardHue()
c.brightnessCompensation = 0;
//device config
- var d = sc.device;
+
+ //Start with a clean configuration
+ var d = {};
d.output = $('#ip').val();
d.username = $('#user').val();
d.type = 'philipshue';
@@ -903,6 +981,9 @@ function beginWizardHue()
//smoothing on
sc.smoothing.enable = true;
}
+
+ window.serverConfig.device = d;
+
requestWriteConfig(sc, true);
resetWizard();
});
@@ -1098,14 +1179,14 @@ function get_hue_lights(){
for(var opt in lightOptions)
{
var val = lightOptions[opt];
- var txt = (val != 'entire' && val != 'disabled') ? 'conf_leds_layout_cl_' : 'wiz_hue_ids_';
+ var txt = (val != 'entire' && val != 'disabled') ? 'conf_leds_layout_cl_' : 'wiz_ids_';
options+= ''+$.i18n(txt+val)+' ';
}
$('.lidsb').append(createTableRow([lightid+' ('+r[lightid].name+')', ''
+ options
- + ' ',''+$.i18n('wiz_hue_blinkblue',lightid)+' ']));
+ + '',''+$.i18n('wiz_hue_blinkblue',lightid)+' ']));
}
if(hueType != 'philipshueentertainment')
@@ -1140,3 +1221,494 @@ function abortConnection(UserInterval){
$('#wizp3').toggle(false);
$("#wiz_hue_usrstate").html($.i18n('wiz_hue_failure_connection'));
}
+
+//****************************
+// Wizard WLED
+//****************************
+var lights = null;
+function startWizardWLED(e)
+{
+ //create html
+
+ var wled_title = 'wiz_wled_title';
+ var wled_intro1 = 'wiz_wled_intro1';
+
+ $('#wiz_header').html(' '+$.i18n(wled_title));
+ $('#wizp1_body').html(''+$.i18n(wled_title)+' '+$.i18n(wled_intro1)+'
');
+ $('#wizp1_footer').html(' '+$.i18n('general_btn_continue')+' '+$.i18n('general_btn_cancel')+' ');
+
+ /*$('#wizp2_body').html('
');
+
+ $('#wh_topcontainer').append('
');
+
+ $('#wizp2_body').append(''+$.i18n('wiz_wled_desc2')+'
');
+
+ createTable("lidsh", "lidsb", "hue_ids_t");
+ $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lights_title'),$.i18n('wiz_pos'),$.i18n('wiz_identify')], true));
+ $('#wizp2_footer').html(' '+$.i18n('general_btn_save')+' '+$.i18n('general_btn_cancel')+' ');
+*/
+ //open modal
+ $("#wizard_modal").modal({
+ backdrop : "static",
+ keyboard: false,
+ show: true
+ });
+
+ //listen for continue
+ $('#btn_wiz_cont').off().on('click',function() {
+
+// For testing only
+ discover_wled();
+
+ var hostAddress = conf_editor.getEditor("root.specificOptions.host").getValue();
+ if(hostAddress != "")
+ {
+ getProperties_wled(hostAddress);
+ identify_wled(hostAddress)
+ }
+
+// For testing only
+
+ });
+}
+
+async function discover_wled(){
+
+ const res = await requestLedDeviceDiscovery ('wled');
+
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+ const r = res.info
+
+ // Process devices returned by discovery
+ console.log(r);
+
+ if(r.devices.length == 0)
+ $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
+ else
+ {
+ for(const device of r.devices)
+ {
+ console.log("Device:", device);
+
+ var ip = device.hostname + ":" + device.port;
+ console.log("Host:", ip);
+
+ //wledIPs.push({internalipaddress : ip});
+ }
+ }
+ }
+}
+
+async function getProperties_wled(hostAddress, resourceFilter){
+
+ let params = { host: hostAddress, filter: resourceFilter};
+
+ const res = await requestLedDeviceProperties ('wled', params);
+
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+ const r = res.info
+
+ // Process properties returned
+ console.log(r);
+ }
+}
+
+function identify_wled(hostAddress){
+
+ let params = { host: hostAddress };
+
+ const res = requestLedDeviceIdentification ("wled", params);
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+
+ const r = res.info
+ console.log(r);
+ }
+}
+
+//****************************
+// Wizard Yeelight
+//****************************
+var lights = null;
+function startWizardYeelight(e)
+{
+ //create html
+
+ var yeelight_title = 'wiz_yeelight_title';
+ var yeelight_intro1 = 'wiz_yeelight_intro1';
+
+ $('#wiz_header').html(' '+$.i18n(yeelight_title));
+ $('#wizp1_body').html(''+$.i18n(yeelight_title)+' '+$.i18n(yeelight_intro1)+'
');
+
+ $('#wizp1_footer').html(' '
+ +$.i18n('general_btn_continue')+' '
+ +$.i18n('general_btn_cancel')+' ');
+
+ $('#wizp2_body').html('
');
+
+ $('#wh_topcontainer').append('
');
+
+ $('#wizp2_body').append(''+$.i18n('wiz_yeelight_desc2')+'
');
+
+ createTable("lidsh", "lidsb", "yee_ids_t");
+ $('.lidsh').append(createTableRow([$.i18n('edt_dev_spec_lights_title'),$.i18n('wiz_pos'),$.i18n('wiz_identify')], true));
+ $('#wizp2_footer').html(' '
+ +$.i18n('general_btn_save')+' '
+ +$.i18n('general_btn_cancel')+'');
+
+ //open modal
+ $("#wizard_modal").modal({backdrop : "static", keyboard: false, show: true });
+
+ //listen for continue
+ $('#btn_wiz_cont').off().on('click',function() {
+ beginWizardYeelight();
+ $('#wizp1').toggle(false);
+ $('#wizp2').toggle(true);
+ });
+}
+
+function beginWizardYeelight()
+{
+ lights = [];
+ configuredLights = conf_editor.getEditor("root.specificOptions.lights").getValue();
+
+ discover_yeelight_lights();
+
+ $('#btn_wiz_save').off().on("click", function(){
+ var yeelightLedConfig = [];
+ var finalLights = [];
+
+ //create yeelight led config
+ for(var key in lights)
+ {
+ if($('#yee_'+key).val() !== "disabled")
+ {
+ //delete lights[key].model;
+
+ // Set Name to layout-position, if empty
+ if ( lights[key].name === "" )
+ {
+ lights[key].name = $.i18n( 'conf_leds_layout_cl_'+$('#yee_'+key).val() );
+ }
+
+ finalLights.push( lights[key]);
+
+ var name = lights[key].host;
+ if ( lights[key].name !== "")
+ name += '_'+lights[key].name;
+
+ var idx_content = assignLightPos(key, $('#yee_'+key).val(), name);
+ yeelightLedConfig.push(JSON.parse(JSON.stringify(idx_content)));
+ }
+ }
+
+ //LED layout
+ window.serverConfig.leds = yeelightLedConfig;
+
+ //LED device config
+ //Start with a clean configuration
+ var d = {};
+
+ d.type = 'yeelight';
+ d.hardwareLedCount = finalLights.length;
+ d.colorOrder = conf_editor.getEditor("root.generalOptions.colorOrder").getValue();
+ d.colorModel = parseInt(conf_editor.getEditor("root.specificOptions.colorModel").getValue());
+
+ d.transEffect = parseInt(conf_editor.getEditor("root.specificOptions.transEffect").getValue());
+ d.transTime = parseInt(conf_editor.getEditor("root.specificOptions.transTime").getValue());
+ d.extraTimeDarkness = parseInt(conf_editor.getEditor("root.specificOptions.extraTimeDarkness").getValue());
+
+ d.brightnessMin = parseInt(conf_editor.getEditor("root.specificOptions.brightnessMin").getValue());
+ d.brightnessSwitchOffOnMinimum = JSON.parse(conf_editor.getEditor("root.specificOptions.brightnessSwitchOffOnMinimum").getValue());
+ d.brightnessMax = parseInt(conf_editor.getEditor("root.specificOptions.brightnessMax").getValue());
+ d.brightnessFactor = parseFloat(conf_editor.getEditor("root.specificOptions.brightnessFactor").getValue());
+
+ d.latchTime = parseInt(conf_editor.getEditor("root.specificOptions.latchTime").getValue());;
+ d.debugLevel = parseInt(conf_editor.getEditor("root.specificOptions.debugLevel").getValue());
+
+ d.lights = finalLights;
+
+ window.serverConfig.device = d;
+
+ //smoothing off
+ window.serverConfig.smoothing.enable = false;
+
+ requestWriteConfig(window.serverConfig, true);
+ resetWizard();
+ });
+
+ $('#btn_wiz_abort').off().on('click', resetWizard);
+}
+
+function getHostInLights(hostname) {
+ return lights.filter(
+ function(lights) {
+ return lights.host === hostname
+ }
+ );
+}
+
+async function discover_yeelight_lights(){
+
+ var light = {};
+ // Get discovered lights
+ const res = await requestLedDeviceDiscovery ('yeelight');
+
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+ const r = res.info
+
+ // Process devices returned by discovery
+ for(const device of r.devices)
+ {
+ //console.log("Device:", device);
+
+ if( device.hostname !== "")
+ {
+ if ( getHostInLights ( device.hostname ).length === 0 )
+ {
+ light = {};
+ light.host = device.hostname;
+ light.port = device.port;
+
+ light.name = device.other.name;
+ light.model = device.other.model;
+ lights.push(light);
+ }
+ }
+ }
+
+ // Add additional items from configuration
+ for(var keyConfig in configuredLights)
+ {
+
+ var [host, port]= configuredLights[keyConfig].host.split(":", 2);
+
+ //In case port has been explicitly provided, overwrite port given as part of hostname
+ if ( configuredLights[keyConfig].port !== 0 )
+ port = configuredLights[keyConfig].port;
+
+ if ( host !== "" )
+ if ( getHostInLights ( host ).length === 0 )
+ {
+ light = {};
+ light.host = host;
+ light.port = port;
+ light.name = configuredLights[keyConfig].name;
+ light.model = "color4";
+ lights.push(light);
+ }
+ }
+
+ assign_yeelight_lights();
+ }
+}
+
+function assign_yeelight_lights(){
+
+ var models = ['color', 'color1', 'color2', 'color4', 'stripe', 'strip1'];
+
+ // If records are left for configuration
+ if(Object.keys(lights).length > 0)
+ {
+ $('#wh_topcontainer').toggle(false);
+ $('#yee_ids_t, #btn_wiz_save').toggle(true);
+
+ var lightOptions = [
+ "top", "topleft", "topright",
+ "bottom", "bottomleft", "bottomright",
+ "left", "lefttop", "leftmiddle", "leftbottom",
+ "right", "righttop", "rightmiddle", "rightbottom",
+ "entire"
+ ];
+
+ lightOptions.unshift("disabled");
+
+ $('.lidsb').html("");
+ var pos = "";
+
+ for(var lightid in lights)
+ {
+ var lightHostname = lights[lightid].host;
+ var lightPort = lights[lightid].port;
+ var lightName = lights[lightid].name;
+
+ if ( lightName === "" )
+ lightName = $.i18n('edt_dev_spec_lights_itemtitle');
+
+ var options = "";
+ for(var opt in lightOptions)
+ {
+ var val = lightOptions[opt];
+ var txt = (val !== 'entire' && val !== 'disabled') ? 'conf_leds_layout_cl_' : 'wiz_ids_';
+ options+= ''+$.i18n(txt+val)+' ';
+ }
+
+ if (! models.includes (lights[lightid].model) )
+ {
+ var enabled = 'disabled'
+ options = ''+$.i18n('wiz_yeelight_unsupported')+' ';
+ }
+
+ $('.lidsb').append(createTableRow([(parseInt(lightid, 10) + 1)+'. '+lightName+' ('+lightHostname+')', ''
+ + options
+ + ' ',''
+ + $.i18n('wiz_identify_light',lightName)+' ']));
+ }
+
+ $('.yee_sel_watch').bind("change", function(){
+ var cC = 0;
+ for(var key in lights)
+ {
+ if($('#yee_'+key).val() !== "disabled")
+ {
+ cC++;
+ }
+ }
+ if ( cC === 0)
+ $('#btn_wiz_save').attr("disabled",true);
+ else
+ $('#btn_wiz_save').attr("disabled",false);
+ });
+ $('.yee_sel_watch').trigger('change');
+ }
+ else
+ {
+ var noLightsTxt = ''+$.i18n('wiz_yeelight_noLights')+'
';
+ $('#wizp2_body').append(noLightsTxt);
+ }
+}
+
+async function getProperties_yeelight(hostname, port){
+
+ let params = { hostname: hostname, port: port};
+
+ const res = await requestLedDeviceProperties ('yeelight', params);
+
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+ const r = res.info
+
+ // Process properties returned
+ console.log(r);
+ }
+}
+
+function identify_yeelight_device(hostname, port){
+
+ let params = { hostname: hostname, port: port };
+
+ const res = requestLedDeviceIdentification ("yeelight", params);
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+ const r = res.info
+ }
+}
+
+//****************************
+// Wizard/Routines Nanoleaf
+//****************************
+async function discover_nanoleaf(){
+
+ const res = await requestLedDeviceDiscovery ('nanoleaf');
+
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+ const r = res.info
+
+ // Process devices returned by discovery
+ console.log(r);
+
+ if(r.devices.length == 0)
+ $('#wiz_hue_ipstate').html($.i18n('wiz_hue_failure_ip'));
+ else
+ {
+ for(const device of r.devices)
+ {
+ console.log("Device:", device);
+
+ var ip = device.hostname + ":" + device.port;
+ console.log("Host:", ip);
+
+ //nanoleafIPs.push({internalipaddress : ip});
+ }
+ }
+ }
+}
+
+async function getProperties_nanoleaf(hostAddress, authToken, resourceFilter){
+
+ let params = { host: hostAddress, token: authToken, filter: resourceFilter};
+
+ const res = await requestLedDeviceProperties ('nanoleaf', params);
+
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+ const r = res.info
+
+ // Process properties returned
+ console.log(r);
+ }
+}
+
+function identify_nanoleaf(hostAddress, authToken){
+
+ let params = { host: hostAddress, token: authToken};
+
+ const res = requestLedDeviceIdentification ("nanoleaf", params);
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+
+ const r = res.info
+ console.log(r);
+ }
+}
+
+//****************************
+// Wizard/Routines RS232-Devices
+//****************************
+async function discover_providerRs232(rs232Type){
+
+ const res = await requestLedDeviceDiscovery (rs232Type);
+
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+ const r = res.info
+
+ // Process serialPorts returned by discover
+ console.log(r);
+ }
+}
+
+//****************************
+// Wizard/Routines HID (USB)-Devices
+//****************************
+async function discover_providerHid(hidType){
+
+ const res = await requestLedDeviceDiscovery (hidType);
+ console.log("discover_providerHid" ,res);
+
+ // TODO: error case unhandled
+ // res can be: false (timeout) or res.error (not found)
+ if(res && !res.error){
+ const r = res.info
+
+ // Process HID returned by discover
+ console.log(r);
+ }
+}
+
diff --git a/bin/compile.sh b/bin/compile.sh
index 75adfc4fa..5a282bd18 100755
--- a/bin/compile.sh
+++ b/bin/compile.sh
@@ -5,7 +5,7 @@ CFG="${2:-Release}"
INST="$( [ "${3:-}" = "install" ] && echo true || echo false )"
sudo apt-get update
-sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev libturbojpeg0-dev python3-dev libxcb-util0-dev libxcb-randr0-dev libxrandr-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libssl-dev libjpeg-dev libqt5sql5-sqlite zlib1g-dev || exit 1
+sudo apt-get install git cmake build-essential qtbase5-dev libqt5serialport5-dev libusb-1.0-0-dev libturbojpeg0-dev python3-dev libxrender-dev libavahi-core-dev libavahi-compat-libdnssd-dev libssl-dev libjpeg-dev libqt5sql5-sqlite zlib1g-dev || exit 1
if [ -e /dev/vc-cma -a -e /dev/vc-mem ]
then
diff --git a/bin/create_oe_depedencies.sh b/bin/create_oe_depedencies.sh
index 0971468f8..194da7a83 100644
--- a/bin/create_oe_depedencies.sh
+++ b/bin/create_oe_depedencies.sh
@@ -18,11 +18,8 @@ tar --create --verbose --gzip --absolute-names --show-transformed-names --derefe
"$IMX6_ROOTFS/usr/lib/arm-linux-gnueabihf/libX11.so.6" \
"$IMX6_ROOTFS/usr/lib/arm-linux-gnueabihf/libXau.so.6" \
"$IMX6_ROOTFS/usr/lib/arm-linux-gnueabihf/libxcb.so.1" \
- "$IMX6_ROOTFS/usr/lib/arm-linux-gnueabihf/libxcb-util.so" \
- "$IMX6_ROOTFS/usr/lib/arm-linux-gnueabihf/libxcb-randr.so" \
"$IMX6_ROOTFS/usr/lib/arm-linux-gnueabihf/libXdmcp.so.6" \
"$IMX6_ROOTFS/usr/lib/arm-linux-gnueabihf/libXext.so.6" \
- "$IMX6_ROOTFS/usr/lib/arm-linux-gnueabihf/libXrandr.so.2" \
"$IMX6_ROOTFS/usr/lib/arm-linux-gnueabihf/libXrender.so.1" \
"$IMX6_ROOTFS/usr/lib/arm-linux-gnueabihf/libXt.so.6" \
"./openelec/hyperiond.sh" \
diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake
index 6c6226551..f30a31baf 100644
--- a/cmake/Dependencies.cmake
+++ b/cmake/Dependencies.cmake
@@ -1,32 +1,32 @@
macro(DeployUnix TARGET)
+ set(TARGET_FILE ${CMAKE_BINARY_DIR}/bin/${TARGET})
+ set(SYSTEM_LIBS_SKIP
+ "libc"
+ "libdl"
+ "libexpat"
+ "libfontconfig"
+ "libfreetype"
+ "libgcc_s"
+ "libgcrypt"
+ "libGL"
+ "libGLdispatch"
+ "libglib-2"
+ "libGLX"
+ "libgpg-error"
+ "libm"
+ "libpthread"
+ "librt"
+ "libstdc++"
+ "libudev"
+ "libusb-1"
+ "libutil"
+ "libX11"
+ "libz"
+ )
+
if(EXISTS ${TARGET_FILE})
- message(STATUS "Collecting Dependencies for target file: ${TARGET_FILE}")
include(GetPrerequisites)
- set(SYSTEM_LIBS_SKIP
- "libc"
- "libdl"
- "libexpat"
- "libfontconfig"
- "libfreetype"
- "libgcc_s"
- "libgcrypt"
- "libGL"
- "libGLdispatch"
- "libglib-2"
- "libGLX"
- "libgpg-error"
- "libm"
- "libpthread"
- "librt"
- "libstdc++"
- "libudev"
- "libusb-1"
- "libutil"
- "libX11"
- "libz"
- )
-
if (APPLE)
set(OPENSSL_ROOT_DIR /usr/local/opt/openssl)
endif(APPLE)
@@ -133,19 +133,17 @@ macro(DeployUnix TARGET)
)
endforeach()
- # Detect the Python version and modules directory
if (NOT CMAKE_VERSION VERSION_LESS "3.12")
- set(PYTHON_VERSION_MAJOR_MINOR "${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR}")
+ # Detect the Python modules directory
execute_process(
COMMAND ${Python3_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(standard_lib=True))"
OUTPUT_VARIABLE PYTHON_MODULES_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
-
else()
- set(PYTHON_VERSION_MAJOR_MINOR "${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}")
+ # Detect the Python modules directory
execute_process(
COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(standard_lib=True))"
OUTPUT_VARIABLE PYTHON_MODULES_DIR
@@ -154,43 +152,19 @@ macro(DeployUnix TARGET)
endif()
- # Pack Python modules to pythonXX.zip or copy to 'share/hyperion/lib/python'
+ # Copy Python modules to 'share/hyperion/lib/python'
if (PYTHON_MODULES_DIR)
- # Since version 3.3.2 CMake has the functionality to generate a zip file built-in.
- if (NOT CMAKE_VERSION VERSION_LESS "3.3.2")
-
- file(GLOB PYTHON_MODULE_FILES RELATIVE "${PYTHON_MODULES_DIR}" "${PYTHON_MODULES_DIR}/*")
- set(PYTHON_ZIP "python${PYTHON_VERSION_MAJOR_MINOR}.zip")
-
- execute_process(
- COMMAND "${CMAKE_COMMAND}" "-E" "tar" "cf" "${CMAKE_BINARY_DIR}/${PYTHON_ZIP}" "--format=zip" ${PYTHON_MODULE_FILES}
- WORKING_DIRECTORY "${PYTHON_MODULES_DIR}"
- OUTPUT_QUIET
- )
-
- install(
- FILES "${CMAKE_BINARY_DIR}/${PYTHON_ZIP}"
- DESTINATION "share/hyperion/bin"
- COMPONENT "Hyperion"
- )
-
- else()
-
- install(
- DIRECTORY ${PYTHON_MODULES_DIR}/
- DESTINATION "share/hyperion/lib/python"
- COMPONENT "Hyperion"
- )
-
- endif()
-
+ install(
+ DIRECTORY ${PYTHON_MODULES_DIR}/
+ DESTINATION "share/hyperion/lib/python"
+ COMPONENT "Hyperion"
+ )
endif(PYTHON_MODULES_DIR)
-
else()
# Run CMake after target was built to run get_prerequisites on ${TARGET_FILE}
add_custom_command(
TARGET ${TARGET} POST_BUILD
- COMMAND "${CMAKE_COMMAND}" "-DTARGET_FILE=$"
+ COMMAND ${CMAKE_COMMAND}
ARGS ${CMAKE_SOURCE_DIR}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
VERBATIM
@@ -199,10 +173,11 @@ macro(DeployUnix TARGET)
endmacro()
macro(DeployWindows TARGET)
+ # TODO Find out what build type it is
+ set(TARGET_FILE ${CMAKE_BINARY_DIR}/bin/Release/${TARGET}.exe)
+
if(EXISTS ${TARGET_FILE})
- message(STATUS "Collecting Dependencies for target file: ${TARGET_FILE}")
find_package(Qt5Core REQUIRED)
- find_package(OpenSSL REQUIRED)
# Find the windeployqt binaries
get_target_property(QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
@@ -216,11 +191,11 @@ macro(DeployWindows TARGET)
execute_process(
COMMAND "${CMAKE_COMMAND}" -E
env "PATH=${COMPILER_PATH};${QT_BIN_DIR}" "${WINDEPLOYQT_EXECUTABLE}"
- --dry-run
- ${WINDEPLOYQT_PARAMS}
- --list mapping
- "${TARGET_FILE}"
- OUTPUT_VARIABLE DEPS
+ --dry-run
+ ${WINDEPLOYQT_PARAMS}
+ --list mapping
+ "${TARGET_FILE}"
+ OUTPUT_VARIABLE DEPS
OUTPUT_STRIP_TRAILING_WHITESPACE
)
@@ -251,36 +226,6 @@ macro(DeployWindows TARGET)
list(REMOVE_AT DEPENDENCIES 0 1)
endwhile()
- # Copy OpenSSL Libs
- if (OPENSSL_FOUND)
- string(REGEX MATCHALL "[0-9]+" openssl_versions "${OPENSSL_VERSION}")
- list(GET openssl_versions 0 openssl_version_major)
- list(GET openssl_versions 1 openssl_version_minor)
-
- set(library_suffix "-${openssl_version_major}_${openssl_version_minor}")
- if(CMAKE_SIZEOF_VOID_P EQUAL 8)
- string(APPEND library_suffix "-x64")
- endif()
-
- find_file(OPENSSL_SSL
- NAMES "libssl${library_suffix}.dll"
- PATHS ${OPENSSL_INCLUDE_DIR}/.. ${OPENSSL_INCLUDE_DIR}/../bin
- NO_DEFAULT_PATH
- )
-
- find_file(OPENSSL_CRYPTO
- NAMES "libcrypto${library_suffix}.dll"
- PATHS ${OPENSSL_INCLUDE_DIR}/.. ${OPENSSL_INCLUDE_DIR}/../bin
- NO_DEFAULT_PATH
- )
-
- install(
- FILES ${OPENSSL_SSL} ${OPENSSL_CRYPTO}
- DESTINATION "bin"
- COMPONENT "Hyperion"
- )
- endif(OPENSSL_FOUND)
-
# Create a qt.conf file in 'bin' to override hard-coded search paths in Qt plugins
file(WRITE "${CMAKE_BINARY_DIR}/qt.conf" "[Paths]\nPlugins=../lib/\n")
install(
@@ -332,7 +277,7 @@ macro(DeployWindows TARGET)
# Run CMake after target was built
add_custom_command(
TARGET ${TARGET} POST_BUILD
- COMMAND "${CMAKE_COMMAND}" "-DTARGET_FILE=$"
+ COMMAND ${CMAKE_COMMAND}
ARGS ${CMAKE_SOURCE_DIR}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
VERBATIM
diff --git a/cmake/nsis/template/NSIS.template.in b/cmake/nsis/template/NSIS.template.in
index b014a44df..660bfa3f4 100644
--- a/cmake/nsis/template/NSIS.template.in
+++ b/cmake/nsis/template/NSIS.template.in
@@ -724,24 +724,6 @@ Section "-Core installation"
@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@
-; Custom vcredist install script, detection is not reliable
-;ReadRegStr $1 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\X64" "Bld"
-;DetailPrint "VCREDIS KEY: $1"
-;
-;IntCmp $1 28508 Equal Val1Less Val1More
-;Equal:
-; DetailPrint "$1 = 28508 "
-; Goto End
-;Val1Less:
-; DetailPrint "$1 < 28508 "
-; Goto End
-;Val1More:
-; DetailPrint "$1 > 28508 "
-; Goto End
-;End:
-
-ExecWait '"$INSTDIR\bin\vc_redist.x64.exe" /install /quiet'
-
SectionEnd
Section "-Add to path"
diff --git a/cmake/packages.cmake b/cmake/packages.cmake
index 687c6ed9d..9c5fdaa41 100644
--- a/cmake/packages.cmake
+++ b/cmake/packages.cmake
@@ -101,16 +101,14 @@ SET ( CPACK_NSIS_PACKAGE_NAME "Hyperion" )
SET ( CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\hyperiond.exe")
SET ( CPACK_NSIS_HELP_LINK "https://www.hyperion-project.org")
SET ( CPACK_NSIS_URL_INFO_ABOUT "https://www.hyperion-project.org")
-# additional hyperiond startmenu link, won't be created if the user disables startmenu links
-SET ( CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Hyperion (Console).lnk' '$INSTDIR\\\\bin\\\\hyperiond.exe' '-d -c'")
-SET ( CPACK_NSIS_DELETE_ICONS_EXTRA "Delete '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Hyperion (Console).lnk'")
-
-
+# hyperiond startmenu link
#SET ( CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Hyperion.lnk' '$INSTDIR\\\\bin\\\\hyperiond.exe'")
#SET ( CPACK_NSIS_DELETE_ICONS_EXTRA "Delete '$SMPROGRAMS\\\\$START_MENU\\\\Hyperion.lnk'")
# hyperiond desktop link
#SET ( CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$DESKTOP\\\\Hyperion.lnk' '$INSTDIR\\\\bin\\\\hyperiond.exe' ")
#SET ( CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "Delete '$DESKTOP\\\\Hyperion.lnk' ")
+
+# With cli args: SET ( CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Hyperion (Debug).lnk' '$INSTDIR\\\\bin\\\\hyperiond.exe' '-d'")
#SET ( CPACK_NSIS_EXTRA_INSTALL_COMMANDS "CreateShortCut \\\"$DESKTOP\\\\Hyperion.lnk\\\" \\\"$INSTDIR\\\\bin\\\\hyperiond.exe\\\" ")
#SET ( CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "Delete \\\"$DESKTOP\\\\Hyperion.lnk\\\" ")
diff --git a/effects/ledtest.json b/effects/ledtest.json
index 3c4c4c279..8a02b0ad9 100644
--- a/effects/ledtest.json
+++ b/effects/ledtest.json
@@ -3,9 +3,9 @@
"script" : "ledtest.py",
"args" :
{
- "sleepTime" : 0.20,
+ "sleepTime" : 0.50,
"testleds" : "all",
- "smoothing-custom-settings" : true,
+ "smoothing-custom-settings" : false,
"smoothing-time_ms" : 500,
"smoothing-updateFrequency" : 20.0
}
diff --git a/effects/ledtest.py b/effects/ledtest.py
index 0174c3abf..bbdb70561 100644
--- a/effects/ledtest.py
+++ b/effects/ledtest.py
@@ -7,7 +7,7 @@
#import colorsys
# Get parameters
-sleepTime = float(hyperion.args.get('sleepTime', 0.2))
+sleepTime = float(hyperion.args.get('sleepTime', 0.5))
testleds = hyperion.args.get('testleds', "all")
ledlist = hyperion.args.get('ledlist', "1")
diff --git a/include/api/JsonAPI.h b/include/api/JsonAPI.h
index 9524d0c2d..65ec2f586 100644
--- a/include/api/JsonAPI.h
+++ b/include/api/JsonAPI.h
@@ -85,7 +85,7 @@ private slots:
/// @param instance The index of instance
/// @param name The name of the instance, just available with H_CREATED
///
- void handleInstanceStateChange(const InstanceState &state, const quint8 &instance, const QString &name = QString());
+ void handleInstanceStateChange(const instanceState &state, const quint8 &instance, const QString &name = QString());
signals:
///
@@ -94,7 +94,7 @@ private slots:
void callbackMessage(QJsonObject);
///
- /// Signal emits whenever a jsonmessage should be forwarded
+ /// Signal emits whenever a JSON-message should be forwarded
///
void forwardJsonMessage(QJsonObject);
@@ -247,7 +247,7 @@ private slots:
///
void handleLoggingCommand(const QJsonObject &message, const QString &command, const int tan);
- /// Handle an incoming JSON Proccessing message
+ /// Handle an incoming JSON Processing message
///
/// @param message the incoming message
///
@@ -271,6 +271,12 @@ private slots:
///
void handleInstanceCommand(const QJsonObject &message, const QString &command, const int tan);
+ /// Handle an incoming JSON Led Device message
+ ///
+ /// @param message the incoming message
+ ///
+ void handleLedDeviceCommand(const QJsonObject &message, const QString &command, const int tan);
+
///
/// Handle an incoming JSON message of unknown type
///
diff --git a/include/commandline/Parser.h b/include/commandline/Parser.h
index 129d5184e..3c2c78487 100644
--- a/include/commandline/Parser.h
+++ b/include/commandline/Parser.h
@@ -28,8 +28,6 @@ class Parser : public QObject
QString _getDescription(const QString description, const QString default_=QString());
public:
- ~Parser() override;
-
bool parse(const QStringList &arguments);
void process(const QStringList &arguments);
void process(const QCoreApplication &app);
diff --git a/include/grabber/AmlogicGrabber.h b/include/grabber/AmlogicGrabber.h
index fee7bc37c..a2f4b78b9 100644
--- a/include/grabber/AmlogicGrabber.h
+++ b/include/grabber/AmlogicGrabber.h
@@ -18,7 +18,7 @@ class AmlogicGrabber : public Grabber
/// @param[in] height The heigth of the captured screenshot
///
AmlogicGrabber(const unsigned width, const unsigned height);
- ~AmlogicGrabber() override;
+ ~AmlogicGrabber();
///
/// Captures a single snapshot of the display and writes the data to the given image. The
diff --git a/include/grabber/AmlogicWrapper.h b/include/grabber/AmlogicWrapper.h
index 31d9d4c91..5df6c95a5 100644
--- a/include/grabber/AmlogicWrapper.h
+++ b/include/grabber/AmlogicWrapper.h
@@ -20,6 +20,11 @@ class AmlogicWrapper : public GrabberWrapper
///
AmlogicWrapper(const unsigned grabWidth, const unsigned grabHeight);
+ ///
+ /// Destructor of this dispmanx frame grabber. Releases any claimed resources.
+ ///
+ virtual ~AmlogicWrapper() {};
+
public slots:
///
/// Performs a single frame grab and computes the led-colors
diff --git a/include/grabber/DispmanxFrameGrabber.h b/include/grabber/DispmanxFrameGrabber.h
index 1aea2e010..82b14b357 100644
--- a/include/grabber/DispmanxFrameGrabber.h
+++ b/include/grabber/DispmanxFrameGrabber.h
@@ -27,7 +27,7 @@ class DispmanxFrameGrabber : public Grabber
/// @param[in] height The heigth of the captured screenshot
///
DispmanxFrameGrabber(const unsigned width, const unsigned height);
- ~DispmanxFrameGrabber() override;
+ ~DispmanxFrameGrabber();
///
diff --git a/include/grabber/DispmanxFrameGrabberMock.h b/include/grabber/DispmanxFrameGrabberMock.h
index 6e76078a8..477909e89 100644
--- a/include/grabber/DispmanxFrameGrabberMock.h
+++ b/include/grabber/DispmanxFrameGrabberMock.h
@@ -36,4 +36,5 @@ int vc_dispmanx_resource_read_data(DISPMANX_RESOURCE_HANDLE_T vc_resource, VC_R
void vc_dispmanx_rect_set(VC_RECT_T *rectangle, int left, int top, int width, int height);
int vc_dispmanx_snapshot(int, DISPMANX_RESOURCE_HANDLE_T resource, int vc_flags);
+
#endif
diff --git a/include/grabber/DispmanxWrapper.h b/include/grabber/DispmanxWrapper.h
index f62e6002b..e231c8091 100644
--- a/include/grabber/DispmanxWrapper.h
+++ b/include/grabber/DispmanxWrapper.h
@@ -22,6 +22,11 @@ class DispmanxWrapper: public GrabberWrapper
///
DispmanxWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz);
+ ///
+ /// Destructor of this dispmanx frame grabber. Releases any claimed resources.
+ ///
+ virtual ~DispmanxWrapper() {};
+
public slots:
///
/// Performs a single frame grab and computes the led-colors
diff --git a/include/grabber/FramebufferFrameGrabber.h b/include/grabber/FramebufferFrameGrabber.h
index 0ba5b6b8a..6296755f6 100644
--- a/include/grabber/FramebufferFrameGrabber.h
+++ b/include/grabber/FramebufferFrameGrabber.h
@@ -18,6 +18,7 @@ class FramebufferFrameGrabber : public Grabber
/// @param[in] height The heigth of the captured screenshot
///
FramebufferFrameGrabber(const QString & device, const unsigned width, const unsigned height);
+ ~FramebufferFrameGrabber();
///
/// Captures a single snapshot of the display and writes the data to the given image. The
@@ -35,6 +36,12 @@ class FramebufferFrameGrabber : public Grabber
virtual void setDevicePath(const QString& path);
private:
+ /// Framebuffer file descriptor
+ int _fbfd;
+
+ /// Pointer to framebuffer
+ unsigned char * _fbp;
+
/// Framebuffer device e.g. /dev/fb0
QString _fbDevice;
};
diff --git a/include/grabber/FramebufferWrapper.h b/include/grabber/FramebufferWrapper.h
index a782d10a0..a7c9243cb 100644
--- a/include/grabber/FramebufferWrapper.h
+++ b/include/grabber/FramebufferWrapper.h
@@ -22,6 +22,11 @@ class FramebufferWrapper: public GrabberWrapper
///
FramebufferWrapper(const QString & device, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz);
+ ///
+ /// Destructor of this framebuffer frame grabber. Releases any claimed resources.
+ ///
+ virtual ~FramebufferWrapper() {};
+
public slots:
///
/// Performs a single frame grab and computes the led-colors
diff --git a/include/grabber/OsxFrameGrabber.h b/include/grabber/OsxFrameGrabber.h
index 5d6923969..59e39930b 100644
--- a/include/grabber/OsxFrameGrabber.h
+++ b/include/grabber/OsxFrameGrabber.h
@@ -25,7 +25,7 @@ class OsxFrameGrabber : public Grabber
/// @param[in] height The heigth of the captured screenshot
///
OsxFrameGrabber(const unsigned display, const unsigned width, const unsigned height);
- ~OsxFrameGrabber() override;
+ ~OsxFrameGrabber();
///
/// Captures a single snapshot of the display and writes the data to the given image. The
diff --git a/include/grabber/OsxWrapper.h b/include/grabber/OsxWrapper.h
index 093fa1627..65ce70ab3 100644
--- a/include/grabber/OsxWrapper.h
+++ b/include/grabber/OsxWrapper.h
@@ -22,6 +22,11 @@ class OsxWrapper: public GrabberWrapper
///
OsxWrapper(const unsigned display, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz);
+ ///
+ /// Destructor of this osx frame grabber. Releases any claimed resources.
+ ///
+ virtual ~OsxWrapper() {};
+
public slots:
///
/// Performs a single frame grab and computes the led-colors
diff --git a/include/grabber/QtGrabber.h b/include/grabber/QtGrabber.h
index 3460a0383..5ba1cc502 100644
--- a/include/grabber/QtGrabber.h
+++ b/include/grabber/QtGrabber.h
@@ -17,7 +17,7 @@ class QtGrabber : public Grabber
QtGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display);
- ~QtGrabber() override;
+ virtual ~QtGrabber();
///
/// Captures a single snapshot of the display and writes the data to the given image. The
diff --git a/include/grabber/QtWrapper.h b/include/grabber/QtWrapper.h
index 67135ed77..3c4b7d289 100644
--- a/include/grabber/QtWrapper.h
+++ b/include/grabber/QtWrapper.h
@@ -21,6 +21,11 @@ class QtWrapper: public GrabberWrapper
///
QtWrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, int display, const unsigned updateRate_Hz);
+ ///
+ /// Destructor of this qt frame grabber. Releases any claimed resources.
+ ///
+ virtual ~QtWrapper() {};
+
public slots:
///
/// Performs a single frame grab and computes the led-colors
diff --git a/include/grabber/V4L2Wrapper.h b/include/grabber/V4L2Wrapper.h
index fc9596a6d..0476b96e9 100644
--- a/include/grabber/V4L2Wrapper.h
+++ b/include/grabber/V4L2Wrapper.h
@@ -16,6 +16,7 @@ class V4L2Wrapper : public GrabberWrapper
VideoStandard videoStandard,
PixelFormat pixelFormat,
int pixelDecimation );
+ virtual ~V4L2Wrapper() {};
bool getSignalDetectionEnable();
diff --git a/include/grabber/X11Grabber.h b/include/grabber/X11Grabber.h
index f39d5aa83..ab7adf456 100644
--- a/include/grabber/X11Grabber.h
+++ b/include/grabber/X11Grabber.h
@@ -1,7 +1,5 @@
#pragma once
-#include
-#include
-#include
+
#include
// Hyperion-utils includes
@@ -10,19 +8,18 @@
// X11 includes
#include
-#include
#include
#include
#include
#include
-class X11Grabber : public Grabber , public QAbstractNativeEventFilter
+class X11Grabber : public Grabber
{
public:
X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation);
- ~X11Grabber() override;
+ virtual ~X11Grabber();
bool Setup();
@@ -61,11 +58,8 @@ class X11Grabber : public Grabber , public QAbstractNativeEventFilter
///
virtual void setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom);
-protected:
- bool nativeEventFilter(const QByteArray & eventType, void * message, long int * result) override;
-
private:
- bool _XShmAvailable, _XShmPixmapAvailable, _XRenderAvailable, _XRandRAvailable;
+ bool _XShmAvailable, _XShmPixmapAvailable, _XRenderAvailable;
XImage* _xImage;
XShmSegmentInfo _shminfo;
@@ -82,8 +76,6 @@ class X11Grabber : public Grabber , public QAbstractNativeEventFilter
Picture _srcPicture;
Picture _dstPicture;
- int _XRandREventBase;
-
XTransform _transform;
int _pixelDecimation;
diff --git a/include/grabber/X11Wrapper.h b/include/grabber/X11Wrapper.h
index 9271d9cd7..51f2c77cb 100644
--- a/include/grabber/X11Wrapper.h
+++ b/include/grabber/X11Wrapper.h
@@ -26,6 +26,11 @@ class X11Wrapper: public GrabberWrapper
///
X11Wrapper(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation, const unsigned updateRate_Hz);
+ ///
+ /// Destructor of this framebuffer frame grabber. Releases any claimed resources.
+ ///
+ virtual ~X11Wrapper() {};
+
public slots:
///
/// Performs a single frame grab and computes the led-colors
diff --git a/include/hyperion/CaptureCont.h b/include/hyperion/CaptureCont.h
index 139f4295b..55693b913 100644
--- a/include/hyperion/CaptureCont.h
+++ b/include/hyperion/CaptureCont.h
@@ -17,6 +17,7 @@ class CaptureCont : public QObject
Q_OBJECT
public:
CaptureCont(Hyperion* hyperion);
+ ~CaptureCont();
void setSystemCaptureEnable(const bool& enable);
void setV4LCaptureEnable(const bool& enable);
diff --git a/include/hyperion/Grabber.h b/include/hyperion/Grabber.h
index 7ec8026bc..3570e7436 100644
--- a/include/hyperion/Grabber.h
+++ b/include/hyperion/Grabber.h
@@ -23,6 +23,7 @@ class Grabber : public QObject
public:
Grabber(QString grabberName = "", int width=0, int height=0, int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
+ virtual ~Grabber();
///
/// Set the video mode (2D/3D)
diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h
index 3218fb039..091fe9b9d 100644
--- a/include/hyperion/Hyperion.h
+++ b/include/hyperion/Hyperion.h
@@ -2,6 +2,7 @@
// stl includes
#include
+#include
// QT includes
#include
@@ -10,7 +11,6 @@
#include
#include
#include
-#include
#include
// hyperion-utils includes
@@ -59,25 +59,32 @@ class Hyperion : public QObject
Q_OBJECT
public:
/// Type definition of the info structure used by the priority muxer
- using InputInfo = PriorityMuxer::InputInfo;
+ typedef PriorityMuxer::InputInfo InputInfo;
+ ///
+ /// RGB-Color channel enumeration
+ ///
+ enum RgbChannel
+ {
+ BLACK, WHITE, RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW, INVALID
+ };
///
/// Destructor; cleans up resources
///
- ~Hyperion() override;
+ virtual ~Hyperion();
///
/// free all alocated objects, should be called only from constructor or before restarting hyperion
///
void freeObjects(bool emitCloseSignal=false);
- ImageProcessor* getImageProcessor() { return _imageProcessor; }
+ ImageProcessor* getImageProcessor() { return _imageProcessor; };
///
/// @brief Get instance index of this instance
/// @return The index of this instance
///
- const quint8 & getInstanceIndex() { return _instIndex; }
+ const quint8 & getInstanceIndex() { return _instIndex; };
///
/// Returns the number of attached leds
@@ -87,7 +94,7 @@ class Hyperion : public QObject
///
/// @brief Return the size of led grid
///
- QSize getLedGridSize() const { return _ledGridSize; }
+ QSize getLedGridSize() const { return _ledGridSize; };
/// gets the methode how image is maped to leds
const int & getLedMappingType();
@@ -103,8 +110,8 @@ class Hyperion : public QObject
///
/// @brief Get the current active led device
- /// @return The device name
- ///
+ /// @return The device nam
+ /// e
const QString & getActiveDeviceType();
///
@@ -199,7 +206,7 @@ public slots:
/// @return EffectEngine instance pointer
///
- EffectEngine* getEffectEngineInstance() { return _effectEngine; }
+ EffectEngine* getEffectEngineInstance() { return _effectEngine; };
///
/// @brief Save an effect
/// @param obj The effect args
@@ -252,7 +259,7 @@ public slots:
/// @brief Get a pointer to the priorityMuxer instance
/// @return PriorityMuxer instance pointer
///
- PriorityMuxer* getMuxerInstance() { return &_muxer; }
+ PriorityMuxer* getMuxerInstance() { return &_muxer; };
///
/// @brief enable/disable automatic/priorized source selection
@@ -328,7 +335,7 @@ public slots:
/// @brief Get the component Register
/// return Component register pointer
///
- ComponentRegister& getComponentRegister() { return _componentRegister; }
+ ComponentRegister& getComponentRegister() { return _componentRegister; };
///
/// @brief Called from components to update their current state. DO NOT CALL FROM USERS
@@ -482,7 +489,7 @@ private slots:
///
/// @brief Apply new videoMode from Daemon to _currVideoMode
///
- void handleNewVideoMode(const VideoMode& mode) { _currVideoMode = mode; }
+ void handleNewVideoMode(const VideoMode& mode) { _currVideoMode = mode; };
private:
friend class HyperionDaemon;
diff --git a/include/hyperion/HyperionIManager.h b/include/hyperion/HyperionIManager.h
index 4943ca73c..d5e83ee96 100644
--- a/include/hyperion/HyperionIManager.h
+++ b/include/hyperion/HyperionIManager.h
@@ -12,7 +12,7 @@
class Hyperion;
class InstanceTable;
-enum class InstanceState{
+enum instanceState{
H_STARTED,
H_ON_STOP,
H_STOPPED,
@@ -29,7 +29,7 @@ class HyperionIManager : public QObject
public:
// global instance pointer
- static HyperionIManager* getInstance() { return HIMinstance; }
+ static HyperionIManager* getInstance() { return HIMinstance; };
static HyperionIManager* HIMinstance;
public slots:
@@ -38,7 +38,7 @@ public slots:
/// @param inst The instance to check
/// @return True when running else false
///
- bool IsInstanceRunning(const quint8& inst) { return _runningInstances.contains(inst); }
+ bool IsInstanceRunning(const quint8& inst) { return _runningInstances.contains(inst); };
///
/// @brief Get a Hyperion instance by index
@@ -103,7 +103,7 @@ public slots:
/// @param instance The index of instance
/// @param name The name of the instance, just available with H_CREATED
///
- void instanceStateChanged(const InstanceState& state, const quint8& instance, const QString& name = QString());
+ void instanceStateChanged(const instanceState& state, const quint8& instance, const QString& name = QString());
///
/// @brief Emits whenever something changes, the lazy version of instanceStateChanged (- H_ON_STOP) + saveName() emit
@@ -172,7 +172,7 @@ private slots:
/// @brief check if a instance is allowed for management. Instance 0 represents the root instance
/// @apram inst The instance to check
///
- bool isInstAllowed(const quint8& inst) { return (inst > 0); }
+ bool isInstAllowed(const quint8& inst) { return (inst > 0); };
private:
Logger* _log;
diff --git a/include/hyperion/LedString.h b/include/hyperion/LedString.h
index 4756bee31..ed981df04 100644
--- a/include/hyperion/LedString.h
+++ b/include/hyperion/LedString.h
@@ -40,7 +40,6 @@ inline QString colorOrderToString(const ColorOrder colorOrder)
return "not-a-colororder";
}
}
-
inline ColorOrder stringToColorOrder(const QString & order)
{
if (order == "rgb")
diff --git a/include/leddevice/LedDevice.h b/include/leddevice/LedDevice.h
index fdc027361..30efd19a7 100644
--- a/include/leddevice/LedDevice.h
+++ b/include/leddevice/LedDevice.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef LEDEVICE_H
+#define LEDEVICE_H
// qt includes
#include
@@ -28,204 +29,397 @@ typedef LedDevice* ( *LedDeviceCreateFuncType ) ( const QJsonObject& );
typedef std::map LedDeviceRegistry;
///
-/// Interface (pure virtual base class) for LedDevices.
+/// @brief Interface (pure virtual base class) for LED-devices.
///
class LedDevice : public QObject
{
Q_OBJECT
public:
- LedDevice(const QJsonObject& config = QJsonObject(), QObject* parent = nullptr);
+
+ ///
+ /// @brief Constructs LED-device
+ ///
+ /// @param deviceConfig Device's configuration as JSON-Object
+ /// @param parent QT parent
+ ///
+ LedDevice(const QJsonObject& deviceConfig = QJsonObject(), QObject* parent = nullptr);
+
+ ///
+ /// @brief Destructor of the LED-device
+ ///
~LedDevice() override;
///
- /// @brief Get color order of device
+ /// @brief Get color order of device.
+ ///
/// @return The color order
///
const QString & getColorOrder() const { return _colorOrder; }
///
- /// @brief Set the current active ledDevice type
+ /// @brief Set the current active LED-device type.
///
/// @param deviceType Device's type
///
void setActiveDeviceType(const QString& deviceType);
///
- /// @brief Get the current active ledDevice type
+ /// @brief Get the current active LED-device type.
///
const QString & getActiveDeviceType() const { return _activeDeviceType; }
+ ///
+ /// @brief Set the number of LEDs supported by the device.
+ ///
+ /// @param[in] ledCount Number of device LEDs
+ ///
void setLedCount(unsigned int ledCount);
+
+ ///
+ /// @brief Get the number of LEDs supported by the device.
+ ///
+ /// @return Number of device's LEDs
+ ///
unsigned int getLedCount() const { return _ledCount; }
- bool enabled() const { return _enabled; }
+ ///
+ /// @brief Check, if the device is enabled.
+ ///
+ /// @return True, if enabled
+ ///
+ bool isEnabled() const { return _isEnabled; }
+
+ ///
+ /// @brief Set a device's latch time.
+ ///
+ /// Latch time is the time-frame a device requires until the next update can be processed.
+ /// During that time-frame any updates done via updateLeds are skipped.
+ ///
+ /// @param[in] latchTime_ms Latch time in milliseconds
+ ///
+ void setLatchTime(int latchTime_ms);
+ ///
+ /// @brief Get the currently defined LatchTime.
+ ///
+ /// @return Latch time in milliseconds
+ ///
int getLatchTime() const { return _latchTime_ms; }
- void setLatchTime( int latchTime_ms );
///
- /// Check, if device is ready to be used
- /// i.e. initialisation and configuration were successfull
+ /// @brief Discover devices of this type available (for configuration).
+ /// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
///
- /// @return True if device is ready
+ /// @return A JSON structure holding a list of devices found
///
- bool isReady() const { return _deviceReady; }
+ virtual QJsonObject discover();
///
- /// Check, if device is in error state
+ /// @brief Discover first device of this type available (for configuration).
+ /// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
///
- /// @return True if device is in error
+ /// @return A string of the device found
///
- bool isInError() const { return _deviceInError; }
+ virtual QString discoverFirst();
- inline bool componentState() const { return enabled(); }
+ ///
+ /// @brief Get the device's properties
+ ///
+ /// Used in context of a set of devices of the same type.
+ ///
+ /// @param[in] params Parameters to address device
+ /// @return A JSON structure holding the device's properties
+ ///
+ virtual QJsonObject getProperties(const QJsonObject& params);
- /// Prints the RGB-Color values to stdout.
///
- /// @param[in] ledValues The RGB-color per led
+ /// @brief Send an update to the device to identify it.
///
- static void printLedValues (const std::vector& ledValues );
+ /// Used in context of a set of devices of the same type.
+ ///
+ /// @param[in] params Parameters to address device
+ ///
+ virtual void identify(const QJsonObject& params) {}
+
+ ///
+ /// @brief Check, if device is properly initialised
+ ///
+ /// i.e. initialisation and configuration were successful.
+ ///
+ /// @return True, if device is initialised
+ ///
+ bool isInitialised() const { return _isDeviceInitialised; }
+ ///
+ /// @brief Check, if device is ready to be used.
+ ///
+ /// i.e. initialisation and opening were successful.
+ ///
+ /// @return True, if device is ready
+ ///
+ bool isReady() const { return _isDeviceReady; }
+
+ ///
+ /// @brief Check, if device is in error state.
+ ///
+ /// @return True, if device is in error
+ ///
+ bool isInError() const { return _isDeviceInError; }
+
+ ///
+ /// @brief Get the LED-Device component's state.
+ ///
+ /// @return True, if enabled
+ ///
+ inline bool componentState() const { return isEnabled(); }
+
+ ///
+ /// @brief Prints the color values to stdout.
+ ///
+ /// @param[in] ledValues The color per led
+ ///
+ static void printLedValues(const std::vector& ledValues);
public slots:
+
///
- /// Is called on thread start, all construction tasks and init should run here
+ /// @brief Is called on thread start, all construction tasks and init should run here.
///
- virtual void start() { _deviceReady = (open() == 0); }
+ virtual void start();
///
- /// Update the RGB-Color values to the leds.
- /// Handles refreshing of leds.
+ /// @brief Stops the device.
///
- /// @param[in] ledValues The RGB-color per led
- /// @return Zero on success else negative (i.e. device is not ready)
+ /// Includes switching-off the device and stopping refreshes.
///
- virtual int updateLeds(const std::vector& ledValues);
+ virtual void stop();
///
- /// Closes the output device.
- /// Includes switching-off the device and stopping refreshes
+ /// @brief Update the color values of the device's LEDs.
+ ///
+ /// Handles refreshing of LEDs.
+ ///
+ /// @param[in] ledValues The color per LED
+ /// @return Zero on success else negative (i.e. device is not ready)
///
- virtual void close();
+ virtual int updateLeds(const std::vector& ledValues);
///
- /// Enables/disables the device for output.
- /// If the device is not ready, it will not be enabled
+ /// @brief Enables/disables the device for output.
+ ///
+ /// If the device is not ready, it will not be enabled.
///
- /// @param enable The new state of the device
+ /// @param[in] enable The new state of the device
///
- void setEnable(bool enable); ///
+ void setEnable(bool enable);
signals:
///
- /// Emits whenever the led device switches between on/off
- /// @param newState The new state of the device
+ /// @brief Emits whenever the LED-Device switches between on/off.
+ ///
+ /// @param[in] newState The new state of the device
///
void enableStateChanged(bool newState);
protected:
///
- /// Initialise a device's configuration
+ /// @brief Initialise the device's configuration.
///
- /// @param deviceConfig the json device config
- /// @return True if success
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
///
virtual bool init(const QJsonObject &deviceConfig);
///
- /// Opens and initiatialises the output device
+ /// @brief Opens the output device.
///
- /// @return Zero on succes (i.e. device is ready and enabled) else negative
+ /// @return Zero, on success (i.e. device is ready), else negative
///
virtual int open();
///
- /// Writes the RGB-Color values to the leds.
+ /// @brief Closes the output device.
///
- /// @param[in] ledValues The RGB-color per led
+ /// @return Zero on success (i.e. device is closed), else negative
///
- /// @return Zero on success else negative
+ virtual int close();
+
+ ///
+ /// @brief Writes the RGB-Color values to the LEDs.
+ ///
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
///
virtual int write(const std::vector& ledValues) = 0;
///
- /// Writes "BLACK" to the output stream
+ /// @brief Writes "BLACK" to the output stream,
+ /// even if the device is not in enabled state (allowing to have a defined state during device power-off).
+ /// @note: latch-time is considered between each write
///
+ /// @param[in] numberOfWrites Write Black given number of times
/// @return Zero on success else negative
///
- virtual int writeBlack();
+ virtual int writeBlack(int numberOfBlack=1);
+
+ ///
+ /// @brief Switch the LEDs on.
+ ///
+ /// Takes care that the device is opened and powered-on.
+ /// Depending on the configuration, the device may store its current state for later restore.
+ /// @see powerOn, storeState
+ ///
+ /// @return True, if success
+ ///
+ virtual bool switchOn();
+
+ ///
+ /// @brief Switch the LEDs off.
+ ///
+ /// Takes care that the LEDs and device are switched-off and device is closed.
+ /// Depending on the configuration, the device may be powered-off or restored to its previous state.
+ /// @see powerOff, restoreState
+ ///
+ /// @return True, if success
+ ///
+ virtual bool switchOff();
+
+ ///
+ /// @brief Power-/turn on the LED-device.
+ ///
+ /// Powers-/Turns on the LED hardware, if supported.
+ ///
+ /// @return True, if success
+ ///
+ virtual bool powerOn();
- // Helper to pipe device config from constructor to start()
+ ///
+ /// @brief Power-/turn off the LED-device.
+ ///
+ /// Depending on the device's capability, the device is powered-/turned off or
+ /// an off state is simulated by writing "Black to LED" (default).
+ ///
+ /// @return True, if success
+ ///
+ virtual bool powerOff();
+
+ ///
+ /// @brief Store the device's original state.
+ ///
+ /// Save the device's state before hyperion color streaming starts allowing to restore state during switchOff().
+ ///
+ /// @return True, if success
+ ///
+ virtual bool storeState();
+
+ ///
+ /// @brief Restore the device's original state.
+ ///
+ /// Restore the device's state as before hyperion color streaming started.
+ /// This includes the on/off state of the device.
+ ///
+ /// @return True, if success
+ ///
+ virtual bool restoreState();
+
+ ///
+ /// @brief Converts an uint8_t array to hex string.
+ ///
+ /// @param data uint8_t array
+ /// @param size of the array
+ /// @param number Number of array items to be converted.
+ /// @return array as string of hex values
+ QString uint8_t_to_hex_string(const uint8_t * data, const qint64 size, qint64 number = -1) const;
+
+ /// Current device's type
+ QString _activeDeviceType;
+
+ /// Helper to pipe device configuration from constructor to start()
QJsonObject _devConfig;
- /// The common Logger instance for all LedDevices
+ /// The common Logger instance for all LED-devices
Logger * _log;
/// The buffer containing the packed RGB values
std::vector _ledBuffer;
- bool _deviceReady;
- bool _deviceInError;
+ /// Timer object which makes sure that LED data is written at a minimum rate
+ /// e.g. some devices will switch off when they do not receive data at least every 15 seconds
+ QTimer* _refreshTimer;
- QString _activeDeviceType;
+ // Device configuration parameters
+ /// Number of hardware LEDs supported by device.
unsigned int _ledCount;
unsigned int _ledRGBCount;
unsigned int _ledRGBWCount;
- /// Timer object which makes sure that led data is written at a minimum rate
- /// e.g. Adalight device will switch off when it does not receive data at least every 15 seconds
- QTimer* _refresh_timer;
- int _refresh_timer_interval;
+ /// Refresh interval in milliseconds
+ int _refreshTimerInterval_ms;
+
+ /// Time a device requires mandatorily between two writes (in milliseconds)
+ int _latchTime_ms;
+
+ /// Does the device allow restoring the original state?
+ bool _isRestoreOrigState;
+
+ /// Device, lights state before streaming via hyperion
+ QJsonObject _orignalStateValues;
+
+ // Device states
+ /// Is the device enabled?
+ bool _isEnabled;
+
+ /// Is the device initialised?
+ bool _isDeviceInitialised;
+
+ /// Is the device ready for processing?
+ bool _isDeviceReady;
+
+ /// Is the device in error state and stopped?
+ bool _isDeviceInError;
+
+ /// Is the device in the switchOff process?
+ bool _isInSwitchOff;
/// Timestamp of last write
QDateTime _lastWriteTime;
- /// Time a device requires mandatorily between two writes
- int _latchTime_ms;
-
protected slots:
- /// Write the last data to the leds again
///
- /// @return Zero on success else negative
+ /// @brief Write the last data to the LEDs again.
///
- int rewriteLeds();
-
- /// Switch the leds off
- /// Writes "Black to LED" or may switch-off the LED hardware, if supported
+ /// @return Zero on success else negative
///
- virtual int switchOff();
+ int rewriteLEDs();
- /// Switch the leds on
- /// May switch-on the LED hardware, if supported
///
- virtual int switchOn();
-
- /// Set device in error state
+ /// @brief Set device in error state
///
- /// @param errorMsg The error message to be logged
+ /// @param[in] errorMsg The error message to be logged
///
- virtual void setInError( const QString& errorMsg);
+ virtual void setInError( const QString& errorMsg);
private:
- /// Start new refresh cycle
- ///
+ /// @brief Start a new refresh cycle
void startRefreshTimer();
- /// Stop refresh cycle
- ///
+ /// @brief Stop refresh cycle
void stopRefreshTimer();
+ /// Is last write refreshing enabled?
+ bool _isRefreshEnabled;
- bool _componentRegistered;
- bool _enabled;
- bool _refresh_enabled;
+ /// Order of Colors supported by the device
+ /// "RGB", "BGR", "RBG", "BRG", "GBR", "GRB"
QString _colorOrder;
/// Last LED values written
- std::vector _last_ledValues;
+ std::vector _lastLedValues;
};
+
+#endif // LEDEVICE_H
diff --git a/include/leddevice/LedDeviceFactory.h b/include/leddevice/LedDeviceFactory.h
index 5a26a8ed2..ea7be2926 100644
--- a/include/leddevice/LedDeviceFactory.h
+++ b/include/leddevice/LedDeviceFactory.h
@@ -1,7 +1,7 @@
+#ifndef LEDEVICEFACTORY_H
+#define LEDEVICEFACTORY_H
-#pragma once
-
-// Leddevice includes
+// LedDevice includes
#include
///
@@ -17,7 +17,9 @@ class LedDeviceFactory
/// @param deviceConfig The configuration of the led-device
///
/// @return The constructed LedDevice or nullptr if configuration is invalid. The ownership of
- /// the constructed LedDevice is tranferred to the caller
+ /// the constructed LedDevice is transferred to the caller
///
static LedDevice * construct(const QJsonObject & deviceConfig);
};
+
+#endif // LEDEVICEFACTORY_H
diff --git a/include/leddevice/LedDeviceWrapper.h b/include/leddevice/LedDeviceWrapper.h
index ec3743b62..585a9c9ce 100644
--- a/include/leddevice/LedDeviceWrapper.h
+++ b/include/leddevice/LedDeviceWrapper.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef LEDEVICEWRAPPER_H
+#define LEDEVICEWRAPPER_H
// util
#include
@@ -19,10 +20,10 @@ class LedDeviceWrapper : public QObject
Q_OBJECT
public:
explicit LedDeviceWrapper(Hyperion* hyperion);
- ~LedDeviceWrapper() override;
+ ~LedDeviceWrapper();
///
- /// @brief Contructs a new LedDevice, moves to thread and starts
- /// @param config With the given config
+ /// @brief Constructs a new LedDevice, moves to thread and starts
+ /// @param config With the given configuration
///
void createLedDevice(const QJsonObject& config);
@@ -33,19 +34,19 @@ class LedDeviceWrapper : public QObject
static const QJsonObject getLedDeviceSchemas();
///
- /// @brief add all device constrcutors to the map
+ /// @brief add all device constructors to the map
///
static int addToDeviceMap(QString name, LedDeviceCreateFuncType funcPtr);
///
- /// @brief Return all available device contructors
- /// @return device constrcutors
+ /// @brief Return all available device constructors
+ /// @return device constructors
///
static const LedDeviceRegistry& getDeviceMap();
///
- /// @brief Get the current latchtime of the ledDevice
- /// @ return latchtime in ms
+ /// @brief Get the current latch time of the ledDevice
+ /// @ return latch time in ms
///
int getLatchTime();
@@ -57,7 +58,7 @@ class LedDeviceWrapper : public QObject
///
/// @brief Return the last enable state
///
- const bool & enabled() { return _enabled; }
+ bool enabled();
///
/// @brief Get the current colorOrder from device
@@ -65,14 +66,14 @@ class LedDeviceWrapper : public QObject
const QString & getColorOrder();
///
- /// @brief Get the number of Leds from device
+ /// @brief Get the number of LEDs from device
///
unsigned int getLedCount() const;
public slots:
///
/// @brief Handle new component state request
- /// @apram component The comp from enum
+ /// @param component The comp from enum
/// @param state The new state
///
void handleComponentState(const hyperion::Components component, const bool state);
@@ -100,13 +101,13 @@ private slots:
protected:
- /// contains all available led device constrcutors
+ /// contains all available led device constructors
static LedDeviceRegistry _ledDeviceMap;
private:
///
/// @brief switchOff() the device and Stops the device thread
- ///
+ ///
void stopDeviceThread();
private:
@@ -117,3 +118,5 @@ private slots:
// the enable state
bool _enabled;
};
+
+#endif // LEDEVICEWRAPPER_H
diff --git a/include/protoserver/ProtoServer.h b/include/protoserver/ProtoServer.h
index 0e18181ef..179bebab9 100644
--- a/include/protoserver/ProtoServer.h
+++ b/include/protoserver/ProtoServer.h
@@ -22,7 +22,7 @@ class ProtoServer : public QObject
public:
ProtoServer(const QJsonDocument& config, QObject* parent = nullptr);
- ~ProtoServer() override;
+ ~ProtoServer();
public slots:
///
diff --git a/include/ssdp/SSDPDiscover.h b/include/ssdp/SSDPDiscover.h
index e149a0e57..ba3adc4ba 100644
--- a/include/ssdp/SSDPDiscover.h
+++ b/include/ssdp/SSDPDiscover.h
@@ -1,7 +1,12 @@
-#pragma once
+#ifndef SSDPDISCOVER_H
+#define SSDPDISCOVER_H
#include
#include
+#include
+#include
+
+#include
class QUdpSocket;
@@ -11,6 +16,23 @@ enum class searchType{
STY_JSONSERVER
};
+struct SSDPService {
+ QString cacheControl;
+ QUrl location;
+ QString server;
+ QString searchTarget;
+ QString uniqueServiceName;
+ QMap otherHeaders;
+};
+
+// Default values
+static const char DEFAULT_SEARCH_ADDRESS[] = "239.255.255.250";
+static const int DEFAULT_SEARCH_PORT = 1900;
+static const char DEFAULT_FILTER[] = ".*";
+static const char DEFAULT_FILTER_HEADER[] = "ST";
+
+constexpr std::chrono::milliseconds DEFAULT_SSDP_TIMEOUT{5000}; // timeout in ms
+
///
/// @brief Search for SSDP sessions, used by stand-alone capture binaries
///
@@ -37,6 +59,120 @@ class SSDPDiscover : public QObject
///
const QString getFirstService(const searchType &type = searchType::STY_WEBSERVER,const QString &st = "urn:hyperion-project.org:device:basic:1", const int &timeout_ms = 3000);
+ ///
+ /// @brief Discover services via ssdp.
+ ///
+ /// Records meeting the search target and filter criteria ( setSearchFilter() ) are stored in a map using the given element as a key.
+ ///
+ /// The search result can be accessed via getServicesDiscoveredJson() or getServicesDiscovered()
+ ///
+ /// Usage sample:
+ /// @code
+ ///
+ /// SSDPDiscover discover;
+ ///
+ /// discover.skipDuplicateKeys(true);
+ /// QString searchTargetFilter = "(.*)IpBridge(.*)";
+ /// discover.setSearchFilter(searchTargetFilter, "SERVER");
+ /// QString searchTarget = "upnp:rootdevice";
+ ///
+ /// if ( discover.discoverServices(searchTarget) > 0 )
+ /// deviceList = discover.getServicesDiscoveredJson();
+ ///
+ ///@endcode
+ ///
+ /// @param[in] searchTarget The ssdp discovery search target (ST)
+ /// @param[in] key Element used as key for the result map
+ ///
+ /// @return Number of service records found (meeting the search & filter criteria)
+ ///
+ int discoverServices(const QString &searchTarget="ssdp:all", const QString &key="LOCATION");
+
+ ///
+ /// @brief Get services discovered during discoverServices()
+ ///
+ /// @return Map of discovered services
+ ///
+ const QMap getServicesDiscovered () { return _services; }
+
+ ///
+ /// @brief Get services discovered during discoverServices().
+ ///
+ /// Hostname and domain are resolved from IP-address and stored in extra elements
+ ///
+ /// Sample result:
+ /// @code
+ ///
+ /// [{
+ /// "cache-control": "max-age=100",
+ /// "domain": "fritz.box",
+ /// "hostname": "ubuntu1910",
+ /// "id": "http://192.168.2.152:8081/description.xml",
+ /// "ip": "192.168.2.152",
+ /// "location": "http://192.168.2.152:8081/description.xml",
+ /// "other": { "ext": "", "host": "239.255.255.250:1900", "hue-bridgeid": "000C29FFFED8D52D"},
+ /// "port": 8081,
+ /// "server": "Linux/3.14.0 UPnP/1.0 IpBridge/1.19.0",
+ /// "st": "upnp:rootdevice",
+ /// "usn": "uuid:2f402f80-da50-11e1-9b23-000c29d8d52d::upnp:rootdevice"
+ /// }]
+ ///
+ ///@endcode
+ ///
+ /// @return Discovered services as JSON-document
+ ///
+ QJsonArray getServicesDiscoveredJson();
+
+ ///
+ /// @brief Set the ssdp discovery address (HOST)
+ ///
+ /// @param[in] IP-address used during discovery
+ ///
+ void setAddress ( const QString &address) { _ssdpAddr = QHostAddress(address); }
+
+ ///
+ /// @brief Set the ssdp discovery port (HOST)
+ ///
+ /// @param[in] port used during discovery
+ ///
+ void setPort ( quint16 port) { _ssdpPort = port; }
+
+ ///
+ /// @brief Set the ssdp discovery max wait time (MX)
+ ///
+ /// @param[in] maxWaitResponseTime
+ ///
+ void setMaxWaitResponseTime ( int maxWaitResponseTime) { _ssdpMaxWaitResponseTime = maxWaitResponseTime; }
+
+ ///
+ /// @brief Set the ssdp discovery search target (ST)
+ ///
+ /// @param[in] searchTarget
+ ///
+ void setSearchTarget ( const QString &searchTarget) { _searchTarget = searchTarget; }
+
+ ///
+ /// @brief Set the ssdp discovery search target filter
+ ///
+ /// @param[in] filter as regular expression
+ /// @param[in] filterHeader Header element the filter is applied to
+ ///
+ /// @return True, if valid regular expression
+ ///
+ bool setSearchFilter ( const QString &filter=DEFAULT_FILTER, const QString &filterHeader="ST");
+
+ ///
+ /// @brief Set the ssdp discovery search target and filter to default values
+ ///
+ void clearSearchFilter () { _filter=DEFAULT_FILTER; _filterHeader="ST"; }
+
+ ///
+ /// @brief Skip duplicate records with the same key-value
+ ///
+ /// @param[in] skip True: skip records with duplicate key-values, False: Allow duplicate key-values
+ ///
+ void skipDuplicateKeys( bool skip ) { _skipDupKeys = skip; }
+
signals:
///
/// @brief Emits whenever a new service has been found, search started with searchForService()
@@ -60,6 +196,21 @@ private slots:
Logger* _log;
QUdpSocket* _udpSocket;
- QString _searchTarget;
+ QHostAddress _ssdpAddr;
+ quint16 _ssdpPort;
+
+ int _ssdpMaxWaitResponseTime;
+ int _ssdpTimeout;
+
+ QMap _services;
+
QStringList _usnList;
+ QString _searchTarget;
+
+ QString _filter;
+ QString _filterHeader;
+ QRegularExpression _regExFilter;
+ bool _skipDupKeys;
};
+
+#endif // SSDPDISCOVER_H
diff --git a/include/ssdp/SSDPHandler.h b/include/ssdp/SSDPHandler.h
index 99fdbdfe5..9eacaccc1 100644
--- a/include/ssdp/SSDPHandler.h
+++ b/include/ssdp/SSDPHandler.h
@@ -24,7 +24,7 @@ class SSDPHandler : public SSDPServer{
///
/// @brief Sends BYE BYE and stop server
- ///
+ ///
void stopServer();
public slots:
@@ -50,23 +50,23 @@ public slots:
///
/// @brief Build http url for current ip:port/desc.xml
///
- QString getDescAddress() const;
+ const QString getDescAddress();
///
/// @brief Get the base address
///
- QString getBaseAddress() const;
+ const QString getBaseAddress();
///
/// @brief Build the ssdp description (description.xml)
///
- QString buildDesc() const;
+ const QString buildDesc();
///
/// @brief Get the local address of interface
/// @return the address, might be empty
///
- QString getLocalAddress() const;
+ const QString getLocalAddress();
///
/// @brief Send alive/byebye message based on _deviceList
diff --git a/include/utils/ColorArgb.h b/include/utils/ColorArgb.h
index 43c32a9e6..9b5bc3643 100644
--- a/include/utils/ColorArgb.h
+++ b/include/utils/ColorArgb.h
@@ -4,6 +4,8 @@
#include
#include
+struct ColorArgb;
+
struct ColorArgb
{
@@ -47,3 +49,4 @@ inline std::ostream& operator<<(std::ostream& os, const ColorArgb& color)
os << "{" << unsigned(color.alpha) << "," << unsigned(color.red) << "," << unsigned(color.green) << "," << unsigned(color.blue) << "}";
return os;
}
+
diff --git a/include/utils/ColorBgr.h b/include/utils/ColorBgr.h
index 5cc19bb71..bfe55ec5f 100644
--- a/include/utils/ColorBgr.h
+++ b/include/utils/ColorBgr.h
@@ -4,6 +4,8 @@
#include
#include
+struct ColorBgr;
+
///
/// Plain-Old-Data structure containing the red-green-blue color specification. Size of the
/// structure is exactly 3-bytes for easy writing to led-device
diff --git a/include/utils/ColorRgb.h b/include/utils/ColorRgb.h
index 0ec41c71b..8de27f2d9 100644
--- a/include/utils/ColorRgb.h
+++ b/include/utils/ColorRgb.h
@@ -6,6 +6,8 @@
#include
+struct ColorRgb;
+
///
/// Plain-Old-Data structure containing the red-green-blue color specification. Size of the
/// structure is exactly 3-bytes for easy writing to led-device
@@ -85,3 +87,4 @@ inline bool operator>=(const ColorRgb & lhs, const ColorRgb & rhs)
{
return (lhs.red >= rhs.red) && (lhs.green >= rhs.green) && (lhs.blue >= rhs.blue);
}
+
diff --git a/include/utils/ColorRgba.h b/include/utils/ColorRgba.h
index e02cc7962..67be78a84 100644
--- a/include/utils/ColorRgba.h
+++ b/include/utils/ColorRgba.h
@@ -4,6 +4,8 @@
#include
#include
+struct ColorRgba;
+
struct ColorRgba
{
@@ -47,3 +49,4 @@ inline std::ostream& operator<<(std::ostream& os, const ColorRgba& color)
os << "{" << unsigned(color.alpha) << "," << unsigned(color.red) << "," << unsigned(color.green) << "," << unsigned(color.blue) << "}";
return os;
}
+
diff --git a/include/utils/ColorRgbw.h b/include/utils/ColorRgbw.h
index 9316f94f8..a06c6d244 100644
--- a/include/utils/ColorRgbw.h
+++ b/include/utils/ColorRgbw.h
@@ -4,6 +4,8 @@
#include
#include
+struct ColorRgbw;
+
///
/// Plain-Old-Data structure containing the red-green-blue color specification. Size of the
/// structure is exactly 3-bytes for easy writing to led-device
diff --git a/include/utils/Components.h b/include/utils/Components.h
index ca70a2d62..8de20ac87 100644
--- a/include/utils/Components.h
+++ b/include/utils/Components.h
@@ -67,7 +67,7 @@ inline const char* componentToIdString(Components c)
}
}
-inline Components stringToComponent(QString component)
+inline Components stringToComponent(QString component)
{
component = component.toUpper();
if (component == "ALL") return COMP_ALL;
diff --git a/include/utils/FileUtils.h b/include/utils/FileUtils.h
index ee26f3d2f..d1e87f576 100644
--- a/include/utils/FileUtils.h
+++ b/include/utils/FileUtils.h
@@ -10,8 +10,8 @@
namespace FileUtils {
- QString getBaseName(QString sourceFile);
- QString getDirName(QString sourceFile);
+QString getBaseName(QString sourceFile);
+QString getDirName(QString sourceFile);
///
/// @brief remove directory recursive given by path
diff --git a/include/utils/GlobalSignals.h b/include/utils/GlobalSignals.h
index b5525c215..f89eaaf6f 100644
--- a/include/utils/GlobalSignals.h
+++ b/include/utils/GlobalSignals.h
@@ -21,7 +21,7 @@ class GlobalSignals : public QObject
return & instance;
}
private:
- GlobalSignals() = default;
+ GlobalSignals() {}
public:
GlobalSignals(GlobalSignals const&) = delete;
diff --git a/include/utils/Image.h b/include/utils/Image.h
index b500a2bb4..73ead228f 100644
--- a/include/utils/Image.h
+++ b/include/utils/Image.h
@@ -256,7 +256,6 @@ class Image
{
_width = 1;
_height = 1;
- delete[] _pixels;
_pixels = new Pixel_T[2];
_endOfPixels = _pixels + 1;
memset(_pixels, 0, (unsigned long) _width * _height * sizeof(Pixel_T));
diff --git a/include/utils/Profiler.h b/include/utils/Profiler.h
index 96aec7257..118c9aa69 100644
--- a/include/utils/Profiler.h
+++ b/include/utils/Profiler.h
@@ -21,7 +21,7 @@ For more profiler function see the macros listed below
*/
#ifndef ENABLE_PROFILER
- #error "Profiler is not for production code, enable it via cmake or remove header include"
+ #error "Profiler is not for productive code, enable it via cmake or remove header include"
#endif
// profiler
@@ -50,3 +50,4 @@ class Profiler
unsigned int _blockId;
clock_t _startTime;
};
+
diff --git a/include/utils/QStringUtils.h b/include/utils/QStringUtils.h
new file mode 100644
index 000000000..52d245c0e
--- /dev/null
+++ b/include/utils/QStringUtils.h
@@ -0,0 +1,42 @@
+#ifndef QSTRINGUTILS_H
+#define QSTRINGUTILS_H
+
+#include
+#include
+
+namespace QStringUtils {
+
+enum class SplitBehavior {
+ KeepEmptyParts,
+ SkipEmptyParts,
+};
+
+inline QStringList split (const QString &string, const QString &sep, SplitBehavior behavior = SplitBehavior::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive)
+{
+ #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
+ return behavior == SplitBehavior::SkipEmptyParts ? string.split(sep, Qt::SkipEmptyParts , cs) : string.split(sep, Qt::KeepEmptyParts , cs);
+ #else
+ return behavior == SplitBehavior::SkipEmptyParts ? string.split(sep, QString::SkipEmptyParts , cs) : string.split(sep, QString::KeepEmptyParts , cs);
+ #endif
+}
+
+inline QStringList split (const QString &string, QChar sep, SplitBehavior behavior = SplitBehavior::KeepEmptyParts, Qt::CaseSensitivity cs = Qt::CaseSensitive)
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
+ return behavior == SplitBehavior::SkipEmptyParts ? string.split(sep, Qt::SkipEmptyParts , cs) : string.split(sep, Qt::KeepEmptyParts , cs);
+#else
+ return behavior == SplitBehavior::SkipEmptyParts ? string.split(sep, QString::SkipEmptyParts , cs) : string.split(sep, QString::KeepEmptyParts , cs);
+#endif
+}
+
+inline QStringList split (const QString &string, const QRegExp &rx, SplitBehavior behavior = SplitBehavior::KeepEmptyParts)
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
+ return behavior == SplitBehavior::SkipEmptyParts ? string.split(rx, Qt::SkipEmptyParts) : string.split(rx, Qt::KeepEmptyParts);
+#else
+ return behavior == SplitBehavior::SkipEmptyParts ? string.split(rx, QString::SkipEmptyParts) : string.split(rx, QString::KeepEmptyParts);
+#endif
+}
+}
+
+#endif // QSTRINGUTILS_H
diff --git a/include/utils/RgbTransform.h b/include/utils/RgbTransform.h
index d4e4bfd1e..078a1cd2f 100644
--- a/include/utils/RgbTransform.h
+++ b/include/utils/RgbTransform.h
@@ -26,6 +26,11 @@ class RgbTransform
///
RgbTransform(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation);
+ ///
+ /// Destructor
+ ///
+ ~RgbTransform();
+
/// @return The current red gamma value
double getGammaR() const;
diff --git a/include/utils/SysInfo.h b/include/utils/SysInfo.h
index eb632e690..a4693fc9d 100644
--- a/include/utils/SysInfo.h
+++ b/include/utils/SysInfo.h
@@ -20,6 +20,7 @@ class SysInfo : public QObject
QString domainName;
};
+ ~SysInfo();
static HyperionSysInfo get();
private:
diff --git a/include/webserver/WebServer.h b/include/webserver/WebServer.h
index 3ad0d1173..98ef7a5ec 100644
--- a/include/webserver/WebServer.h
+++ b/include/webserver/WebServer.h
@@ -34,15 +34,15 @@ class WebServer : public QObject {
public:
WebServer (const QJsonDocument& config, const bool& useSsl, QObject * parent = 0);
- ~WebServer () override;
+ virtual ~WebServer (void);
void start();
void stop();
- quint16 getPort() const { return _port; }
+ quint16 getPort() { return _port; };
/// check if server has been inited
- bool isInited() const { return _inited; }
+ bool isInited() { return _inited; };
///
/// @brief Set a new description, if empty the description is NotFound for clients
diff --git a/libsrc/api/JSONRPC_schema/schema-leddevice.json b/libsrc/api/JSONRPC_schema/schema-leddevice.json
new file mode 100644
index 000000000..73da6c9e1
--- /dev/null
+++ b/libsrc/api/JSONRPC_schema/schema-leddevice.json
@@ -0,0 +1,28 @@
+{
+ "type":"object",
+ "required":true,
+ "properties":{
+ "command": {
+ "type" : "string",
+ "required" : true,
+ "enum" : ["leddevice"]
+ },
+ "tan" : {
+ "type" : "integer"
+ },
+ "subcommand": {
+ "type" : "string",
+ "required" : true,
+ "enum" : ["discover","getProperties","identify"]
+ },
+ "ledDeviceType": {
+ "type" : "string",
+ "required" : true
+ },
+ "params": {
+ "type" : "object",
+ "required" : false
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/libsrc/api/JSONRPC_schema/schema.json b/libsrc/api/JSONRPC_schema/schema.json
index 6cc245fa9..e13982feb 100644
--- a/libsrc/api/JSONRPC_schema/schema.json
+++ b/libsrc/api/JSONRPC_schema/schema.json
@@ -5,7 +5,7 @@
"command": {
"type" : "string",
"required" : true,
- "enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "transform", "correction" , "temperature"]
+ "enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "transform", "correction" , "temperature"]
}
}
}
diff --git a/libsrc/api/JSONRPC_schemas.qrc b/libsrc/api/JSONRPC_schemas.qrc
index 387d97dd3..2018684f9 100644
--- a/libsrc/api/JSONRPC_schemas.qrc
+++ b/libsrc/api/JSONRPC_schemas.qrc
@@ -20,6 +20,7 @@
JSONRPC_schema/schema-videomode.json
JSONRPC_schema/schema-authorize.json
JSONRPC_schema/schema-instance.json
+ JSONRPC_schema/schema-leddevice.json
JSONRPC_schema/schema-hyperion-classic.json
JSONRPC_schema/schema-hyperion-classic.json
diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp
index c9861aa69..9a767579c 100644
--- a/libsrc/api/JsonAPI.cpp
+++ b/libsrc/api/JsonAPI.cpp
@@ -18,6 +18,10 @@
// hyperion includes
#include
+
+#include
+#include
+
#include
#include
#include
@@ -192,6 +196,8 @@ void JsonAPI::handleMessage(const QString &messageString, const QString &httpAut
handleVideoModeCommand(message, command, tan);
else if (command == "instance")
handleInstanceCommand(message, command, tan);
+ else if (command == "leddevice")
+ handleLedDeviceCommand(message, command, tan);
// BEGIN | The following commands are derecated but used to ensure backward compatibility with hyperion Classic remote control
else if (command == "clearall")
@@ -1385,6 +1391,80 @@ void JsonAPI::handleInstanceCommand(const QJsonObject &message, const QString &c
}
}
+void JsonAPI::handleLedDeviceCommand(const QJsonObject &message, const QString &command, const int tan)
+{
+ Debug(_log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+
+ const QString &subc = message["subcommand"].toString().trimmed();
+ const QString &devType = message["ledDeviceType"].toString().trimmed();
+
+ QString full_command = command + "-" + subc;
+
+ // TODO: Validate that device type is a valid one
+/* if ( ! valid type )
+ {
+ sendErrorReply("Unknown device", full_command, tan);
+ }
+ else
+*/ {
+ if (subc == "discover")
+ {
+
+ QJsonObject config;
+ config.insert("type", devType);
+
+ // Pointer of current led device
+ LedDevice* _ledDevice;
+ _ledDevice = LedDeviceFactory::construct(config);
+
+ QJsonObject devicesDiscovered = _ledDevice->discover();
+
+ Debug(_log, "response: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ sendSuccessDataReply(QJsonDocument(devicesDiscovered), full_command, tan);
+
+ delete _ledDevice;
+ }
+ else if (subc == "getProperties")
+ {
+ const QJsonObject ¶ms = message["params"].toObject();
+
+ QJsonObject config;
+ config.insert("type", devType);
+
+ // Pointer of current led device
+ LedDevice* _ledDevice;
+ _ledDevice = LedDeviceFactory::construct(config);
+
+ QJsonObject deviceProperties = _ledDevice->getProperties(params);
+
+ Debug(_log, "response: [%s]", QString(QJsonDocument(deviceProperties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ sendSuccessDataReply(QJsonDocument(deviceProperties), full_command, tan);
+
+ delete _ledDevice;
+ }
+ else if (subc == "identify")
+ {
+ const QJsonObject ¶ms = message["params"].toObject();
+
+ QJsonObject config;
+ config.insert("type", devType);
+
+ // Pointer of current led device
+ LedDevice* _ledDevice;
+ _ledDevice = LedDeviceFactory::construct(config);
+
+ _ledDevice->identify(params);
+
+ sendSuccessReply(full_command, tan);
+ delete _ledDevice;
+ }
+ else
+ {
+ sendErrorReply("Unknown or missing subcommand", full_command, tan);
+ }
+ }
+}
+
void JsonAPI::handleNotImplemented()
{
sendErrorReply("Command not implemented");
@@ -1526,11 +1606,11 @@ void JsonAPI::handleTokenResponse(const bool &success, const QString &token, con
sendErrorReply("Token request timeout or denied", cmd, 5);
}
-void JsonAPI::handleInstanceStateChange(const InstanceState &state, const quint8 &instance, const QString &name)
+void JsonAPI::handleInstanceStateChange(const instanceState &state, const quint8 &instance, const QString &name)
{
switch (state)
{
- case InstanceState::H_ON_STOP:
+ case H_ON_STOP:
if (_hyperion->getInstanceIndex() == instance)
{
handleInstanceSwitch();
diff --git a/libsrc/api/JsonCB.cpp b/libsrc/api/JsonCB.cpp
index 5289b6c48..47b01c324 100644
--- a/libsrc/api/JsonCB.cpp
+++ b/libsrc/api/JsonCB.cpp
@@ -223,7 +223,7 @@ void JsonCB::handlePriorityUpdate()
activePriorities.removeAll(255);
int currentPriority = _prioMuxer->getCurrentPriority();
- for (int priority : activePriorities) {
+ foreach (int priority, activePriorities) {
const Hyperion::InputInfo priorityInfo = _prioMuxer->getInputInfo(priority);
QJsonObject item;
item["priority"] = priority;
diff --git a/libsrc/boblightserver/BoblightClientConnection.cpp b/libsrc/boblightserver/BoblightClientConnection.cpp
index 0336f34f5..cb1d70408 100644
--- a/libsrc/boblightserver/BoblightClientConnection.cpp
+++ b/libsrc/boblightserver/BoblightClientConnection.cpp
@@ -18,6 +18,7 @@
#include
#include "HyperionConfig.h"
#include
+#include
// project includes
#include "BoblightClientConnection.h"
@@ -81,7 +82,7 @@ void BoblightClientConnection::readData()
void BoblightClientConnection::socketClosed()
{
// clear the current channel
- if (_priority != 0 && _priority >= 128 && _priority < 254)
+ if (_priority >= 128 && _priority < 254)
_hyperion->clear(_priority);
emit connectionClosed(this);
@@ -90,12 +91,7 @@ void BoblightClientConnection::socketClosed()
void BoblightClientConnection::handleMessage(const QString & message)
{
//std::cout << "boblight message: " << message.toStdString() << std::endl;
- #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
- QStringList messageParts = message.split(" ", Qt::SkipEmptyParts);
- #else
- QStringList messageParts = message.split(" ", QString::SkipEmptyParts);
- #endif
-
+ QStringList messageParts = QStringUtils::split(message," ",QStringUtils::SplitBehavior::SkipEmptyParts);
if (messageParts.size() > 0)
{
if (messageParts[0] == "hello")
@@ -217,7 +213,7 @@ void BoblightClientConnection::handleMessage(const QString & message)
}
else if (messageParts[0] == "sync")
{
- if (_priority != 0 && _priority >= 128 && _priority < 254)
+ if ( _priority >= 128 && _priority < 254)
_hyperion->setInput(_priority, _ledColors); // send current color values to hyperion
return;
diff --git a/libsrc/boblightserver/BoblightClientConnection.h b/libsrc/boblightserver/BoblightClientConnection.h
index 6b6d8cd93..a2ab4cc06 100644
--- a/libsrc/boblightserver/BoblightClientConnection.h
+++ b/libsrc/boblightserver/BoblightClientConnection.h
@@ -30,7 +30,7 @@ class BoblightClientConnection : public QObject
///
/// Destructor
///
- ~BoblightClientConnection() override;
+ ~BoblightClientConnection();
signals:
///
diff --git a/libsrc/boblightserver/BoblightServer.cpp b/libsrc/boblightserver/BoblightServer.cpp
index 1db0036c1..bd7a65eda 100644
--- a/libsrc/boblightserver/BoblightServer.cpp
+++ b/libsrc/boblightserver/BoblightServer.cpp
@@ -59,8 +59,9 @@ void BoblightServer::stop()
if ( ! _server->isListening() )
return;
- qDeleteAll(_openConnections);
-
+ foreach (BoblightClientConnection * connection, _openConnections) {
+ delete connection;
+ }
_server->close();
Info(_log, "Stopped");
diff --git a/libsrc/bonjour/bonjourbrowserwrapper.cpp b/libsrc/bonjour/bonjourbrowserwrapper.cpp
index df13b950c..8b8c8a67a 100644
--- a/libsrc/bonjour/bonjourbrowserwrapper.cpp
+++ b/libsrc/bonjour/bonjourbrowserwrapper.cpp
@@ -12,7 +12,7 @@ BonjourBrowserWrapper* BonjourBrowserWrapper::instance = nullptr;
BonjourBrowserWrapper::BonjourBrowserWrapper(QObject * parent)
: QObject(parent)
, _bonjourResolver(new BonjourServiceResolver(this))
- , _timerBonjourResolver(new QTimer(this))
+ , _timerBonjourResolver( new QTimer(this))
{
// register meta
qRegisterMetaType>("QMap");
diff --git a/libsrc/commandline/ColorsOption.cpp b/libsrc/commandline/ColorsOption.cpp
index 7caa5f28d..f32cfed8a 100644
--- a/libsrc/commandline/ColorsOption.cpp
+++ b/libsrc/commandline/ColorsOption.cpp
@@ -22,7 +22,7 @@ bool ColorsOption::validate(Parser & parser, QString & value)
QRegularExpressionMatch match = hexRe.match(value);
if(match.hasMatch())
{
- for(const QString m : match.capturedTexts())
+ Q_FOREACH(const QString m, match.capturedTexts())
{
_colors.push_back(QColor(QString("#%1").arg(m)));
}
diff --git a/libsrc/commandline/Parser.cpp b/libsrc/commandline/Parser.cpp
index 84efea45d..e90fd429e 100644
--- a/libsrc/commandline/Parser.cpp
+++ b/libsrc/commandline/Parser.cpp
@@ -4,11 +4,6 @@
using namespace commandline;
-Parser::~Parser()
-{
- qDeleteAll(_options);
-}
-
bool Parser::parse(const QStringList &arguments)
{
if (!_parser.parse(arguments))
@@ -16,7 +11,7 @@ bool Parser::parse(const QStringList &arguments)
return false;
}
- for(Option * option : _options)
+ Q_FOREACH(Option * option, _options)
{
QString value = this->value(*option);
if (!option->validate(*this, value)) {
diff --git a/libsrc/effectengine/EffectEngine.cpp b/libsrc/effectengine/EffectEngine.cpp
index 0ce5c8392..d7b10b6e8 100644
--- a/libsrc/effectengine/EffectEngine.cpp
+++ b/libsrc/effectengine/EffectEngine.cpp
@@ -28,6 +28,7 @@ EffectEngine::EffectEngine(Hyperion * hyperion)
, _log(Logger::getInstance("EFFECTENGINE"))
, _effectFileHandler(EffectFileHandler::getInstance())
{
+
Q_INIT_RESOURCE(EffectEngine);
qRegisterMetaType("hyperion::Components");
diff --git a/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp b/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp
index 26fea04c2..e5c1ab46e 100644
--- a/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp
+++ b/libsrc/grabber/framebuffer/FramebufferFrameGrabber.cpp
@@ -5,7 +5,6 @@
#include
#include
#include
-#include
// STL includes
#include
@@ -15,11 +14,17 @@
FramebufferFrameGrabber::FramebufferFrameGrabber(const QString & device, const unsigned width, const unsigned height)
: Grabber("FRAMEBUFFERGRABBER", width, height)
+ , _fbfd(0)
+ , _fbp(0)
, _fbDevice()
{
setDevicePath(device);
}
+FramebufferFrameGrabber::~FramebufferFrameGrabber()
+{
+}
+
int FramebufferFrameGrabber::grabFrame(Image & image)
{
if (!_enabled) return 0;
@@ -29,15 +34,10 @@ int FramebufferFrameGrabber::grabFrame(Image & image)
PixelFormat pixelFormat;
/* Open the framebuffer device */
- int fbfd = open(QSTRING_CSTR(_fbDevice), O_RDONLY);
- if (fbfd == -1)
- {
- Error(_log, "Error opening %s, %s : ", QSTRING_CSTR(_fbDevice), std::strerror(errno));
- return -1;
- }
+ _fbfd = open(QSTRING_CSTR(_fbDevice), O_RDONLY);
/* get variable screen information */
- ioctl (fbfd, FBIOGET_VSCREENINFO, &vinfo);
+ ioctl (_fbfd, FBIOGET_VSCREENINFO, &vinfo);
bytesPerPixel = vinfo.bits_per_pixel / 8;
capSize = vinfo.xres * vinfo.yres * bytesPerPixel;
@@ -53,28 +53,24 @@ int FramebufferFrameGrabber::grabFrame(Image & image)
#endif
default:
Error(_log, "Unknown pixel format: %d bits per pixel", vinfo.bits_per_pixel);
- close(fbfd);
+ close(_fbfd);
return -1;
}
/* map the device to memory */
- unsigned char * fbp = (unsigned char*)mmap(0, capSize, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fbfd, 0);
- if (fbp == MAP_FAILED) {
- Error(_log, "Error mapping %s, %s : ", QSTRING_CSTR(_fbDevice), std::strerror(errno));
- return -1;
- }
+ _fbp = (unsigned char*)mmap(0, capSize, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, _fbfd, 0);
_imageResampler.setHorizontalPixelDecimation(vinfo.xres/_width);
_imageResampler.setVerticalPixelDecimation(vinfo.yres/_height);
- _imageResampler.processImage(fbp,
+ _imageResampler.processImage(_fbp,
vinfo.xres,
vinfo.yres,
vinfo.xres * bytesPerPixel,
pixelFormat,
image);
- munmap(fbp, capSize);
- close(fbfd);
+ munmap(_fbp, capSize);
+ close(_fbfd);
return 0;
}
@@ -88,24 +84,25 @@ void FramebufferFrameGrabber::setDevicePath(const QString& path)
struct fb_var_screeninfo vinfo;
// Check if the framebuffer device can be opened and display the current resolution
- int fbfd = open(QSTRING_CSTR(_fbDevice), O_RDONLY);
- if (fbfd == -1)
+ _fbfd = open(QSTRING_CSTR(_fbDevice), O_RDONLY);
+ if (_fbfd == 0)
{
- Error(_log, "Error opening %s, %s : ", QSTRING_CSTR(_fbDevice), std::strerror(errno));
+ Error(_log, "Error openning %s", QSTRING_CSTR(_fbDevice));
}
else
{
// get variable screen information
- result = ioctl (fbfd, FBIOGET_VSCREENINFO, &vinfo);
+ result = ioctl (_fbfd, FBIOGET_VSCREENINFO, &vinfo);
if (result != 0)
{
- Error(_log, "Could not get screen information, %s", std::strerror(errno));
+ Error(_log, "Could not get screen information");
}
else
{
Info(_log, "Display opened with resolution: %dx%d@%dbit", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
}
- close(fbfd);
+ close(_fbfd);
}
+
}
}
diff --git a/libsrc/grabber/v4l2/V4L2Grabber.cpp b/libsrc/grabber/v4l2/V4L2Grabber.cpp
index 6168f8246..164e71736 100644
--- a/libsrc/grabber/v4l2/V4L2Grabber.cpp
+++ b/libsrc/grabber/v4l2/V4L2Grabber.cpp
@@ -95,7 +95,7 @@ bool V4L2Grabber::init()
QString v4lDevices_str;
// show list only once
- if (!_deviceName.startsWith("/dev/"))
+ if (!QString(QSTRING_CSTR(_deviceName)).startsWith("/dev/"))
{
for (auto& dev: _v4lDevices)
{
@@ -369,8 +369,11 @@ void V4L2Grabber::close_device()
_fileDescriptor = -1;
- delete _streamNotifier;
- _streamNotifier = nullptr;
+ if (_streamNotifier != nullptr)
+ {
+ delete _streamNotifier;
+ _streamNotifier = nullptr;
+ }
}
void V4L2Grabber::init_read(unsigned int buffer_size)
diff --git a/libsrc/grabber/x11/CMakeLists.txt b/libsrc/grabber/x11/CMakeLists.txt
index 06dcf6d53..4d5914e59 100644
--- a/libsrc/grabber/x11/CMakeLists.txt
+++ b/libsrc/grabber/x11/CMakeLists.txt
@@ -4,7 +4,6 @@ SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/x11)
# Find X11
find_package(X11 REQUIRED)
-find_package(Qt5Widgets REQUIRED)
include_directories( ${X11_INCLUDES} )
@@ -19,7 +18,5 @@ add_library(x11-grabber ${X11_SOURCES} )
target_link_libraries(x11-grabber
hyperion
${X11_LIBRARIES}
- ${X11_Xrandr_LIB}
${X11_Xrender_LIB}
- Qt5::Widgets
)
diff --git a/libsrc/grabber/x11/X11Grabber.cpp b/libsrc/grabber/x11/X11Grabber.cpp
index 130c9ed9c..855ea4c0f 100644
--- a/libsrc/grabber/x11/X11Grabber.cpp
+++ b/libsrc/grabber/x11/X11Grabber.cpp
@@ -1,9 +1,6 @@
#include
#include
-#include
-#include
-
X11Grabber::X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int pixelDecimation)
: Grabber("X11GRABBER", 0, 0, cropLeft, cropRight, cropTop, cropBottom)
, _x11Display(nullptr)
@@ -38,10 +35,6 @@ void X11Grabber::freeResources()
{
// Cleanup allocated resources of the X11 grab
XDestroyImage(_xImage);
- if (_XRandRAvailable)
- {
- qApp->removeNativeEventFilter(this);
- }
if(_XShmAvailable)
{
XShmDetach(_x11Display, &_shminfo);
@@ -58,11 +51,6 @@ void X11Grabber::freeResources()
void X11Grabber::setupResources()
{
- if (_XRandRAvailable)
- {
- qApp->installNativeEventFilter(this);
- }
-
if(_XShmAvailable)
{
_xImage = XShmCreateImage(_x11Display, _windowAttr.visual, _windowAttr.depth, ZPixmap, NULL, &_shminfo, _width, _height);
@@ -111,7 +99,6 @@ bool X11Grabber::Setup()
int dummy, pixmaps_supported;
- _XRandRAvailable = XRRQueryExtension(_x11Display, &_XRandREventBase, &dummy);
_XRenderAvailable = XRenderQueryExtension(_x11Display, &dummy, &dummy);
_XShmAvailable = XShmQueryExtension(_x11Display);
XShmQueryVersion(_x11Display, &dummy, &dummy, &pixmaps_supported);
@@ -306,20 +293,3 @@ void X11Grabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cro
Grabber::setCropping(cropLeft, cropRight, cropTop, cropBottom);
if(_x11Display != nullptr) updateScreenDimensions(true); // segfault on init
}
-
-bool X11Grabber::nativeEventFilter(const QByteArray & eventType, void * message, long int * /*result*/)
-{
- if (!_XRandRAvailable || eventType != "xcb_generic_event_t") {
- return false;
- }
-
- xcb_generic_event_t *e = static_cast(message);
- const uint8_t xEventType = XCB_EVENT_RESPONSE_TYPE(e);
-
- if (xEventType == _XRandREventBase + XCB_RANDR_SCREEN_CHANGE_NOTIFY)
- {
- updateScreenDimensions(true);
- }
-
- return false;
-}
diff --git a/libsrc/hyperion/CaptureCont.cpp b/libsrc/hyperion/CaptureCont.cpp
index 9f12a485b..f97c04cba 100644
--- a/libsrc/hyperion/CaptureCont.cpp
+++ b/libsrc/hyperion/CaptureCont.cpp
@@ -41,6 +41,10 @@ CaptureCont::CaptureCont(Hyperion* hyperion)
handleSettingsUpdate(settings::INSTCAPTURE, _hyperion->getSetting(settings::INSTCAPTURE));
}
+CaptureCont::~CaptureCont()
+{
+}
+
void CaptureCont::handleV4lImage(const QString& name, const Image & image)
{
if(_v4lCaptName != name)
diff --git a/libsrc/hyperion/Grabber.cpp b/libsrc/hyperion/Grabber.cpp
index bf6527ed4..8a57722f0 100644
--- a/libsrc/hyperion/Grabber.cpp
+++ b/libsrc/hyperion/Grabber.cpp
@@ -20,6 +20,10 @@ Grabber::Grabber(QString grabberName, int width, int height, int cropLeft, int c
Grabber::setCropping(cropLeft, cropRight, cropTop, cropBottom);
}
+Grabber::~Grabber()
+{
+}
+
void Grabber::setEnabled(bool enable)
{
Info(_log,"Capture interface is now %s", enable ? "enabled" : "disabled");
diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp
index 32cd10e6e..6940d4700 100644
--- a/libsrc/hyperion/Hyperion.cpp
+++ b/libsrc/hyperion/Hyperion.cpp
@@ -380,7 +380,7 @@ void Hyperion::setColor(const int priority, const std::vector &ledColo
_effectEngine->channelCleared(priority);
// create full led vector from single/multiple colors
- size_t size = _ledString.leds().size();
+ unsigned int size = _ledString.leds().size();
std::vector newLedColors;
while (true)
{
diff --git a/libsrc/hyperion/HyperionIManager.cpp b/libsrc/hyperion/HyperionIManager.cpp
index d22424be5..e1cc54be9 100644
--- a/libsrc/hyperion/HyperionIManager.cpp
+++ b/libsrc/hyperion/HyperionIManager.cpp
@@ -16,7 +16,7 @@ HyperionIManager::HyperionIManager(const QString& rootPath, QObject* parent)
, _rootPath( rootPath )
{
HIMinstance = this;
- qRegisterMetaType("InstanceState");
+ qRegisterMetaType("instanceState");
}
Hyperion* HyperionIManager::getHyperionInstance(const quint8& instance)
@@ -124,7 +124,7 @@ bool HyperionIManager::stopInstance(const quint8& inst)
if(_runningInstances.contains(inst))
{
// notify a ON_STOP rather sooner than later, queued signal listener should have some time to drop the pointer before it's deleted
- emit instanceStateChanged(InstanceState::H_ON_STOP, inst);
+ emit instanceStateChanged(H_ON_STOP, inst);
Hyperion* hyperion = _runningInstances.value(inst);
hyperion->stop();
@@ -146,7 +146,7 @@ bool HyperionIManager::createInstance(const QString& name, const bool& start)
if(_instanceTable->createInstance(name, inst))
{
Info(_log,"New Hyperion instance created with name '%s'",QSTRING_CSTR(name));
- emit instanceStateChanged(InstanceState::H_CREATED, inst, name);
+ emit instanceStateChanged(H_CREATED, inst, name);
emit change();
if(start)
@@ -168,7 +168,7 @@ bool HyperionIManager::deleteInstance(const quint8& inst)
if(_instanceTable->deleteInstance(inst))
{
Info(_log,"Hyperion instance with index '%d' has been deleted", inst);
- emit instanceStateChanged(InstanceState::H_DELETED, inst);
+ emit instanceStateChanged(H_DELETED, inst);
emit change();
return true;
@@ -194,9 +194,8 @@ void HyperionIManager::handleFinished()
Info(_log,"Hyperion instance '%s' has been stopped", QSTRING_CSTR(_instanceTable->getNamebyIndex(instance)));
_runningInstances.remove(instance);
- hyperion->thread()->deleteLater();
hyperion->deleteLater();
- emit instanceStateChanged(InstanceState::H_STOPPED, instance);
+ emit instanceStateChanged(H_STOPPED, instance);
emit change();
}
@@ -209,6 +208,6 @@ void HyperionIManager::handleStarted()
_startQueue.removeAll(instance);
_runningInstances.insert(instance, hyperion);
- emit instanceStateChanged(InstanceState::H_STARTED, instance);
+ emit instanceStateChanged(H_STARTED, instance);
emit change();
}
diff --git a/libsrc/hyperion/ImageProcessor.cpp b/libsrc/hyperion/ImageProcessor.cpp
index 82a85a2de..73935938f 100644
--- a/libsrc/hyperion/ImageProcessor.cpp
+++ b/libsrc/hyperion/ImageProcessor.cpp
@@ -69,8 +69,11 @@ void ImageProcessor::setSize(const unsigned width, const unsigned height)
return;
}
- // Clean up the old buffer and mapping
- delete _imageToLeds;
+ if ( _imageToLeds != nullptr)
+ {
+ // Clean up the old buffer and mapping
+ delete _imageToLeds;
+ }
// Construct a new buffer and mapping
_imageToLeds = (width>0 && height>0) ? (new ImageToLedsMap(width, height, 0, 0, _ledString.leds())) : nullptr;
diff --git a/libsrc/hyperion/LedString.cpp b/libsrc/hyperion/LedString.cpp
index 6ad66cf7b..b43727fa8 100644
--- a/libsrc/hyperion/LedString.cpp
+++ b/libsrc/hyperion/LedString.cpp
@@ -5,6 +5,7 @@
// hyperion includes
#include
+
LedString::LedString()
{
// empty
diff --git a/libsrc/hyperion/LinearColorSmoothing.cpp b/libsrc/hyperion/LinearColorSmoothing.cpp
index 3d5b943f3..c145ed279 100644
--- a/libsrc/hyperion/LinearColorSmoothing.cpp
+++ b/libsrc/hyperion/LinearColorSmoothing.cpp
@@ -43,6 +43,11 @@ LinearColorSmoothing::LinearColorSmoothing(const QJsonDocument& config, Hyperion
connect(_timer, &QTimer::timeout, this, &LinearColorSmoothing::updateLeds);
}
+LinearColorSmoothing::~LinearColorSmoothing()
+{
+
+}
+
void LinearColorSmoothing::handleSettingsUpdate(const settings::type& type, const QJsonDocument& config)
{
if(type == settings::SMOOTHING)
@@ -79,19 +84,28 @@ void LinearColorSmoothing::handleSettingsUpdate(const settings::type& type, cons
int LinearColorSmoothing::write(const std::vector &ledValues)
{
- _targetTime = QDateTime::currentMSecsSinceEpoch() + _settlingTime;
- _targetValues = ledValues;
-
// received a new target color
if (_previousValues.empty())
{
// not initialized yet
+ _targetTime = QDateTime::currentMSecsSinceEpoch() + _settlingTime;
+ _targetValues = ledValues;
+
_previousTime = QDateTime::currentMSecsSinceEpoch();
_previousValues = ledValues;
//Debug( _log, "Start Smoothing timer: settlingTime: %d ms, interval: %d ms (%u Hz), updateDelay: %u frames", _settlingTime, _updateInterval, unsigned(1000.0/_updateInterval), _outputDelay );
QMetaObject::invokeMethod(_timer, "start", Qt::QueuedConnection, Q_ARG(int, _updateInterval));
}
+ else
+ {
+ //std::cout << "LinearColorSmoothing::write> "; LedDevice::printLedValues ( ledValues );
+
+ _targetTime = QDateTime::currentMSecsSinceEpoch() + _settlingTime;
+ memcpy(_targetValues.data(), ledValues.data(), ledValues.size() * sizeof(ColorRgb));
+
+ //std::cout << "LinearColorSmoothing::write> _targetValues: "; LedDevice::printLedValues ( _targetValues );
+ }
return 0;
}
@@ -118,7 +132,7 @@ void LinearColorSmoothing::updateLeds()
//Debug(_log, "elapsed Time [%d], _targetTime [%d] - now [%d], deltaTime [%d]", now -_previousTime, _targetTime, now, deltaTime);
if (deltaTime < 0)
{
- _previousValues = _targetValues;
+ memcpy(_previousValues.data(), _targetValues.data(), _targetValues.size() * sizeof(ColorRgb));
_previousTime = now;
queueColors(_previousValues);
@@ -210,6 +224,7 @@ void LinearColorSmoothing::componentStateChange(const hyperion::Components compo
{
setEnable(state);
}
+
}
void LinearColorSmoothing::setEnable(bool enable)
diff --git a/libsrc/hyperion/LinearColorSmoothing.h b/libsrc/hyperion/LinearColorSmoothing.h
index ed0990ce4..e7d40d62b 100644
--- a/libsrc/hyperion/LinearColorSmoothing.h
+++ b/libsrc/hyperion/LinearColorSmoothing.h
@@ -32,6 +32,9 @@ class LinearColorSmoothing : public QObject
///
LinearColorSmoothing(const QJsonDocument& config, Hyperion* hyperion);
+ /// Destructor
+ virtual ~LinearColorSmoothing();
+
/// LED values as input for the smoothing filter
///
/// @param ledValues The color-value per led
diff --git a/libsrc/hyperion/PriorityMuxer.cpp b/libsrc/hyperion/PriorityMuxer.cpp
index 2c7b13c43..b04187acd 100644
--- a/libsrc/hyperion/PriorityMuxer.cpp
+++ b/libsrc/hyperion/PriorityMuxer.cpp
@@ -22,9 +22,9 @@ PriorityMuxer::PriorityMuxer(int ledCount)
, _activeInputs()
, _lowestPriorityInfo()
, _sourceAutoSelectEnabled(true)
- , _updateTimer(new QTimer(this))
- , _timer(new QTimer(this))
- , _blockTimer(new QTimer(this))
+ , _updateTimer(new QTimer())
+ , _timer(new QTimer())
+ , _blockTimer(new QTimer())
{
// init lowest priority info
_lowestPriorityInfo.priority = PriorityMuxer::LOWEST_PRIORITY;
diff --git a/libsrc/hyperion/SettingsManager.cpp b/libsrc/hyperion/SettingsManager.cpp
index 3f9425b7c..034b01677 100644
--- a/libsrc/hyperion/SettingsManager.cpp
+++ b/libsrc/hyperion/SettingsManager.cpp
@@ -88,7 +88,7 @@ SettingsManager::SettingsManager(const quint8& instance, QObject* parent)
// check if our main schema syntax is IO
if (!valid.second)
{
- for (auto & schemaError : schemaChecker.getMessages())
+ foreach (auto & schemaError, schemaChecker.getMessages())
Error(_log, "Schema Syntax Error: %s", QSTRING_CSTR(schemaError));
throw std::runtime_error("The config schema has invalid syntax. This should never happen! Go fix it!");
}
@@ -97,7 +97,7 @@ SettingsManager::SettingsManager(const quint8& instance, QObject* parent)
Info(_log,"Table upgrade required...");
dbConfig = schemaChecker.getAutoCorrectedConfig(dbConfig);
- for (auto & schemaError : schemaChecker.getMessages())
+ foreach (auto & schemaError, schemaChecker.getMessages())
Warning(_log, "Config Fix: %s", QSTRING_CSTR(schemaError));
saveSettings(dbConfig);
@@ -131,7 +131,7 @@ bool SettingsManager::saveSettings(QJsonObject config, const bool& correct)
Warning(_log,"Fixing json data!");
config = schemaChecker.getAutoCorrectedConfig(config);
- for (auto & schemaError : schemaChecker.getMessages())
+ foreach (auto & schemaError, schemaChecker.getMessages())
Warning(_log, "Config Fix: %s", QSTRING_CSTR(schemaError));
}
diff --git a/libsrc/jsonserver/JsonServer.cpp b/libsrc/jsonserver/JsonServer.cpp
index 4618b9aea..4abae32be 100644
--- a/libsrc/jsonserver/JsonServer.cpp
+++ b/libsrc/jsonserver/JsonServer.cpp
@@ -35,7 +35,9 @@ JsonServer::JsonServer(const QJsonDocument& config)
JsonServer::~JsonServer()
{
- qDeleteAll(_openConnections);
+ foreach (JsonClientConnection * connection, _openConnections) {
+ delete connection;
+ }
}
void JsonServer::start()
diff --git a/libsrc/leddevice/LedDevice.cpp b/libsrc/leddevice/LedDevice.cpp
index 5c831ba5d..bb446e397 100644
--- a/libsrc/leddevice/LedDevice.cpp
+++ b/libsrc/leddevice/LedDevice.cpp
@@ -1,5 +1,4 @@
#include
-#include
//QT include
#include
@@ -13,102 +12,115 @@
#include "hyperion/Hyperion.h"
#include
-LedDevice::LedDevice(const QJsonObject& config, QObject* parent)
+//std includes
+#include
+#include
+
+LedDevice::LedDevice(const QJsonObject& deviceConfig, QObject* parent)
: QObject(parent)
- , _devConfig(config)
- , _log(Logger::getInstance("LEDDEVICE"))
- , _ledBuffer(0)
- , _deviceReady(false)
- , _deviceInError(false)
- , _refresh_timer(new QTimer(this))
- , _refresh_timer_interval(0)
- , _lastWriteTime(QDateTime::currentDateTime())
- , _latchTime_ms(0)
- , _componentRegistered(false)
- , _enabled(false)
- , _refresh_enabled(false)
+ , _devConfig(deviceConfig)
+ , _log(Logger::getInstance("LEDDEVICE"))
+ , _ledBuffer(0)
+ , _refreshTimer(nullptr)
+ , _refreshTimerInterval_ms(0)
+ , _latchTime_ms(0)
+ , _isRestoreOrigState(false)
+ , _isEnabled(false)
+ , _isDeviceInitialised(false)
+ , _isDeviceReady(false)
+ , _isDeviceInError(false)
+ , _isInSwitchOff (false)
+ , _lastWriteTime(QDateTime::currentDateTime())
+ , _isRefreshEnabled (false)
{
- // setup refreshTimer
- _refresh_timer->setTimerType(Qt::PreciseTimer);
- _refresh_timer->setInterval( _refresh_timer_interval );
- connect(_refresh_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds()));
+
}
LedDevice::~LedDevice()
{
- _refresh_timer->deleteLater();
+ delete _refreshTimer;
}
-int LedDevice::open()
+void LedDevice::start()
{
- int retval = -1;
- QString errortext;
- _deviceReady = false;
+ Info(_log, "Start LedDevice '%s'.", QSTRING_CSTR(_activeDeviceType));
+
+ // setup refreshTimer
+ if ( _refreshTimer == nullptr )
+ {
+ _refreshTimer = new QTimer(this);
+ _refreshTimer->setTimerType(Qt::PreciseTimer);
+ _refreshTimer->setInterval( _refreshTimerInterval_ms );
+ connect(_refreshTimer, &QTimer::timeout, this, &LedDevice::rewriteLEDs );
+ }
+
+ close();
+ _isDeviceInitialised = false;
// General initialisation and configuration of LedDevice
if ( init(_devConfig) )
{
- // Everything is OK -> enable device
- _deviceReady = true;
- setEnable(true);
- retval = 0;
+ // Everything is OK -> enable device
+ _isDeviceInitialised = true;
+ setEnable(true);
}
- return retval;
}
-void LedDevice::setInError(const QString& errorMsg)
+void LedDevice::stop()
{
- _deviceInError = true;
- _deviceReady = false;
- _enabled = false;
+ setEnable(false);
this->stopRefreshTimer();
+}
- Error(_log, "Device disabled, device '%s' signals error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(errorMsg));
- emit enableStateChanged(_enabled);
+int LedDevice::open()
+{
+ _isDeviceReady = true;
+ int retval = 0;
+
+ return retval;
+}
+
+int LedDevice::close()
+{
+ _isDeviceReady = false;
+ int retval = 0;
+
+ return retval;
}
-void LedDevice::close()
+void LedDevice::setInError(const QString& errorMsg)
{
- switchOff();
+ _isDeviceInError = true;
+ _isDeviceReady = false;
+ _isEnabled = false;
this->stopRefreshTimer();
+
+ Error(_log, "Device disabled, device '%s' signals error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(errorMsg));
+ emit enableStateChanged(_isEnabled);
}
void LedDevice::setEnable(bool enable)
{
- if ( !_deviceReady && enable )
+ bool isSwitched = false;
+ // switch off device when disabled, default: set black to LEDs when they should go off
+ if ( _isEnabled && !enable)
{
- Debug(_log, "Device '%s' was not ready! Trying to re-open.", QSTRING_CSTR(_activeDeviceType));
- if ( open() < 0 )
- {
- Error(_log, "Device '%s' cannot be enabled, as it is not ready!", QSTRING_CSTR(_activeDeviceType));
- return;
- }
- else
- {
- // Open worked
- _deviceInError = false;
- }
- }
-
- // emit signal when state changed
- if ( _enabled != enable )
- {
- emit enableStateChanged(enable);
- }
- // switch off device when disabled, default: set black to leds when they should go off
- if ( _enabled && !enable )
- {
- switchOff();
+ isSwitched = switchOff();
}
else
{
// switch on device when enabled
- if ( !_enabled && enable )
+ if ( !_isEnabled && enable)
{
- switchOn();
+ isSwitched = switchOn();
}
}
- _enabled = enable;
+
+ if ( isSwitched )
+ {
+ _isEnabled = enable;
+ emit enableStateChanged(enable);
+ }
}
void LedDevice::setActiveDeviceType(const QString& deviceType)
@@ -118,28 +130,28 @@ void LedDevice::setActiveDeviceType(const QString& deviceType)
bool LedDevice::init(const QJsonObject &deviceConfig)
{
- //Debug(_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ Debug(_log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
_colorOrder = deviceConfig["colorOrder"].toString("RGB");
- _activeDeviceType = deviceConfig["type"].toString("file").toLower();
setLedCount(static_cast( deviceConfig["currentLedCount"].toInt(1) )); // property injected to reflect real led count
- _latchTime_ms = deviceConfig["latchTime"].toInt( _latchTime_ms );
- _refresh_timer_interval = deviceConfig["rewriteTime"].toInt( _refresh_timer_interval);
+ _latchTime_ms =deviceConfig["latchTime"].toInt( _latchTime_ms );
+ _refreshTimerInterval_ms = deviceConfig["rewriteTime"].toInt( _refreshTimerInterval_ms);
- if ( _refresh_timer_interval > 0 )
+ if ( _refreshTimerInterval_ms > 0 )
{
- _refresh_enabled = true;
+ _isRefreshEnabled = true;
- if ( _refresh_timer_interval <= _latchTime_ms )
+ if (_refreshTimerInterval_ms <= _latchTime_ms )
{
int new_refresh_timer_interval = _latchTime_ms + 10;
- Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms", _latchTime_ms, _refresh_timer_interval, new_refresh_timer_interval);
- _refresh_timer_interval = new_refresh_timer_interval;
+ Warning(_log, "latchTime(%d) is bigger/equal rewriteTime(%d), set rewriteTime to %dms", _latchTime_ms, _refreshTimerInterval_ms, new_refresh_timer_interval);
+ _refreshTimerInterval_ms = new_refresh_timer_interval;
+ _refreshTimer->setInterval( _refreshTimerInterval_ms );
}
- //Debug(_log, "Refresh interval = %dms",_refresh_timer_interval );
- _refresh_timer->setInterval( _refresh_timer_interval );
+ Debug(_log, "Refresh interval = %dms",_refreshTimerInterval_ms );
+ _refreshTimer->setInterval( _refreshTimerInterval_ms );
_lastWriteTime = QDateTime::currentDateTime();
@@ -150,21 +162,21 @@ bool LedDevice::init(const QJsonObject &deviceConfig)
void LedDevice::startRefreshTimer()
{
- if ( _deviceReady )
+ if ( _isDeviceReady && _isEnabled )
{
- _refresh_timer->start();
+ _refreshTimer->start();
}
}
void LedDevice::stopRefreshTimer()
{
- _refresh_timer->stop();
+ _refreshTimer->stop();
}
int LedDevice::updateLeds(const std::vector& ledValues)
{
int retval = 0;
- if ( !_deviceReady || _deviceInError )
+ if ( !isEnabled() || !_isDeviceReady || _isDeviceInError )
{
//std::cout << "LedDevice::updateLeds(), LedDevice NOT ready!" << std::endl;
return -1;
@@ -179,16 +191,16 @@ int LedDevice::updateLeds(const std::vector& ledValues)
_lastWriteTime = QDateTime::currentDateTime();
// if device requires refreshing, save Led-Values and restart the timer
- if ( _refresh_enabled )
+ if ( _isRefreshEnabled && _isEnabled )
{
this->startRefreshTimer();
- _last_ledValues = ledValues;
+ _lastLedValues = ledValues;
}
}
else
{
//std::cout << "LedDevice::updateLeds(), Skip write. elapsedTime (" << elapsedTimeMs << ") ms < _latchTime_ms (" << _latchTime_ms << ") ms" << std::endl;
- if ( _refresh_enabled )
+ if ( _isRefreshEnabled )
{
//Stop timer to allow for next non-refresh update
this->stopRefreshTimer();
@@ -198,68 +210,200 @@ int LedDevice::updateLeds(const std::vector& ledValues)
return retval;
}
-int LedDevice::writeBlack()
+int LedDevice::rewriteLEDs()
{
- return _deviceReady ? updateLeds(std::vector(static_cast(_ledCount), ColorRgb::BLACK )) : -1;
+ int retval = -1;
+
+ if ( _isDeviceReady && _isEnabled )
+ {
+// qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime());
+// std::cout << "LedDevice::rewriteLEDs(): Rewrite LEDs now, elapsedTime [" << elapsedTimeMs << "] ms" << std::endl;
+// //:TESTING: Inject "white" output records to differentiate from normal writes
+// _lastLedValues.clear();
+// _lastLedValues.resize(static_cast(_ledCount), ColorRgb::WHITE);
+// printLedValues(_lastLedValues);
+// //:TESTING:
+
+ retval = write(_lastLedValues);
+ _lastWriteTime = QDateTime::currentDateTime();
+ }
+ else
+ {
+ // If Device is not ready stop timer
+ this->stopRefreshTimer();
+ }
+ return retval;
}
-int LedDevice::switchOff()
+int LedDevice::writeBlack(int numberOfBlack)
{
- // Stop refresh timer to ensure that "write Black" is executed
- this->stopRefreshTimer();
+ int rc = -1;
- if ( _latchTime_ms > 0 )
+ for (int i = 0; i < numberOfBlack; i++)
{
- // Wait latchtime before writing black
- QEventLoop loop;
- QTimer::singleShot( _latchTime_ms, &loop, SLOT( quit() ) );
- loop.exec();
+ if ( _latchTime_ms > 0 )
+ {
+ // Wait latch time before writing black
+ QEventLoop loop;
+ QTimer::singleShot( _latchTime_ms, &loop, SLOT( quit() ) );
+ loop.exec();
+ }
+ rc = write(std::vector(static_cast(_ledCount), ColorRgb::BLACK ));
}
- int rc = writeBlack();
return rc;
}
-int LedDevice::switchOn()
+bool LedDevice::switchOn()
{
- return 0;
+ bool rc = false;
+ if ( _isDeviceInitialised && ! _isDeviceReady && ! _isEnabled )
+ {
+ _isDeviceInError = false;
+ if ( open() < 0 )
+ {
+ rc = false;
+ }
+ else
+ {
+ storeState();
+
+ if ( powerOn() )
+ {
+ _isEnabled = true;
+ rc = true;
+ }
+ }
+ }
+ return rc;
}
-void LedDevice::setLedCount(unsigned int ledCount)
+bool LedDevice::switchOff()
{
- _ledCount = ledCount;
- _ledRGBCount = _ledCount * sizeof(ColorRgb);
- _ledRGBWCount = _ledCount * sizeof(ColorRgbw);
+ bool rc = false;
+
+ if ( _isDeviceInitialised )
+ {
+ // Disable device to ensure no standard Led updates are written/processed
+ _isEnabled = false;
+ _isInSwitchOff = true;
+
+ this->stopRefreshTimer();
+
+ rc = true;
+
+ if ( _isDeviceReady )
+ {
+ if ( _isRestoreOrigState )
+ {
+ //Restore devices state
+ restoreState();
+ }
+ else
+ {
+ powerOff();
+ }
+
+ }
+ if ( close() < 0 )
+ {
+ rc = false;
+ }
+ }
+ return rc;
}
-void LedDevice::setLatchTime( int latchTime_ms )
+
+bool LedDevice::powerOff()
{
- _latchTime_ms = latchTime_ms;
- Debug(_log, "LatchTime updated to %dms", this->getLatchTime());
+ bool rc = false;
+
+ // Simulate power-off by writing a final "Black" to have a defined outcome
+ if ( writeBlack() >= 0 )
+ {
+ rc = true;
+ }
+ return rc;
}
-int LedDevice::rewriteLeds()
+bool LedDevice::powerOn()
{
- int retval = -1;
+ bool rc = true;
+ return rc;
+}
- if ( _deviceReady )
+bool LedDevice::storeState()
+{
+ bool rc = true;
+
+ if ( _isRestoreOrigState )
{
-// qint64 elapsedTimeMs = _lastWriteTime.msecsTo(QDateTime::currentDateTime());
-// std::cout << "LedDevice::rewriteLEDs(): Rewrite LEDs now, elapsedTime [" << elapsedTimeMs << "] ms" << std::endl;
-// //:TESTING: Inject "white" output records to differentiate from normal writes
-// _last_ledValues.clear();
-// _last_ledValues.resize(static_cast(_ledCount), ColorRgb::WHITE);
-// printLedValues(_last_ledValues);
- //:TESTING:
-
- retval = write(_last_ledValues);
- _lastWriteTime = QDateTime::currentDateTime();
+ // Save device's original state
+ // _originalStateValues = get device's state;
+ // store original power on/off state, if available
}
- else
+ return rc;
+}
+
+bool LedDevice::restoreState()
+{
+ bool rc = true;
+
+ if ( _isRestoreOrigState )
{
- // If Device is not ready stop timer
- this->stopRefreshTimer();
+ // Restore device's original state
+ // update device using _originalStateValues
+ // update original power on/off state, if supported
}
- return retval;
+ return rc;
+}
+
+QJsonObject LedDevice::discover()
+{
+ QJsonObject devicesDiscovered;
+
+ devicesDiscovered.insert("ledDeviceType", _activeDeviceType);
+
+ QJsonArray deviceList;
+ devicesDiscovered.insert("devices", deviceList);
+
+ Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ return devicesDiscovered;
+}
+
+QString LedDevice::discoverFirst()
+{
+ QString deviceDiscovered;
+
+ Debug(_log, "deviceDiscovered: [%s]", QSTRING_CSTR(deviceDiscovered) );
+ return deviceDiscovered;
+}
+
+
+QJsonObject LedDevice::getProperties(const QJsonObject& params)
+{
+ Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+
+ QJsonObject properties;
+
+ QJsonObject deviceProperties;
+ properties.insert("properties", deviceProperties);
+
+ Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+
+ return properties;
+}
+
+void LedDevice::setLedCount(unsigned int ledCount)
+{
+ _ledCount = ledCount;
+ _ledRGBCount = _ledCount * sizeof(ColorRgb);
+ _ledRGBWCount = _ledCount * sizeof(ColorRgbw);
+}
+
+void LedDevice::setLatchTime( int latchTime_ms )
+{
+ _latchTime_ms = latchTime_ms;
+ Debug(_log, "LatchTime updated to %dms", this->getLatchTime());
}
void LedDevice::printLedValues(const std::vector& ledValues)
@@ -271,3 +415,18 @@ void LedDevice::printLedValues(const std::vector& ledValues)
}
std::cout << "]" << std::endl;
}
+
+QString LedDevice::uint8_t_to_hex_string(const uint8_t * data, const qint64 size, qint64 number) const
+{
+ if ( number <= 0 || number > size)
+ {
+ number = size;
+ }
+
+ QByteArray bytes (reinterpret_cast(data), number);
+ #if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
+ return bytes.toHex(':');
+ #else
+ return bytes.toHex();
+ #endif
+}
diff --git a/libsrc/leddevice/LedDeviceFactory.cpp b/libsrc/leddevice/LedDeviceFactory.cpp
index 017771efd..0b0690acb 100644
--- a/libsrc/leddevice/LedDeviceFactory.cpp
+++ b/libsrc/leddevice/LedDeviceFactory.cpp
@@ -18,7 +18,6 @@ LedDevice * LedDeviceFactory::construct(const QJsonObject & deviceConfig)
{
Logger * log = Logger::getInstance("LEDDEVICE");
QJsonDocument config(deviceConfig);
- QString ss(config.toJson(QJsonDocument::Indented));
QString type = deviceConfig["type"].toString("UNSPECIFIED").toLower();
@@ -31,7 +30,6 @@ LedDevice * LedDeviceFactory::construct(const QJsonObject & deviceConfig)
if (dev.first == type)
{
device = dev.second(deviceConfig);
- Info(log,"LedDevice '%s' found.", QSTRING_CSTR(dev.first));
break;
}
}
diff --git a/libsrc/leddevice/LedDeviceSchemas.qrc b/libsrc/leddevice/LedDeviceSchemas.qrc
index f59d19f58..f90c354f7 100644
--- a/libsrc/leddevice/LedDeviceSchemas.qrc
+++ b/libsrc/leddevice/LedDeviceSchemas.qrc
@@ -33,5 +33,7 @@
schemas/schema-ws281x.json
schemas/schema-karate.json
schemas/schema-nanoleaf.json
+ schemas/schema-wled.json
+ schemas/schema-yeelight.json
diff --git a/libsrc/leddevice/LedDeviceTemplate.cpp b/libsrc/leddevice/LedDeviceTemplate.cpp
index 3d6567e11..a462ffa10 100644
--- a/libsrc/leddevice/LedDeviceTemplate.cpp
+++ b/libsrc/leddevice/LedDeviceTemplate.cpp
@@ -4,7 +4,9 @@ LedDeviceTemplate::LedDeviceTemplate(const QJsonObject &deviceConfig)
: LedDevice()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceTemplate::construct(const QJsonObject &deviceConfig)
@@ -14,18 +16,25 @@ LedDevice* LedDeviceTemplate::construct(const QJsonObject &deviceConfig)
bool LedDeviceTemplate::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = LedDevice::init(deviceConfig);
+ bool isInitOK = false;
- // Initiatiale LedDevice configuration and execution environment
- // ...
- if ( 0 /*Error during init*/)
+ // Initialise sub-class
+ if ( LedDevice::init(deviceConfig) )
{
- //Build an errortext, illustrative
- QString errortext = QString ("Error message: %1").arg("errno/text");
- this->setInError(errortext);
- isInitOK = false;
+ // Initialise LedDevice configuration and execution environment
+ // ...
+ if ( 0 /*Error during init*/)
+ {
+ //Build an errortext, illustrative
+ QString errortext = QString ("Error message: %1").arg("errno/text");
+ this->setInError(errortext);
+ isInitOK = false;
+ }
+ else
+ {
+ isInitOK = true;
+ }
}
-
return isInitOK;
}
@@ -33,42 +42,45 @@ int LedDeviceTemplate::open()
{
int retval = -1;
QString errortext;
- _deviceReady = false;
+ _isDeviceReady = false;
- // General initialisation and configuration of LedDevice
- if ( init(_devConfig) )
- {
- // Open/Start LedDevice based on configuration
- //...
+ // Try to open the LedDevice
+ //...
- if ( false /*If opening failed*/ )
- {
- //Build an errortext, illustrative
- errortext = QString ("Failed to xxx. Error message: %1").arg("errno/text");
- }
- else
- {
- // Everything is OK -> enable device
- _deviceReady = true;
- setEnable(true);
- retval = 0;
- }
+ if ( false /*If opening failed*/ )
+ {
+ //Build an errortext, illustrative
+ errortext = QString ("Failed to xxx. Error message: %1").arg("errno/text");
+ }
+ else
+ {
+ // Everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
+ }
- // On error/exceptions, set LedDevice in error
- if ( retval < 0 )
- {
- this->setInError( errortext );
- }
+ // On error/exceptions, set LedDevice in error
+ if ( retval < 0 )
+ {
+ this->setInError( errortext );
}
return retval;
}
-void LedDeviceTemplate::close()
+int LedDeviceTemplate::close()
{
- LedDevice::close();
-
- // LedDevice specific closing activites
+ // LedDevice specific closing activities
//...
+ int retval = 0;
+ _isDeviceReady = false;
+
+ // Test, if device requires closing
+ if ( true /*If device is still open*/ )
+ {
+ // Close device
+ // Everything is OK -> device is closed
+ }
+ return retval;
}
int LedDeviceTemplate::write(const std::vector & ledValues)
@@ -79,3 +91,5 @@ int LedDeviceTemplate::write(const std::vector & ledValues)
return retval;
}
+
+
diff --git a/libsrc/leddevice/LedDeviceTemplate.h b/libsrc/leddevice/LedDeviceTemplate.h
index 65954a804..6096c30cd 100644
--- a/libsrc/leddevice/LedDeviceTemplate.h
+++ b/libsrc/leddevice/LedDeviceTemplate.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef LEDEVICETEMPLATE_H
+#define LEDEVICETEMPLATE_H
// LedDevice includes
#include
@@ -10,46 +11,56 @@
class LedDeviceTemplate : public LedDevice
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a specific LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceTemplate(const QJsonObject &deviceConfig);
- /// constructs leddevice
+ ///
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ ///
static LedDevice* construct(const QJsonObject &deviceConfig);
+protected:
+
///
- /// Sets configuration
+ /// @brief Initialise the device's configuration
+ ///
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
///
- /// @param deviceConfig the json device config
- /// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
-public slots:
///
- /// Closes the output device.
- /// Includes switching-off the device and stopping refreshes
+ /// @brief Opens the output device.
+ ///
+ /// @return Zero on success (i.e. device is ready), else negative
///
- virtual void close() override;
+ virtual int open() override;
-protected:
///
- /// Opens and initiatialises the output device
+ /// @brief Closes the output device.
///
- /// @return Zero on succes (i.e. device is ready and enabled) else negative
+ /// @return Zero on success (i.e. device is closed), else negative
///
- virtual int open() override;
+ virtual int close() override;
- /// Writes the led color values to the led-device
///
- /// @param ledValues The color-value per led
- /// @return Zero on succes else negative
- //////
+ /// @brief Writes the RGB-Color values to the LEDs.
+ ///
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
+ ///
virtual int write(const std::vector & ledValues) override;
private:
-
};
+
+#endif // LEDEVICETEMPLATE_H
diff --git a/libsrc/leddevice/LedDeviceWrapper.cpp b/libsrc/leddevice/LedDeviceWrapper.cpp
index 0890c120e..e5bd76d1e 100644
--- a/libsrc/leddevice/LedDeviceWrapper.cpp
+++ b/libsrc/leddevice/LedDeviceWrapper.cpp
@@ -22,10 +22,10 @@ LedDeviceWrapper::LedDeviceWrapper(Hyperion* hyperion)
, _ledDevice(nullptr)
, _enabled(false)
{
- // prepare the device constrcutor map
+ // prepare the device constructor map
#define REGISTER(className) LedDeviceWrapper::addToDeviceMap(QString(#className).toLower(), LedDevice##className::construct);
- // the REGISTER() calls are autogenerated by cmake.
+ // the REGISTER() calls are auto-generated by cmake.
#include "LedDevice_register.cpp"
#undef REGISTER
@@ -59,7 +59,7 @@ void LedDeviceWrapper::createLedDevice(const QJsonObject& config)
connect(this, &LedDeviceWrapper::updateLeds, _ledDevice, &LedDevice::updateLeds, Qt::QueuedConnection);
connect(this, &LedDeviceWrapper::setEnable, _ledDevice, &LedDevice::setEnable);
- connect(this, &LedDeviceWrapper::closeLedDevice, _ledDevice, &LedDevice::close, Qt::BlockingQueuedConnection);
+ connect(this, &LedDeviceWrapper::closeLedDevice, _ledDevice, &LedDevice::stop, Qt::BlockingQueuedConnection);
connect(_ledDevice, &LedDevice::enableStateChanged, this, &LedDeviceWrapper::handleInternalEnableState, Qt::QueuedConnection);
@@ -72,7 +72,7 @@ const QJsonObject LedDeviceWrapper::getLedDeviceSchemas()
// make sure the resources are loaded (they may be left out after static linking)
Q_INIT_RESOURCE(LedDeviceSchemas);
- // read the json schema from the resource
+ // read the JSON schema from the resource
QDir d(":/leddevices/");
QStringList l = d.entryList();
QJsonObject result, schemaJson;
@@ -91,7 +91,7 @@ const QJsonObject LedDeviceWrapper::getLedDeviceSchemas()
QJsonObject schema;
if(!JsonUtils::parse(schemaPath, data, schema, Logger::getInstance("LedDevice")))
{
- throw std::runtime_error("ERROR: Json schema wrong of file: " + item.toStdString());
+ throw std::runtime_error("ERROR: JSON schema wrong of file: " + item.toStdString());
}
schemaJson = schema;
@@ -134,6 +134,11 @@ unsigned int LedDeviceWrapper::getLedCount() const
return _ledDevice->getLedCount();
}
+bool LedDeviceWrapper::enabled()
+{
+ return _enabled;
+}
+
void LedDeviceWrapper::handleComponentState(const hyperion::Components component, const bool state)
{
if(component == hyperion::COMP_LEDDEVICE)
@@ -155,7 +160,7 @@ void LedDeviceWrapper::handleInternalEnableState(bool newState)
void LedDeviceWrapper::stopDeviceThread()
{
- // turns the leds off & stop refresh timers
+ // turns the LEDs off & stop refresh timers
emit closeLedDevice();
std::cout << "[hyperiond LedDeviceWrapper] LedDevice \'" << QSTRING_CSTR(_ledDevice->getActiveDeviceType()) << "\' closed" << std::endl;
diff --git a/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.cpp b/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.cpp
index 833d4d2f5..532dddd60 100644
--- a/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.cpp
+++ b/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.cpp
@@ -5,11 +5,12 @@
// Local Hyperion includes
#include "LedDeviceHyperionUsbasp.h"
-// Static constants which define the Hyperion Usbasp device
-uint16_t LedDeviceHyperionUsbasp::_usbVendorId = 0x16c0;
-uint16_t LedDeviceHyperionUsbasp::_usbProductId = 0x05dc;
-QString LedDeviceHyperionUsbasp::_usbProductDescription = "Hyperion led controller";
-
+// Constants which define the Hyperion USBasp device
+namespace {
+uint16_t _usbVendorId = 0x16c0;
+uint16_t _usbProductId = 0x05dc;
+QString _usbProductDescription = "Hyperion led controller";
+}
LedDeviceHyperionUsbasp::LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig)
: LedDevice()
@@ -17,11 +18,17 @@ LedDeviceHyperionUsbasp::LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig
, _deviceHandle(nullptr)
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDeviceHyperionUsbasp::~LedDeviceHyperionUsbasp()
{
+ if (_libusbContext != nullptr)
+ {
+ libusb_exit(_libusbContext);
+ }
}
LedDevice* LedDeviceHyperionUsbasp::construct(const QJsonObject &deviceConfig)
@@ -31,93 +38,99 @@ LedDevice* LedDeviceHyperionUsbasp::construct(const QJsonObject &deviceConfig)
bool LedDeviceHyperionUsbasp::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = LedDevice::init(deviceConfig);
+ bool isInitOK = false;
- QString ledType = deviceConfig["ledType"].toString("ws2801");
- if (ledType != "ws2801" && ledType != "ws2812")
+ // Initialise sub-class
+ if ( LedDevice::init(deviceConfig) )
{
- QString errortext = QString ("Invalid ledType; must be 'ws2801' or 'ws2812'.");
- this->setInError(errortext);
- isInitOK = false;
- }
- else
- {
- _writeLedsCommand = (ledType == "ws2801") ? CMD_WRITE_WS2801 : CMD_WRITE_WS2812;
- }
-
- return isInitOK;
-}
-
-int LedDeviceHyperionUsbasp::open()
-{
- int retval = -1;
- QString errortext;
- _deviceReady = false;
-
- // General initialisation and configuration of LedDevice
- if ( init(_devConfig) )
- {
- int error;
-
- // initialize the usb context
- if ((error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS)
+ QString ledType = deviceConfig["ledType"].toString("ws2801");
+ if (ledType != "ws2801" && ledType != "ws2812")
{
- //Error(_log, "Error while initializing USB context(%d):%s", error, libusb_error_name(error));
- errortext = QString ("Error while initializing USB context(%1):%2").arg( error).arg(libusb_error_name(error));
- _libusbContext = nullptr;
+ QString errortext = QString ("Invalid ledType; must be 'ws2801' or 'ws2812'.");
+ this->setInError(errortext);
+ isInitOK = false;
}
else
{
- //libusb_set_debug(_libusbContext, 3);
- Debug(_log, "USB context initialized");
+ _writeLedsCommand = (ledType == "ws2801") ? CMD_WRITE_WS2801 : CMD_WRITE_WS2812;
- // retrieve the list of usb devices
- libusb_device ** deviceList;
- ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
+ int error;
+ // initialize the USB context
+ if ( (error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS )
+ {
+ _libusbContext = nullptr;
- // iterate the list of devices
- for (ssize_t i = 0 ; i < deviceCount; ++i)
+ QString errortext = QString ("Error while initializing USB context(%1):%2").arg(error).arg(libusb_error_name(error));
+ this->setInError(errortext);
+ isInitOK = false;
+ }
+ else
{
- // try to open and initialize the device
- error = testAndOpen(deviceList[i]);
+ Debug(_log, "USB context initialized");
+ //libusb_set_debug(_libusbContext, 3);
+
+ // retrieve the list of USB devices
+ libusb_device ** deviceList;
+ ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
- if (error == 0)
+ // iterate the list of devices
+ for (ssize_t i = 0 ; i < deviceCount; ++i)
{
- // a device was sucessfully opened. break from list
- break;
+ // try to open and initialize the device
+ if ( testAndOpen(deviceList[i]) == 0 )
+ {
+ _device = deviceList[i];
+ // a device was successfully opened. break from list
+ break;
+ }
}
- }
- // free the device list
- libusb_free_device_list(deviceList, 1);
+ // free the device list
+ libusb_free_device_list(deviceList, 1);
- if (_deviceHandle == nullptr)
- {
- //Error(_log, "No %s has been found", QSTRING_CSTR(_usbProductDescription));
- errortext = QString ("No %1 has been found").arg( _usbProductDescription);
- }
- else
- {
- // Everything is OK -> enable device
- _deviceReady = true;
- setEnable(true);
- retval = 0;
+ if (_deviceHandle == nullptr)
+ {
+ QString errortext;
+ errortext = QString ("No %1 has been found").arg( _usbProductDescription);
+ this->setInError( errortext );
+ }
+ else
+ {
+ isInitOK = true;
+ }
}
}
- // On error/exceptions, set LedDevice in error
- if ( retval < 0 )
- {
- this->setInError( errortext );
- }
}
+
+ return isInitOK;
+}
+
+int LedDeviceHyperionUsbasp::open()
+{
+ int retval = -1;
+ _isDeviceReady = false;
+
+ if ( libusb_open(_device, &_deviceHandle) != LIBUSB_SUCCESS )
+ {
+ QString errortext = QString ("Failed to open [%1]").arg(_usbProductDescription);
+ this->setInError(errortext);
+ }
+ else
+ {
+ // Everything is OK -> enable device
+ _isDeviceReady = true;
+ retval = 0;
+ }
+
return retval;
}
-void LedDeviceHyperionUsbasp::close()
+int LedDeviceHyperionUsbasp::close()
{
- LedDevice::close();
+ int retval = 0;
+ _isDeviceReady = false;
- // LedDevice specific closing activites
+ // LedDevice specific closing activities
if (_deviceHandle != nullptr)
{
libusb_release_interface(_deviceHandle, 0);
@@ -126,12 +139,7 @@ void LedDeviceHyperionUsbasp::close()
_deviceHandle = nullptr;
}
-
- if (_libusbContext != nullptr)
- {
- libusb_exit(_libusbContext);
- _libusbContext = nullptr;
- }
+ return retval;
}
int LedDeviceHyperionUsbasp::testAndOpen(libusb_device * device)
@@ -176,7 +184,7 @@ int LedDeviceHyperionUsbasp::write(const std::vector &ledValues)
{
int nbytes = libusb_control_transfer(
_deviceHandle, // device handle
- LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, // request type
+ static_cast( LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT ), // request type
_writeLedsCommand, // request
0, // value
0, // index
@@ -184,7 +192,7 @@ int LedDeviceHyperionUsbasp::write(const std::vector &ledValues)
(3*_ledCount) & 0xffff, // length
5000); // timeout
- // Disabling interupts for a little while on the device results in a PIPE error. All seems to keep functioning though...
+ // Disabling interrupts for a little while on the device results in a PIPE error. All seems to keep functioning though...
if(nbytes < 0 && nbytes != LIBUSB_ERROR_PIPE)
{
Error(_log, "Error while writing data to %s (%s)", QSTRING_CSTR(_usbProductDescription), libusb_error_name(nbytes));
diff --git a/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.h b/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.h
index 47a8ca1de..830100983 100644
--- a/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.h
+++ b/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef LEDEVICEHYPERIONUSBASP_H
+#define LEDEVICEHYPERIONUSBASP_H
// stl includes
#include
@@ -32,7 +33,7 @@ class LedDeviceHyperionUsbasp : public LedDevice
///
/// Sets configuration
///
- /// @param deviceConfig the json device config
+ /// @para#endif // LEDEVICETEMPLATE_Hm deviceConfig the json device config
/// @return true if success
bool init(const QJsonObject &deviceConfig) override;
@@ -49,7 +50,7 @@ public slots:
/// Closes the output device.
/// Includes switching-off the device and stopping refreshes
///
- virtual void close() override;
+ virtual int close() override;
protected:
///
@@ -85,11 +86,11 @@ public slots:
/// libusb context
libusb_context * _libusbContext;
+ /// libusb device
+ libusb_device * _device;
+
/// libusb device handle
libusb_device_handle * _deviceHandle;
-
- /// Usb device identifiers
- static uint16_t _usbVendorId;
- static uint16_t _usbProductId;
- static QString _usbProductDescription;
};
+
+#endif // LEDEVICEHYPERIONUSBASP_H
diff --git a/libsrc/leddevice/dev_hid/LedDeviceLightpack.cpp b/libsrc/leddevice/dev_hid/LedDeviceLightpack.cpp
index df9cfe649..9e2abdb0b 100644
--- a/libsrc/leddevice/dev_hid/LedDeviceLightpack.cpp
+++ b/libsrc/leddevice/dev_hid/LedDeviceLightpack.cpp
@@ -32,20 +32,6 @@ enum DATA_VERSION_INDEXES{
INDEX_FW_VER_MINOR
};
-LedDeviceLightpack::LedDeviceLightpack(const QString & serialNumber)
- : LedDevice()
- , _libusbContext(nullptr)
- , _deviceHandle(nullptr)
- , _busNumber(-1)
- , _addressNumber(-1)
- , _serialNumber(serialNumber)
- , _firmwareVersion({-1,-1})
- , _bitsPerChannel(-1)
- , _hwLedCount(-1)
-{
- _deviceReady = false;
-}
-
LedDeviceLightpack::LedDeviceLightpack(const QJsonObject &deviceConfig)
: LedDevice()
, _libusbContext(nullptr)
@@ -55,13 +41,20 @@ LedDeviceLightpack::LedDeviceLightpack(const QJsonObject &deviceConfig)
, _firmwareVersion({-1,-1})
, _bitsPerChannel(-1)
, _hwLedCount(-1)
+ ,_isOpen(false)
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDeviceLightpack::~LedDeviceLightpack()
{
+ if (_libusbContext != nullptr)
+ {
+ libusb_exit(_libusbContext);
+ }
}
LedDevice* LedDeviceLightpack::construct(const QJsonObject &deviceConfig)
@@ -71,36 +64,29 @@ LedDevice* LedDeviceLightpack::construct(const QJsonObject &deviceConfig)
bool LedDeviceLightpack::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = LedDevice::init(deviceConfig);
- _serialNumber = deviceConfig["output"].toString("");
-
- return isInitOK;
-}
-
-int LedDeviceLightpack::open()
-{
- int retval = -1;
- QString errortext;
- _deviceReady = false;
+ bool isInitOK = false;
- // General initialisation and configuration of LedDevice
- if ( init(_devConfig) )
+ // Initialise sub-class
+ if ( LedDevice::init(deviceConfig) )
{
- int error;
+ _serialNumber = deviceConfig["serial"].toString("");
- // initialize the usb context
- if ((error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS)
+ int error;
+ // initialize the USB context
+ if ( (error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS )
{
- //Error(_log, "Error while initializing USB context(%d): %s", error, libusb_error_name(error));
- errortext = QString ("Error while initializing USB context(%1):%2").arg( error).arg(libusb_error_name(error));
_libusbContext = nullptr;
+
+ QString errortext = QString ("Error while initializing USB context(%1):%2").arg(error).arg(libusb_error_name(error));
+ this->setInError(errortext);
+ isInitOK = false;
}
else
{
- //libusb_set_debug(_libusbContext, 3);
Debug(_log, "USB context initialized");
+ //libusb_set_debug(_libusbContext, 3);
- // retrieve the list of usb devices
+ // retrieve the list of USB devices
libusb_device ** deviceList;
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
@@ -108,11 +94,10 @@ int LedDeviceLightpack::open()
for (ssize_t i = 0 ; i < deviceCount; ++i)
{
// try to open and initialize the device
- error = testAndOpen(deviceList[i], _serialNumber);
-
- if (error == 0)
+ if (testAndOpen(deviceList[i], _serialNumber) == 0)
{
- // a device was sucessfully opened. break from list
+ _device = deviceList[i];
+ // a device was successfully opened. break from list
break;
}
}
@@ -122,53 +107,62 @@ int LedDeviceLightpack::open()
if (_deviceHandle == nullptr)
{
+ QString errortext;
if (_serialNumber.isEmpty())
{
- //Warning(_log, "No Lightpack device has been found");
errortext = QString ("No Lightpack devices were found");
}
else
{
- //Error(_log,"No Lightpack device has been found with serial %", QSTRING_CSTR(_serialNumber));
errortext = QString ("No Lightpack device has been found with serial %1").arg( _serialNumber);
}
+ this->setInError( errortext );
}
else
{
- // Everything is OK -> enable device
- _deviceReady = true;
- setEnable(true);
- retval = 0;
+ isInitOK = true;
}
}
- // On error/exceptions, set LedDevice in error
- if ( retval < 0 )
- {
- this->setInError( errortext );
- }
}
+ return isInitOK;
+}
+
+int LedDeviceLightpack::open()
+{
+ int retval = -1;
+ _isDeviceReady = false;
+
+ if ( libusb_open(_device, &_deviceHandle) != LIBUSB_SUCCESS )
+ {
+ QString errortext = QString ("Failed to open [%1]").arg(_serialNumber);
+ this->setInError(errortext);
+ }
+ else
+ {
+ // Everything is OK -> enable device
+ _isDeviceReady = true;
+ retval = 0;
+ }
+
return retval;
}
-void LedDeviceLightpack::close()
+int LedDeviceLightpack::close()
{
- LedDevice::close();
+ int retval = 0;
+ _isDeviceReady = false;
- // LedDevice specific closing activites
+ // LedDevice specific closing activities
if (_deviceHandle != nullptr)
{
+ _isOpen = false;
libusb_release_interface(_deviceHandle, LIGHTPACK_INTERFACE);
libusb_attach_kernel_driver(_deviceHandle, LIGHTPACK_INTERFACE);
libusb_close(_deviceHandle);
_deviceHandle = nullptr;
}
-
- if (_libusbContext != nullptr)
- {
- libusb_exit(_libusbContext);
- _libusbContext = nullptr;
- }
+ return retval;
}
int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requestedSerialNumber)
@@ -184,7 +178,7 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) ||
(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID))
{
- Info(_log, "Found a lightpack device. Retrieving more information...");
+ Info(_log, "Found a Lightpack device. Retrieving more information...");
// get the hardware address
int busNumber = libusb_get_bus_number(device);
@@ -226,7 +220,7 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
uint8_t buffer[256];
error = libusb_control_transfer(
_deviceHandle,
- LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+ static_cast( LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE),
0x01,
0x0100,
0,
@@ -289,19 +283,19 @@ int LedDeviceLightpack::testAndOpen(libusb_device * device, const QString & requ
int LedDeviceLightpack::write(const std::vector &ledValues)
{
- return write(ledValues.data(), ledValues.size());
+ return write(ledValues.data(), static_cast(ledValues.size()));
}
int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
{
- int count = qMin(_hwLedCount, static_cast( _ledCount));
+ int count = qMin(_hwLedCount, static_cast( size ));
for (int i = 0; i < count ; ++i)
{
const ColorRgb & color = ledValues[i];
- // copy the most significant bits of the rgb values to the first three bytes
- // offset 1 to accomodate for the command byte
+ // copy the most significant bits of the RGB values to the first three bytes
+ // offset 1 to accommodate for the command byte
_ledBuffer[6*i+1] = color.red;
_ledBuffer[6*i+2] = color.green;
_ledBuffer[6*i+3] = color.blue;
@@ -315,14 +309,13 @@ int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
return error >= 0 ? 0 : error;
}
-int LedDeviceLightpack::switchOff()
+bool LedDeviceLightpack::powerOff()
{
- int rc = LedDevice::switchOff();
- if ( _deviceReady )
- {
- unsigned char buf[1] = {CMD_OFF_ALL};
- rc = writeBytes(buf, sizeof(buf)) == sizeof(buf);
- }
+ bool rc = false;
+
+ unsigned char buf[1] = {CMD_OFF_ALL};
+ rc = writeBytes(buf, sizeof(buf)) == sizeof(buf);
+
return rc;
}
@@ -338,7 +331,7 @@ int LedDeviceLightpack::writeBytes(uint8_t *data, int size)
// std::cout << std::endl;
int error = libusb_control_transfer(_deviceHandle,
- LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+ static_cast( LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE ),
0x09,
(2 << 8),
0x00,
@@ -356,7 +349,13 @@ int LedDeviceLightpack::writeBytes(uint8_t *data, int size)
int LedDeviceLightpack::disableSmoothing()
{
unsigned char buf[2] = {CMD_SET_SMOOTH_SLOWDOWN, 0};
- return writeBytes(buf, sizeof(buf)) == sizeof(buf);
+
+ int rc = 0;
+ if ( writeBytes(buf, sizeof(buf)) == sizeof(buf) )
+ {
+ rc = 1;
+ }
+ return rc;
}
libusb_device_handle * LedDeviceLightpack::openDevice(libusb_device *device)
diff --git a/libsrc/leddevice/dev_hid/LedDeviceLightpack.h b/libsrc/leddevice/dev_hid/LedDeviceLightpack.h
index d9f43bc71..bf197bda7 100644
--- a/libsrc/leddevice/dev_hid/LedDeviceLightpack.h
+++ b/libsrc/leddevice/dev_hid/LedDeviceLightpack.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef LEDEVICELIGHTPACK_H
+#define LEDEVICELIGHTPACK_H
// stl includes
#include
@@ -15,79 +16,93 @@
class LedDeviceLightpack : public LedDevice
{
public:
+
///
- /// Constructs the LedDeviceLightpack
+ /// @brief Constructs a Lightpack LED-device
///
/// @param serialNumber serial output device
///
- LedDeviceLightpack(const QString & serialNumber = "");
+ explicit LedDeviceLightpack(const QString & serialNumber = "");
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a Lightpack LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceLightpack(const QJsonObject &deviceConfig);
///
- /// Sets configuration
+ /// @brief Destructor of the LedDevice
///
- /// @param deviceConfig the json device config
- /// @return true if success
- bool init(const QJsonObject &deviceConfig) override;
+ virtual ~LedDeviceLightpack() override;
- /// constructs leddevice
+ ///
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ ///
static LedDevice* construct(const QJsonObject &deviceConfig);
///
- /// Destructor of the LedDevice; closes the output device if it is open
+ /// @brief Initialise the device's configuration
///
- virtual ~LedDeviceLightpack() override;
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
+ ///
+ virtual bool init(const QJsonObject &deviceConfig) override;
///
- /// Opens and configures the output device
+ /// @brief Opens the output device.
///
- /// @return Zero on succes else negative
+ /// @return Zero on success (i.e. device is ready), else negative
+ ///
+ virtual int open() override;
+
+ ///
+ /// @brief Closes the output device.
+ ///
+ /// @return Zero on success (i.e. device is closed), else negative
+ ///
+ virtual int close() override;
+
+ ///
+ /// @brief Power-/turn off the Nanoleaf device.
///
- int open() override;
+ /// @return True if success
+ ///
+ virtual bool powerOff() override;
///
- /// Writes the RGB-Color values to the leds.
+ /// @brief Writes the RGB-Color values to the LEDs.
///
/// @param[in] ledValues Array of RGB values
/// @param[in] size The number of RGB values
///
- /// @return Zero on success else negative
+ /// @return Zero on success, else negative
///
int write(const ColorRgb * ledValues, int size);
///
- /// Switch the leds off
- ///
- /// @return Zero on success else negative
+ /// @brief Get the serial number of the Lightpack
///
- virtual int switchOff() override;
-
- /// Get the serial of the Lightpack
+ /// @return Serial Number
+ /// ///
const QString & getSerialNumber() const;
-public slots:
- ///
- /// Closes the output device.
- /// Includes switching-off the device and stopping refreshes
- ///
- virtual void close() override;
+ bool isOpen(){ return _isOpen; }
protected:
-private:
- ///
- /// Writes the RGB-Color values to the leds.
///
- /// @param[in] ledValues The RGB-color per led
+ /// @brief Writes the RGB-Color values to the LEDs.
///
- /// @return Zero on success else negative
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
///
- virtual int write(const std::vector& ledValues) override;
+ virtual int write(const std::vector & ledValues) override;
+
+private:
///
/// Test if the device is a (or the) lightpack we are looking for
@@ -114,6 +129,9 @@ public slots:
/// libusb context
libusb_context * _libusbContext;
+ /// libusb device
+ libusb_device * _device;
+
/// libusb device handle
libusb_device_handle * _deviceHandle;
@@ -134,4 +152,8 @@ public slots:
/// count of real hardware leds
int _hwLedCount;
+
+ bool _isOpen;
};
+
+#endif // LEDEVICELIGHTPACK_H
diff --git a/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.cpp b/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.cpp
index 97cd8ca69..fe87612ae 100644
--- a/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.cpp
+++ b/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.cpp
@@ -22,14 +22,19 @@ LedDeviceMultiLightpack::LedDeviceMultiLightpack(const QJsonObject &deviceConfig
, _lightpacks()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDeviceMultiLightpack::~LedDeviceMultiLightpack()
{
for (LedDeviceLightpack * device : _lightpacks)
{
- delete device;
+ if ( device != nullptr)
+ {
+ delete device;
+ }
}
}
@@ -38,14 +43,12 @@ LedDevice* LedDeviceMultiLightpack::construct(const QJsonObject &deviceConfig)
return new LedDeviceMultiLightpack(deviceConfig);
}
-int LedDeviceMultiLightpack::open()
+bool LedDeviceMultiLightpack::init(const QJsonObject &deviceConfig)
{
- int retval = -1;
- QString errortext;
- _deviceReady = false;
+ bool isInitOK = false;
- // General initialisation and configuration of LedDevice
- if ( init(_devConfig) )
+ // Initialise sub-class
+ if ( LedDevice::init(deviceConfig) )
{
// retrieve a list with Lightpack serials
QStringList serialList = getLightpackSerials();
@@ -53,47 +56,84 @@ int LedDeviceMultiLightpack::open()
// sort the list of Lightpacks based on the serial to get a fixed order
std::sort(_lightpacks.begin(), _lightpacks.end(), compareLightpacks);
- // open each lightpack device
+ // open each Lightpack device
for (auto serial : serialList)
{
- LedDeviceLightpack * device = new LedDeviceLightpack(serial);
- int error = device->open();
+ QJsonObject devConfig;
+ devConfig["serial"] = serial;
+ devConfig["latchTime"] = deviceConfig["latchTime"];
+ devConfig["rewriteTime"] = deviceConfig["rewriteTime"];
- if (error == 0)
+ LedDeviceLightpack * device = new LedDeviceLightpack(devConfig);
+
+ device->start();
+ if (device->open() == 0)
{
_lightpacks.push_back(device);
}
else
{
- //Error(_log, "Error while creating Lightpack device with serial %s", QSTRING_CSTR(serial));
- errortext = QString ("Error while creating Lightpack device with serial %1").arg( serial );
+ Error(_log, "Error while creating Lightpack device with serial %s", QSTRING_CSTR(serial));
delete device;
}
}
- if (_lightpacks.size() == 0)
+ if (_lightpacks.empty())
{
//Warning(_log, "No Lightpack devices were found");
- errortext = QString ("No Lightpack devices were found");
+ QString errortext = QString ("No Lightpack devices were found");
+ this->setInError(errortext);
+ isInitOK = false;
}
else
{
Info(_log, "%d Lightpack devices were found", _lightpacks.size());
-
- // Everything is OK -> enable device
- _deviceReady = true;
- setEnable(true);
- retval = 0;
+ isInitOK = true;
}
- // On error/exceptions, set LedDevice in error
- if ( retval < 0 )
+ }
+ return isInitOK;
+}
+
+int LedDeviceMultiLightpack::open()
+{
+ int retval = -1;
+ _isDeviceReady = false;
+
+ int lightsInError = 0;
+ // open each Lightpack device
+ for (LedDeviceLightpack * device : _lightpacks)
+ {
+ if (device->open() < 0)
{
- this->setInError( errortext );
+ Error( _log, "Failed to open [%s]", QSTRING_CSTR(device->getSerialNumber()) );
+ ++lightsInError;
}
}
+
+ if ( lightsInError < static_cast(_lightpacks.size()) )
+ {
+ // Everything is OK -> enable device
+ _isDeviceReady = true;
+ retval = 0;
+ }
+ else
+ {
+ this->setInError( "All Lightpacks failed to be opened!" );
+ }
return retval;
}
+int LedDeviceMultiLightpack::close()
+{
+ _isDeviceReady = false;
+
+ for (LedDeviceLightpack * device : _lightpacks)
+ {
+ device->close();
+ }
+ return 0;
+}
+
int LedDeviceMultiLightpack::write(const std::vector &ledValues)
{
const ColorRgb * data = ledValues.data();
@@ -105,7 +145,10 @@ int LedDeviceMultiLightpack::write(const std::vector &ledValues)
if (count > 0)
{
- device->write(data, count);
+ if ( device->isOpen() )
+ {
+ device->write(data, count);
+ }
data += count;
size -= count;
@@ -119,14 +162,16 @@ int LedDeviceMultiLightpack::write(const std::vector &ledValues)
return 0;
}
-int LedDeviceMultiLightpack::switchOff()
+bool LedDeviceMultiLightpack::powerOff()
{
for (LedDeviceLightpack * device : _lightpacks)
{
- device->switchOff();
+ if ( device->isOpen() )
+ {
+ device->powerOff();
+ }
}
-
- return 0;
+ return true;
}
QStringList LedDeviceMultiLightpack::getLightpackSerials()
@@ -135,7 +180,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
Logger * log = Logger::getInstance("LedDevice");
Debug(log, "Getting list of Lightpack serials");
- // initialize the usb context
+ // initialize the USB context
libusb_context * libusbContext;
int error = libusb_init(&libusbContext);
if (error != LIBUSB_SUCCESS)
@@ -147,7 +192,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
//libusb_set_debug(_libusbContext, 3);
Info(log, "USB context initialized in multi Lightpack device");
- // retrieve the list of usb devices
+ // retrieve the list of USB devices
libusb_device ** deviceList;
ssize_t deviceCount = libusb_get_device_list(libusbContext, &deviceList);
@@ -165,7 +210,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) ||
(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID))
{
- Info(log, "Found a lightpack device. Retrieving serial...");
+ Info(log, "Found a Lightpack device. Retrieving serial...");
// get the serial number
QString serialNumber;
@@ -183,7 +228,7 @@ QStringList LedDeviceMultiLightpack::getLightpackSerials()
}
}
- Error(log, "Lightpack device found with serial %s", QSTRING_CSTR(serialNumber));;
+ Info(log, "Lightpack device found with serial %s", QSTRING_CSTR(serialNumber));
serialList.append(serialNumber);
}
}
diff --git a/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.h b/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.h
index c1bec619e..256c3d7bb 100644
--- a/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.h
+++ b/libsrc/leddevice/dev_hid/LedDeviceMultiLightpack.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef LEDEVICEMULTILIGHTPACK_H
+#define LEDEVICEMULTILIGHTPACK_H
// stl includes
#include
@@ -19,43 +20,67 @@
class LedDeviceMultiLightpack : public LedDevice
{
public:
+
+ ///
+ /// @brief Constructs a LedDevice of multiple Lightpack LED-devices
///
- /// Constructs specific LedDevice
+ /// @param deviceConfig Device's configuration as JSON-Object
///
- explicit LedDeviceMultiLightpack(const QJsonObject &);
+ explicit LedDeviceMultiLightpack(const QJsonObject &deviceConfig);
///
- /// Destructor of the LedDevice; closes the output device if it is open
+ /// @brief Destructor of the LedDevice
///
virtual ~LedDeviceMultiLightpack() override;
- /// constructs leddevice
+ ///
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ ///
static LedDevice* construct(const QJsonObject &deviceConfig);
+protected:
+
+ ///
+ /// @brief Initialise the device's configuration
///
- virtual int switchOff() override;
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
+ ///
+ virtual bool init(const QJsonObject &deviceConfig) override;
-protected:
///
- /// Opens and configures the output device7
+ /// @brief Opens the output device.
///
- /// @return Zero on succes else negative
+ /// @return Zero on success (i.e. device is ready), else negative
///
- int open() override;
+ virtual int open() override;
+
+ ///
+ /// @brief Closes the output device.
///
- /// Switch the leds off
+ /// @return Zero on success (i.e. device is closed), else negative
///
- /// @return Zero on success else negative
+ virtual int close() override;
-private:
///
- /// Writes the RGB-Color values to the leds.
+ /// @brief Power-/turn off the Nanoleaf device.
///
- /// @param[in] ledValues The RGB-color per led
+ /// @return True if success
+ ///
+ virtual bool powerOff() override;
+
///
- /// @return Zero on success else negative
+ /// @brief Writes the RGB-Color values to the LEDs.
///
- virtual int write(const std::vector& ledValues) override;
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
+ ///
+ int write(const std::vector & ledValues) override;
+
+private:
static QStringList getLightpackSerials();
static QString getString(libusb_device * device, int stringDescriptorIndex);
@@ -63,3 +88,5 @@ class LedDeviceMultiLightpack : public LedDevice
/// buffer for led data
std::vector _lightpacks;
};
+
+#endif // LEDEVICEMULTILIGHTPACK_H
diff --git a/libsrc/leddevice/dev_hid/LedDevicePaintpack.cpp b/libsrc/leddevice/dev_hid/LedDevicePaintpack.cpp
index 149397602..61fed68a3 100644
--- a/libsrc/leddevice/dev_hid/LedDevicePaintpack.cpp
+++ b/libsrc/leddevice/dev_hid/LedDevicePaintpack.cpp
@@ -5,9 +5,11 @@ LedDevicePaintpack::LedDevicePaintpack(const QJsonObject &deviceConfig)
: ProviderHID()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
_useFeature = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDevicePaintpack::construct(const QJsonObject &deviceConfig)
@@ -17,12 +19,17 @@ LedDevice* LedDevicePaintpack::construct(const QJsonObject &deviceConfig)
bool LedDevicePaintpack::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = ProviderHID::init(deviceConfig);
+ bool isInitOK = false;
- _ledBuffer.resize(_ledRGBCount + 2, uint8_t(0));
- _ledBuffer[0] = 3;
- _ledBuffer[1] = 0;
+ // Initialise sub-class
+ if ( ProviderHID::init(deviceConfig) )
+ {
+ _ledBuffer.resize(_ledRGBCount + 2, uint8_t(0));
+ _ledBuffer[0] = 3;
+ _ledBuffer[1] = 0;
+ isInitOK = true;
+ }
return isInitOK;
}
diff --git a/libsrc/leddevice/dev_hid/LedDevicePaintpack.h b/libsrc/leddevice/dev_hid/LedDevicePaintpack.h
index 86f1967d1..95c7cc997 100644
--- a/libsrc/leddevice/dev_hid/LedDevicePaintpack.h
+++ b/libsrc/leddevice/dev_hid/LedDevicePaintpack.h
@@ -1,38 +1,48 @@
-#pragma once
+#ifndef LEDEVICEPAINTTPACK_H
+#define LEDEVICEPAINTTPACK_H
// Hyperion includes
#include "ProviderHID.h"
///
-/// LedDevice implementation for a paintpack device ()
+/// LedDevice implementation for a paintpack LED-device
///
class LedDevicePaintpack : public ProviderHID
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a Paintpack LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDevicePaintpack(const QJsonObject &deviceConfig);
- /// constructs leddevice
+ ///
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ ///
static LedDevice* construct(const QJsonObject &deviceConfig);
+private:
+
+ ///
+ /// @brief Initialise the device's configuration
///
- /// Sets configuration
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
///
- /// @param deviceConfig the json device config
- /// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
-private:
///
- /// Writes the RGB-Color values to the leds.
+ /// @brief Writes the RGB-Color values to the LEDs.
///
- /// @param[in] ledValues The RGB-color per led
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
///
- /// @return Zero on success else negative
- ///
- virtual int write(const std::vector& ledValues) override;
+ virtual int write(const std::vector & ledValues) override;
};
+
+#endif // LEDEVICEPAINTTPACK_H
diff --git a/libsrc/leddevice/dev_hid/LedDeviceRawHID.cpp b/libsrc/leddevice/dev_hid/LedDeviceRawHID.cpp
index 0e940b328..894686590 100644
--- a/libsrc/leddevice/dev_hid/LedDeviceRawHID.cpp
+++ b/libsrc/leddevice/dev_hid/LedDeviceRawHID.cpp
@@ -5,7 +5,9 @@ LedDeviceRawHID::LedDeviceRawHID(const QJsonObject &deviceConfig)
: ProviderHID()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
_useFeature = true;
}
@@ -17,10 +19,14 @@ LedDevice* LedDeviceRawHID::construct(const QJsonObject &deviceConfig)
bool LedDeviceRawHID::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = ProviderHID::init(deviceConfig);
-
- _ledBuffer.resize(_ledRGBCount);
+ bool isInitOK = false;
+ // Initialise sub-class
+ if ( ProviderHID::init(deviceConfig) )
+ {
+ _ledBuffer.resize(_ledRGBCount);
+ isInitOK = true;
+ }
return isInitOK;
}
diff --git a/libsrc/leddevice/dev_hid/LedDeviceRawHID.h b/libsrc/leddevice/dev_hid/LedDeviceRawHID.h
index 453107123..df409b753 100644
--- a/libsrc/leddevice/dev_hid/LedDeviceRawHID.h
+++ b/libsrc/leddevice/dev_hid/LedDeviceRawHID.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef LEDEVICERAWHID_H
+#define LEDEVICERAWHID_H
// Qt includes
#include
@@ -11,31 +12,40 @@
///
class LedDeviceRawHID : public ProviderHID
{
-
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a Raw-HID LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceRawHID(const QJsonObject &deviceConfig);
- /// constructs leddevice
+ ///
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ ///
static LedDevice* construct(const QJsonObject &deviceConfig);
+private:
+
+ ///
+ /// @brief Initialise the device's configuration
///
- /// Sets configuration
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
///
- /// @param deviceConfig the json device config
- /// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
-private:
///
- /// Writes the led color values to the led-device
+ /// @brief Writes the RGB-Color values to the LEDs.
///
- /// @param ledValues The color-value per led
- /// @return Zero on succes else negative
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
///
virtual int write(const std::vector & ledValues) override;
};
+
+#endif // LEDEVICERAWHID_H
diff --git a/libsrc/leddevice/dev_hid/ProviderHID.cpp b/libsrc/leddevice/dev_hid/ProviderHID.cpp
index 224b02600..289a59969 100644
--- a/libsrc/leddevice/dev_hid/ProviderHID.cpp
+++ b/libsrc/leddevice/dev_hid/ProviderHID.cpp
@@ -21,54 +21,59 @@ ProviderHID::ProviderHID()
ProviderHID::~ProviderHID()
{
+ if (_deviceHandle != nullptr)
+ {
+ hid_close(_deviceHandle);
+ }
+ hid_exit();
}
bool ProviderHID::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = LedDevice::init(deviceConfig);
+ bool isInitOK = false;
- _delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(0);
- auto VendorIdString = deviceConfig["VID"].toString("0x2341").toStdString();
- auto ProductIdString = deviceConfig["PID"].toString("0x8036").toStdString();
+ // Initialise sub-class
+ if ( LedDevice::init(deviceConfig) )
+ {
+ _delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(0);
+ auto VendorIdString = deviceConfig["VID"].toString("0x2341").toStdString();
+ auto ProductIdString = deviceConfig["PID"].toString("0x8036").toStdString();
- // Convert HEX values to integer
- _VendorId = std::stoul(VendorIdString, nullptr, 16);
- _ProductId = std::stoul(ProductIdString, nullptr, 16);
+ // Convert HEX values to integer
+ _VendorId = std::stoul(VendorIdString, nullptr, 16);
+ _ProductId = std::stoul(ProductIdString, nullptr, 16);
+ // Initialize the USB context
+ if ( hid_init() != 0)
+ {
+ this->setInError("Error initializing the HIDAPI context");
+ isInitOK = false;
+ }
+ else
+ {
+ Debug(_log,"HIDAPI initialized");
+ isInitOK = true;
+ }
+ }
return isInitOK;
}
int ProviderHID::open()
{
int retval = -1;
- QString errortext;
- _deviceReady = false;
+ _isDeviceReady = false;
- if ( init(_devConfig) )
- {
- // Initialize the usb context
- int error = hid_init();
- if (error != 0)
- {
- //Error(_log, "Error while initializing the hidapi context");
- errortext = "Error while initializing the hidapi context";
- }
- else
- {
- Debug(_log,"Hidapi initialized");
+ // Open the device
+ Info(_log, "Opening device: VID %04hx PID %04hx\n", _VendorId, _ProductId);
+ _deviceHandle = hid_open(_VendorId, _ProductId, nullptr);
- // Open the device
- Info(_log, "Opening device: VID %04hx PID %04hx\n", _VendorId, _ProductId);
- _deviceHandle = hid_open(_VendorId, _ProductId, nullptr);
-
- if (_deviceHandle == nullptr)
- {
- // Failed to open the device
- Error(_log,"Failed to open HID device. Maybe your PID/VID setting is wrong? Make sure to add a udev rule/use sudo.");
- errortext = "Failed to open HID device";
+ if (_deviceHandle == nullptr)
+ {
+ // Failed to open the device
+ this->setInError( "Failed to open HID device. Maybe your PID/VID setting is wrong? Make sure to add a udev rule/use sudo." );
- // http://www.signal11.us/oss/hidapi/
- /*
+ // http://www.signal11.us/oss/hidapi/
+ /*
std::cout << "Showing a list of all available HID devices:" << std::endl;
auto devs = hid_enumerate(0x00, 0x00);
auto cur_dev = devs;
@@ -83,45 +88,38 @@ int ProviderHID::open()
}
hid_free_enumeration(devs);
*/
- }
- else
- {
- Info(_log,"Opened HID device successful");
- // Everything is OK -> enable device
- _deviceReady = true;
- setEnable(true);
- retval = 0;
- }
-
- // Wait after device got opened if enabled
- if (_delayAfterConnect_ms > 0)
- {
- _blockedForDelay = true;
- QTimer::singleShot(_delayAfterConnect_ms, this, SLOT(unblockAfterDelay()));
- Debug(_log, "Device blocked for %d ms", _delayAfterConnect_ms);
- }
- }
- // On error/exceptions, set LedDevice in error
- if ( retval < 0 )
- {
- this->setInError( errortext );
- }
}
+ else
+ {
+ Info(_log,"Opened HID device successful");
+ // Everything is OK -> enable device
+ _isDeviceReady = true;
+ retval = 0;
+ }
+
+ // Wait after device got opened if enabled
+ if (_delayAfterConnect_ms > 0)
+ {
+ _blockedForDelay = true;
+ QTimer::singleShot(_delayAfterConnect_ms, this, &ProviderHID::unblockAfterDelay );
+ Debug(_log, "Device blocked for %d ms", _delayAfterConnect_ms);
+ }
+
return retval;
}
-void ProviderHID::close()
+int ProviderHID::close()
{
- LedDevice::close();
+ int retval = 0;
+ _isDeviceReady = false;
- // LedDevice specific closing activites
+ // LedDevice specific closing activities
if (_deviceHandle != nullptr)
{
hid_close(_deviceHandle);
_deviceHandle = nullptr;
}
-
- hid_exit();
+ return retval;
}
int ProviderHID::writeBytes(const unsigned size, const uint8_t * data)
@@ -138,7 +136,7 @@ int ProviderHID::writeBytes(const unsigned size, const uint8_t * data)
// Try again in 3 seconds
int delay_ms = 3000;
_blockedForDelay = true;
- QTimer::singleShot(delay_ms, this, SLOT(unblockAfterDelay()));
+ QTimer::singleShot(delay_ms, this, &ProviderHID::unblockAfterDelay );
Debug(_log,"Device blocked for %d ms", delay_ms);
}
// Return here, to not write led data if the device should be blocked after connect
@@ -188,3 +186,38 @@ void ProviderHID::unblockAfterDelay()
Debug(_log,"Device unblocked");
_blockedForDelay = false;
}
+
+QJsonObject ProviderHID::discover()
+{
+ QJsonObject devicesDiscovered;
+ devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
+
+ QJsonArray deviceList;
+
+ // Discover HID Devices
+ auto devs = hid_enumerate(0x00, 0x00);
+
+ if ( devs != nullptr )
+ {
+ auto cur_dev = devs;
+ while (cur_dev)
+ {
+ QJsonObject deviceInfo;
+ deviceInfo.insert("manufacturer",QString::fromWCharArray(cur_dev->manufacturer_string));
+ deviceInfo.insert("path",cur_dev->path);
+ deviceInfo.insert("productIdentifier", QString("0x%1").arg(static_cast(cur_dev->product_id),0,16));
+ deviceInfo.insert("release_number",QString("0x%1").arg(static_cast(cur_dev->release_number),0,16));
+ deviceInfo.insert("serialNumber",QString::fromWCharArray(cur_dev->serial_number));
+ deviceInfo.insert("usage_page", QString("0x%1").arg(static_cast(cur_dev->usage_page),0,16));
+ deviceInfo.insert("vendorIdentifier", QString("0x%1").arg(static_cast(cur_dev->vendor_id),0,16));
+ deviceInfo.insert("interface_number",cur_dev->interface_number);
+ deviceList.append(deviceInfo);
+
+ cur_dev = cur_dev->next;
+ }
+ hid_free_enumeration(devs);
+ }
+
+ devicesDiscovered.insert("devices", deviceList);
+ return devicesDiscovered;
+}
diff --git a/libsrc/leddevice/dev_hid/ProviderHID.h b/libsrc/leddevice/dev_hid/ProviderHID.h
index 9d8cff2c8..dce62bc31 100644
--- a/libsrc/leddevice/dev_hid/ProviderHID.h
+++ b/libsrc/leddevice/dev_hid/ProviderHID.h
@@ -1,6 +1,5 @@
-#pragma once
-
-#include
+#ifndef PROVIDERHID_H
+#define PROVIDERHID_H
// libusb include
#include
@@ -16,46 +15,57 @@ class ProviderHID : public LedDevice
Q_OBJECT
public:
+
+ ///
+ /// @brief Constructs a HID (USB) LED-device
///
- /// Constructs specific LedDevice
+ /// @param deviceConfig Device's configuration as JSON-Object
///
ProviderHID();
///
- /// Destructor of the LedDevice; closes the output device if it is open
+ /// @brief Destructor of the LedDevice
///
virtual ~ProviderHID() override;
///
- /// Sets configuration
+ /// @brief Discover HIB (USB) devices available (for configuration).
+ ///
+ /// @return A JSON structure holding a list of devices found
+ ///
+ virtual QJsonObject discover() override;
+
+protected:
+
+ ///
+ /// @brief Initialise the device's configuration
+ ///
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
///
- /// @param deviceConfig the json device config
- /// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
-public slots:
///
- /// Closes the output device.
- /// Includes switching-off the device and stopping refreshes
+ /// @brief Opens the output device.
///
- virtual void close() override;
+ /// @return Zero on success (i.e. device is ready), else negative
+ ///
+ virtual int open() override;
-protected:
///
- /// Opens and configures the output device
+ /// @brief Closes the output device.
///
- /// @return Zero on succes else negative
+ /// @return Zero on success (i.e. device is closed), else negative
///
- int open() override;
+ virtual int close() override;
- /**
- * Writes the given bytes to the HID-device and
- *
- * @param[in] size The length of the data
- * @param[in] data The data
- *
- * @return Zero on succes else negative
- */
+ ///
+ /// @brief Write the given bytes to the HID-device
+ ///
+ /// @param[in[ size The length of the data
+ /// @param[in] data The data
+ /// @return Zero on success, else negative
+ ///
int writeBytes(const unsigned size, const uint8_t *data);
// HID VID and PID
@@ -74,4 +84,10 @@ public slots:
private slots:
/// Unblock the device after a connection delay
void unblockAfterDelay();
+
+
+private:
+
};
+
+#endif // PROVIDERHID_H
diff --git a/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.cpp b/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.cpp
index b23d5aec6..9aceeb74e 100644
--- a/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.cpp
@@ -1,5 +1,6 @@
// Local-Hyperion includes
#include "LedDeviceAtmoOrb.h"
+#include
// qt includes
#include
@@ -19,7 +20,9 @@ LedDeviceAtmoOrb::LedDeviceAtmoOrb(const QJsonObject &deviceConfig)
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceAtmoOrb::construct(const QJsonObject &deviceConfig)
@@ -31,7 +34,7 @@ LedDeviceAtmoOrb::~LedDeviceAtmoOrb()
{
if ( _udpSocket != nullptr )
{
- _udpSocket->deleteLater();
+ delete _udpSocket;
}
}
@@ -49,30 +52,31 @@ bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
_multiCastGroupPort = static_cast(deviceConfig["port"].toInt(MULTICAST_GROUPL_DEFAULT_PORT));
_numLeds = deviceConfig["numLeds"].toInt(LEDS_DEFAULT_NUMBER);
- #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
- const QStringList orbIds = deviceConfig["orbIds"].toString().simplified().remove(" ").split(",", Qt::SkipEmptyParts);
- #else
- const QStringList orbIds = deviceConfig["orbIds"].toString().simplified().remove(" ").split(",", QString::SkipEmptyParts);
- #endif
-
+ QStringList orbIds = QStringUtils::split(deviceConfig["orbIds"].toString().simplified().remove(" "),",", QStringUtils::SplitBehavior::SkipEmptyParts);
_orbIds.clear();
- for(auto & id_str : orbIds)
+ for (auto & id_str : orbIds)
{
bool ok;
int id = id_str.toInt(&ok);
if (ok)
{
if ( id < 1 || id > 255 )
+ {
Warning(_log, "Skip orb id '%d'. IDs must be in range 1-255", id);
+ }
else
+ {
_orbIds.append(id);
+ }
}
else
+ {
Error(_log, "orb id '%s' is not a number", QSTRING_CSTR(id_str));
+ }
}
- if ( _orbIds.size() == 0 )
+ if ( _orbIds.empty() )
{
this->setInError("No valid OrbIds found!");
isInitOK = false;
@@ -89,43 +93,40 @@ bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
int LedDeviceAtmoOrb::open()
{
int retval = -1;
- _deviceReady = false;
+ _isDeviceReady = false;
- if ( init(_devConfig) )
+ // Try to bind the UDP-Socket
+ if ( _udpSocket != nullptr )
{
- // Try to bind the UDP-Socket
- if ( _udpSocket != nullptr )
+ _groupAddress = QHostAddress(_multicastGroup);
+ if ( !_udpSocket->bind(QHostAddress::AnyIPv4, _multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint) )
{
- _groupAddress = QHostAddress(_multicastGroup);
- if ( !_udpSocket->bind(QHostAddress::AnyIPv4, _multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint) )
+ QString errortext = QString ("(%1) %2, MulticastGroup: (%3)").arg(_udpSocket->error()).arg(_udpSocket->errorString(), _multicastGroup);
+ this->setInError( errortext );
+ }
+ else
+ {
+ _joinedMulticastgroup = _udpSocket->joinMulticastGroup(_groupAddress);
+ if ( !_joinedMulticastgroup )
{
- QString errortext = QString ("(%1) %2, MulticastGroup: (%3)").arg(_udpSocket->error()).arg(_udpSocket->errorString()).arg(_multicastGroup);
+ QString errortext = QString ("(%1) %2, MulticastGroup: (%3)").arg(_udpSocket->error()).arg(_udpSocket->errorString(), _multicastGroup);
this->setInError( errortext );
}
else
{
- _joinedMulticastgroup = _udpSocket->joinMulticastGroup(_groupAddress);
- if ( !_joinedMulticastgroup )
- {
- QString errortext = QString ("(%1) %2, MulticastGroup: (%3)").arg(_udpSocket->error()).arg(_udpSocket->errorString()).arg(_multicastGroup);
- this->setInError( errortext );
- }
- else
- {
- // Everything is OK, device is ready
- _deviceReady = true;
- setEnable(true);
- retval = 0;
- }
+ // Everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
}
}
}
return retval;
}
-void LedDeviceAtmoOrb::close()
+int LedDeviceAtmoOrb::close()
{
- LedDevice::close();
+ int retval = 0;
+ _isDeviceReady = false;
if ( _udpSocket != nullptr )
{
@@ -137,6 +138,7 @@ void LedDeviceAtmoOrb::close()
// Everything is OK -> device is closed
}
}
+ return retval;
}
int LedDeviceAtmoOrb::write(const std::vector &ledValues)
@@ -211,7 +213,9 @@ int LedDeviceAtmoOrb::write(const std::vector &ledValues)
void LedDeviceAtmoOrb::setColor(int orbId, const ColorRgb &color, int commandType)
{
QByteArray bytes;
- bytes.resize(5 + _numLeds * 3);
+
+ // 5 bytes command-header + 3 bytes color information
+ bytes.resize(5 + 3);
bytes.fill('\0');
// Command identifier: C0FFEE
@@ -230,7 +234,6 @@ void LedDeviceAtmoOrb::setColor(int orbId, const ColorRgb &color, int commandTyp
bytes[6] = static_cast(color.green);
bytes[7] = static_cast(color.blue);
- // TODO: Why is the datagram _numLeds * 3 in size, if only bypes 5,6,7 are updated with the color?
//std::cout << "Orb [" << orbId << "] Cmd [" << bytes.toHex(':').toStdString() <<"]"<< std::endl;
sendCommand(bytes);
diff --git a/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.h b/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.h
index fc01ba33e..7fdd199fe 100644
--- a/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.h
+++ b/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.h
@@ -1,9 +1,8 @@
-#pragma once
+#ifndef LEDEVICEATMOORB_H
+#define LEDEVICEATMOORB_H
// Qt includes
-#include
-#include
-#include
+#include
#include
#include
@@ -25,38 +24,39 @@ class LedDeviceAtmoOrb : public LedDevice
public:
///
- /// Constructs specific LedDevice
+ /// @brief Constructs an AtmoOrb LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceAtmoOrb(const QJsonObject &deviceConfig);
///
- /// Sets configuration
+ /// @brief Destructor of the LedDevice
///
- /// @param deviceConfig the json device config
- /// @return true if success
- bool init(const QJsonObject &deviceConfig) override;
+ virtual ~LedDeviceAtmoOrb() override;
- /// constructs leddevice
- static LedDevice* construct(const QJsonObject &deviceConfig);
///
- /// Destructor of this device
+ /// @brief Constructs the LED-device
///
- virtual ~LedDeviceAtmoOrb() override;
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ ///
+ static LedDevice* construct(const QJsonObject &deviceConfig);
protected:
///
- /// Initialise device's network details
+ /// @brief Initialise the device's configuration
+ ///
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
///
- /// @return True if success
- bool initNetwork();
+ virtual bool init(const QJsonObject &deviceConfig) override;
///
- /// Opens and initiatialises the output device
+ /// @brief Opens the output device.
///
- /// @return Zero on succes (i.e. device is ready and enabled) else negative
+ /// @return Zero on success (i.e. device is ready), else negative
///
virtual int open() override;
@@ -65,17 +65,17 @@ class LedDeviceAtmoOrb : public LedDevice
///
/// @return Zero on success (i.e. device is closed), else negative
///
- virtual void close() override;
-
-private:
+ virtual int close() override;
///
- /// Sends the given led-color values to the Orbs
+ /// @brief Writes the RGB-Color values to the LEDs.
///
- /// @param ledValues The color-value per led
- /// @return Zero on success else negative
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
///
- virtual int write(const std::vector &ledValues) override;
+ virtual int write(const std::vector & ledValues) override;
+
+private:
///
/// Set Orbcolor
@@ -93,9 +93,6 @@ class LedDeviceAtmoOrb : public LedDevice
///
void sendCommand(const QByteArray &bytes);
- /// QNetworkAccessManager object for sending requests.
- QNetworkAccessManager *_networkmanager;
-
/// QUdpSocket object used to send data over
QUdpSocket * _udpSocket;
@@ -132,3 +129,5 @@ class LedDeviceAtmoOrb : public LedDevice
QMap lastColorBlueMap;
};
+
+#endif // LEDEVICEATMOORB_H
diff --git a/libsrc/leddevice/dev_net/LedDeviceFadeCandy.cpp b/libsrc/leddevice/dev_net/LedDeviceFadeCandy.cpp
index 49a433de8..15de0b5bc 100644
--- a/libsrc/leddevice/dev_net/LedDeviceFadeCandy.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceFadeCandy.cpp
@@ -6,22 +6,37 @@
typedef SSIZE_T ssize_t;
#endif
-static const signed MAX_NUM_LEDS = 10000; // OPC can handle 21845 leds - in theory, fadecandy device should handle 10000 leds
-static const unsigned OPC_SET_PIXELS = 0; // OPC command codes
-static const unsigned OPC_SYS_EX = 255; // OPC command codes
-static const unsigned OPC_HEADER_SIZE = 4; // OPC header size
+// Constants
+namespace {
+
+const signed MAX_NUM_LEDS = 10000; // OPC can handle 21845 LEDs - in theory, fadecandy device should handle 10000 LEDs
+const unsigned OPC_SET_PIXELS = 0; // OPC command codes
+const unsigned OPC_SYS_EX = 255; // OPC command codes
+const unsigned OPC_HEADER_SIZE = 4; // OPC header size
+
+} //End of constants
+
+// TCP elements
+const quint16 STREAM_DEFAULT_PORT = 7890;
LedDeviceFadeCandy::LedDeviceFadeCandy(const QJsonObject &deviceConfig)
: LedDevice()
- , _client(nullptr)
+ , _client(nullptr)
+ ,_host()
+ ,_port(STREAM_DEFAULT_PORT)
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDeviceFadeCandy::~LedDeviceFadeCandy()
{
- _client->deleteLater();
+ if ( _client != nullptr )
+ {
+ delete _client;
+ }
}
LedDevice* LedDeviceFadeCandy::construct(const QJsonObject &deviceConfig)
@@ -31,46 +46,59 @@ LedDevice* LedDeviceFadeCandy::construct(const QJsonObject &deviceConfig)
bool LedDeviceFadeCandy::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = LedDevice::init(deviceConfig);
+ bool isInitOK = false;
- if ( isInitOK )
+ if ( LedDevice::init(deviceConfig) )
{
- if (_ledCount > MAX_NUM_LEDS)
+ if (getLedCount() > MAX_NUM_LEDS)
{
- //Error(_log, "fadecandy/opc: Invalid attempt to write led values. Not more than %d leds are allowed.", MAX_NUM_LEDS);
QString errortext = QString ("More LED configured than allowed (%1)").arg(MAX_NUM_LEDS);
this->setInError(errortext);
isInitOK = false;
}
else
{
- _host = deviceConfig["output"].toString("127.0.0.1");
- _port = deviceConfig["port"].toInt(7890);
- _channel = deviceConfig["channel"].toInt(0);
- _gamma = deviceConfig["gamma"].toDouble(1.0);
- _noDither = ! deviceConfig["dither"].toBool(false);
- _noInterp = ! deviceConfig["interpolation"].toBool(false);
- _manualLED = deviceConfig["manualLed"].toBool(false);
- _ledOnOff = deviceConfig["ledOn"].toBool(false);
- _setFcConfig = deviceConfig["setFcConfig"].toBool(false);
-
- _whitePoint_r = 1.0;
- _whitePoint_g = 1.0;
- _whitePoint_b = 1.0;
-
- const QJsonArray whitePointConfig = deviceConfig["whitePoint"].toArray();
- if ( !whitePointConfig.isEmpty() && whitePointConfig.size() == 3 )
+ _host = deviceConfig["output"].toString("127.0.0.1");
+ _port = deviceConfig["port"].toInt(STREAM_DEFAULT_PORT);
+
+ //If host not configured the init fails
+ if ( _host.isEmpty() )
{
- _whitePoint_r = whitePointConfig[0].toDouble() / 255.0;
- _whitePoint_g = whitePointConfig[1].toDouble() / 255.0;
- _whitePoint_b = whitePointConfig[2].toDouble() / 255.0;
+ this->setInError("No target hostname nor IP defined");
+ }
+ else
+ {
+ _channel = deviceConfig["channel"].toInt(0);
+ _gamma = deviceConfig["gamma"].toDouble(1.0);
+ _noDither = ! deviceConfig["dither"].toBool(false);
+ _noInterp = ! deviceConfig["interpolation"].toBool(false);
+ _manualLED = deviceConfig["manualLed"].toBool(false);
+ _ledOnOff = deviceConfig["ledOn"].toBool(false);
+ _setFcConfig = deviceConfig["setFcConfig"].toBool(false);
+
+ _whitePoint_r = 1.0;
+ _whitePoint_g = 1.0;
+ _whitePoint_b = 1.0;
+
+ const QJsonArray whitePointConfig = deviceConfig["whitePoint"].toArray();
+ if ( !whitePointConfig.isEmpty() && whitePointConfig.size() == 3 )
+ {
+ _whitePoint_r = whitePointConfig[0].toDouble() / 255.0;
+ _whitePoint_g = whitePointConfig[1].toDouble() / 255.0;
+ _whitePoint_b = whitePointConfig[2].toDouble() / 255.0;
+ }
+
+ _opc_data.resize( _ledRGBCount + OPC_HEADER_SIZE );
+ _opc_data[0] = _channel;
+ _opc_data[1] = OPC_SET_PIXELS;
+ _opc_data[2] = _ledRGBCount >> 8;
+ _opc_data[3] = _ledRGBCount & 0xff;
+
+ if ( initNetwork() )
+ {
+ isInitOK = true;
+ }
}
-
- _opc_data.resize( _ledRGBCount + OPC_HEADER_SIZE );
- _opc_data[0] = _channel;
- _opc_data[1] = OPC_SET_PIXELS;
- _opc_data[2] = _ledRGBCount >> 8;
- _opc_data[3] = _ledRGBCount & 0xff;
}
}
return isInitOK;
@@ -78,62 +106,77 @@ bool LedDeviceFadeCandy::init(const QJsonObject &deviceConfig)
bool LedDeviceFadeCandy::initNetwork()
{
- bool isInitOK = true;
+ bool isInitOK = false;
- // TODO: Add Network-Error handling
- _client = new QTcpSocket(this);
+ if ( _client == nullptr )
+ {
+ _client = new QTcpSocket(this);
+ isInitOK = true;
+ }
return isInitOK;
}
int LedDeviceFadeCandy::open()
{
int retval = -1;
- _deviceReady = false;
+ QString errortext;
+ _isDeviceReady = false;
- if ( init(_devConfig) )
+ // Try to open the LedDevice
+ if ( !tryConnect() )
{
- if ( !initNetwork() )
- {
- this->setInError( "Network error!" );
- }
- else
- {
- _deviceReady = true;
- setEnable(true);
- retval = 0;
- }
+ errortext = QString ("Failed to open device.");
+ this->setInError( errortext );
+ }
+ else
+ {
+ // Everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
}
return retval;
}
-void LedDeviceFadeCandy::close()
+int LedDeviceFadeCandy::close()
{
- LedDevice::close();
+ int retval = 0;
+ _isDeviceReady = false;
- // LedDevice specific closing activites
- _client->close();
+ // LedDevice specific closing activities
+ if ( _client != nullptr )
+ {
+ _client->close();
+ // Everything is OK -> device is closed
+ }
+ return retval;
}
-
bool LedDeviceFadeCandy::isConnected()
{
- return _client->state() == QAbstractSocket::ConnectedState;
+ bool connected = false;
+ if ( _client != nullptr )
+ {
+ connected = _client->state() == QAbstractSocket::ConnectedState;
+ }
+ return connected;
}
bool LedDeviceFadeCandy::tryConnect()
{
- if ( _client->state() == QAbstractSocket::UnconnectedState ) {
- _client->connectToHost( _host, _port);
- if ( _client->waitForConnected(1000) )
- {
- Info(_log,"fadecandy/opc: connected to %s:%i on channel %i", QSTRING_CSTR(_host), _port, _channel);
- if (_setFcConfig)
+ if ( _client != nullptr )
+ {
+ if ( _client->state() == QAbstractSocket::UnconnectedState ) {
+ _client->connectToHost( _host, _port);
+ if ( _client->waitForConnected(1000) )
{
- sendFadeCandyConfiguration();
+ Info(_log,"fadecandy/opc: connected to %s:%i on channel %i", QSTRING_CSTR(_host), _port, _channel);
+ if (_setFcConfig)
+ {
+ sendFadeCandyConfiguration();
+ }
}
}
}
-
return isConnected();
}
@@ -148,15 +191,16 @@ int LedDeviceFadeCandy::write( const std::vector & ledValues )
idx += 3;
}
- return ( transferData()<0 ? -1 : 0 );
+ int retval = transferData()<0 ? -1 : 0;
+ return retval;
}
int LedDeviceFadeCandy::transferData()
{
- if (LedDevice::enabled())
- if ( isConnected() || tryConnect() )
- return _client->write( _opc_data, _opc_data.size() );
-
+ if ( isConnected() || tryConnect() )
+ {
+ return _client->write( _opc_data, _opc_data.size() );
+ }
return -2;
}
diff --git a/libsrc/leddevice/dev_net/LedDeviceFadeCandy.h b/libsrc/leddevice/dev_net/LedDeviceFadeCandy.h
index e3cf0bdb0..274b6b6c8 100644
--- a/libsrc/leddevice/dev_net/LedDeviceFadeCandy.h
+++ b/libsrc/leddevice/dev_net/LedDeviceFadeCandy.h
@@ -1,10 +1,11 @@
-#pragma once
+#ifndef LEDEVICEFADECANDY_H
+#define LEDEVICEFADECANDY_H
// STL/Qt includes
#include
#include
-// Leddevice includes
+// LedDevice includes
#include
///
@@ -17,9 +18,9 @@ class LedDeviceFadeCandy : public LedDevice
public:
///
- /// Constructs the LedDevice for fadecandy/opc server
+ /// @brief Constructs a LED-device for fadecandy/opc server
///
- /// following code shows all config options
+ /// Following code shows all configuration options
/// @code
/// "device" :
/// {
@@ -37,84 +38,95 @@ class LedDeviceFadeCandy : public LedDevice
/// },
///@endcode
///
- /// @param deviceConfig json config for fadecandy
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceFadeCandy(const QJsonObject &deviceConfig);
///
- /// Destructor of the LedDevice; closes the tcp client
+ /// @brief Destructor of the LedDevice
///
- virtual ~LedDeviceFadeCandy();
-
- /// constructs leddevice
- static LedDevice* construct(const QJsonObject &deviceConfig);
+ ~LedDeviceFadeCandy() override;
///
- /// Sets configuration
+ /// @brief Constructs the LED-device
///
- /// @param deviceConfig the json device config
- /// @return true if success
- bool init(const QJsonObject &deviceConfig) override;
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ static LedDevice* construct(const QJsonObject &deviceConfig);
-public slots:
+protected:
///
- /// Closes the output device.
- /// Includes switching-off the device and stopping refreshes
+ /// @brief Initialise the Nanoleaf device's configuration and network address details
///
- virtual void close() override;
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
+ ///
+ virtual bool init(const QJsonObject &deviceConfig) override;
-protected:
+ ///
+ /// @brief Opens the output device.
+ ///
+ /// @return Zero on success (i.e. device is ready), else negative
+ ///
+ virtual int open() override;
///
- /// Initialise device's network details
+ /// @brief Closes the output device.
///
- /// @return True if success
- bool initNetwork();
+ /// @return Zero on success (i.e. device is closed), else negative
+ ///
+ virtual int close() override;
///
- /// Opens and initiatialises the output device
+ /// @brief Writes the RGB-Color values to the LEDs.
///
- /// @return Zero on succes (i.e. device is ready and enabled) else negative
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
///
- virtual int open() override;
+ virtual int write(const std::vector & ledValues) override;
private:
+
///
- /// Writes the led color values to the led-device
- ///
- /// @param ledValues The color-value per led
- /// @return Zero on succes else negative
+ /// @brief Initialise device's network details
///
- virtual int write(const std::vector& ledValues) override;
+ /// @return True if success
+ bool initNetwork();
- /// try to establish connection to opc server, if not connected yet
///
- /// @return true if connection is established
+ /// @brief try to establish connection to opc server, if not connected yet
+ ///
+ /// @return True, if connection is established
///
bool tryConnect();
- /// return the conenction state
///
- /// @return True if connection established
+ /// @brief Return the connection state
+ ///
+ /// @return True, if connection established
///
bool isConnected();
- /// transfer current opc_data buffer to opc server
///
- /// @return amount of transfered bytes. -1 error while transfering, -2 error while connecting
+ /// @brief Transfer current opc_data buffer to opc server
+ ///
+ /// @return amount of transferred bytes. -1 error while transferring, -2 error while connecting
///
int transferData();
- /// send system exclusive commands
///
- /// @param systemId fadecandy device identifier (for standard fadecandy always: 1)
- /// @param commandId id of command
- /// @param msg the sysEx message
- /// @return amount bytes written, -1 if fail
+ /// @brief Send system exclusive commands
+ ///
+ /// @param[in] systemId fadecandy device identifier (for standard fadecandy always: 1)
+ /// @param[in] commandId id of command
+ /// @param[in] msg the sysEx message
+ /// @return amount bytes written, -1 if failed
int sendSysEx(uint8_t systemId, uint8_t commandId, QByteArray msg);
- /// sends the configuration to fcserver
+ ///
+ /// @brief Sends the configuration to fadecandy cserver
+ ///
void sendFadeCandyConfiguration();
QTcpSocket* _client;
@@ -135,3 +147,5 @@ public slots:
bool _ledOnOff;
};
+
+#endif // LEDEVICEFADECANDY_H
diff --git a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp
index a5d79cb18..7912f0933 100644
--- a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp
@@ -1,8 +1,8 @@
// Local-Hyperion includes
#include "LedDeviceNanoleaf.h"
-// ssdp discover
#include
+#include
// Qt includes
#include
@@ -12,61 +12,66 @@
#include
#include
-//
-static const bool verbose = false;
-static const bool verbose3 = false;
+// Constants
+namespace {
-// Controller configuration settings
-static const char CONFIG_ADDRESS[] = "host";
-//static const char CONFIG_PORT[] = "port";
-static const char CONFIG_AUTH_TOKEN[] ="token";
+const bool verbose = false;
+const bool verbose3 = false;
-static const char CONFIG_PANEL_ORDER_TOP_DOWN[] ="panelOrderTopDown";
-static const char CONFIG_PANEL_ORDER_LEFT_RIGHT[] ="panelOrderLeftRight";
-static const char CONFIG_PANEL_START_POS[] ="panelStartPos";
+// Configuration settings
+const char CONFIG_ADDRESS[] = "host";
+//const char CONFIG_PORT[] = "port";
+const char CONFIG_AUTH_TOKEN[] ="token";
+
+const char CONFIG_PANEL_ORDER_TOP_DOWN[] ="panelOrderTopDown";
+const char CONFIG_PANEL_ORDER_LEFT_RIGHT[] ="panelOrderLeftRight";
+const char CONFIG_PANEL_START_POS[] ="panelStartPos";
// Panel configuration settings
-static const char PANEL_LAYOUT[] = "layout";
-static const char PANEL_NUM[] = "numPanels";
-static const char PANEL_ID[] = "panelId";
-static const char PANEL_POSITIONDATA[] = "positionData";
-static const char PANEL_SHAPE_TYPE[] = "shapeType";
-//static const char PANEL_ORIENTATION[] = "0";
-static const char PANEL_POS_X[] = "x";
-static const char PANEL_POS_Y[] = "y";
+const char PANEL_LAYOUT[] = "layout";
+const char PANEL_NUM[] = "numPanels";
+const char PANEL_ID[] = "panelId";
+const char PANEL_POSITIONDATA[] = "positionData";
+const char PANEL_SHAPE_TYPE[] = "shapeType";
+//const char PANEL_ORIENTATION[] = "0";
+const char PANEL_POS_X[] = "x";
+const char PANEL_POS_Y[] = "y";
// List of State Information
-static const char STATE_ON[] = "on";
-static const char STATE_ONOFF_VALUE[] = "value";
-static const char STATE_VALUE_TRUE[] = "true";
-static const char STATE_VALUE_FALSE[] = "false";
+const char STATE_ON[] = "on";
+const char STATE_ONOFF_VALUE[] = "value";
+const char STATE_VALUE_TRUE[] = "true";
+const char STATE_VALUE_FALSE[] = "false";
// Device Data elements
-static const char DEV_DATA_NAME[] = "name";
-static const char DEV_DATA_MODEL[] = "model";
-static const char DEV_DATA_MANUFACTURER[] = "manufacturer";
-static const char DEV_DATA_FIRMWAREVERSION[] = "firmwareVersion";
+const char DEV_DATA_NAME[] = "name";
+const char DEV_DATA_MODEL[] = "model";
+const char DEV_DATA_MANUFACTURER[] = "manufacturer";
+const char DEV_DATA_FIRMWAREVERSION[] = "firmwareVersion";
// Nanoleaf Stream Control elements
-//static const char STREAM_CONTROL_IP[] = "streamControlIpAddr";
-static const char STREAM_CONTROL_PORT[] = "streamControlPort";
-//static const char STREAM_CONTROL_PROTOCOL[] = "streamControlProtocol";
+//const char STREAM_CONTROL_IP[] = "streamControlIpAddr";
+const char STREAM_CONTROL_PORT[] = "streamControlPort";
+//const char STREAM_CONTROL_PROTOCOL[] = "streamControlProtocol";
const quint16 STREAM_CONTROL_DEFAULT_PORT = 60222; //Fixed port for Canvas;
// Nanoleaf OpenAPI URLs
-static const char API_DEFAULT_PORT[] = "16021";
-static const char API_URL_FORMAT[] = "http://%1:%2/api/v1/%3/%4";
-static const char API_ROOT[] = "";
-//static const char API_EXT_MODE_STRING_V1[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\"}}";
-static const char API_EXT_MODE_STRING_V2[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\", \"extControlVersion\" : \"v2\"}}";
-static const char API_STATE[] ="state";
-static const char API_PANELLAYOUT[] = "panelLayout";
-static const char API_EFFECT[] = "effects";
+const int API_DEFAULT_PORT = 16021;
+const char API_BASE_PATH[] = "/api/v1/%1/";
+const char API_ROOT[] = "";
+//const char API_EXT_MODE_STRING_V1[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\"}}";
+const char API_EXT_MODE_STRING_V2[] = "{\"write\" : {\"command\" : \"display\", \"animType\" : \"extControl\", \"extControlVersion\" : \"v2\"}}";
+const char API_STATE[] ="state";
+const char API_PANELLAYOUT[] = "panelLayout";
+const char API_EFFECT[] = "effects";
// Nanoleaf ssdp services
-static const char SSDP_CANVAS[] = "nanoleaf:nl29";
-static const char SSDP_LIGHTPANELS[] = "nanoleaf_aurora:light";
-const int SSDP_TIMEOUT = 5000; // timout in ms
+const char SSDP_ID[] = "ssdp:all";
+const char SSDP_FILTER_HEADER[] = "ST";
+const char SSDP_CANVAS[] = "nanoleaf:nl29";
+const char SSDP_LIGHTPANELS[] = "nanoleaf_aurora:light";
+
+} //End of constants
// Nanoleaf Panel Shapetypes
enum SHAPETYPES {
@@ -84,24 +89,35 @@ enum EXTCONTROLVERSIONS {
EXTCTRLVER_V2
};
-LedDevice* LedDeviceNanoleaf::construct(const QJsonObject &deviceConfig)
+LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject &deviceConfig)
+ : ProviderUdp()
+ ,_restApi(nullptr)
+ ,_apiPort(API_DEFAULT_PORT)
+ ,_topDown(true)
+ ,_leftRight(true)
+ ,_startPos(0)
+ ,_endPos(0)
+ ,_extControlVersion (EXTCTRLVER_V2),
+ _panelLedCount(0)
{
- return new LedDeviceNanoleaf(deviceConfig);
+ _devConfig = deviceConfig;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
-LedDeviceNanoleaf::~LedDeviceNanoleaf()
+LedDevice* LedDeviceNanoleaf::construct(const QJsonObject &deviceConfig)
{
- _networkmanager->deleteLater();
+ return new LedDeviceNanoleaf(deviceConfig);
}
-LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject &deviceConfig)
- : ProviderUdp()
+LedDeviceNanoleaf::~LedDeviceNanoleaf()
{
- _devConfig = deviceConfig;
- _deviceReady = false;
- _networkmanager = nullptr;
- _extControlVersion = EXTCTRLVER_V2;
- _panelLedCount = 0;
+ if ( _restApi != nullptr )
+ {
+ delete _restApi;
+ _restApi = nullptr;
+ }
}
bool LedDeviceNanoleaf::init(const QJsonObject &deviceConfig)
@@ -116,74 +132,89 @@ bool LedDeviceNanoleaf::init(const QJsonObject &deviceConfig)
DebugIf(verbose, _log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
- bool isInitOK = LedDevice::init(deviceConfig);
+ bool isInitOK = false;
- if ( isInitOK )
+ if ( LedDevice::init(deviceConfig) )
{
uint configuredLedCount = this->getLedCount();
Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
Debug(_log, "LedCount : %u", configuredLedCount);
Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
- Debug(_log, "RefreshTime : %d", _refresh_timer_interval);
+ Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms);
Debug(_log, "LatchTime : %d", this->getLatchTime());
// Read panel organisation configuration
if ( deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].isString() )
- _topDown = deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].toString().toInt() == 0 ? true : false;
+ {
+ _topDown = deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].toString().toInt() == 0;
+ }
else
- _topDown = deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].toInt() == 0 ? true : false;
+ {
+ _topDown = deviceConfig[ CONFIG_PANEL_ORDER_TOP_DOWN ].toInt() == 0;
+ }
if ( deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].isString() )
- _leftRight = deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].toString().toInt() == 0 ? true : false;
+ {
+ _leftRight = deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].toString().toInt() == 0;
+ }
else
- _leftRight = deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].toInt() == 0 ? true : false;
+ {
+ _leftRight = deviceConfig[ CONFIG_PANEL_ORDER_LEFT_RIGHT ].toInt() == 0;
+ }
- _startPos = deviceConfig[ CONFIG_PANEL_START_POS ].toInt(0);
+ _startPos = static_cast( deviceConfig[ CONFIG_PANEL_START_POS ].toInt(0) );
+
+ // TODO: Allow to handle port dynamically
//Set hostname as per configuration and_defaultHost default port
_hostname = deviceConfig[ CONFIG_ADDRESS ].toString();
- _api_port = API_DEFAULT_PORT;
- _auth_token = deviceConfig[ CONFIG_AUTH_TOKEN ].toString();
+ _apiPort = API_DEFAULT_PORT;
+ _authToken = deviceConfig[ CONFIG_AUTH_TOKEN ].toString();
- //If host not configured then discover device
+ //If host not configured the init failed
if ( _hostname.isEmpty() )
{
- //Discover Nanoleaf device
- if ( !discoverDevice() )
+ this->setInError("No target hostname nor IP defined");
+ isInitOK = false;
+ }
+ else
+ {
+ if ( initRestAPI( _hostname, _apiPort, _authToken ) )
{
- this->setInError("No target IP defined nor Nanoleaf device was discovered");
- return false;
+ // Read LedDevice configuration and validate against device configuration
+ if ( initLedsConfiguration() )
+ {
+ // Set UDP streaming host and port
+ _devConfig["host"] = _hostname;
+ _devConfig["port"] = STREAM_CONTROL_DEFAULT_PORT;
+
+ isInitOK = ProviderUdp::init(_devConfig);
+ Debug(_log, "Hostname/IP : %s", QSTRING_CSTR( _hostname ));
+ Debug(_log, "Port : %d", _port);
+ }
}
}
-
- // Set UDP streaming port
- _devConfig["host"] = _hostname;
- _devConfig["port"] = STREAM_CONTROL_DEFAULT_PORT;
- isInitOK = ProviderUdp::init(_devConfig);
-
- Debug(_log, "Hostname/IP : %s", QSTRING_CSTR( _hostname ));
- Debug(_log, "Port : %d", _port);
}
return isInitOK;
}
-bool LedDeviceNanoleaf::initLeds()
+bool LedDeviceNanoleaf::initLedsConfiguration()
{
bool isInitOK = true;
//Get Nanoleaf device details and configuration
- _networkmanager = new QNetworkAccessManager();
// Read Panel count and panel Ids
- QString url = getUrl(_hostname, _api_port, _auth_token, API_ROOT );
- QJsonDocument doc = getJson( url );
- if ( this->isInError() )
+ _restApi->setPath(API_ROOT);
+ httpResponse response = _restApi->get();
+ if ( response.error() )
{
+ this->setInError ( response.getErrorReason() );
isInitOK = false;
}
else
{
- QJsonObject jsonAllPanelInfo = doc.object();
+ QJsonObject jsonAllPanelInfo = response.getBody().object();
QString deviceName = jsonAllPanelInfo[DEV_DATA_NAME].toString();
_deviceModel = jsonAllPanelInfo[DEV_DATA_MODEL].toString();
@@ -205,7 +236,7 @@ bool LedDeviceNanoleaf::initLeds()
std::map> panelMap;
// Loop over all children.
- for (const QJsonValue & value : positionData)
+ for (const QJsonValue value : positionData)
{
QJsonObject panelObj = value.toObject();
@@ -239,9 +270,13 @@ bool LedDeviceNanoleaf::initLeds()
DebugIf(verbose3, _log, "panelMap[%u][%u]=%u", posY->first, posX->first, posX->second );
if ( _topDown )
+ {
_panelIds.push_back(posX->second);
+ }
else
+ {
_panelIds.push_front(posX->second);
+ }
}
}
else
@@ -252,9 +287,13 @@ bool LedDeviceNanoleaf::initLeds()
DebugIf(verbose3, _log, "panelMap[%u][%u]=%u", posY->first, posX->first, posX->second );
if ( _topDown )
+ {
_panelIds.push_back(posX->second);
+ }
else
+ {
_panelIds.push_front(posX->second);
+ }
}
}
}
@@ -300,197 +339,199 @@ bool LedDeviceNanoleaf::initLeds()
}
}
}
+ return isInitOK;
+}
+
+bool LedDeviceNanoleaf::initRestAPI(const QString &hostname, const int port, const QString &token )
+{
+ bool isInitOK = false;
+
+ if ( _restApi == nullptr )
+ {
+ _restApi = new ProviderRestApi(hostname, port );
+
+ //Base-path is api-path + authentication token
+ _restApi->setBasePath( QString(API_BASE_PATH).arg(token) );
+ isInitOK = true;
+ }
return isInitOK;
}
int LedDeviceNanoleaf::open()
{
int retval = -1;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ // Set Nanoleaf to External Control (UDP) mode
+ Debug(_log, "Set Nanoleaf to External Control (UDP) streaming mode");
+ QJsonDocument responseDoc = changeToExternalControlMode();
+ // Resolve port for Light Panels
+ QJsonObject jsonStreamControllInfo = responseDoc.object();
+ if ( ! jsonStreamControllInfo.isEmpty() )
+ {
+ //Set default streaming port
+ _port = static_cast(jsonStreamControllInfo[STREAM_CONTROL_PORT].toInt());
+ }
- if ( init(_devConfig) )
+ if ( ProviderUdp::open() == 0 )
{
- if ( !initNetwork() )
- {
- this->setInError( "UDP Network error!" );
- }
- else
- {
- if ( initLeds() )
- {
- _deviceReady = true;
- setEnable(true);
- retval = 0;
- }
- }
+ // Everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
}
return retval;
}
-bool LedDeviceNanoleaf::discoverDevice()
+QJsonObject LedDeviceNanoleaf::discover()
{
+ QJsonObject devicesDiscovered;
+ devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
+
+ QJsonArray deviceList;
- bool isDeviceFound (false);
- // device searching by ssdp
- QString address;
+ // Discover Nanoleaf Devices
SSDPDiscover discover;
- // Discover Canvas device
- address = discover.getFirstService(searchType::STY_WEBSERVER, SSDP_CANVAS, SSDP_TIMEOUT);
+ // Search for Canvas and Light-Panels
+ QString searchTargetFilter = QString("%1|%2").arg(SSDP_CANVAS, SSDP_LIGHTPANELS);
- //No Canvas device not found
- if ( address.isEmpty() ) {
- // Discover Light Panels (Aurora) device
- address = discover.getFirstService(searchType::STY_WEBSERVER, SSDP_LIGHTPANELS, SSDP_TIMEOUT);
+ discover.setSearchFilter(searchTargetFilter, SSDP_FILTER_HEADER);
+ QString searchTarget = SSDP_ID;
- if ( address.isEmpty() ) {
- Warning(_log, "No Nanoleaf device discovered");
- }
+ if ( discover.discoverServices(searchTarget) > 0 )
+ {
+ deviceList = discover.getServicesDiscoveredJson();
}
- // Canvas or Light Panels found
- if ( ! address.isEmpty() ) {
- Info(_log, "Nanoleaf device discovered at [%s]", QSTRING_CSTR( address ));
- isDeviceFound = true;
- // Resolve hostname and port (or use default API port)
- #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
- QStringList addressparts = address.split(":", Qt::SkipEmptyParts);
- #else
- QStringList addressparts = address.split(":", QString::SkipEmptyParts);
- #endif
- _hostname = addressparts[0];
- _api_port = addressparts[1];
- }
- return isDeviceFound;
-}
+ devicesDiscovered.insert("devices", deviceList);
+ Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ return devicesDiscovered;
+}
-QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode()
+QJsonObject LedDeviceNanoleaf::getProperties(const QJsonObject& params)
{
+ Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ QJsonObject properties;
- QString url = getUrl(_hostname, _api_port, _auth_token, API_EFFECT );
- QJsonDocument jsonDoc;
+ // Get Nanoleaf device properties
+ QString host = params["host"].toString("");
+ if ( !host.isEmpty() )
+ {
+ QString authToken = params["token"].toString("");
+ QString filter = params["filter"].toString("");
- _extControlVersion = EXTCTRLVER_V2;
- //Enable UDP Mode v2
- jsonDoc= putJson(url, API_EXT_MODE_STRING_V2);
+ // Resolve hostname and port (or use default API port)
+ QStringList addressparts = QStringUtils::split(host,":", QStringUtils::SplitBehavior::SkipEmptyParts);
+ QString apiHost = addressparts[0];
+ int apiPort;
- return jsonDoc;
-}
+ if ( addressparts.size() > 1)
+ {
+ apiPort = addressparts[1].toInt();
+ }
+ else
+ {
+ apiPort = API_DEFAULT_PORT;
+ }
-QString LedDeviceNanoleaf::getUrl(QString host, QString port, QString auth_token, QString endpoint) const {
- return QString(API_URL_FORMAT).arg(host, port, auth_token, endpoint);
-}
+ initRestAPI(apiHost, apiPort, authToken);
+ _restApi->setPath(filter);
-QJsonDocument LedDeviceNanoleaf::getJson(QString url)
-{
+ // Perform request
+ httpResponse response = _restApi->get();
+ if ( response.error() )
+ {
+ Warning (_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
+ }
- Debug(_log, "GET: [%s]", QSTRING_CSTR( url ));
+ properties.insert("properties", response.getBody().object());
- // Perfrom request
- QNetworkRequest request(url);
- QNetworkReply* reply = _networkmanager->get(request);
- // Connect requestFinished signal to quit slot of the loop.
- QEventLoop loop;
- loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
- // Go into the loop until the request is finished.
- loop.exec();
+ Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
- QJsonDocument jsonDoc;
- if(reply->operation() == QNetworkAccessManager::GetOperation)
- {
- jsonDoc = handleReply( reply );
}
- // Free space.
- reply->deleteLater();
- // Return response
- return jsonDoc;
+ return properties;
}
-QJsonDocument LedDeviceNanoleaf::putJson(QString url, QString json)
+void LedDeviceNanoleaf::identify(const QJsonObject& params)
{
+ Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ QJsonObject properties;
- Debug(_log, "PUT: [%s] [%s]", QSTRING_CSTR( url ), QSTRING_CSTR( json ) );
- // Perfrom request
- QNetworkRequest request(url);
- QNetworkReply* reply = _networkmanager->put(request, json.toUtf8());
- // Connect requestFinished signal to quit slot of the loop.
- QEventLoop loop;
- loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
- // Go into the loop until the request is finished.
- loop.exec();
-
- QJsonDocument jsonDoc;
- if(reply->operation() == QNetworkAccessManager::PutOperation)
+ // Get Nanoleaf device properties
+ QString host = params["host"].toString("");
+ if ( !host.isEmpty() )
{
- jsonDoc = handleReply( reply );
- }
- // Free space.
- reply->deleteLater();
+ QString authToken = params["token"].toString("");
- // Return response
- return jsonDoc;
-}
+ // Resolve hostname and port (or use default API port)
+ QStringList addressparts = QStringUtils::split(host,":", QStringUtils::SplitBehavior::SkipEmptyParts);
+ QString apiHost = addressparts[0];
+ int apiPort;
-QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply )
-{
+ if ( addressparts.size() > 1)
+ {
+ apiPort = addressparts[1].toInt();
+ }
+ else
+ {
+ apiPort = API_DEFAULT_PORT;
+ }
- QJsonDocument jsonDoc;
+ initRestAPI(apiHost, apiPort, authToken);
+ _restApi->setPath("identify");
- int httpStatusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
- Debug(_log, "Reply.httpStatusCode [%d]", httpStatusCode );
+ // Perform request
+ httpResponse response = _restApi->put();
+ if ( response.error() )
+ {
+ Warning (_log, "%s identification failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
+ }
+ }
+}
- if(reply->error() == QNetworkReply::NoError)
+bool LedDeviceNanoleaf::powerOn()
+{
+ if ( _isDeviceReady)
{
- if ( httpStatusCode != 204 ){
- QByteArray response = reply->readAll();
- QJsonParseError error;
- jsonDoc = QJsonDocument::fromJson(response, &error);
- if (error.error != QJsonParseError::NoError)
- {
- this->setInError ( "Got invalid response" );
- }
- else {
- //Debug
- QString strJson(jsonDoc.toJson(QJsonDocument::Compact));
- DebugIf(verbose, _log, "Reply: [%s]", strJson.toUtf8().constData() );
- }
- }
+ //Power-on Nanoleaf device
+ _restApi->setPath(API_STATE);
+ _restApi->put( getOnOffRequest(true) );
}
- else
+ return true;
+}
+
+bool LedDeviceNanoleaf::powerOff()
+{
+ if ( _isDeviceReady)
{
- QString errorReason;
- if ( httpStatusCode > 0 ) {
- QString httpReason = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString();
- QString advise;
- switch ( httpStatusCode ) {
- case 400:
- advise = "Check Request Body";
- break;
- case 401:
- advise = "Check Authentication Token (API Key)";
- break;
- case 404:
- advise = "Check Resource given";
- break;
- default:
- break;
- }
- errorReason = QString ("%1:%2 [%3 %4] - %5").arg(_hostname, _api_port, QString(httpStatusCode) , httpReason, advise);
- }
- else {
- errorReason = QString ("%1:%2 - %3").arg(_hostname, _api_port, reply->errorString());
- }
- this->setInError ( errorReason );
+ //Power-off the Nanoleaf device physically
+ _restApi->setPath(API_STATE);
+ _restApi->put( getOnOffRequest(false) );
}
- // Return response
- return jsonDoc;
+ return true;
}
-int LedDeviceNanoleaf::write(const std::vector & ledValues)
+QString LedDeviceNanoleaf::getOnOffRequest (bool isOn ) const
{
+ QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
+ return QString( "{\"%1\":{\"%2\":%3}}" ).arg(STATE_ON, STATE_ONOFF_VALUE, state);
+}
+
+QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode()
+{
+ _extControlVersion = EXTCTRLVER_V2;
+ //Enable UDP Mode v2
+ _restApi->setPath(API_EFFECT);
+ httpResponse response =_restApi->put(API_EXT_MODE_STRING_V2);
+
+ return response.getBody();
+}
+
+int LedDeviceNanoleaf::write(const std::vector & ledValues)
+{
int retVal = 0;
uint udpBufferSize;
@@ -573,46 +614,6 @@ int LedDeviceNanoleaf::write(const std::vector & ledValues)
return retVal;
}
-QString LedDeviceNanoleaf::getOnOffRequest (bool isOn ) const
-{
- QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
- return QString( "{\"%1\":{\"%2\":%3}}" ).arg(STATE_ON, STATE_ONOFF_VALUE, state);
-}
-
-int LedDeviceNanoleaf::switchOn()
-{
- if ( _deviceReady)
- {
- // Set Nanoleaf to External Control (UDP) mode
- Debug(_log, "Set Nanoleaf to External Control (UDP) streaming mode");
- QJsonDocument responseDoc = changeToExternalControlMode();
- // Resolve port for Ligh Panels
- QJsonObject jsonStreamControllInfo = responseDoc.object();
- if ( ! jsonStreamControllInfo.isEmpty() ) {
- _port = static_cast(jsonStreamControllInfo[STREAM_CONTROL_PORT].toInt());
- }
-
- //Switch on Nanoleaf device
- QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
- putJson(url, this->getOnOffRequest(true) );
- }
- return 0;
-}
-
-int LedDeviceNanoleaf::switchOff()
-{
- //Set all LEDs to Black
- int rc = LedDevice::switchOff();
-
- if ( _deviceReady)
- {
- //Switch off Nanoleaf device physically
- QString url = getUrl(_hostname, _api_port, _auth_token, API_STATE );
- putJson(url, getOnOffRequest(false) );
- }
- return rc;
-}
-
std::string LedDeviceNanoleaf:: uint8_vector_to_hex_string( const std::vector& buffer ) const
{
std::stringstream ss;
diff --git a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.h b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.h
index d2d1f0af3..02c1a90fb 100644
--- a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.h
+++ b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.h
@@ -1,12 +1,11 @@
-#pragma once
+#ifndef LEDEVICENANOLEAF_H
+#define LEDEVICENANOLEAF_H
-// Leddevice includes
+// LedDevice includes
#include
+#include "ProviderRestApi.h"
#include "ProviderUdp.h"
-// ssdp discover
-#include
-
// Qt includes
#include
#include
@@ -19,140 +18,160 @@ class LedDeviceNanoleaf : public ProviderUdp
{
public:
///
- /// Constructs the LedDevice for Nanoleaf LightPanels (aka Aurora) or Canvas
+ /// @brief Constructs LED-device for Nanoleaf LightPanels (aka Aurora) or Canvas
///
- /// following code shows all config options
+ /// following code shows all configuration options
/// @code
/// "device" :
/// {
- /// "type" : "nanoleaf"
- /// "output" : "hostname or IP", // Optional. If empty, device is tried to be discovered
- /// "token" : "Authentication Token",
+ /// "type" : "nanoleaf"
+ /// "host" : "hostname or IP",
+ /// "token": "Authentication Token",
/// },
///@endcode
///
- /// @param deviceConfig json config for nanoleaf
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceNanoleaf(const QJsonObject &deviceConfig);
///
- /// Destructor of the LedDevice; closes the tcp client
+ /// @brief Destructor of the LED-device
///
virtual ~LedDeviceNanoleaf() override;
- /// Constructs leddevice
+ ///
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
static LedDevice* construct(const QJsonObject &deviceConfig);
- /// Switch the device on
- virtual int switchOn() override;
-
- /// Switch the device off
- virtual int switchOff() override;
-
-protected:
+ ///
+ /// @brief Discover Nanoleaf devices available (for configuration).
+ ///
+ /// @return A JSON structure holding a list of devices found
+ ///
+ virtual QJsonObject discover() override;
///
- /// Writes the led color values to the led-device
+ /// @brief Get the Nanoleaf device's resource properties
///
- /// @param ledValues The color-value per led
- /// @return Zero on succes else negative
+ /// Following parameters are required
+ /// @code
+ /// {
+ /// "host" : "hostname or IP [:port]",
+ /// "token" : "authentication token",
+ /// "filter": "resource to query", root "/" is used, if empty
+ /// }
+ ///@endcode
///
- virtual int write(const std::vector & ledValues) override;
+ /// @param[in] params Parameters to query device
+ /// @return A JSON structure holding the device's properties
+ ///
+ virtual QJsonObject getProperties(const QJsonObject& params) override;
///
- /// Initialise Nanoleaf device's configuration and network address details
+ /// @brief Send an update to the Nanoleaf device to identify it.
///
- /// @param deviceConfig the json device config
- /// @return True if success
+ /// Following parameters are required
+ /// @code
+ /// {
+ /// "host" : "hostname or IP [:port]",
+ /// "token" : "authentication token",
+ /// }
+ ///@endcode
///
- bool init(const QJsonObject &deviceConfig) override;
+ /// @param[in] params Parameters to address device
+ ///
+ virtual void identify(const QJsonObject& params) override;
+
+protected:
///
- /// Get Nanoleaf device details and configuration
+ /// @brief Initialise the Nanoleaf device's configuration and network address details
///
- /// @return True, if Nanoleaf device capabilities fit configuration
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
///
- bool initLeds();
+ bool init(const QJsonObject &deviceConfig) override;
///
- /// Opens and initiatialises the output device
+ /// @brief Opens the output device.
///
- /// @return Zero on succes (i.e. device is ready and enabled) else negative
+ /// @return Zero on success (i.e. device is ready), else negative
///
virtual int open() override;
-private:
- ///
- /// Discover Nanoleaf device via SSDP identifiers
///
- /// @return True, if Nanoleaf device was found
+ /// @brief Writes the RGB-Color values to the LEDs.
///
- bool discoverDevice();
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
+ //////
+ virtual int write(const std::vector & ledValues) override;
///
- /// Change Nanoleaf device to External Control (UDP) mode
+ /// @brief Power-/turn on the Nanoleaf device.
///
- /// @return Response from device
+ /// @brief Store the device's original state.
///
- QJsonDocument changeToExternalControlMode();
+ virtual bool powerOn() override;
///
- /// Get command to switch Nanoleaf device on or off
+ /// @brief Power-/turn off the Nanoleaf device.
///
- /// @param isOn True, if to switch on device
- /// @return Command to switch device on/off
+ /// @return True if success
///
- QString getOnOffRequest (bool isOn ) const;
+ virtual bool powerOff() override;
+
+private:
///
- /// Get command as url
+ /// @brief Initialise the access to the REST-API wrapper
///
- /// @param host Hostname or IP
- /// @param port IP-Port
- /// @param _auth_token Authorization token
- /// @param Endpoint command for request
- /// @return Url to execute endpoint/command
+ /// @param[in] host
+ /// @param[in] port
+ /// @param[in] authentication token
///
- QString getUrl(QString host, QString port, QString auth_token, QString endpoint) const;
+ /// @return True, if success
+ ///
+ bool initRestAPI(const QString &hostname, const int port, const QString &token );
///
- /// Execute GET request
+ /// @brief Get Nanoleaf device details and configuration
///
- /// @param url GET request for url
- /// @return Response from device
+ /// @return True, if Nanoleaf device capabilities fit configuration
///
- QJsonDocument getJson(QString url);
+ bool initLedsConfiguration();
///
- /// Execute PUT request
+ /// @brief Change Nanoleaf device to External Control (UDP) mode
///
- /// @param Url for PUT request
- /// @param json Command for request
/// @return Response from device
- ///
- QJsonDocument putJson(QString url, QString json);
+ ///@brief
+ QJsonDocument changeToExternalControlMode();
///
- /// Handle replys for GET and PUT requests
+ /// @brief Get command to power Nanoleaf device on or off
///
- /// @param reply Network reply
- /// @return Response for request, if no error
+ /// @param isOn True, if to switch on device
+ /// @return Command to switch device on/off
///
- QJsonDocument handleReply(QNetworkReply* const &reply );
+ QString getOnOffRequest (bool isOn ) const;
///
- /// convert vector to hex string
+ /// @brief Convert vector to hex string
///
/// @param uint8_t vector
/// @return vector as string of hex values
std::string uint8_vector_to_hex_string( const std::vector& buffer ) const;
- // QNetworkAccessManager object for sending requests.
- QNetworkAccessManager* _networkmanager;
+ ///REST-API wrapper
+ ProviderRestApi* _restApi;
QString _hostname;
- QString _api_port;
- QString _auth_token;
+ int _apiPort;
+ QString _authToken;
bool _topDown;
bool _leftRight;
@@ -163,9 +182,13 @@ class LedDeviceNanoleaf : public ProviderUdp
QString _deviceModel;
QString _deviceFirmwareVersion;
ushort _extControlVersion;
- /// The number of panels with leds
+
+ /// The number of panels with LEDs
uint _panelLedCount;
- /// Array of the pannel ids.
+
+ /// Array of the panel ids.
QVector _panelIds;
};
+
+#endif // LEDEVICENANOLEAF_H
diff --git a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp
index d42687997..c2ca0835e 100644
--- a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp
+++ b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp
@@ -1,98 +1,129 @@
// Local-Hyperion includes
#include "LedDevicePhilipsHue.h"
-// ssdp discover
#include
+#include
+
+#include
bool verbose = false;
+// Constants
+namespace {
+
// Configuration settings
-static const char CONFIG_ADDRESS[] = "output";
-//static const char CONFIG_PORT[] = "port";
-static const char CONFIG_USERNAME[] = "username";
-static const char CONFIG_CLIENTKEY[] = "clientkey";
-static const char CONFIG_BRIGHTNESSFACTOR[] = "brightnessFactor";
-static const char CONFIG_TRANSITIONTIME[] = "transitiontime";
-static const char CONFIG_BLACK_LIGHTS_TIMEOUT[] = "blackLightsTimeout";
-static const char CONFIG_ON_OFF_BLACK[] = "switchOffOnBlack";
-static const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
-static const char CONFIG_LIGHTIDS[] = "lightIds";
-static const char CONFIG_USE_HUE_ENTERTAINMENT_API[] = "useEntertainmentAPI";
-static const char CONFIG_GROUPID[] = "groupId";
-
-static const char CONFIG_VERBOSE[] = "verbose";
-static const char CONFIG_BRIGHTNESS_MIN[] = "brightnessMin";
-static const char CONFIG_BRIGHTNESS_MAX[] = "brightnessMax";
-static const char CONFIG_BRIGHTNESS_THRESHOLD[] = "brightnessThreshold";
-
-static const char CONFIG_SSL_HANDSHAKE_TIMEOUT_MIN[] = "sslHSTimeoutMin";
-static const char CONFIG_SSL_HANDSHAKE_TIMEOUT_MAX[] = "sslHSTimeoutMax";
-static const char CONFIG_SSL_READ_TIMEOUT[] = "sslReadTimeout";
+const char CONFIG_ADDRESS[] = "output";
+//const char CONFIG_PORT[] = "port";
+const char CONFIG_USERNAME[] = "username";
+const char CONFIG_CLIENTKEY[] = "clientkey";
+const char CONFIG_BRIGHTNESSFACTOR[] = "brightnessFactor";
+const char CONFIG_TRANSITIONTIME[] = "transitiontime";
+const char CONFIG_BLACK_LIGHTS_TIMEOUT[] = "blackLightsTimeout";
+const char CONFIG_ON_OFF_BLACK[] = "switchOffOnBlack";
+const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
+const char CONFIG_LIGHTIDS[] = "lightIds";
+const char CONFIG_USE_HUE_ENTERTAINMENT_API[] = "useEntertainmentAPI";
+const char CONFIG_GROUPID[] = "groupId";
+
+const char CONFIG_VERBOSE[] = "verbose";
+const char CONFIG_BRIGHTNESS_MIN[] = "brightnessMin";
+const char CONFIG_BRIGHTNESS_MAX[] = "brightnessMax";
+const char CONFIG_BRIGHTNESS_THRESHOLD[] = "brightnessThreshold";
+
+const char CONFIG_SSL_HANDSHAKE_TIMEOUT_MIN[] = "sslHSTimeoutMin";
+const char CONFIG_SSL_HANDSHAKE_TIMEOUT_MAX[] = "sslHSTimeoutMax";
+const char CONFIG_SSL_READ_TIMEOUT[] = "sslReadTimeout";
// Device Data elements
-static const char DEV_DATA_BRIDGEID[] = "bridgeid";
-static const char DEV_DATA_MODEL[] = "modelid";
-static const char DEV_DATA_NAME[] = "name";
-//static const char DEV_DATA_MANUFACTURER[] = "manufacturer";
-static const char DEV_DATA_FIRMWAREVERSION[] = "swversion";
-static const char DEV_DATA_APIVERSION[] = "apiversion";
+const char DEV_DATA_BRIDGEID[] = "bridgeid";
+const char DEV_DATA_MODEL[] = "modelid";
+const char DEV_DATA_NAME[] = "name";
+//const char DEV_DATA_MANUFACTURER[] = "manufacturer";
+const char DEV_DATA_FIRMWAREVERSION[] = "swversion";
+const char DEV_DATA_APIVERSION[] = "apiversion";
// Philips Hue OpenAPI URLs
-static const char API_DEFAULT_PORT[] = "80";
-static const char API_URL_FORMAT[] = "http://%1:%2/api/%3/%4";
-static const char API_ROOT[] = "";
-static const char API_STATE[] = "state";
-static const char API_CONFIG[] = "config";
-static const char API_LIGHTS[] = "lights";
-static const char API_GROUPS[] = "groups";
+const int API_DEFAULT_PORT = -1; //Use default port per communication scheme
+const char API_BASE_PATH[] = "/api/%1/";
+const char API_ROOT[] = "";
+const char API_STATE[] = "state";
+const char API_CONFIG[] = "config";
+const char API_LIGHTS[] = "lights";
+const char API_GROUPS[] = "groups";
// List of Group / Stream Information
-static const char API_GROUP_NAME[] = "name";
-static const char API_GROUP_TYPE[] = "type";
-static const char API_GROUP_TYPE_ENTERTAINMENT[] = "Entertainment";
-static const char API_STREAM[] = "stream";
-static const char API_STREAM_ACTIVE[] = "active";
-static const char API_STREAM_ACTIVE_VALUE_TRUE[] = "true";
-static const char API_STREAM_ACTIVE_VALUE_FALSE[] = "false";
-static const char API_STREAM_OWNER[] = "owner";
-static const char API_STREAM_RESPONSE_FORMAT[] = "/%1/%2/%3/%4";
+const char API_GROUP_NAME[] = "name";
+const char API_GROUP_TYPE[] = "type";
+const char API_GROUP_TYPE_ENTERTAINMENT[] = "Entertainment";
+const char API_STREAM[] = "stream";
+const char API_STREAM_ACTIVE[] = "active";
+const char API_STREAM_ACTIVE_VALUE_TRUE[] = "true";
+const char API_STREAM_ACTIVE_VALUE_FALSE[] = "false";
+const char API_STREAM_OWNER[] = "owner";
+const char API_STREAM_RESPONSE_FORMAT[] = "/%1/%2/%3/%4";
// List of resources
-static const char API_XY_COORDINATES[] = "xy";
-static const char API_BRIGHTNESS[] = "bri";
-static const char API_TRANSITIONTIME[] = "transitiontime";
-static const char API_MODEID[] = "modelid";
+const char API_XY_COORDINATES[] = "xy";
+const char API_BRIGHTNESS[] = "bri";
+//const char API_SATURATION[] = "sat";
+const char API_TRANSITIONTIME[] = "transitiontime";
+const char API_MODEID[] = "modelid";
// List of State Information
-static const char API_STATE_ON[] = "on";
-static const char API_STATE_VALUE_TRUE[] = "true";
-static const char API_STATE_VALUE_FALSE[] = "false";
+const char API_STATE_ON[] = "on";
+const char API_STATE_VALUE_TRUE[] = "true";
+const char API_STATE_VALUE_FALSE[] = "false";
// List of Error Information
-static const char API_ERROR[] = "error";
-static const char API_ERROR_ADDRESS[] = "address";
-static const char API_ERROR_DESCRIPTION[] = "description";
-static const char API_ERROR_TYPE[] = "type";
+const char API_ERROR[] = "error";
+const char API_ERROR_ADDRESS[] = "address";
+const char API_ERROR_DESCRIPTION[] = "description";
+const char API_ERROR_TYPE[] = "type";
// List of Success Information
-static const char API_SUCCESS[] = "success";
+const char API_SUCCESS[] = "success";
// Phlips Hue ssdp services
-static const char SSDP_ID[] = "urn:schemas-upnp-org:device:Basic:1";
-const int SSDP_TIMEOUT = 5000; // timout in ms
+const char SSDP_ID[] = "upnp:rootdevice";
+const char SSDP_FILTER[] = "(.*)IpBridge(.*)";
+const char SSDP_FILTER_HEADER[] = "SERVER";
// DTLS Connection / SSL / Cipher Suite
-static const char API_SSL_SERVER_NAME[] = "Hue";
-static const char API_SSL_SEED_CUSTOM[] = "dtls_client";
+const char API_SSL_SERVER_NAME[] = "Hue";
+const char API_SSL_SEED_CUSTOM[] = "dtls_client";
const int API_SSL_SERVER_PORT = 2100;
const int STREAM_CONNECTION_RETRYS = 5;
-const int STREAM_REWRITE_TIME = 20;
const int STREAM_SSL_HANDSHAKE_ATTEMPTS = 5;
-const int STREAM_SSL_HANDSHAKE_TIMEOUT_MIN = 400;
-const int STREAM_SSL_HANDSHAKE_TIMEOUT_MAX = 1000;
-const int STREAM_SSL_READ_TIMEOUT = 0;
+constexpr std::chrono::milliseconds STREAM_REWRITE_TIME{20};
const int SSL_CIPHERSUITES[2] = { MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, 0 };
+//Streaming message header and payload definition
+const uint8_t HEADER[] =
+{
+ 'H', 'u', 'e', 'S', 't', 'r', 'e', 'a', 'm', //protocol
+ 0x01, 0x00, //version 1.0
+ 0x01, //sequence number 1
+ 0x00, 0x00, //Reserved write 0’s
+ 0x01, //xy Brightness
+ 0x00, // Reserved, write 0’s
+};
+
+const uint8_t PAYLOAD_PER_LIGHT[] =
+{
+ 0x01, 0x00, 0x06, //light ID
+ //color: 16 bpc
+ 0xff, 0xff,
+ 0xff, 0xff,
+ 0xff, 0xff,
+ /*
+ (message.R >> 8) & 0xff, message.R & 0xff,
+ (message.G >> 8) & 0xff, message.G & 0xff,
+ (message.B >> 8) & 0xff, message.B & 0xff
+ */
+};
+
+} //End of constants
+
bool operator ==(const CiColor& p1, const CiColor& p2)
{
return ((p1.x == p2.x) && (p1.y == p2.y) && (p1.bri == p2.bri));
@@ -191,6 +222,7 @@ double CiColor::crossProduct(XYColor p1, XYColor p2)
bool CiColor::isPointInLampsReach(CiColor p, const CiColorTriangle &colorSpace)
{
+ bool rc = false;
XYColor v1 = { colorSpace.green.x - colorSpace.red.x, colorSpace.green.y - colorSpace.red.y };
XYColor v2 = { colorSpace.blue.x - colorSpace.red.x, colorSpace.blue.y - colorSpace.red.y };
XYColor q = { p.x - colorSpace.red.x, p.y - colorSpace.red.y };
@@ -198,9 +230,9 @@ bool CiColor::isPointInLampsReach(CiColor p, const CiColorTriangle &colorSpace)
double t = crossProduct(v1, q) / crossProduct(v1, v2);
if ( ( s >= 0.0 ) && ( t >= 0.0 ) && ( s + t <= 1.0 ) )
{
- return true;
+ rc = true;
}
- return false;
+ return rc;
}
XYColor CiColor::getClosestPointToPoint(XYColor a, XYColor b, CiColor p)
@@ -233,23 +265,24 @@ double CiColor::getDistanceBetweenTwoPoints(CiColor p1, XYColor p2)
LedDevicePhilipsHueBridge::LedDevicePhilipsHueBridge(const QJsonObject &deviceConfig)
: ProviderUdpSSL()
+ , _restApi(nullptr)
+ , _apiPort(API_DEFAULT_PORT)
, _useHueEntertainmentAPI(false)
- , _networkmanager(nullptr)
, _api_major(0)
, _api_minor(0)
, _api_patch(0)
, _isHueEntertainmentReady(false)
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
}
LedDevicePhilipsHueBridge::~LedDevicePhilipsHueBridge()
{
- if ( _networkmanager != nullptr )
+ if ( _restApi != nullptr )
{
- delete _networkmanager;
- _networkmanager = nullptr;
+ delete _restApi;
+ _restApi = nullptr;
}
}
@@ -267,81 +300,107 @@ bool LedDevicePhilipsHueBridge::init(const QJsonObject &deviceConfig)
DebugIf( verbose, _log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
- bool isInitOK = LedDevice::init(deviceConfig);
-
- log( "DeviceType", "%s", QSTRING_CSTR( this->getActiveDeviceType() ) );
- log( "LedCount", "%u", this->getLedCount() );
- log( "ColorOrder", "%s", QSTRING_CSTR( this->getColorOrder() ) );
- log( "RefreshTime", "%d", _refresh_timer_interval );
- log( "LatchTime", "%d", this->getLatchTime() );
+ bool isInitOK = false;
- if ( isInitOK )
+ if ( LedDevice::init(deviceConfig) )
{
+
+ log( "DeviceType", "%s", QSTRING_CSTR( this->getActiveDeviceType() ) );
+ log( "LedCount", "%u", this->getLedCount() );
+ log( "ColorOrder", "%s", QSTRING_CSTR( this->getColorOrder() ) );
+ log( "RefreshTime", "%d", _refreshTimerInterval_ms );
+ log( "LatchTime", "%d", this->getLatchTime() );
+
//Set hostname as per configuration and_defaultHost default port
QString address = deviceConfig[ CONFIG_ADDRESS ].toString();
- if ( !address.isEmpty() )
+ //If host not configured the init failed
+ if ( address.isEmpty() )
{
- #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
- QStringList addressparts = address.split(":", Qt::SkipEmptyParts);
- #else
- QStringList addressparts = address.split(":", QString::SkipEmptyParts);
- #endif
-
+ this->setInError("No target hostname nor IP defined");
+ return false;
+ }
+ else
+ {
+ QStringList addressparts = QStringUtils::split(address,":", QStringUtils::SplitBehavior::SkipEmptyParts);
_hostname = addressparts[0];
+ log( "Hostname/IP", "%s", QSTRING_CSTR( _hostname ) );
+
if ( addressparts.size() > 1 )
{
- _api_port = addressparts[1];
+ _apiPort = addressparts[1].toInt();
+ log( "Port", "%u", _apiPort );
}
- else
+
+ _username = deviceConfig[ CONFIG_USERNAME ].toString();
+
+ if ( initRestAPI( _hostname, _apiPort, _username ) )
{
- _api_port = API_DEFAULT_PORT;
+ if ( initMaps() )
+ {
+ isInitOK = ProviderUdpSSL::init(_devConfig);
+ }
}
}
- _username = deviceConfig[ CONFIG_USERNAME ].toString();
-
- log( "Hostname/IP", "%s", QSTRING_CSTR( _hostname ) );
- log( "Port", "%s", QSTRING_CSTR( _api_port ) );
}
+
return isInitOK;
}
-int LedDevicePhilipsHueBridge::open()
+bool LedDevicePhilipsHueBridge::initRestAPI(const QString &hostname, const int port, const QString &token )
{
- return open( _hostname, _api_port, _username );
+ bool isInitOK = false;
+
+ if ( _restApi == nullptr )
+ {
+ _restApi = new ProviderRestApi(hostname, port);
+
+ //Base-path is api-path + authentication token (here username)
+ _restApi->setBasePath( QString(API_BASE_PATH).arg(token) );
+
+ isInitOK = true;
+ }
+
+
+ return isInitOK;
}
-int LedDevicePhilipsHueBridge::open( const QString& hostname, const QString& port, const QString& username )
+int LedDevicePhilipsHueBridge::open()
{
- _deviceInError = false;
- bool isInitOK = true;
+ int retval = -1;
+ _isDeviceReady = false;
- //If host not configured then discover device
- if ( hostname.isEmpty() )
+ if( _useHueEntertainmentAPI )
{
- //Discover Philips Hue Bridge device
- if ( !discoverDevice() )
+ // Open bridge for streaming
+ if ( ProviderUdpSSL::open() == 0 )
{
- this->setInError( "No target IP defined nor Philips Hue Bridge was discovered" );
- return false;
+ // Everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
}
}
else
{
- _hostname = hostname;
- _api_port = port;
+ // Everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
}
- _username = username;
- //Get Philips Hue Bridge details and configuration
- if ( _networkmanager == nullptr )
+ return retval;
+}
+
+int LedDevicePhilipsHueBridge::close()
+{
+ _isDeviceReady = false;
+ int retval = 0;
+
+ if( _useHueEntertainmentAPI )
{
- _networkmanager = new QNetworkAccessManager();
+ retval = ProviderUdpSSL::close();
}
- isInitOK = initMaps();
-
- return isInitOK;
+ return retval;
}
const int *LedDevicePhilipsHueBridge::getCiphersuites()
@@ -366,8 +425,12 @@ void LedDevicePhilipsHueBridge::log(const char* msg, const char* type, ...)
QJsonDocument LedDevicePhilipsHueBridge::getAllBridgeInfos()
{
// Read Groups/ Lights and Light-Ids
- QString url = getUrl( _hostname, _api_port, _username, API_ROOT );
- return getJson( url );
+ _restApi->setPath(API_ROOT);
+
+ httpResponse response = _restApi->get();
+ checkApiError(response.getBody());
+
+ return response.getBody();
}
bool LedDevicePhilipsHueBridge::initMaps()
@@ -385,14 +448,17 @@ bool LedDevicePhilipsHueBridge::initMaps()
else
{
setBridgeConfig( doc );
- if( _useHueEntertainmentAPI ) setGroupMap( doc );
+ if( _useHueEntertainmentAPI )
+ {
+ setGroupMap( doc );
+ }
setLightsMap( doc );
}
return isInitOK;
}
-void LedDevicePhilipsHueBridge::setBridgeConfig(QJsonDocument doc)
+void LedDevicePhilipsHueBridge::setBridgeConfig(const QJsonDocument &doc)
{
QJsonObject jsonConfigInfo = doc.object()[ API_CONFIG ].toObject();
if ( verbose )
@@ -406,12 +472,7 @@ void LedDevicePhilipsHueBridge::setBridgeConfig(QJsonDocument doc)
_deviceFirmwareVersion = jsonConfigInfo[DEV_DATA_FIRMWAREVERSION].toString();
_deviceAPIVersion = jsonConfigInfo[DEV_DATA_APIVERSION].toString();
- #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
- QStringList apiVersionParts = _deviceAPIVersion.split(".", Qt::SkipEmptyParts);
- #else
- QStringList apiVersionParts = _deviceAPIVersion.split(".", QString::SkipEmptyParts);
- #endif
-
+ QStringList apiVersionParts = QStringUtils::split(_deviceAPIVersion,".", QStringUtils::SplitBehavior::SkipEmptyParts);
if ( !apiVersionParts.isEmpty() )
{
_api_major = apiVersionParts[0].toUInt();
@@ -438,7 +499,7 @@ void LedDevicePhilipsHueBridge::setBridgeConfig(QJsonDocument doc)
log( "EntertainmentReady", "%d", _isHueEntertainmentReady );
}
-void LedDevicePhilipsHueBridge::setLightsMap(QJsonDocument doc)
+void LedDevicePhilipsHueBridge::setLightsMap(const QJsonDocument &doc)
{
QJsonObject jsonLightsInfo = doc.object()[ API_LIGHTS ].toObject();
@@ -447,12 +508,12 @@ void LedDevicePhilipsHueBridge::setLightsMap(QJsonDocument doc)
// Get all available light ids and their values
QStringList keys = jsonLightsInfo.keys();
- _ledCount = keys.size();
+ _ledCount = static_cast(keys.size());
_lightsMap.clear();
- for ( unsigned int i = 0; i < _ledCount; ++i )
+ for ( int i = 0; i < static_cast(_ledCount); ++i )
{
- _lightsMap.insert(keys.at(i).toUInt(), jsonLightsInfo.take(keys.at(i)).toObject());
+ _lightsMap.insert(keys.at(i).toUShort(), jsonLightsInfo.take(keys.at(i)).toObject());
}
if ( getLedCount() == 0 )
@@ -465,7 +526,7 @@ void LedDevicePhilipsHueBridge::setLightsMap(QJsonDocument doc)
}
}
-void LedDevicePhilipsHueBridge::setGroupMap(QJsonDocument doc)
+void LedDevicePhilipsHueBridge::setGroupMap(const QJsonDocument &doc)
{
QJsonObject jsonGroupsInfo = doc.object()[ API_GROUPS ].toObject();
@@ -474,47 +535,15 @@ void LedDevicePhilipsHueBridge::setGroupMap(QJsonDocument doc)
// Get all available group ids and their values
QStringList keys = jsonGroupsInfo.keys();
- unsigned int _groupsCount = keys.size();
+ int _groupsCount = keys.size();
_groupsMap.clear();
- for ( unsigned int i = 0; i < _groupsCount; ++i )
+ for ( int i = 0; i < _groupsCount; ++i )
{
- _groupsMap.insert( keys.at(i).toUInt(), jsonGroupsInfo.take(keys.at(i)).toObject() );
+ _groupsMap.insert( keys.at(i).toUShort(), jsonGroupsInfo.take(keys.at(i)).toObject() );
}
}
-bool LedDevicePhilipsHueBridge::discoverDevice()
-{
- bool isDeviceFound( false );
-
- // device searching by ssdp
- QString address;
- SSDPDiscover discover;
-
- // Discover Philips Hue Bridge
- address = discover.getFirstService( searchType::STY_WEBSERVER, SSDP_ID, SSDP_TIMEOUT );
- if ( address.isEmpty() )
- {
- Warning(_log, "No Philips Hue Bridge discovered" );
- }
- else
- {
- // Philips Hue Bridge found
- Info(_log, "Philips Hue Bridge discovered at [%s]", QSTRING_CSTR( address ) );
- isDeviceFound = true;
-
- #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
- QStringList addressparts = address.split(":", Qt::SkipEmptyParts);
- #else
- QStringList addressparts = address.split(":", QString::SkipEmptyParts);
- #endif
-
- _hostname = addressparts[0];
- _api_port = addressparts[1];
- }
- return isDeviceFound;
-}
-
const QMap& LedDevicePhilipsHueBridge::getLightMap(void)
{
return _lightsMap;
@@ -525,7 +554,7 @@ const QMap& LedDevicePhilipsHueBridge::getGroupMap(void)
return _groupsMap;
}
-QString LedDevicePhilipsHueBridge::getGroupName(unsigned int groupId)
+QString LedDevicePhilipsHueBridge::getGroupName(quint16 groupId)
{
QString groupName;
if( _groupsMap.contains( groupId ) )
@@ -535,12 +564,12 @@ QString LedDevicePhilipsHueBridge::getGroupName(unsigned int groupId)
}
else
{
- Error(_log, "Group ID %d doesn't exists on this bridge", groupId );
+ Error(_log, "Group ID %u doesn't exists on this bridge", groupId );
}
return groupName;
}
-QJsonArray LedDevicePhilipsHueBridge::getGroupLights(unsigned int groupId)
+QJsonArray LedDevicePhilipsHueBridge::getGroupLights(quint16 groupId)
{
QJsonArray groupLights;
// search user groupid inside _groupsMap and create light if found
@@ -570,144 +599,50 @@ QJsonArray LedDevicePhilipsHueBridge::getGroupLights(unsigned int groupId)
return groupLights;
}
-QString LedDevicePhilipsHueBridge::getUrl(QString host, QString port, QString auth_token, QString endpoint) const {
- return QString(API_URL_FORMAT).arg( host, port, auth_token, endpoint );
-}
-
-QJsonDocument LedDevicePhilipsHueBridge::getJson(QString url)
+bool LedDevicePhilipsHueBridge::checkApiError(const QJsonDocument &response )
{
- DebugIf(verbose, _log, "GET: [%s]", QSTRING_CSTR( url ));
-
- // Perfrom request
- QNetworkRequest request(url);
- QNetworkReply* reply = _networkmanager->get(request);
- // Connect requestFinished signal to quit slot of the loop.
- QEventLoop loop;
- loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
- // Go into the loop until the request is finished.
- loop.exec();
-
- QJsonDocument jsonDoc;
- if( reply->operation() == QNetworkAccessManager::GetOperation )
- {
- jsonDoc = handleReply( reply );
- }
- // Free space.
- reply->deleteLater();
- // Return response
- return jsonDoc;
-}
+ bool apiError = false;
+ QString errorReason;
-QJsonDocument LedDevicePhilipsHueBridge::putJson(QString url, QString json)
-{
- DebugIf(verbose, _log, "PUT: [%s] [%s]", QSTRING_CSTR( url ), QSTRING_CSTR( json ) );
- // Perfrom request
- QNetworkRequest request( url );
- QNetworkReply* reply = _networkmanager->put( request, json.toUtf8() );
- // Connect requestFinished signal to quit slot of the loop.
- QEventLoop loop;
- loop.connect(reply, SIGNAL(finished()), SLOT(quit()));
- // Go into the loop until the request is finished.
- loop.exec();
+ QString strJson(response.toJson(QJsonDocument::Compact));
+ DebugIf(verbose, _log, "Reply: [%s]", strJson.toUtf8().constData() );
- QJsonDocument jsonDoc;
- if( reply->operation() == QNetworkAccessManager::PutOperation )
+ QVariantList rspList = response.toVariant().toList();
+ if ( !rspList.isEmpty() )
{
- jsonDoc = handleReply( reply );
- }
- // Free space.
- reply->deleteLater();
- // Return response
- return jsonDoc;
-}
-
-QJsonDocument LedDevicePhilipsHueBridge::handleReply(QNetworkReply* const &reply )
-{
- QJsonDocument jsonDoc;
+ QVariantMap map = rspList.first().toMap();
+ if ( map.contains( API_ERROR ) )
+ {
+ // API call failed to execute an error message was returned
+ QString errorAddress = map.value(API_ERROR).toMap().value(API_ERROR_ADDRESS).toString();
+ QString errorDesc = map.value(API_ERROR).toMap().value(API_ERROR_DESCRIPTION).toString();
+ QString errorType = map.value(API_ERROR).toMap().value(API_ERROR_TYPE).toString();
- int httpStatusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
- DebugIf(verbose, _log, "Reply.httpStatusCode [%d]", httpStatusCode );
- QString errorReason;
+ log( "Error Type", "%s", QSTRING_CSTR( errorType ) );
+ log( "Error Address", "%s", QSTRING_CSTR( errorAddress ) );
+ log( "Error Address Description", "%s", QSTRING_CSTR( errorDesc ) );
- if( reply->error() == QNetworkReply::NoError )
- {
- if ( httpStatusCode != 204 )
- {
- QByteArray response = reply->readAll();
- QJsonParseError error;
- jsonDoc = QJsonDocument::fromJson(response, &error);
- if ( error.error != QJsonParseError::NoError )
+ if( errorType != "901" )
{
- this->setInError( "Got invalid response" );
- }
- else
- {
- QString strJson(jsonDoc.toJson(QJsonDocument::Compact));
- DebugIf(verbose, _log, "Reply: [%s]", strJson.toUtf8().constData() );
-
- QVariantList rspList = jsonDoc.toVariant().toList();
- if ( !rspList.isEmpty() )
- {
- QVariantMap map = rspList.first().toMap();
- if ( map.contains( API_ERROR ) )
- {
- // API call failsed to execute an error message was returned
- QString errorAddress = map.value(API_ERROR).toMap().value(API_ERROR_ADDRESS).toString();
- QString errorDesc = map.value(API_ERROR).toMap().value(API_ERROR_DESCRIPTION).toString();
- QString errorType = map.value(API_ERROR).toMap().value(API_ERROR_TYPE).toString();
-
- log( "Error Type", "%s", QSTRING_CSTR( errorType ) );
- log( "Error Address", "%s", QSTRING_CSTR( errorAddress ) );
- log( "Error Address Description", "%s", QSTRING_CSTR( errorDesc ) );
-
- if( errorType != "901" )
- {
- errorReason = QString ("(%1) %2, Resource:%3").arg(errorType, errorDesc, errorAddress);
- this->setInError( errorReason );
- }
- }
- }
+ errorReason = QString ("(%1) %2, Resource:%3").arg(errorType, errorDesc, errorAddress);
+ this->setInError( errorReason );
+ apiError = true;
}
}
}
- else
- {
- if ( httpStatusCode > 0 )
- {
- QString httpReason = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString();
- QString advise;
- switch ( httpStatusCode ) {
- case 400:
- advise = "Check Request Body";
- break;
- case 401:
- advise = "Check Authentication Token (API Key)";
- break;
- case 404:
- advise = "Check Resource given";
- break;
- default:
- break;
- }
- errorReason = QString( "%1:%2 [%3 %4] - %5").arg( _hostname, _api_port, QString(httpStatusCode), httpReason, advise );
- }
- else
- {
- errorReason = QString( "%1:%2 - %3").arg( _hostname, _api_port, reply->errorString() );
- }
- this->setInError( errorReason );
- }
- // Return response
- return jsonDoc;
+ return apiError;
}
QJsonDocument LedDevicePhilipsHueBridge::post(const QString& route, const QString& content)
{
- QString url = getUrl(_hostname, _api_port, _username, route );
- return putJson( url, content );
+ _restApi->setPath(route);
+
+ httpResponse response = _restApi->put(content);
+ checkApiError(response.getBody());
+ return response.getBody();
}
-void LedDevicePhilipsHueBridge::setLightState(const unsigned int lightId, QString state)
+void LedDevicePhilipsHueBridge::setLightState(const unsigned int lightId, const QString &state)
{
DebugIf( verbose, _log, "SetLightState [%u]: %s", lightId, QSTRING_CSTR(state) );
post( QString("%1/%2/%3").arg( API_LIGHTS ).arg( lightId ).arg( API_STATE ), state );
@@ -715,17 +650,19 @@ void LedDevicePhilipsHueBridge::setLightState(const unsigned int lightId, QStrin
QJsonDocument LedDevicePhilipsHueBridge::getGroupState(const unsigned int groupId)
{
- QString url = getUrl( _hostname, _api_port, _username, QString("%1/%2").arg( API_GROUPS ).arg( groupId ) );
- return getJson( url );
+ _restApi->setPath( QString("%1/%2").arg( API_GROUPS ).arg( groupId ) );
+ httpResponse response = _restApi->get();
+ checkApiError(response.getBody());
+ return response.getBody();
}
QJsonDocument LedDevicePhilipsHueBridge::setGroupState(const unsigned int groupId, bool state)
{
QString active = state ? API_STREAM_ACTIVE_VALUE_TRUE : API_STREAM_ACTIVE_VALUE_FALSE;
- return post( QString("%1/%2").arg( API_GROUPS ).arg( groupId ), QString("{\"%1\":{\"%2\":%3}}").arg( API_STREAM ).arg( API_STREAM_ACTIVE ).arg( active ) );
+ return post( QString("%1/%2").arg( API_GROUPS ).arg( groupId ), QString("{\"%1\":{\"%2\":%3}}").arg( API_STREAM, API_STREAM_ACTIVE, active ) );
}
-bool LedDevicePhilipsHueBridge::isStreamOwner(const QString streamOwner)
+bool LedDevicePhilipsHueBridge::isStreamOwner(const QString &streamOwner)
{
return ( streamOwner != "" && streamOwner == _username );
}
@@ -839,7 +776,7 @@ void PhilipsHueLight::setOnOffState(bool on)
this->_on = on;
}
-void PhilipsHueLight::setTransitionTime(unsigned int transitionTime)
+void PhilipsHueLight::setTransitionTime(int transitionTime)
{
this->_transitionTime = transitionTime;
}
@@ -854,7 +791,7 @@ bool PhilipsHueLight::getOnOffState() const
return _on;
}
-unsigned int PhilipsHueLight::getTransitionTime() const
+int PhilipsHueLight::getTransitionTime() const
{
return _transitionTime;
}
@@ -874,7 +811,6 @@ LedDevicePhilipsHue::LedDevicePhilipsHue(const QJsonObject& deviceConfig)
, _switchOffOnBlack(false)
, _brightnessFactor(1.0)
, _transitionTime(1)
- , _isRestoreOrigState(true)
, _lightStatesRestored(false)
, _isInitLeds(false)
, _lightsCount(0)
@@ -885,15 +821,17 @@ LedDevicePhilipsHue::LedDevicePhilipsHue(const QJsonObject& deviceConfig)
, _blackLightsTimer(nullptr)
, _blackLightsTimeout(15000)
, _brightnessThreshold(0.0)
- , _handshake_timeout_min(STREAM_SSL_HANDSHAKE_TIMEOUT_MIN)
- , _handshake_timeout_max(STREAM_SSL_HANDSHAKE_TIMEOUT_MAX)
- , _ssl_read_timeout(STREAM_SSL_READ_TIMEOUT)
+ , _handshake_timeout_min(STREAM_SSL_HANDSHAKE_TIMEOUT_MIN.count())
+ , _handshake_timeout_max(STREAM_SSL_HANDSHAKE_TIMEOUT_MAX.count())
+ , _ssl_read_timeout(STREAM_SSL_READ_TIMEOUT.count())
, _stopConnection(false)
, start_retry_left(3)
, stop_retry_left(3)
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDevicePhilipsHue::construct(const QJsonObject &deviceConfig)
@@ -903,10 +841,7 @@ LedDevice* LedDevicePhilipsHue::construct(const QJsonObject &deviceConfig)
LedDevicePhilipsHue::~LedDevicePhilipsHue()
{
- if ( _blackLightsTimer != nullptr )
- {
- _blackLightsTimer->deleteLater();
- }
+ delete _blackLightsTimer;
}
bool LedDevicePhilipsHue::init(const QJsonObject &deviceConfig)
@@ -917,32 +852,32 @@ bool LedDevicePhilipsHue::init(const QJsonObject &deviceConfig)
if ( isInitOK )
{
- // Initiatiale LedDevice configuration and execution environment
+ // Initialise LedDevice configuration and execution environment
_switchOffOnBlack = _devConfig[CONFIG_ON_OFF_BLACK].toBool(true);
_blackLightsTimeout = _devConfig[CONFIG_BLACK_LIGHTS_TIMEOUT].toInt(15000);
_brightnessFactor = _devConfig[CONFIG_BRIGHTNESSFACTOR].toDouble(1.0);
_transitionTime = _devConfig[CONFIG_TRANSITIONTIME].toInt(1);
_isRestoreOrigState = _devConfig[CONFIG_RESTORE_STATE].toBool(true);
- _groupId = _devConfig[CONFIG_GROUPID].toInt(0);
+ _groupId = static_cast(_devConfig[CONFIG_GROUPID].toInt(0));
_brightnessMin = _devConfig[CONFIG_BRIGHTNESS_MIN].toDouble(0.0);
_brightnessMax = _devConfig[CONFIG_BRIGHTNESS_MAX].toDouble(1.0);
_brightnessThreshold = _devConfig[CONFIG_BRIGHTNESS_THRESHOLD].toDouble(0.0);
- _handshake_timeout_min = _devConfig[CONFIG_SSL_HANDSHAKE_TIMEOUT_MIN].toInt(STREAM_SSL_HANDSHAKE_TIMEOUT_MIN);
- _handshake_timeout_max = _devConfig[CONFIG_SSL_HANDSHAKE_TIMEOUT_MAX].toInt(STREAM_SSL_HANDSHAKE_TIMEOUT_MAX);
- _ssl_read_timeout = _devConfig[CONFIG_SSL_READ_TIMEOUT].toInt(STREAM_SSL_READ_TIMEOUT);
+ _handshake_timeout_min = _devConfig[CONFIG_SSL_HANDSHAKE_TIMEOUT_MIN].toInt(STREAM_SSL_HANDSHAKE_TIMEOUT_MIN.count());
+ _handshake_timeout_max = _devConfig[CONFIG_SSL_HANDSHAKE_TIMEOUT_MAX].toInt(STREAM_SSL_HANDSHAKE_TIMEOUT_MAX.count());
+ _ssl_read_timeout = _devConfig[CONFIG_SSL_READ_TIMEOUT].toInt(STREAM_SSL_READ_TIMEOUT.count());
- if( _brightnessMin < 0.0 ) _brightnessMin = 0.0;
- if( _brightnessMax > 1.0 ) _brightnessMax = 1.0;
- if( _brightnessThreshold < 0.0 ) _brightnessThreshold = 0.0;
- if( _brightnessThreshold > 1.0 ) _brightnessThreshold = 1.0;
+ if( _brightnessMin < 0.0 ) { _brightnessMin = 0.0; }
+ if( _brightnessMax > 1.0 ) { _brightnessMax = 1.0; }
+ if( _brightnessThreshold < 0.0 ) { _brightnessThreshold = 0.0; }
+ if( _brightnessThreshold > 1.0 ) { _brightnessThreshold = 1.0; }
- if( _handshake_timeout_min <= 0 ) _handshake_timeout_min = 1;
+ if( _handshake_timeout_min <= 0 ) { _handshake_timeout_min = 1; }
- log( "Off on Black", "%d", _switchOffOnBlack );
+ log( "Off on Black", "%d", static_cast( _switchOffOnBlack ) );
log( "Brightness Factor", "%f", _brightnessFactor );
log( "Transition Time", "%d", _transitionTime );
- log( "Restore Original State", "%d", _isRestoreOrigState );
- log( "Use Hue Entertainment API", "%d", _useHueEntertainmentAPI );
+ log( "Restore Original State", "%d", static_cast( _isRestoreOrigState ) );
+ log( "Use Hue Entertainment API", "%d", static_cast( _useHueEntertainmentAPI) );
if( _useHueEntertainmentAPI )
{
@@ -958,6 +893,8 @@ bool LedDevicePhilipsHue::init(const QJsonObject &deviceConfig)
_useHueEntertainmentAPI = false;
}
}
+
+ isInitOK = initLeds();
}
return isInitOK;
@@ -990,7 +927,7 @@ bool LedDevicePhilipsHue::setLights()
if( !lArray.empty() )
{
- for(const auto id : lArray)
+ for (const auto id : lArray)
{
unsigned int lightId = id.toString().toUInt();
if( lightId > 0 )
@@ -998,7 +935,10 @@ bool LedDevicePhilipsHue::setLights()
if(std::find(_lightIds.begin(), _lightIds.end(), lightId) == _lightIds.end())
{
_lightIds.emplace_back(lightId);
- if(!lightIDStr.isEmpty()) lightIDStr.append(", ");
+ if(!lightIDStr.isEmpty())
+ {
+ lightIDStr.append(", ");
+ }
lightIDStr.append(QString::number(lightId));
}
}
@@ -1024,34 +964,6 @@ bool LedDevicePhilipsHue::setLights()
return isInitOK;
}
-int LedDevicePhilipsHue::open()
-{
- int retval = -1;
- QString errortext;
- _deviceReady = false;
-
- // General initialisation and configuration of LedDevice
- if ( init(_devConfig) )
- {
- if ( LedDevicePhilipsHueBridge::open() )
- // Open/Start LedDevice based on configuration
- {
- if ( initLeds() )
- {
- // Everything is OK -> enable device
- _deviceReady = true;
- setEnable(true);
- retval = 0;
- }
- else
- {
- Debug(_log, "Device not usable." );
- }
- }
- }
- return retval;
-}
-
bool LedDevicePhilipsHue::initLeds()
{
bool isInitOK = false;
@@ -1067,7 +979,7 @@ bool LedDevicePhilipsHue::initLeds()
_devConfig["host"] = _hostname;
_devConfig["sslport"] = API_SSL_SERVER_PORT;
_devConfig["servername"] = API_SSL_SERVER_NAME;
- _devConfig["rewriteTime"] = STREAM_REWRITE_TIME;
+ _devConfig["rewriteTime"] = static_cast( STREAM_REWRITE_TIME.count() );
_devConfig["psk"] = _devConfig[ CONFIG_CLIENTKEY ].toString();
_devConfig["psk_identity"] = _devConfig[ CONFIG_USERNAME ].toString();
_devConfig["seed_custom"] = API_SSL_SEED_CUSTOM;
@@ -1105,7 +1017,7 @@ bool LedDevicePhilipsHue::initLeds()
return isInitOK;
}
-bool LedDevicePhilipsHue::updateLights(QMap map)
+bool LedDevicePhilipsHue::updateLights(const QMap &map)
{
bool isInitOK = true;
@@ -1143,7 +1055,7 @@ bool LedDevicePhilipsHue::updateLights(QMap map)
return isInitOK;
}
-bool LedDevicePhilipsHue::initStream()
+bool LedDevicePhilipsHue::openStream()
{
bool isInitOK = false;
@@ -1165,7 +1077,7 @@ bool LedDevicePhilipsHue::initStream()
{
Debug(_log, "Stream successful stopped");
//Restore Philips Hue devices state
- restoreOriginalState();
+ restoreState();
isInitOK = startStream();
}
else
@@ -1212,10 +1124,11 @@ bool LedDevicePhilipsHue::startStream()
{
Debug(_log, "Start entertainment stream");
+ bool rc = false;
if ( setStreamGroupState( true ) )
{
start_retry_left = 3;
- return true;
+ rc = true;
}
else
{
@@ -1229,23 +1142,24 @@ bool LedDevicePhilipsHue::startStream()
// stream is not active
if( !streamState )
{
- return ( start_retry_left-- > 0 ) ? startStream() : false;
+ rc = ( start_retry_left-- > 0 ) ? startStream() : false;
}
}
}
}
- return false;
+ return rc;
}
bool LedDevicePhilipsHue::stopStream()
{
ProviderUdpSSL::closeSSLConnection();
+ bool rc = false;
if ( setStreamGroupState( false ) )
{
stop_retry_left = 3;
- return true;
+ rc = true;
}
else
{
@@ -1259,13 +1173,13 @@ bool LedDevicePhilipsHue::stopStream()
// stream is still active
if( streamState )
{
- return (stop_retry_left-- > 0) ? stopStream() : false;
+ rc = (stop_retry_left-- > 0) ? stopStream() : false;
}
}
}
}
- return false;
+ return rc;
}
bool LedDevicePhilipsHue::getStreamGroupState()
@@ -1298,23 +1212,42 @@ bool LedDevicePhilipsHue::setStreamGroupState(bool state)
QJsonDocument doc = setGroupState( _groupId, state );
QVariant rsp = doc.toVariant();
- QVariantMap map = rsp.toList().first().toMap();
- if ( !map.contains( API_SUCCESS ) )
- {
- this->setInError( QString("set stream to %1: Neither error nor success contained in Bridge response...").arg( active ) );
- }
- else
+ QVariantList list = rsp.toList();
+ if ( !list.isEmpty() )
{
- QString valueName = QString( API_STREAM_RESPONSE_FORMAT ).arg( API_GROUPS ).arg( _groupId ).arg( API_STREAM ).arg( API_STREAM_ACTIVE );
- if(!map.value( API_SUCCESS ).toMap().value( valueName ).isValid())
+ QVariantMap map = list.first().toMap();
+
+ if ( !map.contains( API_SUCCESS ) )
{
- this->setInError( QString("set stream to %1: Bridge response is not Valid").arg( active ) );
+ this->setInError( QString("set stream to %1: Neither error nor success contained in Bridge response...").arg( active ) );
}
else
{
- bool groupStreamState = map.value( API_SUCCESS ).toMap().value( valueName ).toBool();
- return ( groupStreamState == state );
+ //Check original Hue response {"success":{"/groups/groupID/stream/active":activeYesNo}}
+ QString valueName = QString( API_STREAM_RESPONSE_FORMAT ).arg( API_GROUPS ).arg( _groupId ).arg( API_STREAM, API_STREAM_ACTIVE );
+ if(!map.value( API_SUCCESS ).toMap().value( valueName ).isValid())
+ {
+ //Workaround
+ //Check diyHue response {"success":{"/groups/groupID/stream":{"active":activeYesNo}}}
+ QString diyHueValueName = QString( "/%1/%2/%3" ).arg( API_GROUPS ).arg( _groupId ).arg( API_STREAM);
+ QJsonObject diyHueActiveState = map.value( API_SUCCESS ).toMap().value( diyHueValueName ).toJsonObject();
+
+ if( diyHueActiveState.isEmpty() )
+ {
+ this->setInError( QString("set stream to %1: Bridge response is not Valid").arg( active ) );
+ }
+ else
+ {
+ bool groupStreamState = diyHueActiveState[API_STREAM_ACTIVE].toBool();
+ return ( groupStreamState == state );
+ }
+ }
+ else
+ {
+ bool groupStreamState = map.value( API_SUCCESS ).toMap().value( valueName ).toBool();
+ return ( groupStreamState == state );
+ }
}
}
@@ -1323,33 +1256,9 @@ bool LedDevicePhilipsHue::setStreamGroupState(bool state)
QByteArray LedDevicePhilipsHue::prepareStreamData()
{
- static const uint8_t HEADER[] =
- {
- 'H', 'u', 'e', 'S', 't', 'r', 'e', 'a', 'm', //protocol
- 0x01, 0x00, //version 1.0
- 0x01, //sequence number 1
- 0x00, 0x00, //Reserved write 0’s
- 0x01, //xy Brightness
- 0x00, // Reserved, write 0’s
- };
-
- static const uint8_t PAYLOAD_PER_LIGHT[] =
- {
- 0x01, 0x00, 0x06, //light ID
- //color: 16 bpc
- 0xff, 0xff,
- 0xff, 0xff,
- 0xff, 0xff,
- /*
- (message.R >> 8) & 0xff, message.R & 0xff,
- (message.G >> 8) & 0xff, message.G & 0xff,
- (message.B >> 8) & 0xff, message.B & 0xff
- */
- };
-
QByteArray msg;
msg.reserve(static_cast(sizeof(HEADER) + sizeof(PAYLOAD_PER_LIGHT) * _lights.size()));
- msg.append((char*)HEADER, sizeof(HEADER));
+ msg.append((const char*)HEADER, sizeof(HEADER));
for (PhilipsHueLight& light : _lights)
{
@@ -1370,43 +1279,70 @@ QByteArray LedDevicePhilipsHue::prepareStreamData()
return msg;
}
-void LedDevicePhilipsHue::restoreOriginalState()
+void LedDevicePhilipsHue::stop()
{
- if ( _isRestoreOrigState && !_lightStatesRestored )
- {
- _lightStatesRestored = true;
+ stopBlackTimeoutTimer();
+ LedDevicePhilipsHueBridge::stop();
+}
- if( !_lightIds.empty() )
+int LedDevicePhilipsHue::open()
+{
+ int retval = -1;
+ _isDeviceReady = false;
+
+ if( _useHueEntertainmentAPI )
+ {
+ if ( openStream() )
{
- for ( PhilipsHueLight& light : _lights )
- {
- setLightState( light.getId(),light.getOriginalState() );
- }
+ // Everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
+ }
+ else
+ {
+ // TODO: Stop device (or fallback to classic mode) - suggest to stop device to meet user expectation
+ //_useHueEntertainmentAPI = false; -to be removed, if 1
+ // Everything is OK, device is ready
}
}
+ else
+ {
+ // Classic mode, everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
+ }
+
+ return retval;
+}
+
+int LedDevicePhilipsHue::close()
+{
+ int retval = -1;
+
+ retval = LedDevicePhilipsHueBridge::close();
+
+ return retval;
}
-void LedDevicePhilipsHue::close()
+bool LedDevicePhilipsHue::switchOff()
{
- _isInitLeds = false;
+ Debug(_log, "");
+
this->stopBlackTimeoutTimer();
- LedDevicePhilipsHueBridge::close();
+ stop_retry_left = 3;
+ stopStream();
- if ( _deviceReady )
- {
- if ( !_useHueEntertainmentAPI )
- {
- //Restore Philips Hue devices state
- restoreOriginalState();
- }
- }
+ return LedDevicePhilipsHueBridge::switchOff();
}
int LedDevicePhilipsHue::write(const std::vector & ledValues)
{
// lights will be empty sometimes
- if( _lights.empty() ) return -1;
+ if( _lights.empty() )
+ {
+ return -1;
+ }
// more lights then leds, stop always
if( ledValues.size() < getLightsCount() )
@@ -1417,14 +1353,17 @@ int LedDevicePhilipsHue::write(const std::vector & ledValues)
writeSingleLights( ledValues );
- if( _useHueEntertainmentAPI && !noSignalDetection() && _isInitLeds ) writeStream();
+ if( _useHueEntertainmentAPI && !noSignalDetection() && _isInitLeds )
+ {
+ writeStream();
+ }
return 0;
}
void LedDevicePhilipsHue::noSignalTimeout()
{
- Debug(_log, "No Signal (timeout: %sms), only black color detected - stop stream for \"%s\" [%u]", QSTRING_CSTR( QString::number( _blackLightsTimer->remainingTime() ) ), QSTRING_CSTR(_groupName), _groupId );
+ Debug(_log, "No Signal (timeout: %dms), only black color detected - stop stream for \"%s\" [%u]", _blackLightsTimer->remainingTime(), QSTRING_CSTR(_groupName), _groupId );
_stopConnection = true;
switchOff();
}
@@ -1514,7 +1453,7 @@ int LedDevicePhilipsHue::writeSingleLights(const std::vector& ledValue
void LedDevicePhilipsHue::writeStream()
{
QByteArray streamData = prepareStreamData();
- writeBytes( streamData.size(), reinterpret_cast( streamData.data() ) );
+ writeBytes( static_cast(streamData.size()), reinterpret_cast( streamData.data() ) );
}
void LedDevicePhilipsHue::setOnOffState(PhilipsHueLight& light, bool on)
@@ -1523,7 +1462,7 @@ void LedDevicePhilipsHue::setOnOffState(PhilipsHueLight& light, bool on)
{
light.setOnOffState( on );
QString state = on ? API_STATE_VALUE_TRUE : API_STATE_VALUE_FALSE;
- setLightState( light.getId(), QString("{\"%1\": %2 }").arg( API_STATE_ON ).arg( state ) );
+ setLightState( light.getId(), QString("{\"%1\": %2 }").arg( API_STATE_ON, state ) );
}
}
@@ -1563,7 +1502,7 @@ void LedDevicePhilipsHue::setState(PhilipsHueLight& light, bool on, const CiColo
{
light.setOnOffState( on );
QString state = on ? API_STATE_VALUE_TRUE : API_STATE_VALUE_FALSE;
- stateCmd += QString("\"%1\":%2,").arg( API_STATE_ON ).arg( state );
+ stateCmd += QString("\"%1\":%2,").arg( API_STATE_ON, state );
}
if ( light.getTransitionTime() != _transitionTime )
@@ -1591,78 +1530,186 @@ void LedDevicePhilipsHue::setLightsCount( unsigned int lightsCount )
_lightsCount = lightsCount;
}
-bool LedDevicePhilipsHue::reinitLeds()
+bool LedDevicePhilipsHue::powerOn()
{
- bool isInitOK = initMaps();
-
- if( isInitOK )
+ if ( _isDeviceReady)
{
- isInitOK = initLeds();
+ // TODO: Question: Not clear, if setstream state on will turn of the lights
+ // or do they need to be turned off classically?
+ if ( !_useHueEntertainmentAPI )
+ {
+ //Switch off Philips Hue devices physically
+ for ( PhilipsHueLight& light : _lights )
+ {
+ setOnOffState( light, true );
+ }
+ }
}
-
- return isInitOK;
+ return true;
}
-int LedDevicePhilipsHue::switchOn()
+bool LedDevicePhilipsHue::powerOff()
{
- if ( _deviceReady )
+ if ( _isDeviceReady)
{
- if( !_isInitLeds )
+ // TODO: Question: Not clear, if setstream state off will turn of the lights
+ // or do they need to be turned off classically
+ if ( !_useHueEntertainmentAPI )
{
- _useHueEntertainmentAPI = _devConfig[CONFIG_USE_HUE_ENTERTAINMENT_API].toBool(false);
- Debug(_log, "Update Bridge, Group and Light states");
- reinitLeds();
+ //Switch off Philips Hue devices physically
+ for ( PhilipsHueLight& light : _lights )
+ {
+ setOnOffState( light, false );
+ }
}
+ }
+ return true;
+}
- bool isInitOK = false;
+bool LedDevicePhilipsHue::storeState()
+{
+ bool rc = true;
- if( _useHueEntertainmentAPI )
- {
- isInitOK = initStream();
- }
+ if ( _isRestoreOrigState )
+ {
+ // Save device's original state
+ //_orignalStateValues = get device's state;
- if( !isInitOK )
- {
- _useHueEntertainmentAPI = false;
+ // TODO: Move saveOriginalState out of the HueLight constructor,
+ // as the light state may have change since last close and needs to be stored again before reopen
+ }
- //Switch on Philips Hue devices physically
+ return rc;
+}
+
+bool LedDevicePhilipsHue::restoreState()
+{
+ bool rc = true;
+
+ if ( _isRestoreOrigState && !_lightStatesRestored )
+ {
+ // Restore device's original state
+ _lightStatesRestored = true;
+
+ if( !_lightIds.empty() )
+ {
for ( PhilipsHueLight& light : _lights )
{
- setOnOffState( light, true );
+ setLightState( light.getId(),light.getOriginalState() );
}
}
- _lightStatesRestored = false;
}
- return 0;
+
+ return rc;
}
-int LedDevicePhilipsHue::switchOff()
+QJsonObject LedDevicePhilipsHue::discover()
{
- this->stopBlackTimeoutTimer();
+ QJsonObject devicesDiscovered;
+ devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
- //Set all LEDs to Black
- int rc = LedDevice::switchOff();
+ QJsonArray deviceList;
- if ( _deviceReady )
+ // Discover Devices
+ SSDPDiscover discover;
+
+ discover.skipDuplicateKeys(false);
+ discover.setSearchFilter(SSDP_FILTER, SSDP_FILTER_HEADER);
+ QString searchTarget = SSDP_ID;
+
+ if ( discover.discoverServices(searchTarget) > 0 )
{
- if( _useHueEntertainmentAPI )
+ deviceList = discover.getServicesDiscoveredJson();
+ }
+
+ devicesDiscovered.insert("devices", deviceList);
+ Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+
+ return devicesDiscovered;
+}
+
+QJsonObject LedDevicePhilipsHue::getProperties(const QJsonObject& params)
+{
+ QJsonObject properties;
+
+ // Get Phillips-Bridge device properties
+ QString host = params["host"].toString("");
+ if ( !host.isEmpty() )
+ {
+ QString username = params["user"].toString("");
+ QString filter = params["filter"].toString("");
+
+ // Resolve hostname and port (or use default API port)
+ QStringList addressparts = QStringUtils::split(host,":", QStringUtils::SplitBehavior::SkipEmptyParts);
+ QString apiHost = addressparts[0];
+ int apiPort;
+
+ if ( addressparts.size() > 1 )
{
- stop_retry_left = 3;
- if( stopStream() )
- {
- //Restore Philips Hue devices state
- restoreOriginalState();
- }
+ apiPort = addressparts[1].toInt();
}
else
{
- //Switch off Philips Hue devices physically
- for ( PhilipsHueLight& light : _lights )
- {
- setOnOffState( light, false );
- }
+ apiPort = API_DEFAULT_PORT;
+ }
+
+ initRestAPI(apiHost, apiPort, username);
+ _restApi->setPath(filter);
+
+ // Perform request
+ httpResponse response = _restApi->get();
+ if ( response.error() )
+ {
+ Warning (_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
+ }
+
+ // Perform request
+ properties.insert("properties", response.getBody().object());
+ }
+ return properties;
+}
+
+void LedDevicePhilipsHue::identify(const QJsonObject& params)
+{
+ Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ QJsonObject properties;
+
+ // Identify Phillips-Bridge device
+ QString host = params["host"].toString("");
+ if ( !host.isEmpty() )
+ {
+ QString username = params["user"].toString("");
+ int lightId = params["lightId"].toInt(0);
+
+ // Resolve hostname and port (or use default API port)
+ QStringList addressparts = QStringUtils::split(host,":", QStringUtils::SplitBehavior::SkipEmptyParts);
+ QString apiHost = addressparts[0];
+ int apiPort;
+
+ if ( addressparts.size() > 1 )
+ {
+ apiPort = addressparts[1].toInt();
+ }
+ else
+ {
+ apiPort = API_DEFAULT_PORT;
+ }
+
+ initRestAPI(apiHost, apiPort, username);
+
+ QString resource = QString("%1/%2/%3").arg( API_LIGHTS ).arg( lightId ).arg( API_STATE);
+ _restApi->setPath(resource);
+
+ QString stateCmd;
+ stateCmd += QString("\"%1\":%2,").arg( API_STATE_ON, API_STATE_VALUE_TRUE );
+ stateCmd += QString("\"%1\":\"%2\"").arg( "alert", "select" );
+ stateCmd = "{" + stateCmd + "}";
+
+ // Perform request
+ httpResponse response = _restApi->put(stateCmd);
+ if ( response.error() )
+ {
+ Warning (_log, "%s identification failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
}
- _isInitLeds = false;
}
- return rc;
}
diff --git a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.h b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.h
index c6b78f5a1..d18709ed4 100644
--- a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.h
+++ b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.h
@@ -12,8 +12,9 @@
#include
#include
-// Leddevice includes
+// LedDevice includes
#include
+#include "ProviderRestApi.h"
#include "ProviderUdpSSL.h"
/**
@@ -134,7 +135,7 @@ class PhilipsHueLight
///
/// @param transitionTime the transition time between colors in multiples of 100 ms
///
- void setTransitionTime(unsigned int transitionTime);
+ void setTransitionTime(int transitionTime);
///
/// @param color the color to set
@@ -144,7 +145,7 @@ class PhilipsHueLight
unsigned int getId() const;
bool getOnOffState() const;
- unsigned int getTransitionTime() const;
+ int getTransitionTime() const;
CiColor getColor() const;
///
@@ -162,7 +163,7 @@ class PhilipsHueLight
unsigned int _id;
unsigned int _ledidx;
bool _on;
- unsigned int _transitionTime;
+ int _transitionTime;
CiColor _color;
/// darkes blue color in hue lamp GAMUT = black
CiColor _colorBlack;
@@ -185,14 +186,18 @@ class LedDevicePhilipsHueBridge : public ProviderUdpSSL
public:
explicit LedDevicePhilipsHueBridge(const QJsonObject &deviceConfig);
- ~LedDevicePhilipsHueBridge();
+ ~LedDevicePhilipsHueBridge() override;
///
- /// Sets configuration
+ /// @brief Initialise the access to the REST-API wrapper
///
- /// @param deviceConfig the json device config
- /// @return true if success
- virtual bool init(const QJsonObject &deviceConfig) override;
+ /// @param[in] host
+ /// @param[in] port
+ /// @param[in] authentication token
+ ///
+ /// @return True, if success
+ ///
+ bool initRestAPI(const QString &hostname, const int port, const QString &token );
///
/// @param route the route of the POST request.
@@ -201,28 +206,56 @@ class LedDevicePhilipsHueBridge : public ProviderUdpSSL
///
QJsonDocument post(const QString& route, const QString& content);
- void setLightState(unsigned int lightId = 0, QString state = "");
+ void setLightState(unsigned int lightId = 0, const QString &state = "");
const QMap& getLightMap();
const QMap& getGroupMap();
- QString getGroupName(unsigned int groupId = 0);
+ QString getGroupName(quint16 groupId = 0);
- QJsonArray getGroupLights(unsigned int groupId = 0);
+ QJsonArray getGroupLights(quint16 groupId = 0);
-public slots:
+
+
+protected:
+
+ ///
+ /// @brief Initialise the Hue-Bridge configuration and network address details
///
- /// Connect to bridge to check availbility and user
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
+ ///
+ virtual bool init(const QJsonObject &deviceConfig) override;
+
+ ///
+ /// @brief Opens the Hue-Bridge device and its SSL-connection
+ ///
+ /// @return Zero on success (i.e. device is ready), else negative
///
virtual int open(void) override;
- virtual int open( const QString& hostname, const QString& port, const QString& username );
-protected:
+ ///
+ /// @brief Closes the Hue-Bridge device and its SSL-connection
+ ///
+ /// @return Zero on success (i.e. device is closed), else negative
+ ///
+ virtual int close() override;
+
+ ///
+ /// @brief Check, if Hue API response indicate error
+ ///
+ /// @param[in] response from Hue-Bridge in JSON-format
+ /// return True, Hue Bridge reports error
+ ///
+ bool checkApiError(const QJsonDocument &response );
+
+ ///REST-API wrapper
+ ProviderRestApi* _restApi;
/// Ip address of the bridge
QString _hostname;
- QString _api_port;
+ int _apiPort;
/// User name for the API ("newdeveloper")
QString _username;
@@ -231,7 +264,7 @@ public slots:
QJsonDocument getGroupState( unsigned int groupId );
QJsonDocument setGroupState( unsigned int groupId, bool state);
- bool isStreamOwner(const QString streamOwner);
+ bool isStreamOwner(const QString &streamOwner);
bool initMaps();
void log(const char* msg, const char* type, ...);
@@ -240,56 +273,10 @@ public slots:
private:
- ///
- /// Discover device via SSDP identifiers
- ///
- /// @return True, if device was found
- ///
- bool discoverDevice();
-
- ///
- /// Get command as url
- ///
- /// @param host Hostname or IP
- /// @param port IP-Port
- /// @param _auth_token Authorization token
- /// @param Endpoint command for request
- /// @return Url to execute endpoint/command
- ///
- QString getUrl(QString host, QString port, QString auth_token, QString endpoint) const;
-
- ///
- /// Execute GET request
- ///
- /// @param url GET request for url
- /// @return Response from device
- ///
- QJsonDocument getJson(QString url);
-
- ///
- /// Execute PUT request
- ///
- /// @param Url for PUT request
- /// @param json Command for request
- /// @return Response from device
- ///
- QJsonDocument putJson(QString url, QString json);
-
- ///
- /// Handle replys for GET and PUT requests
- ///
- /// @param reply Network reply
- /// @return Response for request, if no error
- ///
- QJsonDocument handleReply(QNetworkReply* const &reply );
-
QJsonDocument getAllBridgeInfos();
- void setBridgeConfig( QJsonDocument doc );
- void setLightsMap( QJsonDocument doc );
- void setGroupMap( QJsonDocument doc );
-
- /// QNetworkAccessManager for sending requests.
- QNetworkAccessManager* _networkmanager;
+ void setBridgeConfig( const QJsonDocument &doc );
+ void setLightsMap( const QJsonDocument &doc );
+ void setGroupMap( const QJsonDocument &doc );
//Philips Hue Bridge details
QString _deviceModel;
@@ -320,105 +307,209 @@ class LedDevicePhilipsHue: public LedDevicePhilipsHueBridge
public:
///
- /// Constructs specific LedDevice
+ /// @brief Constructs LED-device for Philips Hue Lights system
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDevicePhilipsHue(const QJsonObject &deviceConfig);
///
- /// Destructor of this device
+ /// @brief Destructor of the LED-device
///
virtual ~LedDevicePhilipsHue();
- /// constructs leddevice
+ ///
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
static LedDevice* construct(const QJsonObject &deviceConfig);
///
- /// Sets configuration
+ /// @brief Discover devices of this type available (for configuration).
+ /// @note Mainly used for network devices. Allows to find devices, e.g. via ssdp, mDNS or cloud ways.
///
- /// @param deviceConfig the json device config
- /// @return true if success
- virtual bool init(const QJsonObject &deviceConfig) override;
-
- /// Switch the device on
- virtual int switchOn() override;
+ /// @return A JSON structure holding a list of devices found
+ ///
+ virtual QJsonObject discover() override;
- /// Switch the device off
- virtual int switchOff() override;
+ ///
+ /// @brief Get the Hue Bridge device's resource properties
+ ///
+ /// Following parameters are required
+ /// @code
+ /// {
+ /// "host" : "hostname or IP [:port]",
+ /// "user" : "username",
+ /// "filter": "resource to query", root "/" is used, if empty
+ /// }
+ ///@endcode
+ ///
+ /// @param[in] params Parameters to query device
+ /// @return A JSON structure holding the device's properties
+ ///
+ virtual QJsonObject getProperties(const QJsonObject& params) override;
- /// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
///
- /// @param map Map of lightid/value pairs of bridge
+ /// @brief Send an update to the device to identify it.
///
- void newLights(QMap map);
+ /// Used in context of a set of devices of the same type.
+ ///
+ /// @param[in] params Parameters to address device
+ ///
+ virtual void identify(const QJsonObject& params) override;
+ ///
+ /// @brief Get the number of LEDs supported by the device.
+ ///
+ /// @return Number of device's LEDs
+ ///
unsigned int getLightsCount() const { return _lightsCount; }
- void setLightsCount( unsigned int lightsCount);
-
- bool initStream();
- bool getStreamGroupState();
- bool setStreamGroupState(bool state);
- bool startStream();
- bool stopStream();
void setOnOffState(PhilipsHueLight& light, bool on);
void setTransitionTime(PhilipsHueLight& light);
void setColor(PhilipsHueLight& light, CiColor& color);
void setState(PhilipsHueLight& light, bool on, const CiColor& color);
- void restoreOriginalState();
-
public slots:
///
- /// Closes the output device.
- /// Includes switching-off the device and stopping refreshes
+ /// @brief Stops the device.
///
- virtual void close() override;
+ /// Includes switching-off the device and stopping refreshes.
+ ///
+ virtual void stop() override;
+
+protected:
-private slots:
- /// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
///
- /// @param map Map of lightid/value pairs of bridge
+ /// Initialise the device's configuration
+ ///
+ /// @param deviceConfig Device's configuration in JSON
+ /// @return True, if success
///
- bool updateLights(QMap map);
+ virtual bool init(const QJsonObject &deviceConfig) override;
- void noSignalTimeout();
+ ///
+ /// @brief Opens the output device
+ ///
+ /// @return Zero on success (i.e. device is ready), else negative
+ ///
+ virtual int open() override;
-protected:
+ ///
+ /// @brief Closes the output device.
+ ///
+ /// @return Zero on success (i.e. device is closed), else negative
+ ///
+ virtual int close() override;
///
- /// Opens and initiatialises the output device
+ /// @brief Writes the RGB-Color values to the LEDs.
///
- /// @return Zero on succes (i.e. device is ready and enabled) else negative
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
///
- virtual int open() override;
+ virtual int write(const std::vector& ledValues) override;
///
- /// Get Philips Hue device details and configuration
+ /// @brief Switch the LEDs on.
///
- /// @return True, if Nanoleaf device capabilities fit configuration
+ /// Takes care that the device is opened and powered-on.
+ /// Depending on the configuration, the device may store its current state for later restore.
+ /// @see powerOn, storeState
///
- bool initLeds();
- bool reinitLeds();
+ /// @return True if success
+ ///
+ //virtual bool switchOn() override;
+
+ ///
+ /// @brief Switch the LEDs off.
+ ///
+ /// Takes care that the LEDs and device are switched-off and device is closed.
+ /// Depending on the configuration, the device may be powered-off or restored to its previous state.
+ /// @see powerOff, restoreState
+ ///
+ /// @return True, if success
+ ///
+ virtual bool switchOff() override;
+
+ ///
+ /// @brief Power-/turn on the LED-device.
+ ///
+ /// Powers-/Turns on the LED hardware, if supported.
+ ///
+ /// @return True, if success
+ ///
+ virtual bool powerOn() override;
+
+ ///
+ /// @brief Power-/turn off the LED-device.
+ ///
+ /// Depending on the device's capability, the device is powered-/turned off or
+ /// an off state is simulated by writing "Black to LED" (default).
+ ///
+ /// @return True, if success
+ ///
+ virtual bool powerOff() override;
///
- /// Writes the RGB-Color values to the leds.
+ /// @brief Store the device's original state.
///
- /// @param[in] ledValues The RGB-color per led
+ /// Save the device's state before hyperion color streaming starts allowing to restore state during switchOff().
///
- /// @return Zero on success else negative
+ /// @return True if success
///
- virtual int write(const std::vector & ledValues) override;
+ virtual bool storeState() override;
+
+ ///
+ /// @brief Restore the device's original state.
+ ///
+ /// Restore the device's state as before hyperion color streaming started.
+ /// This includes the on/off state of the device.
+ ///
+ /// @return True, if success
+ ///
+ virtual bool restoreState() override;
+
+private slots:
+
+ void noSignalTimeout();
private:
+ bool initLeds();
+
+ ///
+ /// @brief Creates new PhilipsHueLight(s) based on user lightid with bridge feedback
+ ///
+ /// @param map Map of lightid/value pairs of bridge
+ ///
+ void newLights(QMap map);
+
bool setLights();
- int writeSingleLights(const std::vector& ledValues);
+ /// creates new PhilipsHueLight(s) based on user lightid with bridge feedback
+ ///
+ /// @param map Map of lightid/value pairs of bridge
+ ///
+ bool updateLights(const QMap &map);
+
+ ///
+ /// @brief Set the number of LEDs supported by the device.
+ ///
+ /// @rparam[in] Number of device's LEDs
+ //
+ void setLightsCount( unsigned int lightsCount);
+
+ bool openStream();
+ bool getStreamGroupState();
+ bool setStreamGroupState(bool state);
+ bool startStream();
+ bool stopStream();
void writeStream();
+ int writeSingleLights(const std::vector& ledValues);
bool noSignalDetection();
@@ -430,21 +521,20 @@ private slots:
bool _switchOffOnBlack;
/// The brightness factor to multiply on color change.
double _brightnessFactor;
- /// Transition time in multiples of 100 ms.
- /// The default of the Hue lights is 400 ms, but we may want it snapier.
- unsigned int _transitionTime;
+ /// Transition time in multiples of 100 ms.
+ /// The default of the Hue lights is 400 ms, but we may want it snappier.
+ int _transitionTime;
- bool _isRestoreOrigState;
bool _lightStatesRestored;
bool _isInitLeds;
/// Array of the light ids.
- std::vector _lightIds;
+ std::vector _lightIds;
/// Array to save the lamps.
std::vector _lights;
unsigned int _lightsCount;
- unsigned int _groupId;
+ quint16 _groupId;
double _brightnessMin;
double _brightnessMax;
@@ -452,7 +542,7 @@ private slots:
bool _allLightsBlack;
QTimer* _blackLightsTimer;
- unsigned int _blackLightsTimeout;
+ int _blackLightsTimeout;
double _brightnessThreshold;
int _handshake_timeout_min;
@@ -466,4 +556,5 @@ private slots:
int start_retry_left;
int stop_retry_left;
+
};
diff --git a/libsrc/leddevice/dev_net/LedDeviceTpm2net.cpp b/libsrc/leddevice/dev_net/LedDeviceTpm2net.cpp
index 3a6ac5374..be779ebb8 100644
--- a/libsrc/leddevice/dev_net/LedDeviceTpm2net.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceTpm2net.cpp
@@ -1,10 +1,14 @@
#include "LedDeviceTpm2net.h"
+const ushort TPM2_DEFAULT_PORT = 65506;
+
LedDeviceTpm2net::LedDeviceTpm2net(const QJsonObject &deviceConfig)
: ProviderUdp()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceTpm2net::construct(const QJsonObject &deviceConfig)
@@ -14,13 +18,19 @@ LedDevice* LedDeviceTpm2net::construct(const QJsonObject &deviceConfig)
bool LedDeviceTpm2net::init(const QJsonObject &deviceConfig)
{
+ bool isInitOK = false;
+
_port = TPM2_DEFAULT_PORT;
- bool isInitOK = ProviderUdp::init(deviceConfig);
- _tpm2_max = deviceConfig["max-packet"].toInt(170);
- _tpm2ByteCount = 3 * _ledCount;
- _tpm2TotalPackets = 1 + _tpm2ByteCount / _tpm2_max;
+ // Initialise sub-class
+ if ( ProviderUdp::init(deviceConfig) )
+ {
+ _tpm2_max = deviceConfig["max-packet"].toInt(170);
+ _tpm2ByteCount = 3 * _ledCount;
+ _tpm2TotalPackets = 1 + _tpm2ByteCount / _tpm2_max;
+ isInitOK = true;
+ }
return isInitOK;
}
diff --git a/libsrc/leddevice/dev_net/LedDeviceTpm2net.h b/libsrc/leddevice/dev_net/LedDeviceTpm2net.h
index 2abdae834..70338f7c9 100644
--- a/libsrc/leddevice/dev_net/LedDeviceTpm2net.h
+++ b/libsrc/leddevice/dev_net/LedDeviceTpm2net.h
@@ -1,44 +1,53 @@
-#pragma once
+#ifndef LEDEVICETPM2NET_H
+#define LEDEVICETPM2NET_H
// hyperion includes
#include "ProviderUdp.h"
-const ushort TPM2_DEFAULT_PORT = 65506;
-
///
-/// Implementation of the LedDevice interface for sending led colors via udp tpm2.net packets
+/// Implementation of the LedDevice interface for sending LED colors via udp tpm2.net packets
///
class LedDeviceTpm2net : public ProviderUdp
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a TPM2 LED-device fed via UDP
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceTpm2net(const QJsonObject &deviceConfig);
- /// constructs leddevice
+ ///
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ ///
static LedDevice* construct(const QJsonObject &deviceConfig);
+private:
+
+ ///
+ /// @brief Initialise the device's configuration
///
- /// Sets configuration
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
///
- /// @param deviceConfig the json device config
- /// @return true if success
virtual bool init(const QJsonObject &deviceConfig) override;
-private:
///
- /// Writes the led color values to the led-device
+ /// @brief Writes the RGB-Color values to the LEDs.
///
- /// @param ledValues The color-value per led
- /// @return Zero on succes else negative
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
///
- virtual int write(const std::vector &ledValues) override;
+ virtual int write(const std::vector & ledValues) override;
int _tpm2_max;
int _tpm2ByteCount;
int _tpm2TotalPackets;
int _tpm2ThisPacket;
};
+
+#endif // LEDEVICETPM2NET_H
diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.cpp b/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.cpp
index ce32138b5..22c1a15d7 100644
--- a/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.cpp
@@ -1,3 +1,6 @@
+// hyperion local includes
+#include "LedDeviceUdpArtNet.h"
+
#ifdef _WIN32
#include
#else
@@ -6,16 +9,18 @@
#include
-// hyperion local includes
-#include "LedDeviceUdpArtNet.h"
+const ushort ARTNET_DEFAULT_PORT = 6454;
LedDeviceUdpArtNet::LedDeviceUdpArtNet(const QJsonObject &deviceConfig)
: ProviderUdp()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
+
LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceUdpArtNet(deviceConfig);
@@ -23,12 +28,18 @@ LedDevice* LedDeviceUdpArtNet::construct(const QJsonObject &deviceConfig)
bool LedDeviceUdpArtNet::init(const QJsonObject &deviceConfig)
{
+ bool isInitOK = false;
+
_port = ARTNET_DEFAULT_PORT;
- bool isInitOK = ProviderUdp::init(deviceConfig);
- _artnet_universe = deviceConfig["universe"].toInt(1);
- _artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
+ // Initialise sub-class
+ if ( ProviderUdp::init(deviceConfig) )
+ {
+ _artnet_universe = deviceConfig["universe"].toInt(1);
+ _artnet_channelsPerFixture = deviceConfig["channelsPerFixture"].toInt(3);
+ isInitOK = true;
+ }
return isInitOK;
}
@@ -51,7 +62,6 @@ void LedDeviceUdpArtNet::prepare(const unsigned this_universe, const unsigned th
artnet_packet.SubUni = this_universe & 0xff ;
artnet_packet.Net = (this_universe >> 8) & 0x7f;
artnet_packet.Length = htons(this_dmxChannelCount);
-
}
int LedDeviceUdpArtNet::write(const std::vector &ledValues)
diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.h b/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.h
index 8f2f3da78..f48ad5080 100644
--- a/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.h
+++ b/libsrc/leddevice/dev_net/LedDeviceUdpArtNet.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef LEDEVICEUDPARTNET_H
+#define LEDEVICEUDPARTNET_H
// hyperion includes
#include "ProviderUdp.h"
@@ -13,9 +14,7 @@
*
**/
-const ushort ARTNET_DEFAULT_PORT = 6454;
-
-#define DMX_MAX 512 // 512 usable slots
+const int DMX_MAX = 512; // 512 usable slots
// http://stackoverflow.com/questions/16396013/artnet-packet-structure
typedef union
@@ -23,7 +22,7 @@ typedef union
#pragma pack(push, 1)
struct {
char ID[8]; // "Art-Net"
- uint16_t OpCode; // See Doc. Table 1 - OpCodes eg. 0x5000 OpOutput / OpDmx
+ uint16_t OpCode; // See Doc. Table 1 - OpCodes e.g. 0x5000 OpOutput / OpDmx
uint16_t ProtVer; // 0x0e00 (aka 14)
uint8_t Sequence; // monotonic counter
uint8_t Physical; // 0x00
@@ -39,42 +38,54 @@ typedef union
} artnet_packet_t;
///
-/// Implementation of the LedDevice interface for sending led colors via udp/E1.31 packets
+/// Implementation of the LedDevice interface for sending LED colors to an Art-Net LED-device via UDP
///
class LedDeviceUdpArtNet : public ProviderUdp
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs an Art-Net LED-device fed via UDP
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceUdpArtNet(const QJsonObject &deviceConfig);
- /// constructs leddevice
+ ///
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ ///
static LedDevice* construct(const QJsonObject &deviceConfig);
+private:
+
///
- /// Sets configuration
+ /// @brief Initialise the device's configuration
///
- /// @param deviceConfig the json device config
- /// @return true if success
- bool init(const QJsonObject &deviceConfig) override;
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
+ ///
+ virtual bool init(const QJsonObject &deviceConfig) override;
-private:
///
- /// Writes the led color values to the led-device
+ /// @brief Writes the RGB-Color values to the LEDs.
///
- /// @param ledValues The color-value per led
- /// @return Zero on succes else negative
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
///
- virtual int write(const std::vector &ledValues) override;
+ virtual int write(const std::vector & ledValues) override;
+ ///
+ /// @brief Generate Art-Net communication header
+ ///
void prepare(const unsigned this_universe, const unsigned this_sequence, const unsigned this_dmxChannelCount);
-
artnet_packet_t artnet_packet;
uint8_t _artnet_seq = 1;
int _artnet_channelsPerFixture = 3;
int _artnet_universe = 1;
};
+
+#endif // LEDEVICEUDPARTNET_H
diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp b/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp
index 06f9cd54f..0f6a972b9 100644
--- a/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceUdpE131.cpp
@@ -9,18 +9,43 @@
// hyperion local includes
#include "LedDeviceUdpE131.h"
+const ushort E131_DEFAULT_PORT = 5568;
+
+/* defined parameters from http://tsp.esta.org/tsp/documents/docs/BSR_E1-31-20xx_CP-2014-1009r2.pdf */
+const uint32_t VECTOR_ROOT_E131_DATA = 0x00000004;
+//#define VECTOR_ROOT_E131_EXTENDED 0x00000008
+const uint8_t VECTOR_DMP_SET_PROPERTY = 0x02;
+const uint32_t VECTOR_E131_DATA_PACKET = 0x00000002;
+//#define VECTOR_E131_EXTENDED_SYNCHRONIZATION 0x00000001
+//#define VECTOR_E131_EXTENDED_DISCOVERY 0x00000002
+//#define VECTOR_UNIVERSE_DISCOVERY_UNIVERSE_LIST 0x00000001
+//#define E131_E131_UNIVERSE_DISCOVERY_INTERVAL 10 // seconds
+//#define E131_NETWORK_DATA_LOSS_TIMEOUT 2500 // milli econds
+//#define E131_DISCOVERY_UNIVERSE 64214
+const int DMX_MAX = 512; // 512 usable slots
+
LedDeviceUdpE131::LedDeviceUdpE131(const QJsonObject &deviceConfig)
: ProviderUdp()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
+}
+
+LedDevice* LedDeviceUdpE131::construct(const QJsonObject &deviceConfig)
+{
+ return new LedDeviceUdpE131(deviceConfig);
}
bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig)
{
+ bool isInitOK = false;
+
_port = E131_DEFAULT_PORT;
- bool isInitOK = ProviderUdp::init(deviceConfig);
- if ( isInitOK )
+
+ // Initialise sub-class
+ if ( ProviderUdp::init(deviceConfig) )
{
_e131_universe = deviceConfig["universe"].toInt(1);
_e131_source_name = deviceConfig["source-name"].toString("hyperion on "+QHostInfo::localHostName());
@@ -29,22 +54,26 @@ bool LedDeviceUdpE131::init(const QJsonObject &deviceConfig)
if (_json_cid.isEmpty())
{
_e131_cid = QUuid::createUuid();
- Debug( _log, "e131 no cid found, generated %s", QSTRING_CSTR(_e131_cid.toString()));
+ Debug( _log, "e131 no CID found, generated %s", QSTRING_CSTR(_e131_cid.toString()));
+ isInitOK = true;
}
else
{
_e131_cid = QUuid(_json_cid);
- Debug( _log, "e131 cid found, using %s", QSTRING_CSTR(_e131_cid.toString()));
+ if ( !_e131_cid.isNull() )
+ {
+ Debug( _log, "e131 CID found, using %s", QSTRING_CSTR(_e131_cid.toString()));
+ isInitOK = true;
+ }
+ else
+ {
+ this->setInError("CID configured is not a valid UUID. Format expected is \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"");
+ }
}
}
return isInitOK;
}
-LedDevice* LedDeviceUdpE131::construct(const QJsonObject &deviceConfig)
-{
- return new LedDeviceUdpE131(deviceConfig);
-}
-
// populates the headers
void LedDeviceUdpE131::prepare(const unsigned this_universe, const unsigned this_dmxChannelCount)
{
@@ -120,4 +149,3 @@ int LedDeviceUdpE131::write(const std::vector &ledValues)
return retVal;
}
-
diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpE131.h b/libsrc/leddevice/dev_net/LedDeviceUdpE131.h
index c155eec81..358368953 100644
--- a/libsrc/leddevice/dev_net/LedDeviceUdpE131.h
+++ b/libsrc/leddevice/dev_net/LedDeviceUdpE131.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef LEDEVICEUDPE131_H
+#define LEDEVICEUDPE131_H
// hyperion includes
#include "ProviderUdp.h"
@@ -18,32 +19,30 @@
*
**/
-const ushort E131_DEFAULT_PORT = 5568;
-
/* E1.31 Packet Offsets */
-#define E131_ROOT_PREAMBLE_SIZE 0
-#define E131_ROOT_POSTAMBLE_SIZE 2
-#define E131_ROOT_ID 4
-#define E131_ROOT_FLENGTH 16
-#define E131_ROOT_VECTOR 18
-#define E131_ROOT_CID 22
-
-#define E131_FRAME_FLENGTH 38
-#define E131_FRAME_VECTOR 40
-#define E131_FRAME_SOURCE 44
-#define E131_FRAME_PRIORITY 108
-#define E131_FRAME_RESERVED 109
-#define E131_FRAME_SEQ 111
-#define E131_FRAME_OPT 112
-#define E131_FRAME_UNIVERSE 113
-
-#define E131_DMP_FLENGTH 115
-#define E131_DMP_VECTOR 117
-#define E131_DMP_TYPE 118
-#define E131_DMP_ADDR_FIRST 119
-#define E131_DMP_ADDR_INC 121
-#define E131_DMP_COUNT 123
-#define E131_DMP_DATA 125
+//#define E131_ROOT_PREAMBLE_SIZE 0
+//#define E131_ROOT_POSTAMBLE_SIZE 2
+//#define E131_ROOT_ID 4
+//#define E131_ROOT_FLENGTH 16
+//#define E131_ROOT_VECTOR 18
+//#define E131_ROOT_CID 22
+
+//#define E131_FRAME_FLENGTH 38
+//#define E131_FRAME_VECTOR 40
+//#define E131_FRAME_SOURCE 44
+//#define E131_FRAME_PRIORITY 108
+//#define E131_FRAME_RESERVED 109
+//#define E131_FRAME_SEQ 111
+//#define E131_FRAME_OPT 112
+//#define E131_FRAME_UNIVERSE 113
+
+//#define E131_DMP_FLENGTH 115
+//#define E131_DMP_VECTOR 117
+//#define E131_DMP_TYPE 118
+//#define E131_DMP_ADDR_FIRST 119
+//#define E131_DMP_ADDR_INC 121
+//#define E131_DMP_COUNT 123
+const unsigned int E131_DMP_DATA=125;
/* E1.31 Packet Structure */
typedef union
@@ -83,51 +82,49 @@ typedef union
uint8_t raw[638];
} e131_packet_t;
-/* defined parameters from http://tsp.esta.org/tsp/documents/docs/BSR_E1-31-20xx_CP-2014-1009r2.pdf */
-#define VECTOR_ROOT_E131_DATA 0x00000004
-#define VECTOR_ROOT_E131_EXTENDED 0x00000008
-#define VECTOR_DMP_SET_PROPERTY 0x02
-#define VECTOR_E131_DATA_PACKET 0x00000002
-#define VECTOR_E131_EXTENDED_SYNCHRONIZATION 0x00000001
-#define VECTOR_E131_EXTENDED_DISCOVERY 0x00000002
-#define VECTOR_UNIVERSE_DISCOVERY_UNIVERSE_LIST 0x00000001
-#define E131_E131_UNIVERSE_DISCOVERY_INTERVAL 10 // seconds
-#define E131_NETWORK_DATA_LOSS_TIMEOUT 2500 // milli econds
-#define E131_DISCOVERY_UNIVERSE 64214
-#define DMX_MAX 512 // 512 usable slots
-
///
/// Implementation of the LedDevice interface for sending led colors via udp/E1.31 packets
///
class LedDeviceUdpE131 : public ProviderUdp
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs an E1.31 LED-device fed via UDP
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceUdpE131(const QJsonObject &deviceConfig);
- /// constructs leddevice
+ ///
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ ///
static LedDevice* construct(const QJsonObject &deviceConfig);
+private:
+
+ ///
+ /// @brief Initialise the device's configuration
///
- /// Sets configuration
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
///
- /// @param deviceConfig the json device config
- /// @return true if success
- bool init(const QJsonObject &deviceConfig) override;
+ virtual bool init(const QJsonObject &deviceConfig) override;
-private:
///
- /// Writes the led color values to the led-device
+ /// @brief Writes the RGB-Color values to the LEDs.
///
- /// @param ledValues The color-value per led
- /// @return Zero on succes else negative
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
///
- virtual int write(const std::vector &ledValues) override;
+ virtual int write(const std::vector & ledValues) override;
+ ///
+ /// @brief Generate E1.31 communication header
+ ///
void prepare(const unsigned this_universe, const unsigned this_dmxChannelCount);
e131_packet_t e131_packet;
@@ -137,3 +134,5 @@ class LedDeviceUdpE131 : public ProviderUdp
QString _e131_source_name;
QUuid _e131_cid;
};
+
+#endif // LEDEVICEUDPE131_H
diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpH801.cpp b/libsrc/leddevice/dev_net/LedDeviceUdpH801.cpp
index 7577408ae..52b7d0cf0 100644
--- a/libsrc/leddevice/dev_net/LedDeviceUdpH801.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceUdpH801.cpp
@@ -1,13 +1,20 @@
#include "LedDeviceUdpH801.h"
+// Constants
+namespace {
+
const ushort H801_DEFAULT_PORT = 30977;
-static const char H801_DEFAULT_HOST[] = "255.255.255.255";
+const char H801_DEFAULT_HOST[] = "255.255.255.255";
+
+} //End of constants
LedDeviceUdpH801::LedDeviceUdpH801(const QJsonObject &deviceConfig)
: ProviderUdp()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceUdpH801::construct(const QJsonObject &deviceConfig)
@@ -17,13 +24,15 @@ LedDevice* LedDeviceUdpH801::construct(const QJsonObject &deviceConfig)
bool LedDeviceUdpH801::init(const QJsonObject &deviceConfig)
{
+ bool isInitOK = false;
+
/* The H801 port is fixed */
_latchTime_ms = 10;
_port = H801_DEFAULT_PORT;
_defaultHost = H801_DEFAULT_HOST;
- bool isInitOK = ProviderUdp::init(deviceConfig);
- if ( isInitOK )
+ // Initialise sub-class
+ if ( ProviderUdp::init(deviceConfig) )
{
_ids.clear();
QJsonArray lArray = deviceConfig["lightIds"].toArray();
@@ -44,6 +53,8 @@ bool LedDeviceUdpH801::init(const QJsonObject &deviceConfig)
}
Debug(_log, "H801 using %s:%d", _address.toString().toStdString().c_str(), _port);
+
+ isInitOK = true;
}
return isInitOK;
}
diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpH801.h b/libsrc/leddevice/dev_net/LedDeviceUdpH801.h
index 70dde8c5a..9a106e017 100644
--- a/libsrc/leddevice/dev_net/LedDeviceUdpH801.h
+++ b/libsrc/leddevice/dev_net/LedDeviceUdpH801.h
@@ -1,46 +1,57 @@
-#pragma once
+#ifndef LEDEVICEUDPH801_H
+#define LEDEVICEUDPH801_H
// hyperion includes
#include "ProviderUdp.h"
///
-/// Implementation of the LedDevice interface for sending led colors via udp.
+/// Implementation of the LedDevice interface for sending LED colors to a H801 LED-device via UDP
///
///
-
class LedDeviceUdpH801: public ProviderUdp
{
-protected:
- QList _ids;
- QByteArray _message;
- const int _prefix_size = 2;
- const int _colors = 5;
- const int _id_size = 3;
- const int _suffix_size = 1;
-
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a H801 LED-device fed via UDP
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceUdpH801(const QJsonObject &deviceConfig);
- /// constructs leddevice
- static LedDevice* construct(const QJsonObject &deviceConfig);
///
- /// Sets configuration
+ /// @brief Constructs the LED-device
///
- /// @param deviceConfig the json device config
- /// @return true if success
- bool init(const QJsonObject &deviceConfig) override;
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ ///
+ static LedDevice* construct(const QJsonObject &deviceConfig);
private:
+
///
- /// Writes the led color values to the led-device
+ /// @brief Initialise the device's configuration
///
- /// @param ledValues The color-value per led
- /// @return Zero on succes else negative
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
///
- virtual int write(const std::vector &ledValues) override;
+ virtual bool init(const QJsonObject &deviceConfig) override;
+
+ ///
+ /// @brief Writes the RGB-Color values to the LEDs.
+ ///
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
+ ///
+ virtual int write(const std::vector & ledValues) override;
+
+ QList _ids;
+ QByteArray _message;
+ const int _prefix_size = 2;
+ const int _colors = 5;
+ const int _id_size = 3;
+ const int _suffix_size = 1;
+
};
+
+#endif // LEDEVICEUDPH801_H
diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpRaw.cpp b/libsrc/leddevice/dev_net/LedDeviceUdpRaw.cpp
index 0b49cbb11..0502eb352 100644
--- a/libsrc/leddevice/dev_net/LedDeviceUdpRaw.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceUdpRaw.cpp
@@ -1,10 +1,14 @@
#include "LedDeviceUdpRaw.h"
+const ushort RAW_DEFAULT_PORT=5568;
+
LedDeviceUdpRaw::LedDeviceUdpRaw(const QJsonObject &deviceConfig)
: ProviderUdp()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
@@ -15,6 +19,8 @@ LedDevice* LedDeviceUdpRaw::construct(const QJsonObject &deviceConfig)
bool LedDeviceUdpRaw::init(const QJsonObject &deviceConfig)
{
_port = RAW_DEFAULT_PORT;
+
+ // Initialise sub-class
bool isInitOK = ProviderUdp::init(deviceConfig);
return isInitOK;
}
@@ -23,5 +29,5 @@ int LedDeviceUdpRaw::write(const std::vector &ledValues)
{
const uint8_t * dataPtr = reinterpret_cast(ledValues.data());
- return writeBytes((unsigned)_ledRGBCount, dataPtr);
+ return writeBytes(_ledRGBCount, dataPtr);
}
diff --git a/libsrc/leddevice/dev_net/LedDeviceUdpRaw.h b/libsrc/leddevice/dev_net/LedDeviceUdpRaw.h
index a3beb82af..7cdb85954 100644
--- a/libsrc/leddevice/dev_net/LedDeviceUdpRaw.h
+++ b/libsrc/leddevice/dev_net/LedDeviceUdpRaw.h
@@ -1,39 +1,48 @@
-#pragma once
+#ifndef LEDEVICEUDPRAW_H
+#define LEDEVICEUDPRAW_H
// hyperion includes
#include "ProviderUdp.h"
-#define RAW_DEFAULT_PORT 5568
-
///
-/// Implementation of the LedDevice interface for sending led colors via udp.
+/// Implementation of the LedDevice interface for sending LED colors via UDP
///
class LedDeviceUdpRaw : public ProviderUdp
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a LED-device fed via UDP
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceUdpRaw(const QJsonObject &deviceConfig);
- /// constructs leddevice
+ ///
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ ///
static LedDevice* construct(const QJsonObject &deviceConfig);
+protected:
+
///
- /// Sets configuration
+ /// @brief Initialise the device's configuration
///
- /// @param deviceConfig the json device config
- /// @return true if success
- bool init(const QJsonObject &deviceConfig) override;
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
+ ///
+ virtual bool init(const QJsonObject &deviceConfig) override;
-private:
///
- /// Writes the led color values to the led-device
+ /// @brief Writes the RGB-Color values to the LEDs.
///
- /// @param ledValues The color-value per led
- /// @return Zero on succes else negative
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
///
- virtual int write(const std::vector &ledValues) override;
+ virtual int write(const std::vector & ledValues) override;
};
+
+#endif // LEDEVICEUDPRAW_H
diff --git a/libsrc/leddevice/dev_net/LedDeviceWled.cpp b/libsrc/leddevice/dev_net/LedDeviceWled.cpp
new file mode 100644
index 000000000..952814efb
--- /dev/null
+++ b/libsrc/leddevice/dev_net/LedDeviceWled.cpp
@@ -0,0 +1,291 @@
+// Local-Hyperion includes
+#include "LedDeviceWled.h"
+
+#include
+#include
+
+// Constants
+namespace {
+
+// Configuration settings
+const char CONFIG_ADDRESS[] = "host";
+
+// UDP elements
+const quint16 STREAM_DEFAULT_PORT = 19446;
+
+// WLED JSON-API elements
+const int API_DEFAULT_PORT = -1; //Use default port per communication scheme
+
+const char API_BASE_PATH[] = "/json/";
+const char API_PATH_INFO[] = "info";
+const char API_PATH_STATE[] = "state";
+
+// List of State Information
+const char STATE_ON[] = "on";
+const char STATE_VALUE_TRUE[] = "true";
+const char STATE_VALUE_FALSE[] = "false";
+
+// WLED ssdp services
+// TODO: WLED - Update ssdp discovery parameters when available
+const char SSDP_ID[] = "ssdp:all";
+const char SSDP_FILTER[] = "(.*)";
+const char SSDP_FILTER_HEADER[] = "ST";
+
+} //End of constants
+
+LedDeviceWled::LedDeviceWled(const QJsonObject &deviceConfig)
+ : ProviderUdp()
+ ,_restApi(nullptr)
+ ,_apiPort(API_DEFAULT_PORT)
+{
+ _devConfig = deviceConfig;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
+}
+
+LedDeviceWled::~LedDeviceWled()
+{
+ if ( _restApi != nullptr )
+ {
+ delete _restApi;
+ _restApi = nullptr;
+ }
+}
+
+LedDevice* LedDeviceWled::construct(const QJsonObject &deviceConfig)
+{
+ return new LedDeviceWled(deviceConfig);
+}
+
+bool LedDeviceWled::init(const QJsonObject &deviceConfig)
+{
+ Debug(_log, "");
+ bool isInitOK = false;
+
+ // Initialise LedDevice sub-class, ProviderUdp::init will be executed later, if connectivity is defined
+ if ( LedDevice::init(deviceConfig) )
+ {
+ // Initialise LedDevice configuration and execution environment
+ uint configuredLedCount = this->getLedCount();
+ Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
+ Debug(_log, "LedCount : %u", configuredLedCount);
+ Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
+ Debug(_log, "LatchTime : %d", this->getLatchTime());
+
+ //Set hostname as per configuration
+ QString address = deviceConfig[ CONFIG_ADDRESS ].toString();
+
+ //If host not configured the init fails
+ if ( address.isEmpty() )
+ {
+ this->setInError("No target hostname nor IP defined");
+ return false;
+ }
+ else
+ {
+ QStringList addressparts = QStringUtils::split(address,":", QStringUtils::SplitBehavior::SkipEmptyParts);
+ _hostname = addressparts[0];
+ if ( addressparts.size() > 1 )
+ {
+ _apiPort = addressparts[1].toInt();
+ }
+ else
+ {
+ _apiPort = API_DEFAULT_PORT;
+ }
+
+ if ( initRestAPI( _hostname, _apiPort ) )
+ {
+ // Update configuration with hostname without port
+ _devConfig["host"] = _hostname;
+ _devConfig["port"] = STREAM_DEFAULT_PORT;
+
+ isInitOK = ProviderUdp::init(_devConfig);
+ Debug(_log, "Hostname/IP : %s", QSTRING_CSTR( _hostname ));
+ Debug(_log, "Port : %d", _port);
+ }
+ }
+ }
+ Debug(_log, "[%d]", isInitOK);
+ return isInitOK;
+}
+
+bool LedDeviceWled::initRestAPI(const QString &hostname, const int port )
+{
+ Debug(_log, "");
+ bool isInitOK = false;
+
+ if ( _restApi == nullptr )
+ {
+ _restApi = new ProviderRestApi(hostname, port);
+ _restApi->setBasePath( API_BASE_PATH );
+
+ isInitOK = true;
+ }
+
+ Debug(_log, "[%d]", isInitOK);
+ return isInitOK;
+}
+
+QString LedDeviceWled::getOnOffRequest (bool isOn ) const
+{
+ QString state = isOn ? STATE_VALUE_TRUE : STATE_VALUE_FALSE;
+ return QString( "{\"%1\":%2}" ).arg( STATE_ON, state);
+}
+
+bool LedDeviceWled::powerOn()
+{
+ Debug(_log, "");
+ bool on = true;
+ if ( _isDeviceReady)
+ {
+ //Power-on WLED device
+ _restApi->setPath(API_PATH_STATE);
+ httpResponse response = _restApi->put(getOnOffRequest(true));
+ if ( response.error() )
+ {
+ this->setInError ( response.getErrorReason() );
+ on = false;
+ }
+ }
+ return on;
+}
+
+bool LedDeviceWled::powerOff()
+{
+ Debug(_log, "");
+ bool off = true;
+ if ( _isDeviceReady)
+ {
+ // Write a final "Black" to have a defined outcome
+ writeBlack();
+
+ //Power-off the WLED device physically
+ _restApi->setPath(API_PATH_STATE);
+ httpResponse response = _restApi->put(getOnOffRequest(false));
+ if ( response.error() )
+ {
+ this->setInError ( response.getErrorReason() );
+ off = false;
+ }
+ }
+ return off;
+}
+
+QJsonObject LedDeviceWled::discover()
+{
+ QJsonObject devicesDiscovered;
+ devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
+
+ QJsonArray deviceList;
+
+ // Discover WLED Devices
+ SSDPDiscover discover;
+ discover.skipDuplicateKeys(true);
+ discover.setSearchFilter(SSDP_FILTER, SSDP_FILTER_HEADER);
+ QString searchTarget = SSDP_ID;
+
+ if ( discover.discoverServices(searchTarget) > 0 )
+ {
+ deviceList = discover.getServicesDiscoveredJson();
+ }
+
+ devicesDiscovered.insert("devices", deviceList);
+ Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+
+ return devicesDiscovered;
+}
+
+QJsonObject LedDeviceWled::getProperties(const QJsonObject& params)
+{
+ Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ QJsonObject properties;
+
+ // Get Nanoleaf device properties
+ QString host = params["host"].toString("");
+ if ( !host.isEmpty() )
+ {
+ QString filter = params["filter"].toString("");
+
+ // Resolve hostname and port (or use default API port)
+ QStringList addressparts = QStringUtils::split(host,":", QStringUtils::SplitBehavior::SkipEmptyParts);
+ QString apiHost = addressparts[0];
+ int apiPort;
+
+ if ( addressparts.size() > 1)
+ {
+ apiPort = addressparts[1].toInt();
+ }
+ else
+ {
+ apiPort = API_DEFAULT_PORT;
+ }
+
+ if ( filter.startsWith("/") )
+ filter.remove(0,1);
+
+ initRestAPI(apiHost, apiPort);
+ _restApi->setPath(API_PATH_INFO);
+
+ // Perform request
+ // TODO: WLED::getProperties - Check, if filter is supported
+ httpResponse response = _restApi->put(filter);
+ if ( response.error() )
+ {
+ Warning (_log, "%s get properties failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
+ }
+
+ properties.insert("properties", response.getBody().object());
+
+ Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ }
+ return properties;
+}
+
+void LedDeviceWled::identify(const QJsonObject& params)
+{
+ Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ QJsonObject properties;
+
+ // Get Nanoleaf device properties
+ QString host = params["host"].toString("");
+ if ( !host.isEmpty() )
+ {
+ // Resolve hostname and port (or use default API port)
+ QStringList addressparts = QStringUtils::split(host,":", QStringUtils::SplitBehavior::SkipEmptyParts);
+ QString apiHost = addressparts[0];
+ int apiPort;
+
+ if ( addressparts.size() > 1)
+ apiPort = addressparts[1].toInt();
+ else
+ apiPort = API_DEFAULT_PORT;
+
+ // TODO: WLED::identify - Replace with valid identification code
+
+ // initRestAPI(apiHost, apiPort);
+
+ // QString resource = QString("%1/%2/%3").arg( API_LIGHTS ).arg( lightId ).arg( API_STATE);
+ // _restApi->setPath(resource);
+
+ // QString stateCmd;
+ // stateCmd += QString("\"%1\":%2,").arg( API_STATE_ON ).arg( API_STATE_VALUE_TRUE );
+ // stateCmd += QString("\"%1\":\"%2\"").arg( "alert" ).arg( "select" );
+ // stateCmd = "{" + stateCmd + "}";
+
+ // // Perform request
+ // httpResponse response = _restApi->put(stateCmd);
+ // if ( response.error() )
+ // {
+ // Warning (_log, "%s identification failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
+ // }
+ }
+}
+
+int LedDeviceWled::write(const std::vector &ledValues)
+{
+ const uint8_t * dataPtr = reinterpret_cast(ledValues.data());
+
+ return writeBytes( _ledRGBCount, dataPtr);
+}
diff --git a/libsrc/leddevice/dev_net/LedDeviceWled.h b/libsrc/leddevice/dev_net/LedDeviceWled.h
new file mode 100644
index 000000000..172f62d01
--- /dev/null
+++ b/libsrc/leddevice/dev_net/LedDeviceWled.h
@@ -0,0 +1,132 @@
+#ifndef LEDDEVICEWLED_H
+#define LEDDEVICEWLED_H
+
+// LedDevice includes
+#include
+#include "ProviderRestApi.h"
+#include "ProviderUdp.h"
+
+///
+/// Implementation of a WLED-device
+/// ...
+///
+///
+class LedDeviceWled : public ProviderUdp
+{
+
+public:
+ ///
+ /// @brief Constructs a WLED-device
+ ///
+ /// @param deviceConfig Device's configuration as JSON-Object
+ ///
+ explicit LedDeviceWled(const QJsonObject &deviceConfig);
+
+ ///
+ /// @brief Destructor of the WLED-device
+ ///
+ virtual ~LedDeviceWled() override;
+
+ ///
+ /// @brief Constructs the WLED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ static LedDevice* construct(const QJsonObject &deviceConfig);
+
+ ///
+ /// @brief Discover WLED devices available (for configuration).
+ ///
+ /// @return A JSON structure holding a list of devices found
+ ///
+ virtual QJsonObject discover() override;
+
+ ///
+ /// @brief Get the WLED device's resource properties
+ ///
+ /// Following parameters are required
+ /// @code
+ /// {
+ /// "host" : "hostname or IP [:port]",
+ /// "filter": "resource to query", root "/" is used, if empty
+ /// }
+ ///@endcode
+ ///
+ /// @param[in] params Parameters to query device
+ /// @return A JSON structure holding the device's properties
+ ///
+ virtual QJsonObject getProperties(const QJsonObject& params) override;
+
+ ///
+ /// @brief Send an update to the WLED device to identify it.
+ ///
+ /// Following parameters are required
+ /// @code
+ /// {
+ /// "host" : "hostname or IP [:port]",
+ /// }
+ ///@endcode
+ ///
+ /// @param[in] params Parameters to address device
+ ///
+ virtual void identify(const QJsonObject& params) override;
+
+protected:
+
+ ///
+ /// @brief Initialise the WLED device's configuration and network address details
+ ///
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
+ ///
+ virtual bool init(const QJsonObject &deviceConfig) override;
+
+ ///
+ /// @brief Writes the RGB-Color values to the LEDs.
+ ///
+ /// @param[in] ledValues The RGB-color per LED
+ /// @return Zero on success, else negative
+ ///
+ virtual int write(const std::vector & ledValues) override;
+
+ ///
+ /// @brief Power-/turn on the WLED device.
+ ///
+ /// @brief Store the device's original state.
+ ///
+ virtual bool powerOn() override;
+
+ ///
+ /// @brief Power-/turn off the WLED device.
+ ///
+ /// @return True if success
+ ///
+ virtual bool powerOff() override;
+
+private:
+
+ ///
+ /// @brief Initialise the access to the REST-API wrapper
+ ///
+ /// @param[in] host
+ /// @param[in] port
+ /// @return True, if success
+ ///
+ bool initRestAPI(const QString &hostname, const int port );
+
+ ///
+ /// @brief Get command to power WLED-device on or off
+ ///
+ /// @param isOn True, if to switch on device
+ /// @return Command to switch device on/off
+ ///
+ QString getOnOffRequest (bool isOn ) const;
+
+ ///REST-API wrapper
+ ProviderRestApi* _restApi;
+
+ QString _hostname;
+ int _apiPort;
+};
+
+#endif // LEDDEVICEWLED_H
diff --git a/libsrc/leddevice/dev_net/LedDeviceYeelight.cpp b/libsrc/leddevice/dev_net/LedDeviceYeelight.cpp
new file mode 100644
index 000000000..236acbb7f
--- /dev/null
+++ b/libsrc/leddevice/dev_net/LedDeviceYeelight.cpp
@@ -0,0 +1,1502 @@
+#include "LedDeviceYeelight.h"
+
+#include
+#include
+
+// Qt includes
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+// Constants
+namespace {
+
+const bool verbose = false;
+const bool verbose3 = false;
+
+constexpr std::chrono::milliseconds WRITE_TIMEOUT{1000}; // device write timeout in ms
+constexpr std::chrono::milliseconds READ_TIMEOUT{1000}; // device read timeout in ms
+constexpr std::chrono::milliseconds CONNECT_TIMEOUT{1000}; // device connect timeout in ms
+constexpr std::chrono::milliseconds CONNECT_STREAM_TIMEOUT{1000}; // device streaming connect timeout in ms
+
+const bool TEST_CORRELATION_IDS = false; //Ignore, if yeelight sends responses in different order as request commands
+
+// Configuration settings
+const char CONFIG_LIGHTS [] = "lights";
+
+const char CONFIG_COLOR_MODEL [] = "colorModel";
+const char CONFIG_TRANS_EFFECT [] = "transEffect";
+const char CONFIG_TRANS_TIME [] = "transTime";
+const char CONFIG_EXTRA_TIME_DARKNESS[] = "extraTimeDarkness";
+const char CONFIG_DEBUGLEVEL [] = "debugLevel";
+
+const char CONFIG_BRIGHTNESS_MIN[] = "brightnessMin";
+const char CONFIG_BRIGHTNESS_SWITCHOFF[] = "brightnessSwitchOffOnMinimum";
+const char CONFIG_BRIGHTNESS_MAX[] = "brightnessMax";
+const char CONFIG_BRIGHTNESSFACTOR[] = "brightnessFactor";
+
+const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
+
+const char CONFIG_QUOTA_WAIT_TIME[] = "quotaWait";
+
+// Yeelights API
+const int API_DEFAULT_PORT = 55443;
+const quint16 API_DEFAULT_QUOTA_WAIT_TIME = 1000;
+
+// Yeelight API Command
+const char API_COMMAND_ID[] = "id";
+const char API_COMMAND_METHOD[] = "method";
+const char API_COMMAND_PARAMS[] = "params";
+const char API_COMMAND_PROPS[] = "props";
+
+const char API_PARAM_CLASS_COLOR[] = "color";
+const char API_PARAM_CLASS_HSV[] = "hsv";
+
+const char API_PROP_NAME[] = "name";
+const char API_PROP_MODEL[] = "model";
+const char API_PROP_FWVER[] = "fw_ver";
+
+const char API_PROP_POWER[] = "power";
+const char API_PROP_MUSIC[] = "music_on";
+const char API_PROP_RGB[] = "rgb";
+const char API_PROP_CT[] = "ct";
+const char API_PROP_COLORFLOW[] = "cf";
+const char API_PROP_BRIGHT[] = "bright";
+
+// List of Result Information
+const char API_RESULT_ID[] = "id";
+const char API_RESULT[] = "result";
+//const char API_RESULT_OK[] = "OK";
+
+// List of Error Information
+const char API_ERROR[] = "error";
+const char API_ERROR_CODE[] = "code";
+const char API_ERROR_MESSAGE[] = "message";
+
+// Yeelight ssdp services
+const char SSDP_ID[] = "wifi_bulb";
+const char SSDP_FILTER[] = "yeelight(.*)";
+const char SSDP_FILTER_HEADER[] = "Location";
+const quint16 SSDP_PORT = 1982;
+
+} //End of constants
+
+YeelightLight::YeelightLight( Logger *log, const QString &hostname, quint16 port = API_DEFAULT_PORT)
+ :_log(log)
+ ,_debugLevel(0)
+ ,_isInError(false)
+ ,_host (hostname)
+ ,_port(port)
+ ,_tcpSocket(nullptr)
+ ,_tcpStreamSocket(nullptr)
+ ,_correlationID(0)
+ ,_lastWriteTime(QDateTime::currentMSecsSinceEpoch())
+ ,_lastColorRgbValue(0)
+ ,_transitionEffect(YeelightLight::API_EFFECT_SMOOTH)
+ ,_transitionDuration(API_PARAM_DURATION.count())
+ ,_extraTimeDarkness(API_PARAM_EXTRA_TIME_DARKNESS.count())
+ ,_brightnessMin(0)
+ ,_isBrightnessSwitchOffMinimum(false)
+ ,_brightnessMax(100)
+ ,_brightnessFactor(1.0)
+ ,_transitionEffectParam(API_PARAM_EFFECT_SMOOTH)
+ ,_waitTimeQuota(API_DEFAULT_QUOTA_WAIT_TIME)
+ ,_isOn(false)
+ ,_isInMusicMode(false)
+{
+ _name = hostname;
+
+}
+
+YeelightLight::~YeelightLight()
+{
+ log (3,"~YeelightLight()","" );
+ if ( _tcpSocket != nullptr)
+ {
+ delete _tcpSocket;
+ }
+ log (2,"~YeelightLight()","void" );
+}
+
+void YeelightLight::setHostname( const QString &hostname, quint16 port = API_DEFAULT_PORT )
+{
+ log (3,"setHostname()","" );
+ _host = hostname;
+ _port =port;
+}
+
+void YeelightLight::setStreamSocket( QTcpSocket* socket )
+{
+ log (3,"setStreamSocket()","" );
+ _tcpStreamSocket = socket;
+}
+
+bool YeelightLight::open()
+{
+ _isInError = false;
+ bool rc = false;
+
+ if ( _tcpSocket == nullptr )
+ {
+ _tcpSocket = new QTcpSocket();
+ }
+
+ if ( _tcpSocket->state() == QAbstractSocket::ConnectedState )
+ {
+ log (2,"open()","Device is already connected, skip opening: [%d]", _tcpSocket->state());
+ rc = true;
+ }
+ else
+ {
+ _tcpSocket->connectToHost( _host, _port);
+
+ if ( _tcpSocket->waitForConnected( CONNECT_TIMEOUT.count() ) )
+ {
+ if ( _tcpSocket->state() != QAbstractSocket::ConnectedState )
+ {
+ this->setInError( _tcpSocket->errorString() );
+ rc = false;
+ }
+ else
+ {
+ log (2,"open()","Successfully opened Yeelight: %s", QSTRING_CSTR(_host));
+ rc = true;
+ }
+ }
+ else
+ {
+ this->setInError( _tcpSocket->errorString() );
+ rc = false;
+ }
+ }
+ return rc;
+}
+
+bool YeelightLight::close()
+{
+ bool rc = true;
+
+ if ( _tcpSocket != nullptr )
+ {
+ // Test, if device requires closing
+ if ( _tcpSocket->isOpen() )
+ {
+ log (2,"close()","Close Yeelight: %s", QSTRING_CSTR(_host));
+ _tcpSocket->close();
+ // Everything is OK -> device is closed
+ }
+ }
+
+ if ( _tcpStreamSocket != nullptr )
+ {
+ // Test, if stream socket requires closing
+ if ( _tcpStreamSocket->isOpen() )
+ {
+ log (2,"close()","Close stream Yeelight: %s", QSTRING_CSTR(_host));
+ _tcpStreamSocket->close();
+ }
+ }
+ return rc;
+}
+
+int YeelightLight::writeCommand( const QJsonDocument &command )
+{
+ QJsonArray result;
+ return writeCommand(command, result );
+}
+
+int YeelightLight::writeCommand( const QJsonDocument &command, QJsonArray &result )
+{
+ log( 3,
+ "writeCommand()",
+ "isON[%d], isInMusicMode[%d]",
+ static_cast( _isOn ), static_cast( _isInMusicMode ) );
+ if (_debugLevel >= 2)
+ {
+ QString help = command.toJson(QJsonDocument::Compact);
+ log (2,"writeCommand()","%s", QSTRING_CSTR(help));
+ }
+
+ int rc = -1;
+
+ if ( ! _isInError && _tcpSocket->isOpen() )
+ {
+ qint64 bytesWritten = _tcpSocket->write( command.toJson(QJsonDocument::Compact) + "\r\n");
+ if (bytesWritten == -1 )
+ {
+ this->setInError( QString ("Write Error: %1").arg(_tcpSocket->errorString()) );
+ }
+ else
+ {
+ if ( ! _tcpSocket->waitForBytesWritten(WRITE_TIMEOUT.count()) )
+ {
+ QString errorReason = QString ("(%1) %2").arg(_tcpSocket->error()).arg( _tcpSocket->errorString());
+ log ( 2, "Error:", "bytesWritten: [%d], %s", bytesWritten, QSTRING_CSTR(errorReason));
+ this->setInError ( errorReason );
+ }
+ else
+ {
+ log ( 3, "Success:", "Bytes written [%d]", bytesWritten );
+
+ // Avoid to overrun the Yeelight Command Quota
+ qint64 elapsedTime = QDateTime::currentMSecsSinceEpoch() - _lastWriteTime;
+
+ if ( elapsedTime < _waitTimeQuota )
+ {
+ int waitTime = _waitTimeQuota;
+ log ( 1, "writeCommand():", "Wait %dms, elapsedTime: %dms < quotaTime: %dms", waitTime, elapsedTime, _waitTimeQuota);
+
+ // Wait time (in ms) before doing next write to not overrun Yeelight command quota
+ std::this_thread::sleep_for(std::chrono::milliseconds(_waitTimeQuota));
+ }
+ }
+
+ if ( _tcpSocket->waitForReadyRead(READ_TIMEOUT.count()) )
+ {
+ do
+ {
+ log ( 3, "Reading:", "Bytes available [%d]", _tcpSocket->bytesAvailable() );
+ while ( _tcpSocket->canReadLine() )
+ {
+ QByteArray response = _tcpSocket->readLine();
+
+ YeelightResponse yeeResponse = handleResponse( _correlationID, response );
+ switch ( yeeResponse.error() ) {
+
+ case YeelightResponse::API_NOTIFICATION:
+ rc=0;
+ break;
+ case YeelightResponse::API_OK:
+ result = yeeResponse.getResult();
+ rc=0;
+ break;
+ case YeelightResponse::API_ERROR:
+ result = yeeResponse.getResult();
+ QString errorReason = QString ("(%1) %2").arg(yeeResponse.getErrorCode()).arg( yeeResponse.getErrorReason() );
+ if ( yeeResponse.getErrorCode() != -1)
+ {
+ this->setInError ( errorReason );
+ rc =-1;
+ }
+ else
+ {
+ //(-1) client quota exceeded
+ log ( 1, "writeCommand():", "%s", QSTRING_CSTR(errorReason) );
+ rc = -2;
+ }
+ break;
+ }
+ }
+ log ( 3, "Info:", "Trying to read more responses");
+ }
+ while ( _tcpSocket->waitForReadyRead(500) );
+ }
+
+ log ( 3, "Info:", "No more responses available");
+ }
+
+ //In case of no error or quota exceeded, update late write time avoiding immediate next write
+ if ( rc == 0 || rc == -2 )
+ {
+ _lastWriteTime = QDateTime::currentMSecsSinceEpoch();
+ }
+ }
+ else
+ {
+ log ( 2, "Info:", "Skip write. Device is in error");
+ }
+
+ log (3,"writeCommand() rc","%d", rc );
+ return rc;
+}
+
+bool YeelightLight::streamCommand( const QJsonDocument &command )
+{
+ // ToDo: Wofür gibt es isON, wenn es beim StreamCommand nicht verwendet wird?
+ //log (3,"streamCommand()","isON[%d], isInMusicMode[%d]", _isOn, _isInMusicMode );
+ if (_debugLevel >= 2)
+ {
+ QString help = command.toJson(QJsonDocument::Compact);
+ log (3,"streamCommand()","%s", QSTRING_CSTR(help));
+ }
+
+ bool rc = false;
+
+ if ( ! _isInError && _tcpStreamSocket->isOpen() )
+ {
+ qint64 bytesWritten = _tcpStreamSocket->write( command.toJson(QJsonDocument::Compact) + "\r\n");
+ if (bytesWritten == -1 )
+ {
+ this->setInError( QString ("Streaming Error %1").arg(_tcpStreamSocket->errorString()) );
+ }
+ else
+ {
+ if ( ! _tcpStreamSocket->waitForBytesWritten(WRITE_TIMEOUT.count()) )
+ {
+ int error = _tcpStreamSocket->error();
+ QString errorReason = QString ("(%1) %2").arg(error).arg( _tcpStreamSocket->errorString());
+ log ( 1, "Error:", "bytesWritten: [%d], %s", bytesWritten, QSTRING_CSTR(errorReason));
+
+ if ( error == QAbstractSocket::RemoteHostClosedError )
+ {
+ log (1,"streamCommand()","RemoteHostClosedError - Give it a retry");
+ _isInMusicMode = false;
+ rc = true;
+ }
+ else
+ {
+ this->setInError ( errorReason );
+ }
+ }
+ else
+ {
+ log ( 3, "Success:", "Bytes written [%d]", bytesWritten );
+ rc = true;
+ }
+ }
+ }
+ else
+ {
+ log ( 2, "Info:", "Skip write. Device is in error");
+ }
+
+ //log (2,"streamCommand() rc","%d, isON[%d], isInMusicMode[%d]", rc, _isOn, _isInMusicMode );
+ return rc;
+}
+
+YeelightResponse YeelightLight::handleResponse(int correlationID, QByteArray const &response )
+{
+ log (3,"handleResponse()","" );
+
+ //std::cout << _name.toStdString() <<"| Response: [" << response.toStdString() << "]" << std::endl << std::flush;
+
+ YeelightResponse yeeResponse;
+ QString errorReason;
+
+ QJsonParseError error;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(response, &error);
+
+ if (error.error != QJsonParseError::NoError)
+ {
+ yeeResponse.setErrorCode (-10000);
+ yeeResponse.setErrorReason( "Got invalid response" );
+ }
+ else
+ {
+ QString strJson(jsonDoc.toJson(QJsonDocument::Compact));
+
+ QJsonObject jsonObj = jsonDoc.object();
+
+ if ( !jsonObj[API_COMMAND_METHOD].isNull() )
+ {
+ yeeResponse.setError(YeelightResponse::API_NOTIFICATION);
+ yeeResponse.setResult( QJsonArray() );
+ // Do process notifications only for debugging
+ if ( verbose3 )
+ {
+ log ( 3, "Info:", "Notification found : [%s]", QSTRING_CSTR( jsonObj[API_COMMAND_METHOD].toString()));
+
+ QString method = jsonObj[API_COMMAND_METHOD].toString();
+
+ if ( method == API_COMMAND_PROPS )
+ {
+
+ if ( jsonObj.contains(API_COMMAND_PARAMS) && jsonObj[API_COMMAND_PARAMS].isObject() )
+ {
+ QVariantMap paramsMap = jsonObj[API_COMMAND_PARAMS].toVariant().toMap();
+
+ // Loop over all children.
+ for (const QString & property : paramsMap.keys())
+ {
+ QString value = paramsMap[property].toString();
+ log ( 3, "Notification ID:", "[%s]:[%s]", QSTRING_CSTR( property ), QSTRING_CSTR( value ));
+ }
+ }
+ }
+ else
+ {
+ log ( 1, "Error:", "Invalid notification message: [%s]", strJson.toUtf8().constData() );
+ }
+ }
+ }
+ else
+ {
+ int id = jsonObj[API_RESULT_ID].toInt();
+ //log ( 3, "Correlation ID:", "%d", id );
+
+ if ( id != correlationID && TEST_CORRELATION_IDS)
+ {
+ errorReason = QString ("%1| API is out of sync, received ID [%2], expected [%3]").
+ arg( _name ).arg( id ).arg( correlationID );
+
+ yeeResponse.setErrorCode (-11000);
+ yeeResponse.setErrorReason( errorReason );
+
+ this->setInError ( errorReason );
+ }
+ else
+ {
+
+ if ( jsonObj.contains(API_RESULT) && jsonObj[API_RESULT].isArray() )
+ {
+
+ // API call returned an result
+ yeeResponse.setResult( jsonObj[API_RESULT].toArray() );
+
+ // Break down result only for debugging
+ if ( verbose3 )
+ {
+ // Debug output
+ if(!yeeResponse.getResult().empty())
+ {
+ for(const auto item : yeeResponse.getResult())
+ {
+ log ( 3, "Result:", "%s", QSTRING_CSTR( item.toString() ));
+ }
+ }
+ }
+ }
+ else
+ {
+ yeeResponse.setError(YeelightResponse::API_ERROR);
+ if ( jsonObj.contains(API_ERROR) && jsonObj[API_ERROR].isObject() )
+ {
+ QVariantMap errorMap = jsonObj[API_ERROR].toVariant().toMap();
+
+ yeeResponse.setErrorCode (errorMap.value(API_ERROR_CODE).toInt());
+ yeeResponse.setErrorReason( errorMap.value(API_ERROR_MESSAGE).toString() );
+ }
+ else
+ {
+ yeeResponse.setErrorCode (-10010);
+ yeeResponse.setErrorReason( "No valid result message" );
+ log ( 1, "Reply:", "[%s]", strJson.toUtf8().constData());
+ }
+ }
+ }
+ }
+ }
+ log (3,"handleResponse()", "yeeResponse.error [%d]", yeeResponse.error() );
+ return yeeResponse;
+}
+
+void YeelightLight::setInError(const QString& errorMsg)
+{
+ _isInError = true;
+ Error(_log, "Yeelight device '%s' signals error: '%s'", QSTRING_CSTR( _name ), QSTRING_CSTR(errorMsg));
+}
+
+QJsonDocument YeelightLight::getCommand(const QString &method, const QJsonArray ¶ms)
+{
+ //Increment Correlation-ID
+ ++_correlationID;
+
+ QJsonObject obj;
+ obj.insert(API_COMMAND_ID,_correlationID);
+ obj.insert(API_COMMAND_METHOD,method);
+ obj.insert(API_COMMAND_PARAMS,params);
+
+ return QJsonDocument(obj);
+}
+
+QJsonObject YeelightLight::getProperties()
+{
+ log (3,"getProperties()","" );
+ QJsonObject properties;
+
+ //Selected properties
+ //QJsonArray propertyList = { API_PROP_NAME, API_PROP_MODEL, API_PROP_POWER, API_PROP_RGB, API_PROP_BRIGHT, API_PROP_CT, API_PROP_FWVER };
+
+ //All properties
+ QJsonArray propertyList = {"power","bright","ct","rgb","hue","sat","color_mode","flowing","delayoff","music_on","name","bg_power","bg_flowing","bg_ct","bg_bright","bg_hue","bg_sat","bg_rgb","nl_br","active_mode" };
+
+ QJsonDocument command = getCommand( API_METHOD_GETPROP, propertyList );
+
+ QJsonArray result;
+
+ if ( writeCommand( command, result ) > -1 )
+ {
+
+ // Debug output
+ if( !result.empty())
+ {
+ int i = 0;
+ for(const auto item : result)
+ {
+ log (1,"Property:", "%s = %s", QSTRING_CSTR( propertyList.at(i).toString() ), QSTRING_CSTR( item.toString() ));
+ properties.insert( propertyList.at(i).toString(), item );
+ ++i;
+ }
+ }
+ }
+
+ log (2,"getProperties()","QJsonObject");
+ return properties;
+}
+
+bool YeelightLight::identify()
+{
+ log (3,"identify()","" );
+ bool rc = true;
+
+ /*
+ count 6, total number of visible state changing before color flow is stopped
+ action 0, 0 means smart LED recover to the state before the color flow started
+
+ Duration: 500, Gradual change timer sleep-time, in milliseconds
+ Mode: 1, color
+ Value: 100, RGB value when mode is 1 (blue)
+ Brightness: 100, Brightness value
+
+ Duration: 500
+ Mode: 1
+ Value: 16711696 (red)
+ Brightness: 10
+ */
+ QJsonArray colorflowParams = { API_PROP_COLORFLOW, 6, 0, "500,1,100,100,500,1,16711696,10"};
+
+ //Blink White
+ //QJsonArray colorflowParams = { API_PROP_COLORFLOW, 6, 0, "500,2,4000,1,500,2,4000,50"};
+
+ QJsonDocument command = getCommand( API_METHOD_SETSCENE, colorflowParams );
+
+ if ( writeCommand( command ) < 0 )
+ {
+ rc= false;
+ }
+
+ log( 2, "identify() rc","%d", static_cast(rc) );
+ return rc;
+}
+
+bool YeelightLight::isInMusicMode( bool deviceCheck)
+{
+ bool inMusicMode = false;
+
+ if ( deviceCheck )
+ {
+ // Get status from device directly
+ QJsonArray propertylist = { API_PROP_MUSIC };
+
+ QJsonDocument command = getCommand( API_METHOD_GETPROP, propertylist );
+
+ QJsonArray result;
+
+ if ( writeCommand( command, result ) >= 0 )
+ {
+ if( !result.empty())
+ {
+ inMusicMode = result.at(0).toString() == "1";
+ }
+ }
+ }
+ else
+ {
+ // Test indirectly avoiding command quota
+ if ( _tcpStreamSocket != nullptr)
+ {
+ if ( _tcpStreamSocket->state() == QAbstractSocket::ConnectedState )
+ {
+ log (3,"isInMusicMode", "Yes, as socket is in ConnectedState");
+ inMusicMode = true;
+ }
+ else
+ {
+ log (1,"isInMusicMode", "No, StreamSocket state: %d", _tcpStreamSocket->state());
+ }
+ }
+ }
+ _isInMusicMode = inMusicMode;
+
+ log( 3, "isInMusicMode()", "%d", static_cast( _isInMusicMode ) );
+
+ return _isInMusicMode;
+}
+
+void YeelightLight::mapProperties(const QJsonObject &properties)
+{
+ log (3,"mapProperties()","" );
+
+ if ( _name.isEmpty() )
+ {
+ _name = properties.value(API_PROP_NAME).toString();
+ if ( _name.isEmpty() )
+ {
+ _name = _host;
+ }
+ }
+ _model = properties.value(API_PROP_MODEL).toString();
+ _fw_ver = properties.value(API_PROP_FWVER).toString();
+
+ _power = properties.value(API_PROP_POWER).toString();
+ _colorRgbValue = properties.value(API_PROP_RGB).toString().toInt();
+ _bright = properties.value(API_PROP_BRIGHT).toString().toInt();
+ _ct = properties.value(API_PROP_CT).toString().toInt();
+
+ log (2,"mapProperties() rc","void" );
+}
+
+void YeelightLight::storeState()
+{
+ log (3,"storeState()","" );
+
+ _originalStateProperties = this->getProperties();
+ mapProperties( _originalStateProperties );
+
+ log (2,"storeState() rc","void" );
+}
+
+bool YeelightLight::restoreState()
+{
+ log (3,"restoreState()","" );
+ bool rc = false;
+
+ QJsonArray paramlist = { API_PARAM_CLASS_COLOR, _colorRgbValue, _bright };
+
+ if ( _isInMusicMode )
+ {
+ rc = streamCommand( getCommand( API_METHOD_SETSCENE, paramlist ) );
+ }
+ else
+ {
+ if ( writeCommand( getCommand( API_METHOD_SETSCENE, paramlist ) ) >= 0 )
+ {
+ rc =true;
+ }
+ }
+
+ log( 2, "restoreState() rc","%d", static_cast(rc) );
+ return rc;
+}
+
+bool YeelightLight::setPower(bool on)
+{
+ return setPower( on, _transitionEffect, _transitionDuration);
+}
+
+bool YeelightLight::setPower(bool on, YeelightLight::API_EFFECT effect, int duration, API_MODE mode)
+{
+ bool rc = false;
+ log( 3,
+ "setPower()",
+ "isON[%d], isInMusicMode[%d]",
+ static_cast( _isOn), static_cast(_isInMusicMode ) );
+
+ // Disable music mode to get power-off command executed
+ if ( !on && _isInMusicMode )
+ {
+ if ( _tcpStreamSocket != nullptr )
+ {
+ _tcpStreamSocket->close();
+ }
+ }
+
+ QString powerParam = on ? API_METHOD_POWER_ON : API_METHOD_POWER_OFF;
+ QString effectParam = effect == YeelightLight::API_EFFECT_SMOOTH ? API_PARAM_EFFECT_SMOOTH : API_PARAM_EFFECT_SUDDEN;
+
+ QJsonArray paramlist = { powerParam, effectParam, duration, mode };
+
+ // If power off was successful, automatically music-mode is off too
+ if ( writeCommand( getCommand( API_METHOD_POWER, paramlist ) ) > -1 )
+ {
+ _isOn = on;
+ if ( !on )
+ {
+ _isInMusicMode = false;
+ }
+ rc =true;
+ }
+ log( 2,
+ "setPower() rc",
+ "%d, isON[%d], isInMusicMode[)%d]",
+ static_cast(rc), static_cast( _isOn ), static_cast( _isInMusicMode ) );
+
+ return rc;
+}
+
+bool YeelightLight::setColorRGB(const ColorRgb &color)
+{
+ bool rc = true;
+
+ int colorParam = (color.red * 65536) + (color.green * 256) + color.blue;
+
+ if ( colorParam == 0 )
+ {
+ colorParam = 1;
+ }
+
+ if ( colorParam != _lastColorRgbValue )
+ {
+ int bri = std::max( { color.red, color.green, color.blue } ) * 100 / 255;
+ int duration = _transitionDuration;
+
+ if ( bri < _brightnessMin )
+ {
+ if ( _isBrightnessSwitchOffMinimum )
+ {
+ log( 2,
+ "Set Color RGB:",
+ "Turn off, brightness [%d] < _brightnessMin [%d], "
+ "_isBrightnessSwitchOffMinimum [%d]",
+ bri,_brightnessMin, static_cast(_isBrightnessSwitchOffMinimum ) );
+ // Set brightness to 0
+ bri = 0;
+ duration = _transitionDuration + _extraTimeDarkness;
+ }
+ else
+ {
+ //If not switchOff on MinimumBrightness, avoid switch-off
+ log( 2,
+ "Set Color RGB:",
+ "Set brightness[%d] to minimum brightness [%d], if not _isBrightnessSwitchOffMinimum [%d]",
+ bri, _brightnessMin, static_cast( _isBrightnessSwitchOffMinimum ) );
+ bri = _brightnessMin;
+ }
+ }
+ else
+ {
+ bri = ( qMin( _brightnessMax, static_cast (_brightnessFactor * qMax( _brightnessMin, bri ) ) ) );
+ }
+
+ log ( 3, "Set Color RGB:", "{%u,%u,%u} -> [%d], [%d], [%d], [%d]", color.red, color.green, color.blue, colorParam, bri, _transitionEffect, _transitionDuration );
+ QJsonArray paramlist = { API_PARAM_CLASS_COLOR, colorParam, bri };
+
+ // Only add transition effect and duration, if device smoothing is configured (older FW do not support this parameters in set_scene
+ if ( _transitionEffect == YeelightLight::API_EFFECT_SMOOTH )
+ {
+ paramlist << _transitionEffectParam << duration;
+ }
+
+ bool writeOK = false;
+ if ( _isInMusicMode )
+ {
+ writeOK = streamCommand( getCommand( API_METHOD_SETSCENE, paramlist ) );
+ }
+ else
+ {
+ if ( writeCommand( getCommand( API_METHOD_SETSCENE, paramlist ) ) >= 0 )
+ {
+ writeOK = true;
+ }
+ }
+ if ( writeOK )
+ {
+ _lastColorRgbValue = colorParam;
+ }
+ else
+ {
+ rc = false;
+ }
+ }
+ //log (2,"setColorRGB() rc","%d, isON[%d], isInMusicMode[%d]", rc, _isOn, _isInMusicMode );
+ return rc;
+}
+
+bool YeelightLight::setColorHSV(const ColorRgb &colorRGB)
+{
+ bool rc = true;
+
+ QColor color(colorRGB.red, colorRGB.green, colorRGB.blue);
+
+ if ( color != _color )
+ {
+ int hue;
+ int sat;
+ int bri;
+ int duration = _transitionDuration;
+
+ color.getHsv( &hue, &sat, &bri);
+
+ //Align to Yeelight number ranges (hue: 0-359, sat: 0-100, bri: 0-100)
+ if ( hue == -1)
+ {
+ hue = 0;
+ }
+ sat = sat * 100 / 255;
+ bri = bri * 100 / 255;
+
+ if ( bri < _brightnessMin )
+ {
+ if ( _isBrightnessSwitchOffMinimum )
+ {
+ log( 2,
+ "Set Color HSV:",
+ "Turn off, brightness [%d] < _brightnessMin [%d], "
+ "_isBrightnessSwitchOffMinimum [%d]",
+ bri,
+ _brightnessMin,
+ static_cast( _isBrightnessSwitchOffMinimum ) );
+ // Set brightness to 0
+ bri = 0;
+ duration = _transitionDuration + _extraTimeDarkness;
+ }
+ else
+ {
+ //If not switchOff on MinimumBrightness, avoid switch-off
+ log( 2,
+ "Set Color HSV:",
+ "Set brightness[%d] to minimum brightness [%d], if not _isBrightnessSwitchOffMinimum [%d]",
+ bri, _brightnessMin, static_cast( _isBrightnessSwitchOffMinimum ));
+ bri = _brightnessMin;
+ }
+ }
+ else
+ {
+ bri = ( qMin( _brightnessMax, static_cast (_brightnessFactor * qMax( _brightnessMin, bri ) ) ) );
+ }
+ log ( 2, "Set Color HSV:", "{%u,%u,%u}, [%d], [%d]", hue, sat, bri, _transitionEffect, duration );
+ QJsonArray paramlist = { API_PARAM_CLASS_HSV, hue, sat, bri };
+
+ // Only add transition effect and duration, if device smoothing is configured (older FW do not support this parameters in set_scene
+ if ( _transitionEffect == YeelightLight::API_EFFECT_SMOOTH )
+ {
+ paramlist << _transitionEffectParam << duration;
+ }
+
+ bool writeOK=false;
+ if ( _isInMusicMode )
+ {
+ writeOK = streamCommand( getCommand( API_METHOD_SETSCENE, paramlist ) );
+ }
+ else
+ {
+ if ( writeCommand( getCommand( API_METHOD_SETSCENE, paramlist ) ) >= 0 )
+ {
+ writeOK = true;
+ }
+ }
+
+ if ( writeOK )
+ {
+ _isOn = true;
+ if ( bri == 0 )
+ {
+ _isOn = false;
+ _isInMusicMode = false;
+ }
+ _color = color;
+ }
+ else
+ {
+ rc = false;
+ }
+ }
+ else
+ {
+ //log ( 3, "setColorHSV", "Skip update. Same Color as before");
+ }
+ log( 3,
+ "setColorHSV() rc",
+ "%d, isON[%d], isInMusicMode[%d]",
+ static_cast( rc ), static_cast