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/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 cb5127b54..65ec2f586 100644
--- a/include/api/JsonAPI.h
+++ b/include/api/JsonAPI.h
@@ -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/leddevice/LedDevice.h b/include/leddevice/LedDevice.h
index 5f7512154..fbb7904d8 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,205 +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
+ ///
virtual ~LedDevice();
///
- /// @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 A JSON structure holding a list of devices found
+ ///
+ virtual QJsonObject discover();
+
+ ///
+ /// @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 ready
+ /// @return A string of the device found
///
- bool isReady() const { return _deviceReady; }
+ virtual QString discoverFirst();
///
- /// Check, if device is in error state
+ /// @brief Get the device's properties
///
- /// @return True if device is in error
+ /// Used in context of a set of devices of the same type.
///
- bool isInError() const { return _deviceInError; }
+ /// @param[in] params Parameters to address device
+ /// @return A JSON structure holding the device's properties
+ ///
+ virtual QJsonObject getProperties(const QJsonObject& params);
+
+ ///
+ /// @brief Send an update to the device to identify it.
+ ///
+ /// 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; }
- inline bool componentState() const { return enabled(); }
+ ///
+ /// @brief Check, if device is in error state.
+ ///
+ /// @return True, if device is in error
+ ///
+ bool isInError() const { return _isDeviceInError; }
- /// Prints the RGB-Color values to stdout.
///
- /// @param[in] ledValues The RGB-color per led
+ /// @brief Get the LED-Device component's state.
///
- static void printLedValues (const std::vector& ledValues );
+ /// @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 ? true : false);}
+ 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.
///
- virtual void close();
+ /// @param[in] ledValues The color per LED
+ /// @return Zero on success else negative (i.e. device is not ready)
+ ///
+ 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.
///
- /// @param enable The new state of the device
+ /// If the device is not ready, it will not be enabled.
///
- void setEnable(bool enable); ///
+ /// @param[in] enable The new state of the device
+ ///
+ 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;
- /// Timestamp of last write
- QDateTime _lastWriteTime;
+ /// Time a device requires mandatorily between two writes (in milliseconds)
+ int _latchTime_ms;
+
+ /// Does the device allow restoring the original state?
+ bool _isRestoreOrigState;
- /// Time a device requires mandatorily between two writes
- int _latchTime_ms;
+ /// 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;
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 347146cb2..6235dcbfe 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
@@ -21,8 +22,8 @@ class LedDeviceWrapper : public QObject
explicit LedDeviceWrapper(Hyperion* hyperion);
~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; }
+ const 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,7 +101,7 @@ private slots:
protected:
- /// contains all available led device constrcutors
+ /// contains all available led device constructors
static LedDeviceRegistry _ledDeviceMap;
private:
@@ -117,3 +118,5 @@ private slots:
// the enable state
bool _enabled;
};
+
+#endif // LEDEVICEWRAPPER_H
diff --git a/include/ssdp/SSDPDiscover.h b/include/ssdp/SSDPDiscover.h
index e149a0e57..77ace92ae 100644
--- a/include/ssdp/SSDPDiscover.h
+++ b/include/ssdp/SSDPDiscover.h
@@ -1,7 +1,10 @@
-#pragma once
+#ifndef SSDPDISCOVER_H
+#define SSDPDISCOVER_H
#include
#include
+#include
+#include
class QUdpSocket;
@@ -11,6 +14,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";
+
+const int DEFAULT_SSDP_TIMEOUT = 5000; // timeout in ms
+
///
/// @brief Search for SSDP sessions, used by stand-alone capture binaries
///
@@ -37,6 +57,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 +194,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/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 e314b208d..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");
diff --git a/libsrc/leddevice/LedDevice.cpp b/libsrc/leddevice/LedDevice.cpp
index 5c831ba5d..0e76b5810 100644
--- a/libsrc/leddevice/LedDevice.cpp
+++ b/libsrc/leddevice/LedDevice.cpp
@@ -1,5 +1,4 @@
#include
-#include
//QT include
#include
@@ -13,102 +12,109 @@
#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(new QTimer(this))
+ , _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()));
+ _refreshTimer->setTimerType(Qt::PreciseTimer);
+ _refreshTimer->setInterval( _refreshTimerInterval_ms );
+ connect(_refreshTimer, &QTimer::timeout, this, &LedDevice::rewriteLEDs );
}
LedDevice::~LedDevice()
{
- _refresh_timer->deleteLater();
+ _refreshTimer->deleteLater();
}
-int LedDevice::open()
+void LedDevice::start()
{
- int retval = -1;
- QString errortext;
- _deviceReady = false;
+ Info(_log, "Start LedDevice '%s'.", QSTRING_CSTR(_activeDeviceType));
+ 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;
}
-void LedDevice::close()
+int LedDevice::close()
{
- switchOff();
+ _isDeviceReady = false;
+ int retval = 0;
+
+ return retval;
+}
+
+void LedDevice::setInError(const QString& errorMsg)
+{
+ _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 )
- {
- 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 )
+ bool isSwitched = false;
+ // switch off device when disabled, default: set black to LEDs when they should go off
+ if ( _isEnabled && !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 +124,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 +156,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 +185,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 +204,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 +409,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 b9128ae5b..a462ffa10 100644
--- a/libsrc/leddevice/LedDeviceTemplate.cpp
+++ b/libsrc/leddevice/LedDeviceTemplate.cpp
@@ -4,11 +4,9 @@ LedDeviceTemplate::LedDeviceTemplate(const QJsonObject &deviceConfig)
: LedDevice()
{
_devConfig = deviceConfig;
- _deviceReady = false;
-}
+ _isDeviceReady = false;
-LedDeviceTemplate::~LedDeviceTemplate()
-{
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceTemplate::construct(const QJsonObject &deviceConfig)
@@ -18,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;
}
@@ -37,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)
diff --git a/libsrc/leddevice/LedDeviceTemplate.h b/libsrc/leddevice/LedDeviceTemplate.h
index d548f8bef..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,51 +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);
///
- /// Destructor of this LedDevice
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
///
- virtual ~LedDeviceTemplate() override;
-
- /// constructs leddevice
static LedDevice* construct(const QJsonObject &deviceConfig);
+protected:
+
+ ///
+ /// @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;
-public slots:
///
- /// Closes the output device.
- /// Includes switching-off the device and stopping refreshes
+ /// @brief Opens the output device.
///
- virtual void close() override;
-
-protected:
+ /// @return Zero on success (i.e. device is ready), else negative
///
- /// Opens and initiatialises the output device
+ virtual int open() override;
+
///
- /// @return Zero on succes (i.e. device is ready and enabled) else negative
+ /// @brief Closes the output device.
///
- virtual int open() override;
+ /// @return Zero on success (i.e. device is closed), else negative
+ ///
+ 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..560c5a63a 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();
}
+const 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..8a67db73b 100644
--- a/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.cpp
+++ b/libsrc/leddevice/dev_hid/LedDeviceHyperionUsbasp.cpp
@@ -5,23 +5,28 @@
// Local Hyperion includes
#include "LedDeviceHyperionUsbasp.h"
-// Static constants which define the Hyperion Usbasp device
+// Static constants which define the Hyperion USBasp device
uint16_t LedDeviceHyperionUsbasp::_usbVendorId = 0x16c0;
uint16_t LedDeviceHyperionUsbasp::_usbProductId = 0x05dc;
QString LedDeviceHyperionUsbasp::_usbProductDescription = "Hyperion led controller";
-
LedDeviceHyperionUsbasp::LedDeviceHyperionUsbasp(const QJsonObject &deviceConfig)
: LedDevice()
, _libusbContext(nullptr)
, _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 +36,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);
- if (error == 0)
+ // retrieve the list of USB devices
+ libusb_device ** deviceList;
+ ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
+
+ // 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 +137,7 @@ void LedDeviceHyperionUsbasp::close()
_deviceHandle = nullptr;
}
-
- if (_libusbContext != nullptr)
- {
- libusb_exit(_libusbContext);
- _libusbContext = nullptr;
- }
+ return retval;
}
int LedDeviceHyperionUsbasp::testAndOpen(libusb_device * device)
@@ -176,7 +182,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 +190,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..09f6d43e4 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,6 +86,9 @@ public slots:
/// libusb context
libusb_context * _libusbContext;
+ /// libusb device
+ libusb_device * _device;
+
/// libusb device handle
libusb_device_handle * _deviceHandle;
@@ -93,3 +97,5 @@ public slots:
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 d2a5b1ddb..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
- foreach (auto serial , serialList)
+ // 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..2c39cc78c 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
+ ///
+ virtual 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 d3c7b4adb..b1209ae8a 100644
--- a/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceAtmoOrb.cpp
@@ -19,7 +19,9 @@ LedDeviceAtmoOrb::LedDeviceAtmoOrb(const QJsonObject &deviceConfig)
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceAtmoOrb::construct(const QJsonObject &deviceConfig)
@@ -57,22 +59,28 @@ bool LedDeviceAtmoOrb::init(const QJsonObject &deviceConfig)
_orbIds.clear();
- foreach(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 +97,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) )
+ {
+ QString errortext = QString ("(%1) %2, MulticastGroup: (%3)").arg(_udpSocket->error()).arg(_udpSocket->errorString(), _multicastGroup);
+ this->setInError( errortext );
+ }
+ else
{
- _groupAddress = QHostAddress(_multicastGroup);
- if ( !_udpSocket->bind(QHostAddress::AnyIPv4, _multiCastGroupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint) )
+ _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 +142,7 @@ void LedDeviceAtmoOrb::close()
// Everything is OK -> device is closed
}
}
+ return retval;
}
int LedDeviceAtmoOrb::write(const std::vector &ledValues)
@@ -211,7 +217,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 +238,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..4d1f5c41a 100644
--- a/libsrc/leddevice/dev_net/LedDeviceFadeCandy.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceFadeCandy.cpp
@@ -6,22 +6,32 @@
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 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_SYS_EX = 255; // OPC command codes
static const unsigned OPC_HEADER_SIZE = 4; // OPC header size
+// 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 )
+ {
+ _client->deleteLater();
+ }
}
LedDevice* LedDeviceFadeCandy::construct(const QJsonObject &deviceConfig)
@@ -31,46 +41,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 +101,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 +186,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 350413fab..44ed2970e 100644
--- a/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceNanoleaf.cpp
@@ -16,7 +16,7 @@
static const bool verbose = false;
static const bool verbose3 = false;
-// Controller configuration settings
+// Configuration settings
static const char CONFIG_ADDRESS[] = "host";
//static const char CONFIG_PORT[] = "port";
static const char CONFIG_AUTH_TOKEN[] ="token";
@@ -54,8 +54,8 @@ static const char STREAM_CONTROL_PORT[] = "streamControlPort";
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 int API_DEFAULT_PORT = 16021;
+static const char API_BASE_PATH[] = "/api/v1/%1/";
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\"}}";
@@ -64,9 +64,10 @@ static const char API_PANELLAYOUT[] = "panelLayout";
static const char API_EFFECT[] = "effects";
// Nanoleaf ssdp services
+static const char SSDP_ID[] = "ssdp:all";
+static const char SSDP_FILTER_HEADER[] = "ST";
static const char SSDP_CANVAS[] = "nanoleaf:nl29";
static const char SSDP_LIGHTPANELS[] = "nanoleaf_aurora:light";
-const int SSDP_TIMEOUT = 5000; // timout in ms
// Nanoleaf Panel Shapetypes
enum SHAPETYPES {
@@ -84,24 +85,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 +128,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 = static_cast( deviceConfig[ CONFIG_PANEL_START_POS ].toInt(0) );
- _startPos = 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 +232,7 @@ bool LedDeviceNanoleaf::initLeds()
std::map> panelMap;
// Loop over all children.
- foreach (const QJsonValue & value, positionData)
+ for (const QJsonValue value : positionData)
{
QJsonObject panelObj = value.toObject();
@@ -239,9 +266,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 +283,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 +335,209 @@ 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;
+ devicesDiscovered.insert("devices", deviceList);
+ Debug(_log, "devicesDiscovered: [%s]", QString(QJsonDocument(devicesDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+
+ return devicesDiscovered;
+}
+
+QJsonObject LedDeviceNanoleaf::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 authToken = params["token"].toString("");
+ QString filter = params["filter"].toString("");
+
// Resolve hostname and port (or use default API port)
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
- QStringList addressparts = address.split(":", Qt::SkipEmptyParts);
+ QStringList addressparts = host.split(":", Qt::SkipEmptyParts);
#else
- QStringList addressparts = address.split(":", QString::SkipEmptyParts);
+ QStringList addressparts = host.split(":", QString::SkipEmptyParts);
#endif
- _hostname = addressparts[0];
- _api_port = addressparts[1];
- }
- return isDeviceFound;
-}
+ QString apiHost = addressparts[0];
+ int apiPort;
-QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode()
-{
+ if ( addressparts.size() > 1)
+ {
+ apiPort = addressparts[1].toInt();
+ }
+ else
+ {
+ apiPort = API_DEFAULT_PORT;
+ }
- QString url = getUrl(_hostname, _api_port, _auth_token, API_EFFECT );
- QJsonDocument jsonDoc;
+ initRestAPI(apiHost, apiPort, authToken);
+ _restApi->setPath(filter);
- _extControlVersion = EXTCTRLVER_V2;
- //Enable UDP Mode v2
- jsonDoc= putJson(url, API_EXT_MODE_STRING_V2);
+ // 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()));
+ }
- return jsonDoc;
-}
+ properties.insert("properties", response.getBody().object());
+
+ Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
-QString LedDeviceNanoleaf::getUrl(QString host, QString port, QString auth_token, QString endpoint) const {
- return QString(API_URL_FORMAT).arg(host, port, auth_token, endpoint);
+ }
+ return properties;
}
-QJsonDocument LedDeviceNanoleaf::getJson(QString url)
+void LedDeviceNanoleaf::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() )
+ {
+ QString authToken = params["token"].toString("");
- Debug(_log, "GET: [%s]", QSTRING_CSTR( url ));
+ // Resolve hostname and port (or use default API port)
+ #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
+ QStringList addressparts = host.split(":", Qt::SkipEmptyParts);
+ #else
+ QStringList addressparts = host.split(":", QString::SkipEmptyParts);
+ #endif
- // 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();
+ QString apiHost = addressparts[0];
+ int apiPort;
- QJsonDocument jsonDoc;
- if(reply->operation() == QNetworkAccessManager::GetOperation)
- {
- jsonDoc = handleReply( reply );
+ if ( addressparts.size() > 1)
+ {
+ apiPort = addressparts[1].toInt();
+ }
+ else
+ {
+ apiPort = API_DEFAULT_PORT;
+ }
+
+ initRestAPI(apiHost, apiPort, authToken);
+ _restApi->setPath("identify");
+
+ // Perform request
+ httpResponse response = _restApi->put();
+ if ( response.error() )
+ {
+ Warning (_log, "%s identification failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
+ }
}
- // Free space.
- reply->deleteLater();
- // Return response
- return jsonDoc;
}
-QJsonDocument LedDeviceNanoleaf::putJson(QString url, QString json)
+bool LedDeviceNanoleaf::powerOn()
{
-
- 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)
+ if ( _isDeviceReady)
{
- jsonDoc = handleReply( reply );
+ //Power-on Nanoleaf device
+ _restApi->setPath(API_STATE);
+ _restApi->put( getOnOffRequest(true) );
}
- // Free space.
- reply->deleteLater();
+ return true;
+}
- // Return response
- return jsonDoc;
+bool LedDeviceNanoleaf::powerOff()
+{
+ if ( _isDeviceReady)
+ {
+ //Power-off the Nanoleaf device physically
+ _restApi->setPath(API_STATE);
+ _restApi->put( getOnOffRequest(false) );
+ }
+ return true;
}
-QJsonDocument LedDeviceNanoleaf::handleReply(QNetworkReply* const &reply )
+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 jsonDoc;
+QJsonDocument LedDeviceNanoleaf::changeToExternalControlMode()
+{
+ _extControlVersion = EXTCTRLVER_V2;
+ //Enable UDP Mode v2
- int httpStatusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
- Debug(_log, "Reply.httpStatusCode [%d]", httpStatusCode );
+ _restApi->setPath(API_EFFECT);
+ httpResponse response =_restApi->put(API_EXT_MODE_STRING_V2);
- if(reply->error() == QNetworkReply::NoError)
- {
- 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() );
- }
- }
- }
- else
- {
- 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 );
- }
- // Return response
- return jsonDoc;
+ return response.getBody();
}
int LedDeviceNanoleaf::write(const std::vector & ledValues)
{
-
int retVal = 0;
uint udpBufferSize;
@@ -573,46 +620,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..47c6b9793 100644
--- a/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp
+++ b/libsrc/leddevice/dev_net/LedDevicePhilipsHue.cpp
@@ -38,8 +38,8 @@ static const char DEV_DATA_FIRMWAREVERSION[] = "swversion";
static 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 int API_DEFAULT_PORT = -1; //Use default port per communication scheme
+static const char API_BASE_PATH[] = "/api/%1/";
static const char API_ROOT[] = "";
static const char API_STATE[] = "state";
static const char API_CONFIG[] = "config";
@@ -60,6 +60,7 @@ static 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_SATURATION[] = "sat";
static const char API_TRANSITIONTIME[] = "transitiontime";
static const char API_MODEID[] = "modelid";
@@ -78,8 +79,9 @@ static const char API_ERROR_TYPE[] = "type";
static 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
+static const char SSDP_ID[] = "upnp:rootdevice";
+static const char SSDP_FILTER[] = "(.*)IpBridge(.*)";
+static const char SSDP_FILTER_HEADER[] = "SERVER";
// DTLS Connection / SSL / Cipher Suite
static const char API_SSL_SERVER_NAME[] = "Hue";
@@ -191,6 +193,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 +201,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,28 +236,31 @@ 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;
}
}
bool LedDevicePhilipsHueBridge::init(const QJsonObject &deviceConfig)
{
+ Debug(_log, "");
+
_useHueEntertainmentAPI = deviceConfig[CONFIG_USE_HUE_ENTERTAINMENT_API].toBool(false);
// Overwrite non supported/required features
@@ -267,81 +273,117 @@ 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() )
+ {
+ this->setInError("No target hostname nor IP defined");
+ return false;
+ }
+ else
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
- QStringList addressparts = address.split(":", Qt::SkipEmptyParts);
+ QStringList addressparts = address.split(":", Qt::SkipEmptyParts);
#else
- QStringList addressparts = address.split(":", QString::SkipEmptyParts);
+ QStringList addressparts = address.split(":", QString::SkipEmptyParts);
#endif
_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 ) );
}
+ Debug(_log, "[%d]", isInitOK);
return isInitOK;
}
-int LedDevicePhilipsHueBridge::open()
+bool LedDevicePhilipsHueBridge::initRestAPI(const QString &hostname, const int port, const QString &token )
{
- return open( _hostname, _api_port, _username );
+ Debug(_log, "");
+ 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;
+ }
+
+ Debug(_log, "[%d]", isInitOK);
+ return isInitOK;
}
-int LedDevicePhilipsHueBridge::open( const QString& hostname, const QString& port, const QString& username )
+int LedDevicePhilipsHueBridge::open()
{
- _deviceInError = false;
- bool isInitOK = true;
+ Debug(_log, "");
+ 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;
+ Debug(_log, "[%d]", retval);
+ return retval;
+}
+
+int LedDevicePhilipsHueBridge::close()
+{
+ Debug(_log, "");
+
+ _isDeviceReady = false;
+ int retval = 0;
- //Get Philips Hue Bridge details and configuration
- if ( _networkmanager == nullptr )
+ if( _useHueEntertainmentAPI )
{
- _networkmanager = new QNetworkAccessManager();
+ retval = ProviderUdpSSL::close();
}
- isInitOK = initMaps();
-
- return isInitOK;
+ Debug(_log, "[%d]", retval);
+ return retval;
}
const int *LedDevicePhilipsHueBridge::getCiphersuites()
@@ -366,8 +408,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 +431,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 )
@@ -411,7 +460,7 @@ void LedDevicePhilipsHueBridge::setBridgeConfig(QJsonDocument doc)
#else
QStringList apiVersionParts = _deviceAPIVersion.split(".", QString::SkipEmptyParts);
#endif
-
+
if ( !apiVersionParts.isEmpty() )
{
_api_major = apiVersionParts[0].toUInt();
@@ -438,7 +487,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();
@@ -465,7 +514,7 @@ void LedDevicePhilipsHueBridge::setLightsMap(QJsonDocument doc)
}
}
-void LedDevicePhilipsHueBridge::setGroupMap(QJsonDocument doc)
+void LedDevicePhilipsHueBridge::setGroupMap(const QJsonDocument &doc)
{
QJsonObject jsonGroupsInfo = doc.object()[ API_GROUPS ].toObject();
@@ -483,38 +532,6 @@ void LedDevicePhilipsHueBridge::setGroupMap(QJsonDocument doc)
}
}
-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;
@@ -570,141 +587,47 @@ 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;
-}
+ 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();
-QJsonDocument LedDevicePhilipsHueBridge::handleReply(QNetworkReply* const &reply )
-{
- QJsonDocument jsonDoc;
+ log( "Error Type", "%s", QSTRING_CSTR( errorType ) );
+ log( "Error Address", "%s", QSTRING_CSTR( errorAddress ) );
+ log( "Error Address Description", "%s", QSTRING_CSTR( errorDesc ) );
- int httpStatusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
- DebugIf(verbose, _log, "Reply.httpStatusCode [%d]", httpStatusCode );
- QString errorReason;
-
- 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)
@@ -715,17 +638,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 );
}
@@ -874,7 +799,6 @@ LedDevicePhilipsHue::LedDevicePhilipsHue(const QJsonObject& deviceConfig)
, _switchOffOnBlack(false)
, _brightnessFactor(1.0)
, _transitionTime(1)
- , _isRestoreOrigState(true)
, _lightStatesRestored(false)
, _isInitLeds(false)
, _lightsCount(0)
@@ -893,7 +817,9 @@ LedDevicePhilipsHue::LedDevicePhilipsHue(const QJsonObject& deviceConfig)
, stop_retry_left(3)
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDevicePhilipsHue::construct(const QJsonObject &deviceConfig)
@@ -911,6 +837,7 @@ LedDevicePhilipsHue::~LedDevicePhilipsHue()
bool LedDevicePhilipsHue::init(const QJsonObject &deviceConfig)
{
+ Debug(_log, "");
verbose = deviceConfig[CONFIG_VERBOSE].toBool(false);
bool isInitOK = LedDevicePhilipsHueBridge::init(deviceConfig);
@@ -958,13 +885,16 @@ bool LedDevicePhilipsHue::init(const QJsonObject &deviceConfig)
_useHueEntertainmentAPI = false;
}
}
- }
+ isInitOK = initLeds();
+ }
+ Debug(_log, "[%d]", isInitOK);
return isInitOK;
}
bool LedDevicePhilipsHue::setLights()
{
+ Debug(_log, "");
bool isInitOK = true;
_lightIds.clear();
@@ -990,7 +920,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 )
@@ -1021,39 +951,13 @@ bool LedDevicePhilipsHue::setLights()
isInitOK = updateLights( getLightMap() );
}
+ Debug(_log, "[%d]", isInitOK);
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()
{
+ Debug(_log, "");
bool isInitOK = false;
if ( !this->isInError() )
@@ -1101,12 +1005,13 @@ bool LedDevicePhilipsHue::initLeds()
isInitOK = false;
}
}
-
+ Debug(_log, "[%d]", isInitOK);
return isInitOK;
}
bool LedDevicePhilipsHue::updateLights(QMap map)
{
+ Debug(_log, "");
bool isInitOK = true;
// search user lightid inside map and create light if found
@@ -1140,10 +1045,11 @@ bool LedDevicePhilipsHue::updateLights(QMap map)
isInitOK = false;
}
+ Debug(_log, "[%d]", isInitOK);
return isInitOK;
}
-bool LedDevicePhilipsHue::initStream()
+bool LedDevicePhilipsHue::openStream()
{
bool isInitOK = false;
@@ -1165,7 +1071,7 @@ bool LedDevicePhilipsHue::initStream()
{
Debug(_log, "Stream successful stopped");
//Restore Philips Hue devices state
- restoreOriginalState();
+ restoreState();
isInitOK = startStream();
}
else
@@ -1240,6 +1146,7 @@ bool LedDevicePhilipsHue::startStream()
bool LedDevicePhilipsHue::stopStream()
{
+ // TODO: Is is right that the sslconnection is closed before changing the stream state
ProviderUdpSSL::closeSSLConnection();
if ( setStreamGroupState( false ) )
@@ -1306,7 +1213,7 @@ bool LedDevicePhilipsHue::setStreamGroupState(bool state)
}
else
{
- QString valueName = QString( API_STREAM_RESPONSE_FORMAT ).arg( API_GROUPS ).arg( _groupId ).arg( API_STREAM ).arg( API_STREAM_ACTIVE );
+ 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())
{
this->setInError( QString("set stream to %1: Bridge response is not Valid").arg( active ) );
@@ -1370,37 +1277,68 @@ QByteArray LedDevicePhilipsHue::prepareStreamData()
return msg;
}
-void LedDevicePhilipsHue::restoreOriginalState()
+void LedDevicePhilipsHue::stop()
{
- if ( _isRestoreOrigState && !_lightStatesRestored )
- {
- _lightStatesRestored = true;
+ Debug(_log, "");
- if( !_lightIds.empty() )
+ // TODO: Check, if anything specific before switch-off during stopping is required, otherwise remove
+ // LedDevicePhilipsHueBridge::stop();
+
+ Debug(_log, "LedDevicePhilipsHue::stop() [void]");
+}
+
+int LedDevicePhilipsHue::open()
+{
+ Debug(_log, "");
+ 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;
+ }
+ Debug(_log, "[%d]", retval);
+ return retval;
}
-void LedDevicePhilipsHue::close()
+int LedDevicePhilipsHue::close()
{
- _isInitLeds = false;
+ Debug(_log, "");
+ int retval = -1;
+
+ retval = LedDevicePhilipsHueBridge::close();
+
+ Debug(_log, "[%d]", retval);
+ return retval;
+}
+
+bool LedDevicePhilipsHue::switchOff()
+{
+ 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)
@@ -1523,7 +1461,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 +1501,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 +1529,195 @@ void LedDevicePhilipsHue::setLightsCount( unsigned int lightsCount )
_lightsCount = lightsCount;
}
-bool LedDevicePhilipsHue::reinitLeds()
+bool LedDevicePhilipsHue::powerOn()
{
- bool isInitOK = initMaps();
-
- if( isInitOK )
+ Debug(_log, "");
+ 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 )
+ Debug(_log, "");
+ 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()
+{
+ Debug(_log, "");
+ 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
+ Debug(_log, "[%d]", rc);
+ return rc;
+}
+
+bool LedDevicePhilipsHue::restoreState()
+{
+ Debug(_log, "");
+ 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;
+ Debug(_log, "[%d]", rc);
+ return rc;
}
-int LedDevicePhilipsHue::switchOff()
+QJsonObject LedDevicePhilipsHue::discover()
{
- this->stopBlackTimeoutTimer();
+ Debug(_log, "");
- //Set all LEDs to Black
- int rc = LedDevice::switchOff();
+ QJsonObject devicesDiscovered;
+ devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
- if ( _deviceReady )
+ QJsonArray deviceList;
+
+ // 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)
+ #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
+ QStringList addressparts = host.split(":", Qt::SkipEmptyParts);
+ #else
+ QStringList addressparts = host.split(":", QString::SkipEmptyParts);
+ #endif
+
+ QString apiHost = addressparts[0];
+ int apiPort;
+
+ if ( addressparts.size() > 1)
+ apiPort = addressparts[1].toInt();
+ else
+ apiPort = API_DEFAULT_PORT;
+
+ initRestAPI(apiHost, apiPort, username);
+ _restApi->setPath(filter);
+
+ // Perform request
+ httpResponse response = _restApi->get();
+ if ( response.error() )
{
- stop_retry_left = 3;
- if( stopStream() )
- {
- //Restore Philips Hue devices state
- restoreOriginalState();
- }
+ 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)
+ #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
+ QStringList addressparts = host.split(":", Qt::SkipEmptyParts);
+ #else
+ QStringList addressparts = host.split(":", QString::SkipEmptyParts);
+ #endif
+
+ 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() )
{
- //Switch off Philips Hue devices physically
- for ( PhilipsHueLight& light : _lights )
- {
- setOnOffState( light, false );
- }
+ 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..86f2823ea 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"
/**
@@ -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.
@@ -211,18 +216,46 @@ class LedDevicePhilipsHueBridge : public ProviderUdpSSL
QJsonArray getGroupLights(unsigned int 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,205 @@ 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
///
- bool updateLights(QMap map);
+ /// @param deviceConfig Device's configuration in JSON
+ /// @return True, if success
+ ///
+ 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;
///
- /// Writes the RGB-Color values to the leds.
+ /// @brief Switch the LEDs off.
///
- /// @param[in] ledValues The RGB-color per led
+ /// 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 Zero on success else negative
+ /// @return True, if success
///
- virtual int write(const std::vector & ledValues) override;
+ 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;
+
+ ///
+ /// @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() 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:
+ 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(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,11 +517,10 @@ private slots:
bool _switchOffOnBlack;
/// The brightness factor to multiply on color change.
double _brightnessFactor;
- /// Transition time in multiples of 100 ms.
+ /// 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;
- bool _isRestoreOrigState;
bool _lightStatesRestored;
bool _isInitLeds;
@@ -466,4 +552,8 @@ private slots:
int start_retry_left;
int stop_retry_left;
+
+private slots:
+
+ void noSignalTimeout();
};
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..31e0cc4df 100644
--- a/libsrc/leddevice/dev_net/LedDeviceUdpH801.cpp
+++ b/libsrc/leddevice/dev_net/LedDeviceUdpH801.cpp
@@ -7,7 +7,9 @@ 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 +19,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 +48,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..76f7d787f
--- /dev/null
+++ b/libsrc/leddevice/dev_net/LedDeviceWled.cpp
@@ -0,0 +1,301 @@
+// Local-Hyperion includes
+#include "LedDeviceWled.h"
+
+// ssdp discover
+#include
+
+// Configuration settings
+static const char CONFIG_ADDRESS[] = "host";
+
+// UDP elements
+const quint16 STREAM_DEFAULT_PORT = 19446;
+
+// WLED JSON-API elements
+static const int API_DEFAULT_PORT = -1; //Use default port per communication scheme
+
+static const char API_BASE_PATH[] = "/json/";
+static const char API_PATH_INFO[] = "info";
+static const char API_PATH_STATE[] = "state";
+
+// List of State Information
+static const char STATE_ON[] = "on";
+static const char STATE_VALUE_TRUE[] = "true";
+static const char STATE_VALUE_FALSE[] = "false";
+
+// WLED ssdp services
+// TODO: WLED - Update ssdp discovery parameters when available
+static const char SSDP_ID[] = "ssdp:all";
+static const char SSDP_FILTER[] = "(.*)";
+static const char SSDP_FILTER_HEADER[] = "ST";
+
+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
+ {
+ #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];
+ 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)
+ #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
+ QStringList addressparts = host.split(":", Qt::SkipEmptyParts);
+ #else
+ QStringList addressparts = host.split(":", QString::SkipEmptyParts);
+ #endif
+
+ 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)
+ #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
+ QStringList addressparts = host.split(":", Qt::SkipEmptyParts);
+ #else
+ QStringList addressparts = host.split(":", QString::SkipEmptyParts);
+ #endif
+
+ 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..4342e6ab8
--- /dev/null
+++ b/libsrc/leddevice/dev_net/LedDeviceYeelight.cpp
@@ -0,0 +1,1503 @@
+#include "LedDeviceYeelight.h"
+
+// ssdp discover
+#include
+
+// Qt includes
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+static const bool verbose = false;
+static const bool verbose3 = false;
+
+// Constants
+const int WRITE_TIMEOUT = 1000; // device write timeout in ms
+const int READ_TIMEOUT = 1000; // device write timeout in ms
+const int CONNECT_TIMEOUT = 1000; // device connect timeout in ms
+const int CONNECT_STREAM_TIMEOUT = 1000; // device streaming connect timeout in ms
+
+static const bool TEST_CORRELATION_IDS = false; //Ignore, if yeelight sends responses in different order as request commands
+
+// Configuration settings
+static const char CONFIG_LIGHTS [] = "lights";
+
+static const char CONFIG_COLOR_MODEL [] = "colorModel";
+static const char CONFIG_TRANS_EFFECT [] = "transEffect";
+static const char CONFIG_TRANS_TIME [] = "transTime";
+static const char CONFIG_EXTRA_TIME_DARKNESS[] = "extraTimeDarkness";
+static const char CONFIG_DEBUGLEVEL [] = "debugLevel";
+
+static const char CONFIG_BRIGHTNESS_MIN[] = "brightnessMin";
+static const char CONFIG_BRIGHTNESS_SWITCHOFF[] = "brightnessSwitchOffOnMinimum";
+static const char CONFIG_BRIGHTNESS_MAX[] = "brightnessMax";
+static const char CONFIG_BRIGHTNESSFACTOR[] = "brightnessFactor";
+
+static const char CONFIG_RESTORE_STATE[] = "restoreOriginalState";
+
+static const char CONFIG_QUOTA_WAIT_TIME[] = "quotaWait";
+
+// Yeelights API
+static const int API_DEFAULT_PORT = 55443;
+static const quint16 API_DEFAULT_QUOTA_WAIT_TIME = 1000;
+
+// Yeelight API Command
+static const char API_COMMAND_ID[] = "id";
+static const char API_COMMAND_METHOD[] = "method";
+static const char API_COMMAND_PARAMS[] = "params";
+static const char API_COMMAND_PROPS[] = "props";
+
+static const char API_PARAM_CLASS_COLOR[] = "color";
+static const char API_PARAM_CLASS_HSV[] = "hsv";
+
+static const char API_PROP_NAME[] = "name";
+static const char API_PROP_MODEL[] = "model";
+static const char API_PROP_FWVER[] = "fw_ver";
+
+static const char API_PROP_POWER[] = "power";
+static const char API_PROP_MUSIC[] = "music_on";
+static const char API_PROP_RGB[] = "rgb";
+static const char API_PROP_CT[] = "ct";
+static const char API_PROP_COLORFLOW[] = "cf";
+static const char API_PROP_BRIGHT[] = "bright";
+
+// List of Result Information
+static const char API_RESULT_ID[] = "id";
+static const char API_RESULT[] = "result";
+//static const char API_RESULT_OK[] = "OK";
+
+// List of Error Information
+static const char API_ERROR[] = "error";
+static const char API_ERROR_CODE[] = "code";
+static const char API_ERROR_MESSAGE[] = "message";
+
+// Yeelight ssdp services
+static const char SSDP_ID[] = "wifi_bulb";
+static const char SSDP_FILTER[] = "yeelight(.*)";
+static const char SSDP_FILTER_HEADER[] = "Location";
+const quint16 SSDP_PORT = 1982;
+
+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)
+ ,_extraTimeDarkness(API_PARAM_EXTRA_TIME_DARKNESS)
+ ,_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)
+ {
+ _tcpSocket->deleteLater();
+ }
+ 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 ) )
+ {
+ 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) )
+ {
+ 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) )
+ {
+ 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) )
+ {
+ 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( _isOn ), static_cast( _isInMusicMode ) );
+ return rc;
+}
+
+
+void YeelightLight::setTransitionEffect ( YeelightLight::API_EFFECT effect ,int duration )
+{
+ if( effect != _transitionEffect )
+ {
+ _transitionEffect = effect;
+ _transitionEffectParam = effect == YeelightLight::API_EFFECT_SMOOTH ? API_PARAM_EFFECT_SMOOTH : API_PARAM_EFFECT_SUDDEN;
+ }
+
+ if( duration != _transitionDuration )
+ {
+ _transitionDuration = duration;
+ }
+
+}
+
+void YeelightLight::setBrightnessConfig (int min, int max, bool switchoff, int extraTime, double factor )
+{
+ _brightnessMin = min;
+ _isBrightnessSwitchOffMinimum = switchoff;
+ _brightnessMax = max;
+ _brightnessFactor = factor;
+ _extraTimeDarkness = extraTime;
+}
+
+bool YeelightLight::setMusicMode(bool on, const QHostAddress &hostAddress, int port)
+{
+ bool rc = false;
+ int musicModeParam = on ? API_METHOD_MUSIC_MODE_ON : API_METHOD_MUSIC_MODE_OFF;
+
+ QJsonArray paramlist = { musicModeParam };
+
+ if ( on )
+ {
+ paramlist << hostAddress.toString() << port;
+ }
+
+ // Music Mode is only on, if write did not fail nor quota was exceeded
+ if ( writeCommand( getCommand( API_METHOD_MUSIC_MODE, paramlist ) ) > -1 )
+ {
+ _isInMusicMode = on;
+ rc = true;
+ }
+
+ log( 2,
+ "setMusicMode() rc", "%d, isInMusicMode[%d]", static_cast( rc ), static_cast( _isInMusicMode ) );
+ return rc;
+}
+
+void YeelightLight::log(const int logLevel, const char* msg, const char* type, ...)
+{
+ if ( logLevel <= _debugLevel)
+ {
+ const size_t max_val_length = 1024;
+ char val[max_val_length];
+ va_list args;
+ va_start(args, type);
+ vsnprintf(val, max_val_length, type, args);
+ va_end(args);
+ std::string s = msg;
+ uint max = 20;
+ s.append(max - s.length(), ' ');
+
+ Debug( _log, "%d|%15.15s| %s: %s", logLevel, QSTRING_CSTR(_name), s.c_str(), val);
+ }
+}
+
+//---------------------------------------------------------------------------------
+
+LedDeviceYeelight::LedDeviceYeelight(const QJsonObject &deviceConfig)
+ : LedDevice()
+ ,_lightsCount (0)
+ ,_outputColorModel(0)
+ ,_transitionEffect(YeelightLight::API_EFFECT_SMOOTH)
+ ,_transitionDuration(API_PARAM_DURATION)
+ ,_extraTimeDarkness(0)
+ ,_brightnessMin(0)
+ ,_isBrightnessSwitchOffMinimum(false)
+ ,_brightnessMax(100)
+ ,_brightnessFactor(1.0)
+ ,_waitTimeQuota(API_DEFAULT_QUOTA_WAIT_TIME)
+ ,_debuglevel(0)
+ ,_musicModeServerPort(-1)
+{
+ _devConfig = deviceConfig;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
+}
+
+LedDeviceYeelight::~LedDeviceYeelight()
+{
+ if ( _tcpMusicModeServer != nullptr )
+ {
+ _tcpMusicModeServer->deleteLater();
+ }
+}
+
+LedDevice* LedDeviceYeelight::construct(const QJsonObject &deviceConfig)
+{
+ return new LedDeviceYeelight(deviceConfig);
+}
+
+bool LedDeviceYeelight::init(const QJsonObject &deviceConfig)
+{
+ // Overwrite non supported/required features
+ if (deviceConfig["rewriteTime"].toInt(0) > 0)
+ {
+ Info (_log, "Yeelights do not require rewrites. Refresh time is ignored.");
+ _devConfig["rewriteTime"] = 0;
+ }
+
+ DebugIf(verbose, _log, "deviceConfig: [%s]", QString(QJsonDocument(_devConfig).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+
+ bool isInitOK = false;
+
+ if ( LedDevice::init(deviceConfig) )
+ {
+ Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
+ Debug(_log, "LedCount : %u", this->getLedCount());
+ Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
+ Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms);
+ Debug(_log, "LatchTime : %d", this->getLatchTime());
+
+ //Get device specific configuration
+
+ bool ok;
+ if ( deviceConfig[ CONFIG_COLOR_MODEL ].isString() )
+ {
+ _outputColorModel = deviceConfig[ CONFIG_COLOR_MODEL ].toString().toInt(&ok,MODEL_RGB);
+ }
+ else
+ {
+ _outputColorModel = deviceConfig[ CONFIG_COLOR_MODEL ].toInt(MODEL_RGB);
+ }
+
+ if ( deviceConfig[ CONFIG_TRANS_EFFECT ].isString() )
+ {
+ _transitionEffect = static_cast( deviceConfig[ CONFIG_TRANS_EFFECT ].toString().toInt(&ok, YeelightLight::API_EFFECT_SMOOTH) );
+ }
+ else
+ {
+ _transitionEffect = static_cast( deviceConfig[ CONFIG_TRANS_EFFECT ].toInt(YeelightLight::API_EFFECT_SMOOTH) );
+ }
+
+ _transitionDuration = deviceConfig[ CONFIG_TRANS_TIME ].toInt(API_PARAM_DURATION);
+ _extraTimeDarkness = _devConfig[CONFIG_EXTRA_TIME_DARKNESS].toInt(0);
+
+ _brightnessMin = _devConfig[CONFIG_BRIGHTNESS_MIN].toInt(0);
+ _isBrightnessSwitchOffMinimum = _devConfig[CONFIG_BRIGHTNESS_SWITCHOFF].toBool(true);
+ _brightnessMax = _devConfig[CONFIG_BRIGHTNESS_MAX].toInt(100);
+ _brightnessFactor = _devConfig[CONFIG_BRIGHTNESSFACTOR].toDouble(1.0);
+
+ if ( deviceConfig[ CONFIG_DEBUGLEVEL ].isString() )
+ {
+ _debuglevel = deviceConfig[ CONFIG_DEBUGLEVEL ].toString().toInt();
+ }
+ else
+ {
+ _debuglevel = deviceConfig[ CONFIG_DEBUGLEVEL ].toInt(0);
+ }
+
+ QString outputColorModel = _outputColorModel == MODEL_RGB ? "RGB": "HSV";
+ QString transitionEffect = _transitionEffect == YeelightLight::API_EFFECT_SMOOTH ? API_PARAM_EFFECT_SMOOTH : API_PARAM_EFFECT_SUDDEN;
+
+ Debug(_log, "colorModel : %s", QSTRING_CSTR(outputColorModel));
+ Debug(_log, "Transitioneffect : %s", QSTRING_CSTR(transitionEffect));
+ Debug(_log, "Transitionduration: %d", _transitionDuration);
+ Debug(_log, "Extra time darkn. : %d", _extraTimeDarkness );
+
+ Debug(_log, "Brightn. Min : %d", _brightnessMin );
+ Debug(_log, "Brightn. Min Off : %d", _isBrightnessSwitchOffMinimum );
+ Debug(_log, "Brightn. Max : %d", _brightnessMax );
+ Debug(_log, "Brightn. Factor : %.2f", _brightnessFactor );
+
+ _isRestoreOrigState = _devConfig[CONFIG_RESTORE_STATE].toBool(false);
+ Debug(_log, "RestoreOrigState : %d", _isRestoreOrigState);
+
+ _waitTimeQuota = _devConfig[CONFIG_QUOTA_WAIT_TIME].toInt(0);
+ Debug(_log, "Wait time (quota) : %d", _waitTimeQuota );
+
+ Debug(_log, "Debuglevel : %d", _debuglevel);
+
+ QJsonArray configuredYeelightLights = _devConfig[CONFIG_LIGHTS].toArray();
+ uint configuredYeelightsCount = 0;
+ for (const QJsonValue light : configuredYeelightLights)
+ {
+ QString host = light.toObject().value("host").toString();
+ int port = light.toObject().value("port").toInt(API_DEFAULT_PORT);
+ if ( !host.isEmpty() )
+ {
+ QString name = light.toObject().value("name").toString();
+ Debug(_log, "Light [%u] - %s (%s:%d)", configuredYeelightsCount, QSTRING_CSTR(name), QSTRING_CSTR(host), port );
+ ++configuredYeelightsCount;
+ }
+ }
+ Debug(_log, "Light configured : %u", configuredYeelightsCount );
+
+ uint configuredLedCount = this->getLedCount();
+ if (configuredYeelightsCount < configuredLedCount )
+ {
+ QString errorReason = QString("Not enough Yeelights [%1] for configured LEDs [%2] found!")
+ .arg(configuredYeelightsCount)
+ .arg(configuredLedCount);
+ this->setInError(errorReason);
+ isInitOK = false;
+ }
+ else
+ {
+
+ if ( configuredYeelightsCount > configuredLedCount )
+ {
+ Warning(_log, "More Yeelights defined [%u] than configured LEDs [%u].", configuredYeelightsCount, configuredLedCount );
+ }
+
+ _lightsAddressList.clear();
+ for (int j = 0; j < static_cast( configuredLedCount ); ++j)
+ {
+ QString address = configuredYeelightLights[j].toObject().value("host").toString();
+ int port = configuredYeelightLights[j].toObject().value("port").toInt(API_DEFAULT_PORT);
+
+ #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
+ QStringList addressparts = address.split(":", Qt::SkipEmptyParts);
+ #else
+ QStringList addressparts = address.split(":", QString::SkipEmptyParts);
+ #endif
+
+ QString apiHost = addressparts[0];
+ int apiPort = port;
+
+ _lightsAddressList.append( {apiHost, apiPort} );
+ }
+
+ if ( updateLights(_lightsAddressList) )
+ {
+ isInitOK = true;
+ }
+ }
+ }
+ return isInitOK;
+}
+
+bool LedDeviceYeelight::startMusicModeServer()
+{
+ DebugIf(verbose, _log, "enabled [%d], _isDeviceReady [%d]", _isEnabled, _isDeviceReady);
+
+ bool rc = false;
+ if ( _tcpMusicModeServer == nullptr )
+ {
+ _tcpMusicModeServer = new QTcpServer(this);
+ }
+
+ if ( ! _tcpMusicModeServer->isListening() )
+ {
+ if (! _tcpMusicModeServer->listen())
+ {
+ QString errorReason = QString ("(%1) %2").arg(_tcpMusicModeServer->serverError()).arg( _tcpMusicModeServer->errorString());
+ Error( _log, "Error: MusicModeServer: %s", QSTRING_CSTR(errorReason));
+ this->setInError ( errorReason );
+
+ Error( _log, "Failed to start music mode server");
+ }
+ else
+ {
+ QList ipAddressesList = QNetworkInterface::allAddresses();
+ // use the first non-localhost IPv4 address
+ for (int i = 0; i < ipAddressesList.size(); ++i) {
+ if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
+ (ipAddressesList.at(i).toIPv4Address() != 0U))
+ {
+ _musicModeServerAddress = ipAddressesList.at(i);
+ break;
+ }
+ }
+ if ( _musicModeServerAddress.isNull() )
+ {
+ Error( _log, "Failed to resolve IP for music mode server");
+ }
+ }
+ }
+
+ if ( _tcpMusicModeServer->isListening() )
+ {
+ _musicModeServerPort = _tcpMusicModeServer->serverPort();
+ Debug (_log, "The music mode server is running at %s:%d", QSTRING_CSTR(_musicModeServerAddress.toString()), _musicModeServerPort);
+ rc = true;
+ }
+ DebugIf(verbose, _log, "rc [%d], enabled [%d], _isDeviceReady [%d]", rc, _isEnabled, _isDeviceReady);
+ return rc;
+}
+
+bool LedDeviceYeelight::stopMusicModeServer()
+{
+ DebugIf(verbose, _log, "enabled [%d], _isDeviceReady [%d]", _isEnabled, _isDeviceReady);
+
+ bool rc = false;
+ if ( _tcpMusicModeServer != nullptr )
+ {
+ Debug(_log, "Stop MusicModeServer");
+ _tcpMusicModeServer->close();
+ rc = true;
+ }
+ DebugIf(verbose, _log, "rc [%d], enabled [%d], _isDeviceReady [%d]", rc, _isEnabled, _isDeviceReady);
+ return rc;
+}
+
+int LedDeviceYeelight::open()
+{
+ DebugIf(verbose, _log, "enabled [%d], _isDeviceReady [%d]", _isEnabled, _isDeviceReady);
+ int retval = -1;
+ _isDeviceReady = false;
+
+ // Open/Start LedDevice based on configuration
+ if ( !_lights.empty() )
+ {
+ if ( startMusicModeServer() )
+ {
+ int lightsInError = 0;
+ for (YeelightLight& light : _lights)
+ {
+ light.setTransitionEffect( _transitionEffect, _transitionDuration );
+ light.setBrightnessConfig( _brightnessMin, _brightnessMax, _isBrightnessSwitchOffMinimum, _extraTimeDarkness, _brightnessFactor );
+ light.setQuotaWaitTime(_waitTimeQuota);
+ light.setDebuglevel(_debuglevel);
+
+ if ( ! light.open() )
+ {
+ Error( _log, "Failed to open [%s]", QSTRING_CSTR(light.getName()) );
+ ++lightsInError;
+ }
+ }
+ if ( lightsInError < static_cast(_lights.size()) )
+ {
+ // Everything is OK -> enable device
+ _isDeviceReady = true;
+ retval = 0;
+ }
+ else
+ {
+ this->setInError( "All Yeelights failed to be opened!" );
+ }
+ }
+ }
+ else
+ {
+ // On error/exceptions, set LedDevice in error
+ }
+
+ DebugIf(verbose, _log, "retval [%d], enabled [%d], _isDeviceReady [%d]", retval, _isEnabled, _isDeviceReady);
+ return retval;
+}
+
+int LedDeviceYeelight::close()
+{
+ DebugIf(verbose, _log, "enabled [%d], _isDeviceReady [%d]", _isEnabled, _isDeviceReady);
+ int retval = 0;
+ _isDeviceReady = false;
+
+ // LedDevice specific closing activities
+
+ //Close all Yeelight lights
+ for (YeelightLight& light : _lights)
+ {
+ light.close();
+ }
+
+ //Close music mode server
+ stopMusicModeServer();
+
+ DebugIf(verbose, _log, "retval [%d], enabled [%d], _isDeviceReady [%d]", retval, _isEnabled, _isDeviceReady);
+ return retval;
+}
+
+bool LedDeviceYeelight::updateLights(const QVector &list)
+{
+ bool rc = false;
+ DebugIf(verbose, _log, "enabled [%d], _isDeviceReady [%d]", _isEnabled, _isDeviceReady);
+ if(!_lightsAddressList.empty())
+ {
+ // search user light-id inside map and create light if found
+ _lights.clear();
+
+ _lights.reserve( static_cast( _lightsAddressList.size() ));
+
+ for(auto & yeelightAddress : _lightsAddressList )
+ {
+ QString host = yeelightAddress.host;
+
+ if ( list.contains(yeelightAddress) )
+ {
+ int port = yeelightAddress.port;
+
+ Debug(_log,"Add Yeelight %s:%d", QSTRING_CSTR(host), port );
+ _lights.emplace_back( _log, host, port );
+ }
+ else
+ {
+ Warning(_log,"Configured light-address %s is not available", QSTRING_CSTR(host) );
+ }
+ }
+ setLightsCount ( static_cast( _lights.size() ));
+ rc = true;
+ }
+ return rc;
+}
+
+bool LedDeviceYeelight::powerOn()
+{
+ if ( _isDeviceReady)
+ {
+ //Power-on all Yeelights
+ for (YeelightLight& light : _lights)
+ {
+ if ( light.isReady() && !light.isInMusicMode() )
+ {
+ light.setPower(true, YeelightLight::API_EFFECT_SMOOTH, 5000);
+ }
+ }
+ }
+ return true;
+}
+
+bool LedDeviceYeelight::powerOff()
+{
+ if ( _isDeviceReady)
+ {
+ writeBlack();
+
+ //Power-off all Yeelights
+ for (YeelightLight& light : _lights)
+ {
+ light.setPower( false, _transitionEffect, API_PARAM_DURATION_POWERONOFF);
+ }
+ }
+ return true;
+}
+
+bool LedDeviceYeelight::storeState()
+{
+ bool rc = true;
+
+ for (YeelightLight& light : _lights)
+ {
+ light.storeState();
+ }
+ return rc;
+}
+
+bool LedDeviceYeelight::restoreState()
+{
+ bool rc = true;
+
+ for (YeelightLight& light : _lights)
+ {
+ light.restoreState();
+ if ( !light.wasOriginallyOn() )
+ {
+ light.setPower( false, _transitionEffect, API_PARAM_DURATION_POWERONOFF);
+ }
+ }
+ return rc;
+}
+
+QJsonObject LedDeviceYeelight::discover()
+{
+ QJsonObject devicesDiscovered;
+ devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
+
+ QJsonArray deviceList;
+
+ // Discover WLED Devices
+ SSDPDiscover discover;
+ discover.setPort(SSDP_PORT);
+ 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 LedDeviceYeelight::getProperties(const QJsonObject& params)
+{
+ Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+ QJsonObject properties;
+
+ QString apiHostname = params["hostname"].toString("");
+ quint16 apiPort = static_cast( params["port"].toInt(API_DEFAULT_PORT) );
+ Debug (_log, "apiHost [%s], apiPort [%d]", QSTRING_CSTR(apiHostname), apiPort);
+
+ if ( !apiHostname.isEmpty() )
+ {
+ YeelightLight yeelight(_log, apiHostname, apiPort);
+
+ //yeelight.setDebuglevel(3);
+ if ( yeelight.open() )
+ {
+ properties.insert("properties", yeelight.getProperties());
+ yeelight.close();
+ }
+ }
+ Debug(_log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+
+ return properties;
+}
+
+void LedDeviceYeelight::identify(const QJsonObject& params)
+{
+ Debug(_log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData() );
+
+ QString apiHostname = params["hostname"].toString("");
+ quint16 apiPort = static_cast( params["port"].toInt(API_DEFAULT_PORT) );
+ Debug (_log, "apiHost [%s], apiPort [%d]", QSTRING_CSTR(apiHostname), apiPort);
+
+ if ( !apiHostname.isEmpty() )
+ {
+ YeelightLight yeelight(_log, apiHostname, apiPort);
+ //yeelight.setDebuglevel(3);
+
+ if ( yeelight.open() )
+ {
+ yeelight.identify();
+ yeelight.close();
+ }
+ }
+}
+
+int LedDeviceYeelight::write(const std::vector & ledValues)
+{
+ //DebugIf(verbose, _log, "enabled [%d], _isDeviceReady [%d]", _isEnabled, _isDeviceReady);
+ int rc = -1;
+
+ //Update on all Yeelights by iterating through lights and set colors.
+ unsigned int idx = 0;
+ int lightsInError = 0;
+ for (YeelightLight& light : _lights)
+ {
+ // Get color
+ ColorRgb color = ledValues.at(idx);
+
+ if ( light.isReady() )
+ {
+ bool skipWrite = false;
+ if ( !light.isInMusicMode() )
+ {
+ if ( light.setMusicMode(true, _musicModeServerAddress, _musicModeServerPort) )
+ {
+ // Wait for callback of the device to establish streaming socket
+ if ( _tcpMusicModeServer->waitForNewConnection(CONNECT_STREAM_TIMEOUT) )
+ {
+ light.setStreamSocket( _tcpMusicModeServer->nextPendingConnection() );
+ }
+ else
+ {
+ QString errorReason = QString ("(%1) %2").arg(_tcpMusicModeServer->serverError()).arg( _tcpMusicModeServer->errorString());
+ Warning( _log, "write Error [%s]: _tcpMusicModeServer: %s", QSTRING_CSTR(light.getName()), QSTRING_CSTR(errorReason));
+ light.setInError("Failed to get stream socket");
+ }
+ }
+ else
+ {
+ DebugIf(verbose,_log, "setMusicMode failed due to command quota issue, skip write and try with next");
+ skipWrite = true;
+ }
+ }
+
+ if ( !skipWrite )
+ {
+ // Update light with given color
+ if ( _outputColorModel == MODEL_RGB )
+ {
+ light.setColorRGB( color );
+ }
+ else
+ {
+ light.setColorHSV( color );
+ }
+ }
+ }
+ else
+ {
+ ++lightsInError;
+ }
+ ++idx;
+ }
+
+ if ( ! (lightsInError < static_cast(_lights.size())) )
+ {
+ this->setInError( "All Yeelights in error - stopping device!" );
+ }
+ else
+ {
+ // Minimum one Yeelight device is working, continue updating devices
+ rc = 0;
+ }
+
+ //DebugIf(verbose, _log, "rc [%d]", rc );
+
+ return rc;
+}
diff --git a/libsrc/leddevice/dev_net/LedDeviceYeelight.h b/libsrc/leddevice/dev_net/LedDeviceYeelight.h
new file mode 100644
index 000000000..aa227c196
--- /dev/null
+++ b/libsrc/leddevice/dev_net/LedDeviceYeelight.h
@@ -0,0 +1,621 @@
+#ifndef LEDEVICEYEELIGHT_H
+#define LEDEVICEYEELIGHT_H
+
+// LedDevice includes
+#include
+
+// Qt includes
+#include
+#include
+#include
+#include
+
+// List of State Information
+static const char API_METHOD_POWER[] = "set_power";
+static const char API_METHOD_POWER_ON[] = "on";
+static const char API_METHOD_POWER_OFF[] = "off";
+
+static const char API_METHOD_MUSIC_MODE[] = "set_music";
+static const int API_METHOD_MUSIC_MODE_ON = 1;
+static const int API_METHOD_MUSIC_MODE_OFF = 0;
+
+static const char API_METHOD_SETRGB[] = "set_rgb";
+static const char API_METHOD_SETSCENE[] = "set_scene";
+static const char API_METHOD_GETPROP[] = "get_prop";
+
+static const char API_PARAM_EFFECT_SUDDEN[] = "sudden";
+static const char API_PARAM_EFFECT_SMOOTH[] = "smooth";
+
+static const int API_PARAM_DURATION = 50;
+static const int API_PARAM_DURATION_POWERONOFF = 1000;
+static const int API_PARAM_EXTRA_TIME_DARKNESS = 200;
+
+///
+/// Response object for Yeelight-API calls and JSON-responses
+///
+class YeelightResponse
+{
+public:
+
+ enum API_REPLY{
+ API_OK,
+ API_ERROR,
+ API_NOTIFICATION,
+ };
+
+ explicit YeelightResponse() {}
+
+ API_REPLY error() { return _error;}
+ void setError(const YeelightResponse::API_REPLY replyType) { _error = replyType; }
+
+ QJsonArray getResult() const { return _resultArray; }
+ void setResult(const QJsonArray &result) { _resultArray = result; }
+
+ int getErrorCode() const { return _errorCode; }
+ void setErrorCode(const int &errorCode) { _errorCode = errorCode; _error = API_ERROR;}
+
+ QString getErrorReason() const { return _errorReason; }
+ void setErrorReason(const QString &errorReason) { _errorReason = errorReason; }
+
+private:
+
+ QJsonArray _resultArray;
+ API_REPLY _error = API_OK;
+
+ int _errorCode = 0;
+ QString _errorReason;
+};
+
+///
+/// Implementation of one Yeelight light.
+///
+class YeelightLight
+{
+
+public:
+
+ enum API_EFFECT{
+ API_EFFECT_SMOOTH,
+ API_EFFECT_SUDDEN
+ };
+
+ enum API_MODE{
+ API_TURN_ON_MODE,
+ API_CT_MODE,
+ API_RGB_MODE,
+ API_HSV_MODE,
+ API_COLOR_FLOW_MODE,
+ API_NIGHT_LIGHT_MODE
+ };
+
+ /// @brief Constructs one Yeelight light
+ ///
+ /// @param[in] log Logger instance
+ /// @param[in] hostname or IP-address
+ /// @param[in] port, default port 55443 is used when not provided
+ ///
+ YeelightLight( Logger *log, const QString &hostname, quint16 port);
+
+ ///
+ /// @brief Destructor of the Yeelight light
+ ///
+ virtual ~YeelightLight();
+
+ ///
+ /// @brief Set the Yeelight light connectivity parameters
+ ///
+ /// @param[in] hostname or IP-address
+ /// @param[in] port, default port 55443 is used when not provided
+ ///
+ void setHostname( const QString &hostname, quint16 port);
+
+ ///
+ /// @brief Set the Yeelight light name
+ ///
+ /// @param[in] name
+ ///
+ void setName( const QString& name ) { _name = name; }
+
+ ///
+ /// @brief Get the Yeelight light name
+ ///
+ /// @return The Yeelight light name
+ ///
+ QString getName() const { return _name; }
+
+ ///
+ /// @brief Opens the Yeelight light connectivity
+ ///
+ /// @return True, on success (i.e. device is open)
+ ///
+ bool open();
+
+ ///
+ /// @brief Closes the Yeelight light connectivity
+ ///
+ /// @return True, on success (i.e. device is closed)
+ ///
+ bool close();
+
+ ///
+ /// @brief Send a command to light up Yeelight light to allow identification
+ ///
+ /// @return True, if success
+ ///
+ bool identify();
+
+ ///
+ /// @brief Execute a Yeelight-API command
+ ///
+ /// @param[in] command The API command request in JSON
+ /// @return 0: success, -1: error, -2: command quota exceeded
+ ///
+ int writeCommand( const QJsonDocument &command );
+
+ ///
+ /// @brief Execute a Yeelight-API command
+ ///
+ /// @param[in] command The API command request in JSON
+ /// @param[out] result The response to the command in JSON
+ /// @return 0: success, -1: error, -2: command quota exceeded
+ ///
+ int writeCommand( const QJsonDocument &command, QJsonArray &result );
+
+ ///
+ /// @brief Stream a Yeelight-API command
+ ///
+ /// Yeelight must be in music mode, i.e. Streaming socket is established
+ ///
+ /// @param[in] command The API command request in JSON
+ /// @return True, on success
+ ///
+ bool streamCommand( const QJsonDocument &command );
+
+ ///
+ /// @brief Set the Yeelight light streaming socket
+ ///
+ /// @param[in] socket
+ ///
+ void setStreamSocket( QTcpSocket* socket );
+
+ ///
+ /// @brief Power on/off on the Yeelight light
+ ///
+ /// @param[in] on True: power on, False: power off
+ ///
+ /// @return True, if success
+ ///
+ bool setPower( bool on );
+
+ ///
+ /// @brief Power on/off on the Yeelight light
+ ///
+ /// @param[in] on True: power on, False: power off
+ /// @param[in] effect Transition effect, sudden or smooth
+ /// @param[in] duration Duration of the transition, if smooth
+ /// @param[in] mode Color mode after powering on
+ ///
+ /// @return True, if success
+ ///
+ bool setPower( bool on, API_EFFECT effect, int duration, API_MODE mode = API_RGB_MODE );
+
+ ///
+ /// @brief Set the Yeelight light to the given color (using RGB mode)
+ ///
+ /// @param[in] color as RGB value
+ ///
+ /// @return True, if success
+ ///
+ bool setColorRGB( const ColorRgb &color );
+
+ ///
+ /// @brief Set the Yeelight light to the given color (using HSV mode)
+ ///
+ /// @param[in] color as RGB value
+ ///
+ /// @return True, if success
+ ///
+ bool setColorHSV( const ColorRgb &color );
+
+ ///
+ /// @brief Set the Yeelight light effect and duration while transiting between color updates
+ ///
+ /// @param[in] effect Transition effect, sudden or smooth
+ /// @param[in] duration Duration of the transition, if smooth
+ ///
+ void setTransitionEffect ( API_EFFECT effect ,int duration = API_PARAM_DURATION );
+
+ ///
+ /// @brief Set the Yeelight light brightness configuration behaviour
+ ///
+ /// @param[in] min Minimum Brightness (in %). Every value lower than minimum will be set to minimum.
+ /// @param[in] max Maximum Brightness (in %). Every value greater than maximum will be set to maximum.
+ /// @param[in] switchoff True, power-off light, if brightness is lower then minimum
+ /// @param[in] extraTime Additional time (in ms), which added to transition duration while powering-off
+ /// @param[in] factor Brightness factor to multiply on color change.
+ ///
+ void setBrightnessConfig (int min = 1, int max = 100, bool switchoff = false, int extraTime = 0, double factor = 1);
+
+ ///
+ /// @brief Set the Yeelight light into music-mode
+ ///
+ /// @param[in] on True: music-mode on, False: music-mode off
+ /// @param[in] hostAddress of the music-mode server
+ /// @param[in] port of the music-mode server
+ ///
+ bool setMusicMode( bool on, const QHostAddress &hostAddress = {} , int port = -1 );
+
+ ///
+ /// @brief Set the wait-time between two Yeelight light commands
+ ///
+ /// The write of a command is delayed by the given wait-time, if the last write happen in the wait-time time frame.
+ /// Used to avoid that the Yeelight light runs into the quota exceed error scenario.
+ /// A Yeelight light can do 60 commands/min ( -> wait-time = 1000ms).
+ ///
+ /// @param[in] waitTime in milliseconds
+ ///
+ void setQuotaWaitTime( int waitTime ) { _waitTimeQuota = waitTime; }
+
+ ///
+ /// @brief Get the Yeelight light properties
+ ///
+ /// @return properties as JSON-object
+ ///
+ QJsonObject getProperties();
+
+ ///
+ /// @brief Get the Yeelight light properties and store them along the Yeelight light for later access
+ ///
+ void storeState();
+
+ ///
+ /// @brief Restore the Yeelight light's original state.
+ ///
+ /// Restore the device's state as before hyperion color streaming started.
+ ///
+ /// @return True, if success
+ ///
+ virtual bool restoreState();
+
+ ///
+ /// @brief Check, if light was originally powered on before hyperion color streaming started..
+ ///
+ /// @return True, if light was on at start
+ ///
+ bool wasOriginallyOn() const { return _power == API_METHOD_POWER_ON ? true : false; }
+
+ ///
+ /// @brief Check, if the Yeelight light is ready for updates
+ ///
+ /// @return True, if ready
+ ///
+ bool isReady() const { return !_isInError; }
+
+ ///
+ /// @brief Check, if the Yeelight light is powered on
+ ///
+ /// @return True, if powered on
+ ///
+ bool isOn() const { return _isOn; }
+
+ ///
+ /// @brief Check, if the Yeelight light is in music-mode
+ ///
+ /// @return True, if in music mode
+ ///
+ bool isInMusicMode( bool deviceCheck = false );
+
+ ///
+ /// @brief Set the Yeelight light in error state
+ ///
+ /// @param[in] errorMsg The error message to be logged
+ ///
+ void setInError( const QString& errorMsg );
+
+ ///
+ /// @brief Set the Yeelight light debug-level
+ ///
+ /// @param[in] level Debug level (0: no debug output, 1-3: verbosity level)
+ ///
+ void setDebuglevel ( int level ) { _debugLevel = level; }
+
+private:
+
+ YeelightResponse handleResponse(int correlationID, QByteArray const &response );
+
+ ///
+ /// @brief Build Yeelight-API command
+ ///
+ /// @param[in] method Control method to be invoked
+ /// @param[in] params Parameters for control method
+ /// @return Yeelight-API command in JSON format
+ ///
+ QJsonDocument getCommand(const QString &method, const QJsonArray ¶ms);
+
+ ///
+ /// @brief Map Yeelight light properties into the Yeelight light members for direct access
+ ///
+ /// @param[in] properties Yeelight light's properties as JSON-Object
+ ///
+ void mapProperties(const QJsonObject &properties);
+
+ ///
+ /// @brief Write a Yeelight light specific log-line for debugging purposed
+ ///
+ /// @param[in] logLevel Debug level (0: no debug output, 1-3: verbosity level)
+ /// @param[in] msg Log message prefix (max 20 characters)
+ /// @param[in] type log message text
+ /// @param[in] ... variable input to log message text
+ /// ///
+ void log(const int logLevel,const char* msg, const char* type, ...);
+
+ Logger* _log;
+ int _debugLevel;
+
+ /// Error status of Yeelight light
+ bool _isInError;
+
+ /// IP address/port of the Yeelight light
+ QString _host;
+ quint16 _port;
+
+ /// Yeelight light communication socket
+ QTcpSocket* _tcpSocket;
+ /// Music mode server communication socket
+ QTcpSocket* _tcpStreamSocket;
+
+ /// ID of last command written or streamed
+ int _correlationID;
+ /// Timestamp of last write
+ qint64 _lastWriteTime;
+
+ /// Last color written to Yeelight light (RGB represented as QColor)
+ QColor _color;
+ /// Last color written to Yeelight light (RGB represented as int)
+ int _lastColorRgbValue;
+
+ /// Yeelight light behavioural parameters
+ API_EFFECT _transitionEffect;
+ int _transitionDuration;
+ int _extraTimeDarkness;
+
+ int _brightnessMin;
+ bool _isBrightnessSwitchOffMinimum;
+ int _brightnessMax;
+ double _brightnessFactor;
+
+ QString _transitionEffectParam;
+
+ /// Wait time to avoid quota exceed scenario
+ int _waitTimeQuota;
+
+ /// Yeelight light properties
+ QJsonObject _originalStateProperties;
+ QString _name;
+ QString _model;
+ QString _power;
+ QString _fw_ver;
+ int _colorRgbValue;
+ int _bright;
+ int _ct;
+
+ /// Yeelight light status
+ bool _isOn;
+ bool _isInMusicMode;
+};
+
+///
+/// Implementation of the LedDevice interface for sending to
+/// Yeelight devices via network
+///
+class LedDeviceYeelight : public LedDevice
+{
+public:
+
+ ///
+ /// @brief Constructs a Yeelight LED-device serving multiple lights
+ ///
+ /// @param deviceConfig Device's configuration as JSON-Object
+ ///
+ explicit LedDeviceYeelight(const QJsonObject &deviceConfig);
+
+ ///
+ /// @brief Destructor of the LedDevice
+ ///
+ virtual ~LedDeviceYeelight() override;
+
+ ///
+ /// @brief Constructs the LED-device
+ ///
+ /// @param[in] deviceConfig Device's configuration as JSON-Object
+ /// @return LedDevice constructed
+ ///
+ static LedDevice* construct(const QJsonObject &deviceConfig);
+
+ ///
+ /// @brief Discover Yeelight devices available (for configuration).
+ ///
+ /// @return A JSON structure holding a list of devices found
+ ///
+ virtual QJsonObject discover() override;
+
+ ///
+ /// @brief Get a Yeelight device's resource properties
+ ///
+ /// Following parameters are required
+ /// @code
+ /// {
+ /// "hostname" : "hostname or IP",
+ /// "port" : port, default port 55443 is used when not provided
+ /// }
+ ///@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 Yeelight device to identify it.
+ ///
+ /// Following parameters are required
+ /// @code
+ /// {
+ /// "hostname" : "hostname or IP",
+ /// "port" : port, default port 55443 is used when not provided
+ /// }
+ ///@endcode
+ ///
+ /// @param[in] params Parameters to address device
+ ///
+ virtual void identify(const QJsonObject& params) override;
+
+protected:
+
+ ///
+ /// @brief Initialise the device's configuration
+ ///
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
+ ///
+ virtual bool init(const QJsonObject &deviceConfig) override;
+
+ ///
+ /// @brief Opens the output device.
+ ///
+ /// @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 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 Nanoleaf device.
+ ///
+ /// @brief Store the device's original state.
+ ///
+ virtual bool powerOn() override;
+
+ ///
+ /// @brief Power-/turn off the Nanoleaf device.
+ ///
+ /// @return True if success
+ ///
+ virtual bool powerOff() override;
+
+ ///
+ /// @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() 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:
+
+ struct yeelightAddress {
+ QString host;
+ int port;
+
+ bool operator == (yeelightAddress const& a) const
+ {
+ return ((host == a.host) && (port == a.port));
+ }
+ };
+
+ enum COLOR_MODEL{
+ MODEL_HSV,
+ MODEL_RGB
+ };
+
+ ///
+ /// @brief Start music-mode server
+ ///
+ /// @return True, if music mode server is running
+ ///
+ bool startMusicModeServer();
+
+ ///
+ /// @brief Stop music-mode server
+ ///
+ /// @return True, if music mode server has been stopped
+ ///
+ bool stopMusicModeServer();
+
+ ///
+ /// @brief Update list of Yeelight lights handled by the LED-device
+ ///
+ /// @param[in] list List of Yeelight lights
+ ///
+ /// @return False, if no lights were provided
+ ///
+ bool updateLights(const QVector &list);
+
+ ///
+ /// @brief Set the number of Yeelight lights handled by the LED-device
+ ///
+ /// @param[in] lightsCount Number of Yeelight lights
+ ///
+ void setLightsCount( unsigned int lightsCount ) { _lightsCount = lightsCount; }
+
+ ///
+ /// @brief Get the number of Yeelight lights handled by the LED-device
+ ///
+ /// @return Number of Yeelight lights
+ ///
+ uint getLightsCount() const { return _lightsCount; }
+
+ /// Array of the Yeelight addresses handled by the LED-device
+ QVector _lightsAddressList;
+
+ /// Array to save the lights
+ std::vector _lights;
+ unsigned int _lightsCount;
+
+ /// Yeelight configuration/behavioural parameters
+ int _outputColorModel;
+ YeelightLight::API_EFFECT _transitionEffect;
+ int _transitionDuration;
+ int _extraTimeDarkness;
+
+ int _brightnessMin;
+ bool _isBrightnessSwitchOffMinimum;
+ int _brightnessMax;
+ double _brightnessFactor;
+
+ int _waitTimeQuota;
+
+ int _debuglevel;
+
+ ///Music mode Server details
+ QHostAddress _musicModeServerAddress;
+ int _musicModeServerPort;
+ QTcpServer* _tcpMusicModeServer = nullptr;
+
+};
+
+#endif // LEDEVICEYEELIGHT_H
diff --git a/libsrc/leddevice/dev_net/ProviderRestApi.cpp b/libsrc/leddevice/dev_net/ProviderRestApi.cpp
new file mode 100644
index 000000000..e16ce11aa
--- /dev/null
+++ b/libsrc/leddevice/dev_net/ProviderRestApi.cpp
@@ -0,0 +1,242 @@
+// Local-Hyperion includes
+#include "ProviderRestApi.h"
+
+// Qt includes
+#include
+#include
+#include
+
+//std includes
+#include
+
+static const QChar ONE_SLASH = '/';
+
+ProviderRestApi::ProviderRestApi(const QString &host, const int &port, const QString &basePath)
+ :_log(Logger::getInstance("LDEDEVICE"))
+ ,_networkManager(nullptr)
+ ,_scheme("http")
+ ,_hostname(host)
+ ,_port(port)
+{
+ _networkManager = new QNetworkAccessManager();
+
+ _apiUrl.setScheme(_scheme);
+ _apiUrl.setHost(host);
+ _apiUrl.setPort(port);
+ _basePath = basePath;
+}
+
+ProviderRestApi::ProviderRestApi(const QString &host, const int &port)
+ : ProviderRestApi(host, port, "") {}
+
+ProviderRestApi::ProviderRestApi()
+ : ProviderRestApi("", -1) {}
+
+ProviderRestApi::~ProviderRestApi()
+{
+ if ( _networkManager != nullptr )
+ {
+ _networkManager->deleteLater();
+ }
+}
+
+void ProviderRestApi::setBasePath(const QString &basePath)
+{
+ _basePath.clear();
+ appendPath (_basePath, basePath );
+}
+
+void ProviderRestApi::setPath ( const QString &path )
+{
+ _path.clear();
+ appendPath (_path, path );
+}
+
+void ProviderRestApi::appendPath ( const QString &path )
+{
+ appendPath (_path, path );
+}
+
+void ProviderRestApi::appendPath (QString& path, const QString &appendPath)
+{
+ if ( !appendPath.isEmpty() && appendPath != ONE_SLASH )
+ {
+ if (path.isEmpty() || path == ONE_SLASH )
+ {
+ path.clear();
+ if (appendPath[0] != ONE_SLASH )
+ {
+ path.push_back(ONE_SLASH);
+ }
+ }
+ else if (path[path.size()-1] == ONE_SLASH && appendPath[0] == ONE_SLASH)
+ {
+ path.chop(1);
+ }
+ else if (path[path.size()-1] != ONE_SLASH && appendPath[0] != ONE_SLASH)
+ {
+ path.push_back(ONE_SLASH);
+ }
+ else
+ {
+ // Only one slash.
+ }
+
+ path.append(appendPath);
+ }
+}
+
+void ProviderRestApi::setFragment(const QString &fragment)
+{
+ _fragment = fragment;
+}
+
+void ProviderRestApi::setQuery(const QUrlQuery &query)
+{
+ _query = query;
+}
+
+QUrl ProviderRestApi::getUrl()
+{
+ QUrl url = _apiUrl;
+
+ QString fullPath = _basePath;
+ appendPath (fullPath, _path );
+
+ url.setPath(fullPath);
+ url.setFragment( _fragment );
+ url.setQuery( _query );
+ return url;
+}
+
+httpResponse ProviderRestApi::get()
+{
+ return get( getUrl() );
+}
+
+httpResponse ProviderRestApi::get(const QUrl &url)
+{
+ Debug(_log, "GET: [%s]", QSTRING_CSTR( url.toString() ));
+
+ // Perform 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();
+
+ httpResponse response;
+ if(reply->operation() == QNetworkAccessManager::GetOperation)
+ {
+ response = getResponse(reply );
+ }
+ // Free space.
+ reply->deleteLater();
+ // Return response
+ return response;
+}
+
+httpResponse ProviderRestApi::put(const QString &body)
+{
+ return put( getUrl(), body );
+}
+
+httpResponse ProviderRestApi::put(const QUrl &url, const QString &body)
+{
+ Debug(_log, "PUT: [%s] [%s]", QSTRING_CSTR( url.toString() ), QSTRING_CSTR( body ) );
+ // Perform request
+ QNetworkRequest request(url);
+ QNetworkReply* reply = _networkManager->put(request, body.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();
+
+ httpResponse response;
+ if(reply->operation() == QNetworkAccessManager::PutOperation)
+ {
+ response = getResponse(reply);
+ }
+ // Free space.
+ reply->deleteLater();
+
+ // Return response
+ return response;
+}
+
+httpResponse ProviderRestApi::getResponse(QNetworkReply* const &reply)
+{
+ httpResponse response;
+
+ int httpStatusCode = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
+ response.setHttpStatusCode(httpStatusCode);
+
+ Debug(_log, "Reply.httpStatusCode [%d]", httpStatusCode );
+
+ response.setNetworkReplyError(reply->error());
+
+ if(reply->error() == QNetworkReply::NoError)
+ {
+ if ( httpStatusCode != 204 ){
+ QByteArray replyData = reply->readAll();
+
+ if ( !replyData.isEmpty())
+ {
+ QJsonParseError error;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(replyData, &error);
+
+ if (error.error != QJsonParseError::NoError)
+ {
+ //Received not valid JSON response
+ //std::cout << "Response: [" << replyData.toStdString() << "]" << std::endl;
+ response.setError(true);
+ response.setErrorReason(error.errorString());
+ }
+ else
+ {
+ //std::cout << "Response: [" << QString (jsonDoc.toJson(QJsonDocument::Compact)).toStdString() << "]" << std::endl;
+ response.setBody( jsonDoc );
+ }
+ }
+ else
+ { // Create valid body which is empty
+ response.setBody( QJsonDocument() );
+ }
+ }
+ }
+ else
+ {
+ 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 ("[%3 %4] - %5").arg(QString(httpStatusCode) , httpReason, advise);
+ }
+ else {
+ errorReason = reply->errorString();
+ }
+ response.setError(true);
+ response.setErrorReason(errorReason);
+
+ // Create valid body which is empty
+ response.setBody( QJsonDocument() );
+ }
+ return response;
+}
+
diff --git a/libsrc/leddevice/dev_net/ProviderRestApi.h b/libsrc/leddevice/dev_net/ProviderRestApi.h
new file mode 100644
index 000000000..32c267316
--- /dev/null
+++ b/libsrc/leddevice/dev_net/ProviderRestApi.h
@@ -0,0 +1,216 @@
+#ifndef PROVIDERRESTKAPI_H
+#define PROVIDERRESTKAPI_H
+
+// Local-Hyperion includes
+#include
+
+// Qt includes
+#include
+#include
+#include
+#include
+
+///
+/// Response object for REST-API calls and JSON-responses
+///
+class httpResponse
+{
+public:
+
+ explicit httpResponse() {}
+
+ bool error() { return _hasError;}
+ void setError(const bool hasError) { _hasError = hasError; }
+
+ QJsonDocument getBody() const { return _responseBody; }
+ void setBody(const QJsonDocument &body) { _responseBody = body; }
+
+ QString getErrorReason() const { return _errorReason; }
+ void setErrorReason(const QString &errorReason) { _errorReason = errorReason; }
+
+ int getHttpStatusCode() const { return _httpStatusCode; }
+ void setHttpStatusCode(const int httpStatusCode) { _httpStatusCode = httpStatusCode; }
+
+ QNetworkReply::NetworkError getNetworkReplyError() const { return _networkReplyError; }
+ void setNetworkReplyError (const QNetworkReply::NetworkError networkReplyError) { _networkReplyError = networkReplyError; }
+
+private:
+
+ QJsonDocument _responseBody;
+ bool _hasError = false;
+ QString _errorReason;
+
+ int _httpStatusCode = 0;
+ QNetworkReply::NetworkError _networkReplyError = QNetworkReply::NoError;
+};
+
+///
+/// Wrapper class supporting REST-API calls with JSON requests and responses
+///
+/// Usage sample:
+/// @code
+///
+/// ProviderRestApi* _restApi = new ProviderRestApi(hostname, port );
+///
+/// _restApi->setBasePath( QString("/api/%1/").arg(token) );
+/// _restApi->setPath( QString("%1/%2").arg( "groups" ).arg( groupId ) );
+///
+/// httpResponse response = _restApi->get();
+/// if ( !response.error() )
+/// response.getBody();
+///
+/// delete _restApi;
+///
+///@endcode
+///
+class ProviderRestApi
+{
+public:
+
+ ///
+ /// @brief Constructor of the REST-API wrapper
+ ///
+ explicit ProviderRestApi();
+
+ ///
+ /// @brief Constructor of the REST-API wrapper
+ ///
+ /// @param[in] host
+ /// @param[in] port
+ ///
+ explicit ProviderRestApi(const QString &host, const int &port);
+
+ ///
+ /// @brief Constructor of the REST-API wrapper
+ ///
+ /// @param[in] host
+ /// @param[in] port
+ /// @param[in] API base-path
+ ///
+ explicit ProviderRestApi(const QString &host, const int &port, const QString &basePath);
+
+ ///
+ /// @brief Destructor of the REST-API wrapper
+ ///
+ virtual ~ProviderRestApi();
+
+ ///
+ /// @brief Get the URL as defined using scheme, host, port, API-basepath, path, query, fragment
+ ///
+ /// @return url
+ ///
+ QUrl getUrl();
+
+ ///
+ /// @brief Set an API's base path (the stable path element before addressing resources)
+ ///
+ /// @param[in] basePath, e.g. "/api/v1/" or "/json"
+ ///
+ void setBasePath(const QString &basePath);
+
+ ///
+ /// @brief Set an API's path to address resources
+ ///
+ /// @param[in] path, e.g. "/lights/1/state/"
+ ///
+ void setPath ( const QString &path );
+
+ ///
+ /// @brief Append an API's path element to path set before
+ ///
+ /// @param[in] path
+ ///
+ void appendPath (const QString &appendPath);
+
+ ///
+ /// @brief Set an API's fragment
+ ///
+ /// @param[in] fragment, e.g. "question3"
+ ///
+ void setFragment(const QString&fragment);
+
+ ///
+ /// @brief Set an API's query string
+ ///
+ /// @param[in] query, e.g. "&A=128&FX=0"
+ ///
+ void setQuery(const QUrlQuery &query);
+
+ ///
+ /// @brief Execute GET request
+ ///
+ /// @return Response The body of the response in JSON
+ ///
+ httpResponse get();
+
+ ///
+ /// @brief Execute GET request
+ ///
+ /// @param[in] url GET request for URL
+ /// @return Response The body of the response in JSON
+ ///
+ httpResponse get(const QUrl &url);
+
+ ///
+ /// @brief Execute PUT request
+ ///
+ /// @param[in] body The body of the request in JSON
+ /// @return Response The body of the response in JSON
+ ///
+ httpResponse put(const QString &body = "");
+
+ ///
+ /// @brief Execute PUT request
+ ///
+ /// @param[in] URL for PUT request
+ /// @param[in] body The body of the request in JSON
+ /// @return Response The body of the response in JSON
+ ///
+ httpResponse put(const QUrl &url, const QString &body = "");
+
+ ///
+ /// @brief Execute POST request
+ ///
+ /// @param[in] body The body of the request in JSON
+ /// @return Response The body of the response in JSON
+ ///
+ httpResponse post(QString body = "");
+
+ ///
+ /// @brief Handle responses for REST requests
+ ///
+ /// @param[in] reply Network reply
+ /// @return Response The body of the response in JSON
+ ///
+ httpResponse getResponse(QNetworkReply* const &reply);
+
+private:
+
+ ///
+ /// @brief Append an API's path element to path given as param
+ ///
+ /// @param[in/out] path to be updated
+ /// @param[in] path, element to be appended
+ ///
+ void appendPath (QString &path, const QString &appendPath);
+
+ Logger* _log;
+
+ // QNetworkAccessManager object for sending REST-requests.
+ QNetworkAccessManager* _networkManager;
+
+ QUrl _apiUrl;
+
+ QString _scheme;
+ QString _hostname;
+ int _port;
+
+ QString _basePath;
+ QString _path;
+
+ QString _fragment;
+ QUrlQuery _query;
+
+};
+
+#endif // PROVIDERRESTKAPI_H
diff --git a/libsrc/leddevice/dev_net/ProviderUdp.cpp b/libsrc/leddevice/dev_net/ProviderUdp.cpp
index 3df9b8e47..9dccd41f7 100644
--- a/libsrc/leddevice/dev_net/ProviderUdp.cpp
+++ b/libsrc/leddevice/dev_net/ProviderUdp.cpp
@@ -22,7 +22,7 @@ ProviderUdp::ProviderUdp()
, _port(1)
, _defaultHost("127.0.0.1")
{
- _deviceReady = false;
+ _isDeviceReady = false;
_latchTime_ms = 1;
}
@@ -36,53 +36,59 @@ ProviderUdp::~ProviderUdp()
bool ProviderUdp::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = LedDevice::init(deviceConfig);
-
- QString host = deviceConfig["host"].toString(_defaultHost);
+ bool isInitOK = false;
- if (_address.setAddress(host) )
- {
- Debug( _log, "Successfully parsed %s as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
- }
- else
+ // Initialise sub-class
+ if ( LedDevice::init(deviceConfig) )
{
- Debug( _log, "Failed to parse [%s] as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
- QHostInfo info = QHostInfo::fromName(host);
- if (info.addresses().isEmpty())
+ QString host = deviceConfig["host"].toString(_defaultHost);
+
+ if (_address.setAddress(host) )
{
- Debug( _log, "Failed to parse [%s] as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
- QString errortext = QString ("Invalid target address [%1]!").arg(host);
- this->setInError ( errortext );
- return false;
+ Debug( _log, "Successfully parsed %s as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
}
else
{
- Debug( _log, "Successfully parsed %s as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
- _address = info.addresses().first();
+ Debug( _log, "Failed to parse [%s] as an ip address.", deviceConfig["host"].toString().toStdString().c_str());
+ QHostInfo info = QHostInfo::fromName(host);
+ if (info.addresses().isEmpty())
+ {
+ Debug( _log, "Failed to parse [%s] as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
+ QString errortext = QString ("Invalid target address [%1]!").arg(host);
+ this->setInError ( errortext );
+ return false;
+ }
+ else
+ {
+ Debug( _log, "Successfully parsed %s as a hostname.", deviceConfig["host"].toString().toStdString().c_str());
+ _address = info.addresses().first();
+ }
}
- }
- int config_port = deviceConfig["port"].toInt(_port);
- if ( config_port <= 0 || config_port > MAX_PORT )
- {
- QString errortext = QString ("Invalid target port [%1]!").arg(config_port);
- this->setInError ( errortext );
- isInitOK = false;
- }
- else
- {
- _port = static_cast(config_port);
- Debug( _log, "UDP using %s:%d", _address.toString().toStdString().c_str() , _port );
- }
+ int config_port = deviceConfig["port"].toInt(_port);
+ if ( config_port <= 0 || config_port > MAX_PORT )
+ {
+ QString errortext = QString ("Invalid target port [%1]!").arg(config_port);
+ this->setInError ( errortext );
+ isInitOK = false;
+ }
+ else
+ {
+ _port = static_cast(config_port);
+ Debug( _log, "UDP using %s:%d", _address.toString().toStdString().c_str() , _port );
+ _udpSocket = new QUdpSocket(this);
+
+ isInitOK = true;
+ }
+ }
return isInitOK;
}
-bool ProviderUdp::initNetwork()
+int ProviderUdp::open()
{
- bool isInitOK = false;
-
- _udpSocket = new QUdpSocket(this);
+ int retval = -1;
+ _isDeviceReady = false;
// Try to bind the UDP-Socket
if ( _udpSocket != nullptr )
@@ -94,37 +100,21 @@ bool ProviderUdp::initNetwork()
QString warntext = QString ("Could not bind local address: %1, (%2) %3").arg(localAddress.toString()).arg(_udpSocket->error()).arg(_udpSocket->errorString());
Warning ( _log, "%s", QSTRING_CSTR(warntext));
}
- isInitOK = true;
+ // Everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
}
- return isInitOK;
-}
-
-int ProviderUdp::open()
-{
- int retval = -1;
- QString errortext;
- _deviceReady = false;
-
- if ( init(_devConfig) )
+ else
{
- if ( ! initNetwork())
- {
- this->setInError( "UDP Network error!" );
- }
- else
- {
- // Everything is OK -> enable device
- _deviceReady = true;
- setEnable(true);
- retval = 0;
- }
+ this->setInError( " Open error. UDP Socket not initialised!" );
}
return retval;
}
-void ProviderUdp::close()
+int ProviderUdp::close()
{
- LedDevice::close();
+ int retval = 0;
+ _isDeviceReady = false;
if ( _udpSocket != nullptr )
{
@@ -136,6 +126,7 @@ void ProviderUdp::close()
// Everything is OK -> device is closed
}
}
+ return retval;
}
int ProviderUdp::writeBytes(const unsigned size, const uint8_t * data)
diff --git a/libsrc/leddevice/dev_net/ProviderUdp.h b/libsrc/leddevice/dev_net/ProviderUdp.h
index d4582c71b..910b682ca 100644
--- a/libsrc/leddevice/dev_net/ProviderUdp.h
+++ b/libsrc/leddevice/dev_net/ProviderUdp.h
@@ -1,13 +1,15 @@
-#pragma once
+#ifndef PROVIDERUDP_H
+#define PROVIDERUDP_H
-// Hyperion includes
+// LedDevice includes
#include
+
+// Hyperion includes
#include
-// qt
+// Qt includes
#include
-
-class QUdpSocket;
+#include
///
/// The ProviderUdp implements an abstract base-class for LedDevices using UDP packets.
@@ -15,53 +17,49 @@ class QUdpSocket;
class ProviderUdp : public LedDevice
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs an UDP LED-device
///
ProviderUdp();
///
- /// Destructor of the LedDevice; closes the output device if it is open
+ /// @brief Destructor of the UDP LED-device
///
virtual ~ProviderUdp() override;
+protected:
+
///
- /// Sets configuration
+ /// @brief Initialise the UDP device's configuration and network address details
+ ///
+ /// @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
///
- virtual void close() override;
-
-protected:
-
+ /// @brief Opens the output device.
///
- /// Initialise device's network details
+ /// @return Zero on success (i.e. device is ready), else negative
///
- /// @return True if success
- bool initNetwork();
+ virtual int open() override;
///
- /// Opens and configures the output device
+ /// @brief Closes the UDP 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/bits to the UDP-device and sleeps the latch time to ensure that the
+ /// @brief Writes the given bytes/bits to the UDP-device and sleeps the latch time to ensure that the
/// values are latched.
///
/// @param[in] size The length of the data
/// @param[in] data The data
///
- /// @return Zero on succes else negative
+ /// @return Zero on success, else negative
///
int writeBytes(const unsigned size, const uint8_t *data);
@@ -71,3 +69,5 @@ public slots:
ushort _port;
QString _defaultHost;
};
+
+#endif // PROVIDERUDP_H
diff --git a/libsrc/leddevice/dev_net/ProviderUdpSSL.cpp b/libsrc/leddevice/dev_net/ProviderUdpSSL.cpp
index 0eab17a88..ef171f9cf 100644
--- a/libsrc/leddevice/dev_net/ProviderUdpSSL.cpp
+++ b/libsrc/leddevice/dev_net/ProviderUdpSSL.cpp
@@ -12,6 +12,9 @@
// Local Hyperion includes
#include "ProviderUdpSSL.h"
+const int MAX_RETRY = 5;
+const ushort MAX_PORT_SSL = 65535;
+
ProviderUdpSSL::ProviderUdpSSL()
: LedDevice()
, client_fd()
@@ -38,7 +41,7 @@ ProviderUdpSSL::ProviderUdpSSL()
, _debugStreamer(false)
, _debugLevel(0)
{
- _deviceReady = false;
+ _isDeviceReady = false;
_latchTime_ms = 1;
}
@@ -48,114 +51,131 @@ ProviderUdpSSL::~ProviderUdpSSL()
bool ProviderUdpSSL::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = LedDevice::init(deviceConfig);
-
- _debugStreamer = deviceConfig["debugStreamer"].toBool(false);
- _debugLevel = deviceConfig["debugLevel"].toString().toInt(0);
-
- //PSK Pre Shared Key
- _psk = deviceConfig["psk"].toString();
- _psk_identity = deviceConfig["psk_identity"].toString();
- _port = deviceConfig["sslport"].toInt(2100);
- _server_name = deviceConfig["servername"].toString();
-
- if( deviceConfig.contains("transport_type") ) _transport_type = deviceConfig["transport_type"].toString("DTLS");
- if( deviceConfig.contains("seed_custom") ) _custom = deviceConfig["seed_custom"].toString("dtls_client");
- if( deviceConfig.contains("retry_left") ) _retry_left = deviceConfig["retry_left"].toInt(MAX_RETRY);
- if( deviceConfig.contains("read_timeout") ) _read_timeout = deviceConfig["read_timeout"].toInt(0);
- if( deviceConfig.contains("hs_timeout_min") ) _handshake_timeout_min = deviceConfig["hs_timeout_min"].toInt(400);
- if( deviceConfig.contains("hs_timeout_max") ) _handshake_timeout_max = deviceConfig["hs_timeout_max"].toInt(1000);
- if( deviceConfig.contains("hs_attempts") ) _handshake_attempts = deviceConfig["hs_attempts"].toInt(5);
-
- QString host = deviceConfig["host"].toString(_defaultHost);
- QStringList debugLevels = QStringList() << "No Debug" << "Error" << "State Change" << "Informational" << "Verbose";
-
- configLog( "SSL Streamer Debug", "%s", ( _debugStreamer ) ? "yes" : "no" );
- configLog( "SSL DebugLevel", "[%d] %s", _debugLevel, QSTRING_CSTR( debugLevels[ _debugLevel ]) );
-
- configLog( "SSL Servername", "%s", QSTRING_CSTR( _server_name ) );
- configLog( "SSL Host", "%s", QSTRING_CSTR( host ) );
- configLog( "SSL Port", "%d", _port );
- configLog( "PSK", "%s", QSTRING_CSTR( _psk ) );
- configLog( "PSK-Identity", "%s", QSTRING_CSTR( _psk_identity ) );
- configLog( "SSL Transport Type", "%s", QSTRING_CSTR( _transport_type ) );
- configLog( "SSL Seed Custom", "%s", QSTRING_CSTR( _custom ) );
- configLog( "SSL Retry Left", "%d", _retry_left );
- configLog( "SSL Read Timeout", "%d", _read_timeout );
- configLog( "SSL Handshake Timeout min", "%d", _handshake_timeout_min );
- configLog( "SSL Handshake Timeout max", "%d", _handshake_timeout_max );
- configLog( "SSL Handshake attempts", "%d", _handshake_attempts );
-
- if ( _address.setAddress(host) )
- {
- Debug( _log, "Successfully parsed %s as an ip address.", QSTRING_CSTR( host ) );
- }
- else
+ bool isInitOK = false;
+
+ // Initialise sub-class
+ if ( LedDevice::init(deviceConfig) )
{
- Debug( _log, "Failed to parse [%s] as an ip address.", QSTRING_CSTR( host ) );
- QHostInfo info = QHostInfo::fromName(host);
- if ( info.addresses().isEmpty() )
+ _debugStreamer = deviceConfig["debugStreamer"].toBool(false);
+ _debugLevel = deviceConfig["debugLevel"].toString().toInt(0);
+
+ //PSK Pre Shared Key
+ _psk = deviceConfig["psk"].toString();
+ _psk_identity = deviceConfig["psk_identity"].toString();
+ _port = deviceConfig["sslport"].toInt(2100);
+ _server_name = deviceConfig["servername"].toString();
+
+ if( deviceConfig.contains("transport_type") ) _transport_type = deviceConfig["transport_type"].toString("DTLS");
+ if( deviceConfig.contains("seed_custom") ) _custom = deviceConfig["seed_custom"].toString("dtls_client");
+ if( deviceConfig.contains("retry_left") ) _retry_left = deviceConfig["retry_left"].toInt(MAX_RETRY);
+ if( deviceConfig.contains("read_timeout") ) _read_timeout = deviceConfig["read_timeout"].toInt(0);
+ if( deviceConfig.contains("hs_timeout_min") ) _handshake_timeout_min = deviceConfig["hs_timeout_min"].toInt(400);
+ if( deviceConfig.contains("hs_timeout_max") ) _handshake_timeout_max = deviceConfig["hs_timeout_max"].toInt(1000);
+ if( deviceConfig.contains("hs_attempts") ) _handshake_attempts = deviceConfig["hs_attempts"].toInt(5);
+
+ QString host = deviceConfig["host"].toString(_defaultHost);
+ QStringList debugLevels = QStringList() << "No Debug" << "Error" << "State Change" << "Informational" << "Verbose";
+
+ configLog( "SSL Streamer Debug", "%s", ( _debugStreamer ) ? "yes" : "no" );
+ configLog( "SSL DebugLevel", "[%d] %s", _debugLevel, QSTRING_CSTR( debugLevels[ _debugLevel ]) );
+
+ configLog( "SSL Servername", "%s", QSTRING_CSTR( _server_name ) );
+ configLog( "SSL Host", "%s", QSTRING_CSTR( host ) );
+ configLog( "SSL Port", "%d", _port );
+ configLog( "PSK", "%s", QSTRING_CSTR( _psk ) );
+ configLog( "PSK-Identity", "%s", QSTRING_CSTR( _psk_identity ) );
+ configLog( "SSL Transport Type", "%s", QSTRING_CSTR( _transport_type ) );
+ configLog( "SSL Seed Custom", "%s", QSTRING_CSTR( _custom ) );
+ configLog( "SSL Retry Left", "%d", _retry_left );
+ configLog( "SSL Read Timeout", "%d", _read_timeout );
+ configLog( "SSL Handshake Timeout min", "%d", _handshake_timeout_min );
+ configLog( "SSL Handshake Timeout max", "%d", _handshake_timeout_max );
+ configLog( "SSL Handshake attempts", "%d", _handshake_attempts );
+
+ if ( _address.setAddress(host) )
+ {
+ Debug( _log, "Successfully parsed %s as an ip address.", QSTRING_CSTR( host ) );
+ }
+ else
{
- Debug( _log, "Failed to parse [%s] as a hostname.", QSTRING_CSTR( host ) );
- QString errortext = QString("Invalid target address [%1]!").arg(host);
+ Debug( _log, "Failed to parse [%s] as an ip address.", QSTRING_CSTR( host ) );
+ QHostInfo info = QHostInfo::fromName(host);
+ if ( info.addresses().isEmpty() )
+ {
+ Debug( _log, "Failed to parse [%s] as a hostname.", QSTRING_CSTR( host ) );
+ QString errortext = QString("Invalid target address [%1]!").arg(host);
+ this->setInError( errortext );
+ isInitOK = false;
+ }
+ else
+ {
+ Debug( _log, "Successfully parsed %s as a hostname.", QSTRING_CSTR( host ) );
+ _address = info.addresses().first();
+ }
+ }
+
+ int config_port = deviceConfig["sslport"].toInt(_port);
+
+ if ( config_port <= 0 || config_port > MAX_PORT_SSL )
+ {
+ QString errortext = QString ("Invalid target port [%1]!").arg(config_port);
this->setInError( errortext );
isInitOK = false;
}
else
{
- Debug( _log, "Successfully parsed %s as a hostname.", QSTRING_CSTR( host ) );
- _address = info.addresses().first();
+ _ssl_port = config_port;
+ Debug( _log, "UDP SSL using %s:%u", QSTRING_CSTR( _address.toString() ), _ssl_port );
+ isInitOK = true;
}
}
+ return isInitOK;
+}
- int config_port = deviceConfig["sslport"].toInt(_port);
+int ProviderUdpSSL::open()
+{
+ int retval = -1;
+ _isDeviceReady = false;
+
+ // TODO: Question: Just checking .... Is this one time initialisation or required with every open request (during switch-off/switch-on)?
+ // In case one time initialisation, it should go to the init method.
+ // Everything that is required to pen a UDP-SSL connection again (after it maybe was closed remotely should go here)
- if ( config_port <= 0 || config_port > MAX_PORT_SSL )
+ if ( !initNetwork() )
{
- QString errortext = QString ("Invalid target port [%1]!").arg(config_port);
- this->setInError( errortext );
- isInitOK = false;
+ this->setInError( "UDP SSL Network error!" );
}
else
{
- _ssl_port = config_port;
- Debug( _log, "UDP SSL using %s:%u", QSTRING_CSTR( _address.toString() ), _ssl_port );
+ // Everything is OK -> enable device
+ _isDeviceReady = true;
+ retval = 0;
}
- return isInitOK;
+ return retval;
}
-int ProviderUdpSSL::open()
+int ProviderUdpSSL::close()
{
- int retval = -1;
- QString errortext;
- _deviceReady = false;
+ // LedDevice specific closing activities
+ int retval = 0;
+ _isDeviceReady = false;
- if ( init(_devConfig) )
+ // TODO: You may want to check, if the device is already closed or close it and return, if ok or not
+ // Test, if device requires closing
+ if ( true /*If device is still open*/ )
{
- if ( !initNetwork() )
- {
- this->setInError( "UDP SSL Network error!" );
- }
- else
- {
- // Everything is OK -> enable device
- _deviceReady = true;
- setEnable(true);
- retval = 0;
- }
+ // Close device
+
+ LedDevice::close();
+ closeSSLConnection();
+ // Everything is OK -> device is closed
}
return retval;
}
-void ProviderUdpSSL::close()
-{
- LedDevice::close();
- closeSSLConnection();
-}
-
void ProviderUdpSSL::closeSSLConnection()
{
- if( _deviceReady && !_stopConnection )
+ if( _isDeviceReady && !_stopConnection )
{
closeSSLNotify();
freeSSLConnection();
@@ -412,7 +432,7 @@ bool ProviderUdpSSL::startSSLHandshake()
void ProviderUdpSSL::freeSSLConnection()
{
- sslLog( "SSL Connection cleanup..." );
+ sslLog( "SSL Connection clean-up..." );
_stopConnection = true;
@@ -425,15 +445,15 @@ void ProviderUdpSSL::freeSSLConnection()
mbedtls_x509_crt_free(&cacert);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
- sslLog( "SSL Connection cleanup...ok" );
+ sslLog( "SSL Connection clean-up...ok" );
}
catch (std::exception &e)
{
- sslLog( QString("SSL Connection cleanup Error: %s").arg( e.what() ) );
+ sslLog( QString("SSL Connection clean-up Error: %s").arg( e.what() ) );
}
catch (...)
{
- sslLog( "SSL Connection cleanup Error: " );
+ sslLog( "SSL Connection clean-up Error: " );
}
}
diff --git a/libsrc/leddevice/dev_net/ProviderUdpSSL.h b/libsrc/leddevice/dev_net/ProviderUdpSSL.h
index da0a5a7f1..b9e101ae2 100644
--- a/libsrc/leddevice/dev_net/ProviderUdpSSL.h
+++ b/libsrc/leddevice/dev_net/ProviderUdpSSL.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef PROVIDERUDPSSL_H
+#define PROVIDERUDPSSL_H
#include
#include
@@ -45,12 +46,8 @@
#include
#include
-#define READ_TIMEOUT_MS 1000
-#define MAX_RETRY 5
-
//----------- END mbedtls
-const ushort MAX_PORT_SSL = 65535;
class ProviderUdpSSL : public LedDevice
{
@@ -58,44 +55,45 @@ class ProviderUdpSSL : public LedDevice
public:
///
- /// Constructs specific LedDevice
+ /// @brief Constructs an UDP SSL LED-device
///
ProviderUdpSSL();
///
- /// Destructor of the LedDevice; closes the output device if it is open
+ /// @brief Destructor of the LED-device
///
virtual ~ProviderUdpSSL() override;
+protected:
+
///
- /// Sets configuration
+ /// @brief Initialise the UDP-SSL device's configuration and network address details
+ ///
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success#endif // PROVIDERUDP_H
///
- /// @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;
-
-protected:
+ /// @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
+ /// @return Zero on success (i.e. device is closed), else negative
///
- bool initNetwork();
+ virtual int close() override;
///
- /// Opens and configures the output device
+ /// @brief Initialise device's network details
///
- /// @return Zero on succes else negative
+ /// @return True, if success
///
- int open() override;
+ bool initNetwork();
///
/// Writes the given bytes/bits to the UDP-device and sleeps the latch time to ensure that the
@@ -208,3 +206,5 @@ public slots:
bool _debugStreamer;
int _debugLevel;
};
+
+#endif // PROVIDERUDPSSL_H
diff --git a/libsrc/leddevice/dev_other/LedDeviceFile.cpp b/libsrc/leddevice/dev_other/LedDeviceFile.cpp
index ab47a8795..afd27aeb2 100644
--- a/libsrc/leddevice/dev_other/LedDeviceFile.cpp
+++ b/libsrc/leddevice/dev_other/LedDeviceFile.cpp
@@ -9,8 +9,10 @@ LedDeviceFile::LedDeviceFile(const QJsonObject &deviceConfig)
, _file (nullptr)
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
_printTimeStamp = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDeviceFile::~LedDeviceFile()
@@ -49,38 +51,30 @@ void LedDeviceFile::initFile(const QString &fileName)
int LedDeviceFile::open()
{
int retval = -1;
- QString errortext;
- _deviceReady = false;
+ _isDeviceReady = false;
- if ( init(_devConfig) )
+ if ( ! _file->isOpen() )
{
- if ( ! _file->isOpen() )
+ Debug(_log, "QIODevice::WriteOnly, %s", QSTRING_CSTR(_fileName));
+ if ( !_file->open(QIODevice::WriteOnly | QIODevice::Text) )
+ {
+ QString errortext = QString ("(%1) %2, file: (%3)").arg(_file->error()).arg(_file->errorString(),_fileName);
+ this->setInError( errortext );
+ }
+ else
{
- Debug(_log, "QIODevice::WriteOnly, %s", QSTRING_CSTR(_fileName));
- if ( !_file->open(QIODevice::WriteOnly | QIODevice::Text) )
- {
- errortext = QString ("(%1) %2, file: (%3)").arg(_file->error()).arg(_file->errorString()).arg(_fileName);
- }
- else
- {
- _deviceReady = true;
- setEnable(true);
- retval = 0;
- }
-
- if ( retval < 0 )
- {
- this->setInError( errortext );
- }
+ _isDeviceReady = true;
+ retval = 0;
}
}
return retval;
}
-void LedDeviceFile::close()
+int LedDeviceFile::close()
{
- LedDevice::close();
+ int retval = 0;
+ _isDeviceReady = false;
if ( _file != nullptr)
{
// Test, if device requires closing
@@ -91,6 +85,7 @@ void LedDeviceFile::close()
_file->close();
}
}
+ return retval;
}
int LedDeviceFile::write(const std::vector & ledValues)
diff --git a/libsrc/leddevice/dev_other/LedDeviceFile.h b/libsrc/leddevice/dev_other/LedDeviceFile.h
index b9f5b8520..d5a6ae224 100644
--- a/libsrc/leddevice/dev_other/LedDeviceFile.h
+++ b/libsrc/leddevice/dev_other/LedDeviceFile.h
@@ -35,14 +35,6 @@ class LedDeviceFile : public LedDevice
/// @return LedDevice constructed
static LedDevice* construct(const QJsonObject &deviceConfig);
- public slots:
- ///
- /// @brief Closes the output device.
- ///
- /// @return Zero on success (i.e. device is closed), else negative
- ///
- virtual void close() override;
-
protected:
///
@@ -60,6 +52,13 @@ class LedDeviceFile : public LedDevice
///
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 Writes the RGB-Color values to the LEDs.
///
diff --git a/libsrc/leddevice/dev_other/LedDevicePiBlaster.cpp b/libsrc/leddevice/dev_other/LedDevicePiBlaster.cpp
index a3f388139..89ef50e50 100644
--- a/libsrc/leddevice/dev_other/LedDevicePiBlaster.cpp
+++ b/libsrc/leddevice/dev_other/LedDevicePiBlaster.cpp
@@ -13,7 +13,9 @@ LedDevicePiBlaster::LedDevicePiBlaster(const QJsonObject &deviceConfig)
: _fid(nullptr)
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
signal(SIGPIPE, SIG_IGN);
@@ -55,7 +57,7 @@ bool LedDevicePiBlaster::init(const QJsonObject &deviceConfig)
return false;
}
- // walk through the json config and populate the mapping tables
+ // walk through the JSON configuration and populate the mapping tables
for(QJsonArray::const_iterator gpioArray = gpioMapping.begin(); gpioArray != gpioMapping.end(); ++gpioArray)
{
const QJsonObject value = (*gpioArray).toObject();
@@ -84,56 +86,57 @@ int LedDevicePiBlaster::open()
{
int retval = -1;
QString errortext;
- _deviceReady = false;
+ _isDeviceReady = false;
- if ( init(_devConfig) )
+ if (_fid != nullptr)
+ {
+ // The file pointer is already open
+ errortext = QString ("Device (%1) is already open.").arg(_deviceName);
+ }
+ else
{
- if (_fid != nullptr)
+ if (!QFile::exists(_deviceName))
{
- // The file pointer is already open
- errortext = QString ("Device (%1) is already open.").arg(_deviceName);
+ errortext = QString ("The device (%1) does not yet exist.").arg(_deviceName);
}
else
{
- if (!QFile::exists(_deviceName))
+ _fid = fopen(QSTRING_CSTR(_deviceName), "w");
+ if (_fid == nullptr)
{
- errortext = QString ("The device (%1) does not yet exist.").arg(_deviceName);
+ errortext = QString ("Failed to open device (%1). Error message: %2").arg(_deviceName, strerror(errno));
}
else
{
- _fid = fopen(QSTRING_CSTR(_deviceName), "w");
- if (_fid == nullptr)
- {
- errortext = QString ("Failed to open device (%1). Error message: %2").arg(_deviceName, strerror(errno));
- }
- else
- {
- Info( _log, "Connected to device(%s)", QSTRING_CSTR(_deviceName));
- retval = 0;
- setEnable(true);
- }
+ Info( _log, "Connected to device(%s)", QSTRING_CSTR(_deviceName));
+
+ // Everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
}
}
+ }
- if ( retval < 0 )
- {
- this->setInError( errortext );
- }
+ // On error/exceptions, set LedDevice in error
+ if ( retval < 0 )
+ {
+ this->setInError( errortext );
}
return retval;
}
-void LedDevicePiBlaster::close()
+int LedDevicePiBlaster::close()
{
- LedDevice::close();
+ int retval = 0;
+ _isDeviceReady = false;
- // LedDevice specific closing activites
- // Close the device (if it is opened)
+ // Test, if device requires closing
if (_fid != nullptr)
{
fclose(_fid);
_fid = nullptr;
}
+ return retval;
}
int LedDevicePiBlaster::write(const std::vector & ledValues)
diff --git a/libsrc/leddevice/dev_other/LedDevicePiBlaster.h b/libsrc/leddevice/dev_other/LedDevicePiBlaster.h
index fb6ff795b..5ece87376 100644
--- a/libsrc/leddevice/dev_other/LedDevicePiBlaster.h
+++ b/libsrc/leddevice/dev_other/LedDevicePiBlaster.h
@@ -1,57 +1,64 @@
-#pragma once
+#ifndef LEDEVICEPIBLASTER_H
+#define LEDEVICEPIBLASTER_H
-// Hyperion-Leddevice includes
+// LedDevice includes
#include
///
/// Implementation of the LedDevice interface for writing to pi-blaster based PWM LEDs
///
-
class LedDevicePiBlaster : public LedDevice
{
public:
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a pi-Blaster LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDevicePiBlaster(const QJsonObject &deviceConfig);
+ ///
+ /// @brief Destructor of the LedDevice
+ ///
virtual ~LedDevicePiBlaster() override;
///
- /// Sets configuration
+ /// @brief Constructs the LED-device
///
- /// @param deviceConfig the json device config
- /// @return true if success
- bool init(const QJsonObject &deviceConfig) override;
-
- /// constructs leddevice
+ /// @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 device's configuration
///
- virtual void close() override;
+ /// @param[in] deviceConfig the JSON device configuration
+ bool init(const QJsonObject &deviceConfig) override;
-protected:
///
/// Attempts to open the piblaster-device. This will only succeed if the device is not yet open
/// and the device is available.
///
- /// @return Zero on succes else negative
+ /// @return Zero on success (i.e. device is ready), else negative
///
- int open() override;
+ virtual int open() override;
-private:
///
- /// Writes the colors to the PiBlaster device
+ /// @brief Closes the output device.
+ ///
+ /// @return Zero on success (i.e. device is closed), else negative
+ ///
+ virtual int close() override;
+
+private:
+
///
- /// @param ledValues The color value for each 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
///
int write(const std::vector &ledValues) override;
@@ -65,3 +72,5 @@ public slots:
FILE * _fid;
};
+
+#endif // LEDEVICETEMPLATE_H
diff --git a/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp b/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp
index 8d6df23e4..284a1e681 100644
--- a/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp
+++ b/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.cpp
@@ -4,7 +4,9 @@ LedDeviceWS281x::LedDeviceWS281x(const QJsonObject &deviceConfig)
: LedDevice()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDeviceWS281x::~LedDeviceWS281x()
@@ -20,10 +22,11 @@ bool LedDeviceWS281x::init(const QJsonObject &deviceConfig)
{
QString errortext;
- bool isInitOK = LedDevice::init(deviceConfig);
- if ( isInitOK )
- {
+ bool isInitOK = false;
+ // Initialise sub-class
+ if ( LedDevice::init(deviceConfig) )
+ {
QString whiteAlgorithm = deviceConfig["whiteAlgorithm"].toString("white_off");
_whiteAlgorithm = RGBW::stringToWhiteAlgorithm(whiteAlgorithm);
@@ -43,7 +46,7 @@ bool LedDeviceWS281x::init(const QJsonObject &deviceConfig)
else
{
memset(&_led_string, 0, sizeof(_led_string));
- _led_string.freq = deviceConfig["freq"].toInt(800000ul);
+ _led_string.freq = deviceConfig["freq"].toInt(800000UL);
_led_string.dmanum = deviceConfig["dma"].toInt(5);
_led_string.channel[_channel].gpionum = deviceConfig["gpio"].toInt(18);
_led_string.channel[_channel].count = deviceConfig["leds"].toInt(256);
@@ -59,15 +62,7 @@ bool LedDeviceWS281x::init(const QJsonObject &deviceConfig)
Debug( _log, "ws281x strip type : %d", _led_string.channel[_channel].strip_type );
- if (ws2811_init(&_led_string) < 0)
- {
- errortext = "Unable to initialize ws281x library.";
- isInitOK = false;
- }
- else
- {
- isInitOK = true;
- }
+ isInitOK = true;
}
}
}
@@ -79,14 +74,40 @@ bool LedDeviceWS281x::init(const QJsonObject &deviceConfig)
return isInitOK;
}
-void LedDeviceWS281x::close()
+int LedDeviceWS281x::open()
{
- LedDevice::close();
+ int retval = -1;
+ _isDeviceReady = false;
+
+ // Try to open the LedDevice
- if (_deviceReady)
+ ws2811_return_t rc = ws2811_init(&_led_string);
+ if ( rc != WS2811_SUCCESS )
+ {
+ QString errortext = QString ("Failed to open. Error message: %1").arg( ws2811_get_return_t_str(rc) );
+ this->setInError( errortext );
+ }
+ else
+ {
+ // Everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
+ }
+ return retval;
+}
+
+int LedDeviceWS281x::close()
+{
+ int retval = 0;
+ _isDeviceReady = false;
+
+ // LedDevice specific closing activities
+ if ( isInitialised() )
{
ws2811_fini(&_led_string);
}
+
+ return retval;
}
// Send new values down the LED chain
diff --git a/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.h b/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.h
index a6dc6c4eb..5ac4b76f9 100644
--- a/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.h
+++ b/libsrc/leddevice/dev_rpi_pwm/LedDeviceWS281x.h
@@ -1,52 +1,65 @@
-#pragma once
+#ifndef LEDEVICEWS281X_H
+#define LEDEVICEWS281X_H
// LedDevice includes
#include
#include
///
-/// Implementation of the LedDevice interface for writing to Ws2812 led device via pwm.
+/// Implementation of the LedDevice interface for writing to WS281x LED-device via pwm.
///
class LedDeviceWS281x : public LedDevice
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs an WS281x LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceWS281x(const QJsonObject &deviceConfig);
///
- /// Destructor of the LedDevice, waits for DMA to complete and then cleans up
+ /// @brief Destructor of the LedDevice
///
virtual ~LedDeviceWS281x() override;
- /// constructs leddevice
+ ///
+ /// @brief Destructor of the LedDevice
+ ///
static LedDevice* construct(const QJsonObject &deviceConfig);
+protected:
+
+ ///
+ /// @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;
-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:
///
- /// Writes the led color values to the led-device
+ /// @brief Closes the output device.
+ ///
+ /// @return Zero on success (i.e. device is closed), else negative
+ ///
+ virtual int close() override;
+
+ ///
+ /// @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;
private:
@@ -55,3 +68,5 @@ public slots:
RGBW::WhiteAlgorithm _whiteAlgorithm;
ColorRgbw _temp_rgbw;
};
+
+#endif // LEDEVICEWS281X_H
diff --git a/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp b/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp
index 462c3452b..f8509fa61 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp
+++ b/libsrc/leddevice/dev_serial/LedDeviceAdalight.cpp
@@ -2,13 +2,13 @@
LedDeviceAdalight::LedDeviceAdalight(const QJsonObject &deviceConfig)
: ProviderRs232()
- , _headerSize(6)
- , _ligthBerryAPA102Mode(false)
+ , _headerSize(6)
+ , _ligthBerryAPA102Mode(false)
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
- connect(this,SIGNAL(receivedData(QByteArray)),this,SLOT(receivedData(QByteArray)));
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceAdalight::construct(const QJsonObject &deviceConfig)
@@ -18,43 +18,49 @@ LedDevice* LedDeviceAdalight::construct(const QJsonObject &deviceConfig)
bool LedDeviceAdalight::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = ProviderRs232::init(deviceConfig);
+ bool isInitOK = false;
- _ligthBerryAPA102Mode = deviceConfig["lightberry_apa102_mode"].toBool(false);
+ // Initialise sub-class
+ if ( ProviderRs232::init(deviceConfig) )
+ {
- // create ledBuffer
- unsigned int totalLedCount = _ledCount;
+ _ligthBerryAPA102Mode = deviceConfig["lightberry_apa102_mode"].toBool(false);
- if (_ligthBerryAPA102Mode)
- {
- const unsigned int startFrameSize = 4;
- const unsigned int bytesPerRGBLed = 4;
- const unsigned int endFrameSize = qMax(((_ledCount + 15) / 16), bytesPerRGBLed);
- _ledBuffer.resize(_headerSize + (_ledCount * bytesPerRGBLed) + startFrameSize + endFrameSize, 0x00);
-
- // init constant data values
- for (signed iLed=1; iLed<= static_cast( _ledCount); iLed++)
+ // create ledBuffer
+ unsigned int totalLedCount = _ledCount;
+
+ if (_ligthBerryAPA102Mode)
{
- _ledBuffer[iLed*4+_headerSize] = 0xFF;
+ const unsigned int startFrameSize = 4;
+ const unsigned int bytesPerRGBLed = 4;
+ const unsigned int endFrameSize = qMax(((_ledCount + 15) / 16), bytesPerRGBLed);
+ _ledBuffer.resize(_headerSize + (_ledCount * bytesPerRGBLed) + startFrameSize + endFrameSize, 0x00);
+
+ // init constant data values
+ for (signed iLed=1; iLed<= static_cast( _ledCount); iLed++)
+ {
+ _ledBuffer[iLed*4+_headerSize] = 0xFF;
+ }
+ Debug( _log, "Adalight driver with activated LightBerry APA102 mode");
+ }
+ else
+ {
+ totalLedCount -= 1;
+ _ledBuffer.resize(_headerSize + _ledRGBCount, 0x00);
}
- Debug( _log, "Adalight driver with activated LightBerry APA102 mode");
- }
- else
- {
- totalLedCount -= 1;
- _ledBuffer.resize(_headerSize + _ledRGBCount, 0x00);
- }
- _ledBuffer[0] = 'A';
- _ledBuffer[1] = 'd';
- _ledBuffer[2] = 'a';
- _ledBuffer[3] = (totalLedCount >> 8) & 0xFF; // LED count high byte
- _ledBuffer[4] = totalLedCount & 0xFF; // LED count low byte
- _ledBuffer[5] = _ledBuffer[3] ^ _ledBuffer[4] ^ 0x55; // Checksum
+ _ledBuffer[0] = 'A';
+ _ledBuffer[1] = 'd';
+ _ledBuffer[2] = 'a';
+ _ledBuffer[3] = (totalLedCount >> 8) & 0xFF; // LED count high byte
+ _ledBuffer[4] = totalLedCount & 0xFF; // LED count low byte
+ _ledBuffer[5] = _ledBuffer[3] ^ _ledBuffer[4] ^ 0x55; // Checksum
- Debug( _log, "Adalight header for %d leds: %c%c%c 0x%02x 0x%02x 0x%02x", _ledCount,
- _ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3], _ledBuffer[4], _ledBuffer[5] );
+ Debug( _log, "Adalight header for %d leds: %c%c%c 0x%02x 0x%02x 0x%02x", _ledCount,
+ _ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3], _ledBuffer[4], _ledBuffer[5] );
+ isInitOK = true;
+ }
return isInitOK;
}
@@ -74,11 +80,8 @@ int LedDeviceAdalight::write(const std::vector & ledValues)
{
memcpy(_headerSize + _ledBuffer.data(), ledValues.data(), ledValues.size() * 3);
}
-
- return writeBytes(_ledBuffer.size(), _ledBuffer.data());
-}
-void LedDeviceAdalight::receivedData(QByteArray data)
-{
- Debug(_log, ">>received %d bytes data", data.size());
+ int rc = writeBytes(_ledBuffer.size(), _ledBuffer.data());
+
+ return rc;
}
diff --git a/libsrc/leddevice/dev_serial/LedDeviceAdalight.h b/libsrc/leddevice/dev_serial/LedDeviceAdalight.h
index 5caed855d..3812a4570 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceAdalight.h
+++ b/libsrc/leddevice/dev_serial/LedDeviceAdalight.h
@@ -1,37 +1,47 @@
-#pragma once
+#ifndef LEDEVICETADALIGHT_H
+#define LEDEVICETADALIGHT_H
// hyperion includes
#include "ProviderRs232.h"
///
-/// Implementation of the LedDevice interface for writing to an Adalight led device.
+/// Implementation of the LedDevice interface for writing to an Adalight LED-device.
///
class LedDeviceAdalight : public ProviderRs232
{
Q_OBJECT
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs an Adalight LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceAdalight(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);
- virtual bool init(const QJsonObject &deviceConfig) override;
+private:
-public slots:
- void receivedData(QByteArray data);
+ ///
+ /// @brief Initialise the device's configuration
+ ///
+ /// @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;
@@ -39,3 +49,4 @@ public slots:
bool _ligthBerryAPA102Mode;
};
+#endif // LEDEVICETADALIGHT_H
diff --git a/libsrc/leddevice/dev_serial/LedDeviceAtmo.cpp b/libsrc/leddevice/dev_serial/LedDeviceAtmo.cpp
index 7e4b91892..a9de4bd92 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceAtmo.cpp
+++ b/libsrc/leddevice/dev_serial/LedDeviceAtmo.cpp
@@ -5,9 +5,12 @@ LedDeviceAtmo::LedDeviceAtmo(const QJsonObject &deviceConfig)
: ProviderRs232()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
+
LedDevice* LedDeviceAtmo::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceAtmo(deviceConfig);
@@ -15,13 +18,13 @@ LedDevice* LedDeviceAtmo::construct(const QJsonObject &deviceConfig)
bool LedDeviceAtmo::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = ProviderRs232::init(deviceConfig);
+ bool isInitOK = false;
- if ( isInitOK )
+ // Initialise sub-class
+ if ( ProviderRs232::init(deviceConfig) )
{
if (_ledCount != 5)
{
- //Error( _log, "%d channels configured. This should always be 5!", _ledCount);
QString errortext = QString ("%1 channels configured. This should always be 5!").arg(_ledCount);
this->setInError(errortext);
isInitOK = false;
@@ -33,6 +36,8 @@ bool LedDeviceAtmo::init(const QJsonObject &deviceConfig)
_ledBuffer[1] = 0x00; // StartChannel(Low)
_ledBuffer[2] = 0x00; // StartChannel(High)
_ledBuffer[3] = 0x0F; // Number of Databytes send (always! 15)
+
+ isInitOK = true;
}
}
return isInitOK;
diff --git a/libsrc/leddevice/dev_serial/LedDeviceAtmo.h b/libsrc/leddevice/dev_serial/LedDeviceAtmo.h
index 7c662ed30..9aa13e94a 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceAtmo.h
+++ b/libsrc/leddevice/dev_serial/LedDeviceAtmo.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef LEDEVICEATMO_H
+#define LEDEVICEATMO_H
// hyperion includes
#include "ProviderRs232.h"
@@ -9,24 +10,35 @@
class LedDeviceAtmo : public ProviderRs232
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs an Atmo LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceAtmo(const QJsonObject &deviceConfig);
- /// constructs leddevice
+ ///
+ /// @brief Destructor of the LedDevice
+ ///
static LedDevice* construct(const QJsonObject &deviceConfig);
+private:
+
+ ///
+ /// @brief Initialise the device's configuration
+ ///
+ /// @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;
};
+
+#endif // LEDEVICEATMO_H
diff --git a/libsrc/leddevice/dev_serial/LedDeviceDMX.cpp b/libsrc/leddevice/dev_serial/LedDeviceDMX.cpp
index 06dfced19..db8dbf2af 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceDMX.cpp
+++ b/libsrc/leddevice/dev_serial/LedDeviceDMX.cpp
@@ -1,4 +1,5 @@
#include "LedDeviceDMX.h"
+
#include
#ifndef _WIN32
#include
@@ -13,9 +14,12 @@ LedDeviceDMX::LedDeviceDMX(const QJsonObject &deviceConfig)
, _dmxChannelCount(0)
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
+
LedDevice* LedDeviceDMX::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceDMX(deviceConfig);
@@ -23,18 +27,19 @@ LedDevice* LedDeviceDMX::construct(const QJsonObject &deviceConfig)
bool LedDeviceDMX::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = ProviderRs232::init(deviceConfig);
+ bool isInitOK = false;
- if ( isInitOK )
+ // Initialise sub-class
+ if ( ProviderRs232::init(deviceConfig) )
{
- QString dmxString = deviceConfig["dmxdevice"].toString("invalid");
- if (dmxString == "raw")
+ QString dmxTypeString = deviceConfig["dmxtype"].toString("invalid");
+ if (dmxTypeString == "raw")
{
_dmxDeviceType = 0;
_dmxStart = 1;
_dmxSlotsPerLed = 3;
}
- else if (dmxString == "McCrypt")
+ else if (dmxTypeString == "McCrypt")
{
_dmxDeviceType = 1;
_dmxStart = 1;
@@ -43,12 +48,12 @@ bool LedDeviceDMX::init(const QJsonObject &deviceConfig)
else
{
//Error(_log, "unknown dmx device type %s", QSTRING_CSTR(dmxString));
- QString errortext = QString ("unknown dmx device type: %1").arg(dmxString);
+ QString errortext = QString ("unknown dmx device type: %1").arg(dmxTypeString);
this->setInError(errortext);
return false;
}
- Debug(_log, "_dmxString \"%s\", _dmxDeviceType %d", QSTRING_CSTR(dmxString), _dmxDeviceType );
+ Debug(_log, "_dmxTypeString \"%s\", _dmxDeviceType %d", QSTRING_CSTR(dmxTypeString), _dmxDeviceType );
_rs232Port.setStopBits(QSerialPort::TwoStop);
_dmxLedCount = qMin(static_cast(_ledCount), 512/_dmxSlotsPerLed);
@@ -59,6 +64,8 @@ bool LedDeviceDMX::init(const QJsonObject &deviceConfig)
_ledBuffer.resize(_dmxChannelCount, 0);
_ledBuffer[0] = 0x00; // NULL START code
+
+ isInitOK = true;
}
return isInitOK;
}
diff --git a/libsrc/leddevice/dev_serial/LedDeviceDMX.h b/libsrc/leddevice/dev_serial/LedDeviceDMX.h
index 6bf157903..717432f6b 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceDMX.h
+++ b/libsrc/leddevice/dev_serial/LedDeviceDMX.h
@@ -1,37 +1,53 @@
-#pragma once
+#ifndef LEDEVICEDMX_H
+#define LEDEVICEDMX_H
// hyperion includes
#include "ProviderRs232.h"
///
-/// Implementation of the LedDevice interface for writing to DMX512 rs232 led device.
+/// Implementation of the LedDevice interface for writing to DMX512 rs232 LED-device.
///
class LedDeviceDMX : public ProviderRs232
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a DMX LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceDMX(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
+ ///
+ /// @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;
+
int _dmxDeviceType = 0;
int _dmxStart = 1;
int _dmxSlotsPerLed = 3;
int _dmxLedCount = 0;
unsigned int _dmxChannelCount = 0;
};
+
+#endif // LEDEVICEDMX_H
diff --git a/libsrc/leddevice/dev_serial/LedDeviceKarate.cpp b/libsrc/leddevice/dev_serial/LedDeviceKarate.cpp
index 647ac2211..e37d85077 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceKarate.cpp
+++ b/libsrc/leddevice/dev_serial/LedDeviceKarate.cpp
@@ -5,9 +5,9 @@ LedDeviceKarate::LedDeviceKarate(const QJsonObject &deviceConfig)
: ProviderRs232()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
- connect(this,SIGNAL(receivedData(QByteArray)),this,SLOT(receivedData(QByteArray)));
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceKarate::construct(const QJsonObject &deviceConfig)
@@ -17,9 +17,10 @@ LedDevice* LedDeviceKarate::construct(const QJsonObject &deviceConfig)
bool LedDeviceKarate::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = ProviderRs232::init(deviceConfig);
+ bool isInitOK = false;
- if ( isInitOK )
+ // Initialise sub-class
+ if ( ProviderRs232::init(deviceConfig) )
{
if (_ledCount != 16)
{
@@ -30,15 +31,16 @@ bool LedDeviceKarate::init(const QJsonObject &deviceConfig)
}
else
{
-
_ledBuffer.resize(4 + _ledCount * 3); // 4-byte header, 3 RGB values
- _ledBuffer[0] = 0xAA; // Startbyte
- _ledBuffer[1] = 0x12; // Send all Channels in Batch
- _ledBuffer[2] = 0x00; // Checksum
- _ledBuffer[3] = _ledCount * 3; // Number of Databytes send
+ _ledBuffer[0] = 0xAA; // Startbyte
+ _ledBuffer[1] = 0x12; // Send all Channels in Batch
+ _ledBuffer[2] = 0x00; // Checksum
+ _ledBuffer[3] = _ledCount * 3; // Number of Databytes send
Debug( _log, "Karatelight header for %d leds: 0x%02x 0x%02x 0x%02x 0x%02x", _ledCount,
_ledBuffer[0], _ledBuffer[1], _ledBuffer[2], _ledBuffer[3] );
+
+ isInitOK = true;
}
}
return isInitOK;
@@ -62,8 +64,3 @@ int LedDeviceKarate::write(const std::vector &ledValues)
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
}
-
-void LedDeviceKarate::receivedData(QByteArray data)
-{
- Debug(_log, ">>received %d bytes data %s", data.size(),data.data());
-}
diff --git a/libsrc/leddevice/dev_serial/LedDeviceKarate.h b/libsrc/leddevice/dev_serial/LedDeviceKarate.h
index b531f29c3..b09d892d7 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceKarate.h
+++ b/libsrc/leddevice/dev_serial/LedDeviceKarate.h
@@ -1,36 +1,47 @@
-#pragma once
+#ifndef LEDEVICEKARATE_H
+#define LEDEVICEKARATE_H
// hyperion includes
#include "ProviderRs232.h"
///
-/// Implementation of the LedDevice interface for writing to serial device using tpm2 protocol.
+/// Implementation of the LedDevice interface for writing to serial device
///
class LedDeviceKarate : public ProviderRs232
{
Q_OBJECT
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a Karate LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceKarate(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);
- virtual bool init(const QJsonObject &deviceConfig) override;
-
-public slots:
- void receivedData(QByteArray data);
-
private:
+
+ ///
+ /// @brief Initialise the device's configuration
+ ///
+ /// @param[in] deviceConfig the JSON device configuration
+ /// @return True, if success
///
- /// Writes the led color values to the led-device
+ virtual bool init(const QJsonObject &deviceConfig) override;
+
+ /// @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 // LEDEVICEKARATE_H
diff --git a/libsrc/leddevice/dev_serial/LedDeviceSedu.cpp b/libsrc/leddevice/dev_serial/LedDeviceSedu.cpp
index b2bcdeb38..495c78ba3 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceSedu.cpp
+++ b/libsrc/leddevice/dev_serial/LedDeviceSedu.cpp
@@ -10,7 +10,9 @@ LedDeviceSedu::LedDeviceSedu(const QJsonObject &deviceConfig)
: ProviderRs232()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceSedu::construct(const QJsonObject &deviceConfig)
@@ -20,31 +22,37 @@ LedDevice* LedDeviceSedu::construct(const QJsonObject &deviceConfig)
bool LedDeviceSedu::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = ProviderRs232::init(deviceConfig);
-
- std::vector frameSpecs{{0xA1, 256}, {0xA2, 512}, {0xB0, 768}, {0xB1, 1536}, {0xB2, 3072} };
+ bool isInitOK = false;
- for (const FrameSpec& frameSpec : frameSpecs)
+ // Initialise sub-class
+ if ( ProviderRs232::init(deviceConfig) )
{
- if ((unsigned)_ledRGBCount <= frameSpec.size)
+ std::vector frameSpecs{{0xA1, 256}, {0xA2, 512}, {0xB0, 768}, {0xB1, 1536}, {0xB2, 3072} };
+
+ for (const FrameSpec& frameSpec : frameSpecs)
{
- _ledBuffer.clear();
- _ledBuffer.resize(frameSpec.size + 3, 0);
- _ledBuffer[0] = 0x5A;
- _ledBuffer[1] = frameSpec.id;
- _ledBuffer.back() = 0xA5;
- break;
+ if ((unsigned)_ledRGBCount <= frameSpec.size)
+ {
+ _ledBuffer.clear();
+ _ledBuffer.resize(frameSpec.size + 3, 0);
+ _ledBuffer[0] = 0x5A;
+ _ledBuffer[1] = frameSpec.id;
+ _ledBuffer.back() = 0xA5;
+ break;
+ }
}
- }
- if (_ledBuffer.size() == 0)
- {
- //Warning(_log, "More rgb-channels required then available");
- QString errortext = "More rgb-channels required then available";
- this->setInError(errortext);
- isInitOK = false;
+ if (_ledBuffer.empty())
+ {
+ //Warning(_log, "More rgb-channels required then available");
+ QString errortext = "More rgb-channels required then available";
+ this->setInError(errortext);
+ }
+ else
+ {
+ isInitOK = true;
+ }
}
-
return isInitOK;
}
diff --git a/libsrc/leddevice/dev_serial/LedDeviceSedu.h b/libsrc/leddevice/dev_serial/LedDeviceSedu.h
index 2ceced2bd..f59da2f29 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceSedu.h
+++ b/libsrc/leddevice/dev_serial/LedDeviceSedu.h
@@ -1,32 +1,47 @@
-#pragma once
+#ifndef LEDEVICESEDU_H
+#define LEDEVICESEDU_H
// hyperion includes
#include "ProviderRs232.h"
///
-/// Implementation of the LedDevice interface for writing to SEDU led device.
+/// Implementation of the LedDevice interface for writing to SEDU LED-device.
///
class LedDeviceSedu : public ProviderRs232
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a SEDU LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceSedu(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);
-
- virtual bool init(const QJsonObject &deviceConfig) override;
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 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;
};
+
+#endif // LEDEVICESEDU_H
diff --git a/libsrc/leddevice/dev_serial/LedDeviceTpm2.cpp b/libsrc/leddevice/dev_serial/LedDeviceTpm2.cpp
index d9668ec38..a29aac3ce 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceTpm2.cpp
+++ b/libsrc/leddevice/dev_serial/LedDeviceTpm2.cpp
@@ -5,9 +5,12 @@ LedDeviceTpm2::LedDeviceTpm2(const QJsonObject &deviceConfig)
: ProviderRs232()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
+
LedDevice* LedDeviceTpm2::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceTpm2(deviceConfig);
@@ -15,15 +18,21 @@ LedDevice* LedDeviceTpm2::construct(const QJsonObject &deviceConfig)
bool LedDeviceTpm2::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = ProviderRs232::init(deviceConfig);
+ bool isInitOK = false;
+
+ // Initialise sub-class
+ if ( ProviderRs232::init(deviceConfig) )
+ {
- _ledBuffer.resize(5 + _ledRGBCount);
- _ledBuffer[0] = 0xC9; // block-start byte
- _ledBuffer[1] = 0xDA; // DATA frame
- _ledBuffer[2] = (_ledRGBCount >> 8) & 0xFF; // frame size high byte
- _ledBuffer[3] = _ledRGBCount & 0xFF; // frame size low byte
- _ledBuffer.back() = 0x36; // block-end byte
+ _ledBuffer.resize(5 + _ledRGBCount);
+ _ledBuffer[0] = 0xC9; // block-start byte
+ _ledBuffer[1] = 0xDA; // DATA frame
+ _ledBuffer[2] = (_ledRGBCount >> 8) & 0xFF; // frame size high byte
+ _ledBuffer[3] = _ledRGBCount & 0xFF; // frame size low byte
+ _ledBuffer.back() = 0x36; // block-end byte
+ isInitOK = true;
+ }
return isInitOK;
}
diff --git a/libsrc/leddevice/dev_serial/LedDeviceTpm2.h b/libsrc/leddevice/dev_serial/LedDeviceTpm2.h
index 55b9e613c..a53b0a66c 100644
--- a/libsrc/leddevice/dev_serial/LedDeviceTpm2.h
+++ b/libsrc/leddevice/dev_serial/LedDeviceTpm2.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef LEDEVICETPM2_H
+#define LEDEVICETPM2_H
// hyperion includes
#include "ProviderRs232.h"
@@ -9,24 +10,38 @@
class LedDeviceTpm2 : public ProviderRs232
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a TPM 2 LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceTpm2(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
+ ///
+ /// @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;
};
+
+#endif // LEDEVICETPM2_H
diff --git a/libsrc/leddevice/dev_serial/ProviderRs232.cpp b/libsrc/leddevice/dev_serial/ProviderRs232.cpp
index 711a53539..5a89c8487 100644
--- a/libsrc/leddevice/dev_serial/ProviderRs232.cpp
+++ b/libsrc/leddevice/dev_serial/ProviderRs232.cpp
@@ -1,290 +1,295 @@
-// STL includes
-#include
-#include
-
-// Qt includes
-#include
-#include
-#include
+// LedDevice includes
+#include
+#include "ProviderRs232.h"
+
+// qt includes
#include
+#include
-// Local Hyperion includes
-#include "ProviderRs232.h"
+// Constants
+const int WRITE_TIMEOUT = 1000; // device write timeout in ms
+const int OPEN_TIMEOUT = 5000; // device open timeout in ms
+const int MAX_WRITE_TIMEOUTS = 5; // maximum number of allowed timeouts
+
+const int NUM_POWEROFF_WRITE_BLACK = 2; // Number of write "BLACK" during powering off
ProviderRs232::ProviderRs232()
: _rs232Port(this)
- , _writeTimeout(this)
- , _blockedForDelay(false)
- , _stateChanged(true)
- , _bytesToWrite(0)
- , _frameDropCounter(0)
- , _lastError(QSerialPort::NoError)
- , _preOpenDelayTimeOut(0)
- , _preOpenDelay(2000)
- , _enableAutoDeviceName(false)
+ ,_baudRate_Hz(1000000)
+ ,_isAutoDeviceName(false)
+ ,_delayAfterConnect_ms(0)
+ ,_frameDropCounter(0)
{
- connect(&_rs232Port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(error(QSerialPort::SerialPortError)));
- connect(&_rs232Port, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
- connect(&_rs232Port, SIGNAL(readyRead()), this, SLOT(readyRead()));
-
- _writeTimeout.setInterval(5000);
- _writeTimeout.setSingleShot(true);
- connect(&_writeTimeout, SIGNAL(timeout()), this, SLOT(writeTimeout()));
}
bool ProviderRs232::init(const QJsonObject &deviceConfig)
{
- closeDevice();
+ bool isInitOK = false;
- bool isInitOK = LedDevice::init(deviceConfig);
+ // Initialise sub-class
+ if ( LedDevice::init(deviceConfig) )
+ {
- _deviceName = deviceConfig["output"].toString("auto");
- _enableAutoDeviceName = _deviceName == "auto";
- _baudRate_Hz = deviceConfig["rate"].toInt();
- _delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(1500);
- _preOpenDelay = deviceConfig["delayBeforeConnect"].toInt(1500);
+ Debug(_log, "DeviceType : %s", QSTRING_CSTR( this->getActiveDeviceType() ));
+ Debug(_log, "LedCount : %u", this->getLedCount());
+ Debug(_log, "ColorOrder : %s", QSTRING_CSTR( this->getColorOrder() ));
+ Debug(_log, "RefreshTime : %d", _refreshTimerInterval_ms);
+ Debug(_log, "LatchTime : %d", this->getLatchTime());
- return isInitOK;
-}
+ _deviceName = deviceConfig["output"].toString("auto");
+ // If device name was given as unix /dev/ system-location, get port name
+ if ( _deviceName.startsWith(QLatin1String("/dev/")) )
+ _deviceName = _deviceName.mid(5);
-void ProviderRs232::close()
-{
- LedDevice::close();
+ _isAutoDeviceName = _deviceName.toLower() == "auto";
+ _baudRate_Hz = deviceConfig["rate"].toInt();
+ _delayAfterConnect_ms = deviceConfig["delayAfterConnect"].toInt(1500);
- // LedDevice specific closing activites
- closeDevice();
-}
+ Debug(_log, "deviceName : %s", QSTRING_CSTR(_deviceName));
+ Debug(_log, "AutoDevice : %d", _isAutoDeviceName);
+ Debug(_log, "baudRate_Hz : %d", _baudRate_Hz);
+ Debug(_log, "delayAfCon ms: %d", _delayAfterConnect_ms);
-QString ProviderRs232::findSerialDevice()
-{
- // take first available usb serial port - currently no probing!
- for( auto port : QSerialPortInfo::availablePorts())
- {
- if (port.hasProductIdentifier() && port.hasVendorIdentifier() && !port.isBusy())
- {
- Info(_log, "found serial device: %s", port.systemLocation().toLocal8Bit().constData());
- return port.systemLocation();
- }
+ isInitOK = true;
}
- return "";
+ return isInitOK;
}
-void ProviderRs232::bytesWritten(qint64 bytes)
+ProviderRs232::~ProviderRs232()
{
- _bytesToWrite -= bytes;
- if (_bytesToWrite <= 0)
- {
- _blockedForDelay = false;
- _writeTimeout.stop();
- }
}
-
-void ProviderRs232::readyRead()
+int ProviderRs232::open()
{
- emit receivedData(_rs232Port.readAll());
- //Debug(_log, "received data");
-}
-
+ int retval = -1;
+ _isDeviceReady = false;
+ _isInSwitchOff = false;
-void ProviderRs232::error(QSerialPort::SerialPortError error)
-{
- if ( error != QSerialPort::NoError )
+ // open device physically
+ if ( tryOpen(_delayAfterConnect_ms) )
{
- if (_lastError != error)
- {
- _lastError = error;
- switch (error)
- {
- case QSerialPort::DeviceNotFoundError:
- Error(_log, "An error occurred while attempting to open an non-existing device."); break;
- case QSerialPort::PermissionError:
- Error(_log, "An error occurred while attempting to open an already opened device by another process or a user not having enough permission and credentials to open. Device disabled.");
- _deviceReady = false;
- break;
- case QSerialPort::OpenError:
- Error(_log, "An error occurred while attempting to open an already opened device in this object."); break;
- case QSerialPort::NotOpenError:
- Error(_log, "This error occurs when an operation is executed that can only be successfully performed if the device is open."); break;
- case QSerialPort::ParityError:
- Error(_log, "Parity error detected by the hardware while reading data."); break;
- case QSerialPort::FramingError:
- Error(_log, "Framing error detected by the hardware while reading data."); break;
- case QSerialPort::BreakConditionError:
- Error(_log, "Break condition detected by the hardware on the input line."); break;
- case QSerialPort::WriteError:
- Error(_log, "An I/O error occurred while writing the data."); break;
- case QSerialPort::ReadError:
- Error(_log, "An I/O error occurred while reading the data."); break;
- case QSerialPort::ResourceError:
- Error(_log, "An I/O error occurred when a resource becomes unavailable, e.g. when the device is unexpectedly removed from the system."); break;
- case QSerialPort::UnsupportedOperationError:
- Error(_log, "The requested device operation is not supported or prohibited by the running operating system. Device disabled.");
- _deviceReady = false;
- break;
- case QSerialPort::TimeoutError:
- Error(_log, "A timeout error occurred."); break;
- default:
- Error(_log,"An unidentified error occurred. Device disabled. (%d)", error);
- _deviceReady = false;
- }
- _rs232Port.clearError();
- this->setInError( "Rs232 SerialPortError, see details in previous log lines!" );
- closeDevice();
- }
+ // Everything is OK, device is ready
+ _isDeviceReady = true;
+ retval = 0;
}
+ return retval;
}
-ProviderRs232::~ProviderRs232()
+int ProviderRs232::close()
{
- disconnect(&_rs232Port, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(error(QSerialPort::SerialPortError)));
-}
+ int retval = 0;
-void ProviderRs232::closeDevice()
-{
- _writeTimeout.stop();
+ _isDeviceReady = false;
+ // Test, if device requires closing
if (_rs232Port.isOpen())
{
+ if ( _rs232Port.flush() )
+ {
+ Debug(_log,"Flush was successful");
+ }
+ Debug(_log,"Close UART: %s", QSTRING_CSTR(_deviceName) );
_rs232Port.close();
- Debug(_log,"Close UART: %s", _deviceName.toLocal8Bit().constData());
+ // Everything is OK -> device is closed
}
-
- _stateChanged = true;
- _bytesToWrite = 0;
- _blockedForDelay = false;
- _deviceReady = false;
+ return retval;
}
-int ProviderRs232::open()
+bool ProviderRs232::powerOff()
{
- int retval = -1;
- _deviceReady = false;
-
- // General initialisation and configuration of LedDevice
- if ( init(_devConfig) )
+ // Simulate power-off by writing a final "Black" to have a defined outcome
+ bool rc = false;
+ if ( writeBlack( NUM_POWEROFF_WRITE_BLACK ) >= 0 )
{
- if ( tryOpen(_delayAfterConnect_ms) )
- {
- // Everything is OK -> enable device
- _deviceReady = true;
- setEnable(true);
- retval = 0;
- }
- else
- {
- this->setInError( "Error opening device!" );
- }
-
+ rc = true;
}
- return retval;
+ return rc;
}
bool ProviderRs232::tryOpen(const int delayAfterConnect_ms)
{
if (_deviceName.isEmpty() || _rs232Port.portName().isEmpty())
{
- if ( _enableAutoDeviceName )
+ if (!_rs232Port.isOpen())
{
- _deviceName = findSerialDevice();
- if ( _deviceName.isEmpty() )
+ if ( _isAutoDeviceName )
{
- return false;
+ _deviceName = discoverFirst();
+ if (_deviceName.isEmpty())
+ {
+ this->setInError( QString("No serial device found automatically!") );
+ return false;
+ }
}
}
- Info(_log, "Opening UART: %s", _deviceName.toLocal8Bit().constData());
+
_rs232Port.setPortName(_deviceName);
}
- if ( ! _rs232Port.isOpen() )
+ if (!_rs232Port.isOpen())
{
+ Info(_log, "Opening UART: %s", QSTRING_CSTR(_deviceName));
+
_frameDropCounter = 0;
+ _rs232Port.setBaudRate( _baudRate_Hz );
+
+ Debug(_log, "_rs232Port.open(QIODevice::WriteOnly): %s, Baud rate [%d]bps", QSTRING_CSTR(_deviceName), _baudRate_Hz);
+
QSerialPortInfo serialPortInfo(_deviceName);
- if (! serialPortInfo.isNull())
+
+ QJsonObject portInfo;
+ Debug(_log, "portName: %s", QSTRING_CSTR(serialPortInfo.portName()));
+ Debug(_log, "systemLocation: %s", QSTRING_CSTR(serialPortInfo.systemLocation()));
+ Debug(_log, "description: %s", QSTRING_CSTR(serialPortInfo.description()));
+ Debug(_log, "manufacturer: %s", QSTRING_CSTR(serialPortInfo.manufacturer()));
+ Debug(_log, "productIdentifier: %s", QSTRING_CSTR(QString("0x%1").arg(serialPortInfo.productIdentifier(), 0, 16)));
+ Debug(_log, "vendorIdentifier: %s", QSTRING_CSTR(QString("0x%1").arg(serialPortInfo.vendorIdentifier(), 0, 16)));
+ Debug(_log, "serialNumber: %s", QSTRING_CSTR(serialPortInfo.serialNumber()));
+
+ if (!serialPortInfo.isNull() )
{
- if ( _preOpenDelayTimeOut > QDateTime::currentMSecsSinceEpoch() )
- {
- return false;
- }
- if ( ! _rs232Port.open(QIODevice::ReadWrite) )
+ if ( !_rs232Port.open(QIODevice::WriteOnly) )
{
- if ( _stateChanged )
- {
- Error(_log, "Unable to open RS232 device (%s)", _deviceName.toLocal8Bit().constData());
- _stateChanged = false;
- }
+ this->setInError(_rs232Port.errorString());
return false;
}
- Debug(_log, "Setting baud rate to %d", _baudRate_Hz);
- _rs232Port.setBaudRate(_baudRate_Hz);
- _stateChanged = true;
- _preOpenDelayTimeOut = 0;
}
else
{
QString errortext = QString("Invalid serial device name: [%1]!").arg(_deviceName);
- this->setInError(errortext);
- _preOpenDelayTimeOut = QDateTime::currentMSecsSinceEpoch() + _preOpenDelay;
+ this->setInError( errortext );
return false;
}
}
if (delayAfterConnect_ms > 0)
{
- _blockedForDelay = true;
- QTimer::singleShot(delayAfterConnect_ms, this, SLOT(unblockAfterDelay()));
- Debug(_log, "Device blocked for %d ms", delayAfterConnect_ms);
+
+ Debug(_log, "delayAfterConnect for %d ms - start", delayAfterConnect_ms);
+
+ // Wait delayAfterConnect_ms before allowing write
+ QEventLoop loop;
+ QTimer::singleShot( delayAfterConnect_ms, &loop, SLOT( quit() ) );
+ loop.exec();
+
+ Debug(_log, "delayAfterConnect for %d ms - finished", delayAfterConnect_ms);
}
return _rs232Port.isOpen();
}
+void ProviderRs232::setInError(const QString& errorMsg)
+{
+ _rs232Port.clearError();
+ this->close();
-int ProviderRs232::writeBytes(const qint64 size, const uint8_t * data)
+ LedDevice::setInError( errorMsg );
+}
+
+int ProviderRs232::writeBytes(const qint64 size, const uint8_t *data)
{
- if (! _blockedForDelay)
+ DebugIf(_isInSwitchOff, _log, "_inClosing [%d], enabled [%d], _deviceReady [%d], _frameDropCounter [%d]", _isInSwitchOff, this->isEnabled(), _isDeviceReady, _frameDropCounter);
+
+ int rc = 0;
+ if (!_rs232Port.isOpen())
{
- if (!_rs232Port.isOpen())
- {
- return tryOpen(5000) ? 0 : -1;
- }
+ Debug(_log, "!_rs232Port.isOpen()");
- if (_frameDropCounter > 5)
+ if ( !tryOpen(OPEN_TIMEOUT) )
{
- Debug(_log, "%d frames dropped", _frameDropCounter);
- }
- _frameDropCounter = 0;
- _blockedForDelay = true;
- _bytesToWrite = size;
- qint64 bytesWritten = _rs232Port.write(reinterpret_cast(data), size);
- if (bytesWritten == -1 || bytesWritten != size)
- {
- Warning(_log,"failed writing data");
- QTimer::singleShot(500, this, SLOT(unblockAfterDelay()));
return -1;
}
- _writeTimeout.start();
+ }
+
+ DebugIf( _isInSwitchOff, _log, "[%s]", QSTRING_CSTR(uint8_t_to_hex_string(data, size, 32)) );
+
+ qint64 bytesWritten = _rs232Port.write(reinterpret_cast(data), size);
+ if (bytesWritten == -1 || bytesWritten != size)
+ {
+ this->setInError( QString ("Rs232 SerialPortError: %1").arg(_rs232Port.errorString()) );
+ rc = -1;
}
else
{
- _frameDropCounter++;
+ if (!_rs232Port.waitForBytesWritten(WRITE_TIMEOUT))
+ {
+ if ( _rs232Port.error() == QSerialPort::TimeoutError )
+ {
+ Debug(_log, "Timeout after %dms: %d frames already dropped", WRITE_TIMEOUT, _frameDropCounter);
+
+ ++_frameDropCounter;
+
+ // Check,if number of timeouts in a given time frame is greater than defined
+ // TODO: ProviderRs232::writeBytes - Add time frame to check for timeouts that devices does not close after absolute number of timeouts
+ if ( _frameDropCounter > MAX_WRITE_TIMEOUTS )
+ {
+ this->setInError( QString ("Timeout writing data to %1").arg(_deviceName) );
+ rc = -1;
+ }
+ else
+ {
+ //give it another try
+ _rs232Port.clearError();
+ }
+ }
+ else
+ {
+ this->setInError( QString ("Rs232 SerialPortError: %1").arg(_rs232Port.errorString()) );
+ rc = -1;
+ }
+ }
+ else
+ {
+ DebugIf(_isInSwitchOff,_log, "In Closing: bytesWritten [%d], _rs232Port.error() [%d], %s", bytesWritten, _rs232Port.error(), _rs232Port.error() == QSerialPort::NoError ? "No Error" : QSTRING_CSTR(_rs232Port.errorString()) );
+ }
}
- return 0;
+ DebugIf(_isInSwitchOff, _log, "[%d], _inClosing[%d], enabled [%d], _deviceReady [%d]", rc, _isInSwitchOff, this->isEnabled(), _isDeviceReady);
+ return rc;
}
-void ProviderRs232::writeTimeout()
+QString ProviderRs232::discoverFirst()
{
- //Error(_log, "Timeout on write data to %s", _deviceName.toLocal8Bit().constData());
- QString errortext = QString ("Timeout on write data to %1").arg(_deviceName);
- setInError( errortext );
- close();
+ // take first available USB serial port - currently no probing!
+ for (auto const & port : QSerialPortInfo::availablePorts())
+ {
+ if (!port.isNull() && !port.isBusy())
+ {
+ Info(_log, "found serial device: %s", QSTRING_CSTR(port.portName()));
+ return port.portName();
+ }
+ }
+ return "";
}
-void ProviderRs232::unblockAfterDelay()
+QJsonObject ProviderRs232::discover()
{
- _blockedForDelay = false;
+ QJsonObject devicesDiscovered;
+ devicesDiscovered.insert("ledDeviceType", _activeDeviceType );
+
+ QJsonArray deviceList;
+
+ // Discover serial Devices
+ for (auto &port : QSerialPortInfo::availablePorts() )
+ {
+ if ( !port.isNull() )
+ {
+ QJsonObject portInfo;
+ portInfo.insert("description", port.description());
+ portInfo.insert("manufacturer", port.manufacturer());
+ portInfo.insert("portName", port.portName());
+ portInfo.insert("productIdentifier", QString("0x%1").arg(port.productIdentifier(), 0, 16));
+ portInfo.insert("serialNumber", port.serialNumber());
+ portInfo.insert("systemLocation", port.systemLocation());
+ portInfo.insert("vendorIdentifier", QString("0x%1").arg(port.vendorIdentifier(), 0, 16));
+
+ deviceList.append(portInfo);
+ }
+ }
+
+ devicesDiscovered.insert("devices", deviceList);
+ return devicesDiscovered;
}
diff --git a/libsrc/leddevice/dev_serial/ProviderRs232.h b/libsrc/leddevice/dev_serial/ProviderRs232.h
index 36b454a36..069c274f9 100644
--- a/libsrc/leddevice/dev_serial/ProviderRs232.h
+++ b/libsrc/leddevice/dev_serial/ProviderRs232.h
@@ -1,13 +1,12 @@
-#pragma once
-
-#include
-#include
-#include
-#include
+#ifndef PROVIDERRS232_H
+#define PROVIDERRS232_H
// LedDevice includes
#include
+// qt includes
+#include
+
///
/// The ProviderRs232 implements an abstract base-class for LedDevices using a RS232-device.
///
@@ -16,91 +15,106 @@ class ProviderRs232 : public LedDevice
Q_OBJECT
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a RS232 LED-device
///
ProviderRs232();
///
- /// Sets configuration
+ /// @brief Destructor of the UDP LED-device
///
- /// @param deviceConfig the json device config
- /// @return true if success
- virtual bool init(const QJsonObject &deviceConfig) override;
+ virtual ~ProviderRs232() override;
+
+protected:
///
- /// Destructor of the LedDevice; closes the output device if it is open
+ /// @brief Initialise the RS232 device's configuration and network address details
///
- virtual ~ProviderRs232() 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
///
- int open() override;
+ virtual int open() override;
-public slots:
///
- /// Closes the output device.
- /// Includes switching-off the device and stopping refreshes
+ /// @brief Closes the UDP device.
+ ///
+ /// @return Zero on success (i.e. device is closed), else negative
///
- virtual void close() override;
+ virtual int close() override;
-private slots:
+ ///
+ /// @brief Power-/turn off a RS232-device
+ ///
+ /// The off-state is simulated by writing "Black to LED"
+ ///
+ /// @return True, if success
+ ///
+ virtual bool powerOff() override;
- /// Unblock the device after a connection delay
- void writeTimeout();
- void unblockAfterDelay();
- void error(QSerialPort::SerialPortError setInError);
- void bytesWritten(qint64 bytes);
- void readyRead();
+ ///
+ /// @brief Discover first devices of a serial device available (for configuration)
+ ///
+ /// @return A string of the device found
+ ///
+ virtual QString discoverFirst() override;
-signals:
- void receivedData(QByteArray data);
+ ///
+ /// @brief Discover RS232 serial devices available (for configuration).
+ ///
+ /// @return A JSON structure holding a list of devices found
+ ///
+ virtual QJsonObject discover() override;
-protected:
- /**
- * Writes the given bytes to the RS232-device and
- *
- * @param[in[ size The length of the data
- * @param[in] data The data
- *
- * @return Zero on success else negative
- */
+ ///
+ /// @brief Write the given bytes to the RS232-device
+ ///
+ /// @param[in[ size The length of the data
+ /// @param[in] data The data
+ /// @return Zero on success, else negative
+ ///
int writeBytes(const qint64 size, const uint8_t *data);
- void closeDevice();
+ /// The name of the output device
+ QString _deviceName;
+ /// The RS232 serial-device
+ QSerialPort _rs232Port;
+ /// The used baud-rate of the output device
+ qint32 _baudRate_Hz;
- QString findSerialDevice();
+protected slots:
- // tries to open device if not opened
- bool tryOpen(const int delayAfterConnect_ms);
+ ///
+ /// @brief Set device in error state
+ ///
+ /// @param errorMsg The error message to be logged
+ ///
+ virtual void setInError( const QString& errorMsg) override;
+private:
- /// The name of the output device
- QString _deviceName;
+ ///
+ /// @brief Try to open device if not opened
+ ///
+ /// @return True,if on success
+ ///
+ bool tryOpen(const int delayAfterConnect_ms);
- /// The used baudrate of the output device
- qint32 _baudRate_Hz;
+ /// Try to auto-discover device name?
+ bool _isAutoDeviceName;
/// Sleep after the connect before continuing
int _delayAfterConnect_ms;
- /// The RS232 serial-device
- QSerialPort _rs232Port;
-
- /// A timeout timer for the asynchronous connection
- QTimer _writeTimeout;
-
- bool _blockedForDelay;
-
- bool _stateChanged;
-
- qint64 _bytesToWrite;
- qint64 _frameDropCounter;
- QSerialPort::SerialPortError _lastError;
- qint64 _preOpenDelayTimeOut;
- int _preOpenDelay;
- bool _enableAutoDeviceName;
+ /// Frames dropped, as write failed
+ int _frameDropCounter;
};
+
+#endif // PROVIDERRS232_H
diff --git a/libsrc/leddevice/dev_spi/LedDeviceAPA102.cpp b/libsrc/leddevice/dev_spi/LedDeviceAPA102.cpp
index b2ad5de05..084d6ab95 100644
--- a/libsrc/leddevice/dev_spi/LedDeviceAPA102.cpp
+++ b/libsrc/leddevice/dev_spi/LedDeviceAPA102.cpp
@@ -4,7 +4,9 @@ LedDeviceAPA102::LedDeviceAPA102(const QJsonObject &deviceConfig)
: ProviderSpi()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceAPA102::construct(const QJsonObject &deviceConfig)
@@ -14,10 +16,12 @@ LedDevice* LedDeviceAPA102::construct(const QJsonObject &deviceConfig)
bool LedDeviceAPA102::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = ProviderSpi::init(deviceConfig);
+ bool isInitOK = false;
- if ( isInitOK )
+ // Initialise sub-class
+ if ( ProviderSpi::init(deviceConfig) )
{
+
const unsigned int startFrameSize = 4;
const unsigned int endFrameSize = qMax(((_ledCount + 15) / 16), 4);
const unsigned int APAbufferSize = (_ledCount * 4) + startFrameSize + endFrameSize;
@@ -27,6 +31,9 @@ bool LedDeviceAPA102::init(const QJsonObject &deviceConfig)
_ledBuffer[1] = 0x00;
_ledBuffer[2] = 0x00;
_ledBuffer[3] = 0x00;
+
+ isInitOK = true;
+
}
return isInitOK;
}
diff --git a/libsrc/leddevice/dev_spi/LedDeviceAPA102.h b/libsrc/leddevice/dev_spi/LedDeviceAPA102.h
index 3e0485381..527a2114b 100644
--- a/libsrc/leddevice/dev_spi/LedDeviceAPA102.h
+++ b/libsrc/leddevice/dev_spi/LedDeviceAPA102.h
@@ -1,4 +1,5 @@
-#pragma once
+#ifndef LEDEVICEAPA102_H
+#define LEDEVICEAPA102_H
// hyperion includes
#include "ProviderSpi.h"
@@ -9,26 +10,39 @@
class LedDeviceAPA102 : public ProviderSpi
{
public:
+
+ ///
+ /// @brief Constructs an APA102 LED-device
///
- /// Constructs specific LedDevice
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceAPA102(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;
};
+
+#endif // LEDEVICEAPA102_H
diff --git a/libsrc/leddevice/dev_spi/LedDeviceAPA104.cpp b/libsrc/leddevice/dev_spi/LedDeviceAPA104.cpp
index a273de880..2ad830a7e 100644
--- a/libsrc/leddevice/dev_spi/LedDeviceAPA104.cpp
+++ b/libsrc/leddevice/dev_spi/LedDeviceAPA104.cpp
@@ -46,9 +46,12 @@ LedDeviceAPA104::LedDeviceAPA104(const QJsonObject &deviceConfig)
}
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
+
LedDevice* LedDeviceAPA104::construct(const QJsonObject &deviceConfig)
{
return new LedDeviceAPA104(deviceConfig);
@@ -58,12 +61,16 @@ bool LedDeviceAPA104::init(const QJsonObject &deviceConfig)
{
_baudRate_Hz = 2235000;
- bool isInitOK = ProviderSpi::init(deviceConfig);
- if ( isInitOK )
+ bool isInitOK = false;
+
+ // Initialise sub-class
+ if ( ProviderSpi::init(deviceConfig) )
{
WarningIf(( _baudRate_Hz < 2000000 || _baudRate_Hz > 2470000 ), _log, "SPI rate %d outside recommended range (2000000 -> 2470000)", _baudRate_Hz);
_ledBuffer.resize(_ledRGBCount * SPI_BYTES_PER_COLOUR + SPI_FRAME_END_LATCH_BYTES, 0x00);
+
+ isInitOK = true;
}
return isInitOK;
}
diff --git a/libsrc/leddevice/dev_spi/LedDeviceAPA104.h b/libsrc/leddevice/dev_spi/LedDeviceAPA104.h
index b4ecd3b95..2c70494b1 100644
--- a/libsrc/leddevice/dev_spi/LedDeviceAPA104.h
+++ b/libsrc/leddevice/dev_spi/LedDeviceAPA104.h
@@ -1,6 +1,7 @@
-#pragma once
+#ifndef LEDEVICEAPA104_H
+#define LEDEVICEAPA104_H
-// hyperion inclusdes
+// hyperion includes
#include "ProviderSpi.h"
///
@@ -9,34 +10,43 @@
class LedDeviceAPA104 : public ProviderSpi
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs an APA104 LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceAPA104(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;
const int SPI_BYTES_PER_COLOUR;
const int SPI_FRAME_END_LATCH_BYTES;
uint8_t bitpair_to_byte[4];
};
+
+#endif // LEDEVICEAPA104_H
diff --git a/libsrc/leddevice/dev_spi/LedDeviceLpd6803.cpp b/libsrc/leddevice/dev_spi/LedDeviceLpd6803.cpp
index 0d5f3c6dc..8fa1ebca2 100644
--- a/libsrc/leddevice/dev_spi/LedDeviceLpd6803.cpp
+++ b/libsrc/leddevice/dev_spi/LedDeviceLpd6803.cpp
@@ -4,7 +4,9 @@ LedDeviceLpd6803::LedDeviceLpd6803(const QJsonObject &deviceConfig)
: ProviderSpi()
{
_devConfig = deviceConfig;
- _deviceReady = false;
+ _isDeviceReady = false;
+
+ _activeDeviceType = deviceConfig["type"].toString("UNSPECIFIED").toLower();
}
LedDevice* LedDeviceLpd6803::construct(const QJsonObject &deviceConfig)
@@ -14,12 +16,16 @@ LedDevice* LedDeviceLpd6803::construct(const QJsonObject &deviceConfig)
bool LedDeviceLpd6803::init(const QJsonObject &deviceConfig)
{
- bool isInitOK = ProviderSpi::init(deviceConfig);
- if ( isInitOK )
+ bool isInitOK = false;
+
+ // Initialise sub-class
+ if ( ProviderSpi::init(deviceConfig) )
{
unsigned messageLength = 4 + 2*_ledCount + _ledCount/8 + 1;
// Initialise the buffer
_ledBuffer.resize(messageLength, 0x00);
+
+ isInitOK = true;
}
return isInitOK;
}
diff --git a/libsrc/leddevice/dev_spi/LedDeviceLpd6803.h b/libsrc/leddevice/dev_spi/LedDeviceLpd6803.h
index c9ab7d490..65a117413 100644
--- a/libsrc/leddevice/dev_spi/LedDeviceLpd6803.h
+++ b/libsrc/leddevice/dev_spi/LedDeviceLpd6803.h
@@ -1,45 +1,55 @@
-#pragma once
+#ifndef LEDEVICELPD6803_H
+#define LEDEVICELPD6803_H
// Local hyperion includes
#include "ProviderSpi.h"
///
-/// Implementation of the LedDevice interface for writing to LDP6803 led device.
+/// Implementation of the LedDevice interface for writing to LDP6803 LED-device.
///
/// 00000000 00000000 00000000 00000000 1RRRRRGG GGGBBBBB 1RRRRRGG GGGBBBBB ...
/// |---------------------------------| |---------------| |---------------|
-/// 32 zeros to start the frame Led1 Led2 ...
+/// 32 zeros to start the frame LED1 LED2 ...
///
/// For each led, the first bit is always 1, and then you have 5 bits each for red, green and blue
-/// (R, G and B in the above illustration) making 16 bits per led. Total bytes = 4 + (2 x number of
-/// leds)
+/// (R, G and B in the above illustration) making 16 bits per led. Total bytes = 4 + (2 x number of LEDs)
///
class LedDeviceLpd6803 : public ProviderSpi
{
public:
+
///
- /// Constructs specific LedDevice
+ /// @brief Constructs a LDP6803 LED-device
///
- /// @param deviceConfig json device config
+ /// @param deviceConfig Device's configuration as JSON-Object
///
explicit LedDeviceLpd6803(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