From c421035e17308de446c94ee7da8a060864474d2c Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Tue, 25 Oct 2022 22:03:25 +0200 Subject: [PATCH] v3.5.0 - Upgrade - Add Backgroundcolor to Pages - Add Tilt-Slider and TILT_Fucntions (Open/Stop/Close) to Blinds/Cover/Shutter popUp - Add PageNavigation via Datapoint - Add New Parameters to popUpNotify / Layout 2 --- ioBroker/NsPanelTs_without_Examples.ts | 4292 ++++++++++++++++++++++++ 1 file changed, 4292 insertions(+) create mode 100644 ioBroker/NsPanelTs_without_Examples.ts diff --git a/ioBroker/NsPanelTs_without_Examples.ts b/ioBroker/NsPanelTs_without_Examples.ts new file mode 100644 index 00000000..ae164f1b --- /dev/null +++ b/ioBroker/NsPanelTs_without_Examples.ts @@ -0,0 +1,4292 @@ +/*----------------------------------------------------------------------- +TypeScript v3.5.0 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar/@Britzelpuf +- abgestimmt auf TFT 43 / v3.5.0 / BerryDriver 4 / Tasmota 12.2.0 +@joBr99 Projekt: https://github.com/joBr99/nspanel-lovelace-ui/tree/main/ioBroker + +NsPanelTs.ts (dieses TypeScript in ioBroker) Stable: https://github.com/joBr99/nspanel-lovelace-ui/blob/main/ioBroker/NsPanelTs.ts +icon_mapping.ts: https://github.com/joBr99/nspanel-lovelace-ui/blob/main/ioBroker/icon_mapping.ts (TypeScript muss in global liegen) + +ioBroker-Unterstützung: https://forum.iobroker.net/topic/50888/sonoff-nspanel +WIKI zu diesem Projekt unter: https://github.com/joBr99/nspanel-lovelace-ui/wiki (siehe Sidebar) +Icons unter: https://htmlpreview.github.io/?https://github.com/jobr99/Generate-HASP-Fonts/blob/master/cheatsheet.html + +******************************************************************************* +Achtung Änderung des Sonoff ESP-Temperatursensors +!!! Bitte "SetOption146 1" in der Tasmota-Console ausführen !!! +******************************************************************************* + +ReleaseNotes: + Bugfixes und Erweiterungen: + - cardQR (für Gäste WLAN) + - cardThermo (Neues Design für Alias Thermostat und zusätzlich für Alias Klimaanlage) + - 08.05.2022 - v2.9.0 - Menüpfeile bei HardwareButtons (button1Page; button2Page) mit Navigation auf Page 0 + - 08.05.2022 - v2.9.0 - Standard-Brightness über neuen Parameter active einstellbar (Test mit 2.9.3) + - 08.05.2022 - v2.9.0 - Schalter (Licht, Dimmer, Hue, etc) in cardGrid lassen sich wieder schalten + - 14.06.2022 - v2.9.0 - Aktion auf Submenüs schaltet unmittelbar auf vorheriges Mainmenu (Many thanks to Grrzzz) + - 14.06.2022 - v2.9.0 - Menü-Pfeile in Subpages (z.B. card QR, cardMedia, etc) (Many thanks to Grrzzz) + - 15.06.2022 - v3.0.0 - Date/Time im Screensaver auf Basis localString (de-DE/en-EN/nl-NL/etc.) + - 16.06.2022 - v3.0.0 - Multilingual - config.locale (en-EN, de-DE, nl-NL, da-DK, es-ES, fr-FR, it-IT, ru-RU, etc.) + - 16.06.2022 - v3.0.0 - Bugfix by Grrzzz - Subpages + - 18.06.2022 - v3.1.0 - Längere Textfelder in cardEntities + - 18.06.2022 - V3.1.0 - Detail-Page Lights/Shutter hat neuen Parameter "id" + - 19.06.2022 - v3.1.0 - Bugfix toLocalTimeString in en-EN/en-US + - 19.06.2022 - v3.1.0 - Fehler in findLocale abgefangen + - 19.06.2022 - v3.1.0 - Umstellung auf "Home Assistant" Sprachfile + - 19.06.2022 - v3.1.0 - Alias "light" und "socket" haben optionalen Parameter icon2 für negative Zustände + - 29.06.2022 - v3.1.1 - Bugfix Github #286 (Active Page) + Bugfix pageThermo, pageMedia, pageAlarm as first Page + - 25.08.2022 - v3.1.0 - Code-Verbesserungen (klein0r) + - 26.08.2022 - v3.2.0 - pageItem mit CIE (XY) Parameter für ColorWheel (Steuerung für z.B Deconz-Farben bei denen Hue nicht greift) + - 28.08.2022 - v3.2.0 - Wechsel zwischen Weather-Forecast und eigenen Datenpunkten im Screensaver (minütlich) + - 28.08.2022 - v3.2.0 - Bugfix für 3.2.0 in GenerateDetailPage: Color-Language nicht über findLocales, da nicht in Sprachfile enthalten + - 29.08.2022 - v3.3.0 - Upgrade TFT 40 + - 29.08.2022 - v3.3.1 - Upgrade TFT 41 + - 04.09.2022 - v3.3.1 - Überarbeitung und BugFix für cardAlarm + - 13.09.2022 - v3.3.1.3 BugFix Screensaver Toggle + - 13.09.2022 - v3.3.1.3 Überarbeitung und BugFix und Refresh Features für cardMedia (Breaking Changes) + - 13.09.2022 - v3.3.1.3 Hinzufügen von SpotifyPremium, Sonos und Chromecast (Google home) zur cardMedia-Logik + - 15.09.2022 - V3.4.0 - BugFix Dimmode + - 15.09.2022 - V3.4.0 - Colormode für Screensaver + AutoColor WeatherForecast + - 16.09.2022 - v3.4.0.1 Visualisierung der Relay Zustände (MRIcons) im Screensaver + Bugfix Screensaver MRIcon2 + - 17.09.2022 - v3.4.0.2 Bugfix for screensaver icons with scaled colors + - 17.09.2022 - v3.4.0.3 Bugfix bNext / bPrev by joBr99 + - 18.09.2022 - v3.4.0.4 Add On/Off Colors in config.mrIcon1ScreensaverEntity and config.mrIcon2ScreensaverEntity + - 19.09.2022 - v3.4.0.5 Add Mode to cardThermo (Alias Thermostat) + - 03.10.2022 - v3.4.0.6 Add 5 Entities in US Panel Version to cardEntities + - 03.10.2022 - v3.4.0.6 Fix screenSaverDoubleClick + - 03.10.2022 - v3.4.0.6 Add cardPower (experimental) + - 05.10.2022 - v3.4.0.6 Add sueezeboxrpc to cardMedia + - 07.10.2022 - v3.4.0.6 Time-configurable change for screensaver icons + - 07.10.2022 - v3.5.0 Add Backgroundcolor to Pages + - 08.10.2022 - v3.5.0 Add Tilt-Slider and TILT_Fucntions (Open/Stop/Close) to Blinds/Cover/Shutter popUp + - 12.10.2022 - v3.5.0 Add PageNavigation via Datapoint + - 25.10.2022 - v3.5.0 Add New Parameters to popUpNotify / Layout 2 + +Wenn Rule definiert, dann können die Hardware-Tasten ebenfalls für Seitensteuerung (dann nicht mehr als Releais) genutzt werden +Tasmota Konsole: + Rule2 on Button1#state do Publish %topic%/%prefix%/RESULT {"CustomRecv":"event,button1"} endon on Button2#state do Publish %topic%/%prefix%/RESULT {"CustomRecv":"event,button2"} endon + Rule2 1 (Rule aktivieren) + Rule2 0 (Rule deaktivieren) + +Mögliche Seiten-Ansichten: + screensaver Page - wird nach definiertem Zeitraum (config) mit Dimm-Modus aktiv (Uhrzeit, Datum, Aktuelle Temperatur mit Symbol) + (die 4 kleineren Icons können als Wetter-Vorschau + 4Tage (Symbol + Höschsttemperatur) oder zur Anzeige definierter Infos konfiguriert werden) + cardEntities Page - 4 vertikale angeordnete Steuerelemente - auch als Subpage + cardGrid Page - 6 horizontal angeordnete Steuerelemente in 2 Reihen a 3 Steuerelemente - auch als Subpage + cardThermo Page - Thermostat mit Solltemperatur, Isttemperatur, Mode - Weitere Eigenschaften können im Alias definiert werden + cardMedia Page - Mediaplayer - Ausnahme: Alias sollte mit Alias-Manager automatisch über Alexa-Verzeichnes Player angelegt werden + cardAlarm Page - Alarmseite mit Zustand und Tastenfeld + cardPower Page - Energiefluss + +Popup-Pages: + popupLight Page - in Abhängigkeit zum gewählten Alias werden "Helligkeit", "Farb-Temperatur" und "Farbauswahl" bereitgestellt + popupShutter Page - die Shutter-Potition (Rollo, Jalousie, Markise, Leinwand, etc.) kann über einen Slider verändert werden. + popupNotify Page - Info - Seite mit Headline Text und Buttons - Intern für manuelle Updates / Extern zur Befüllung von Datenpunkten unter 0_userdata + screensaver Notify - Über zwei externe Datenpunkte in 0_userdata können "Headline" und "Text" an den Screensaver zur Info gesendet werden + +Mögliche Aliase: (Vorzugsweise mit ioBroker-Adapter "Geräte verwalten" konfigurieren, da SET, GET, ACTUAL, etc. verwendet werden) + Info - Werte aus Datenpunkt + Schieberegler - Slider numerische Werte (SET/ACTUAL) + Lautstärke - Volume (SET/ACTUAL) und MUTE + Lautstärke-Gruppe - analog Lautstärke + Licht - An/Aus (Schalter) + Steckdose - An/Aus (Schalter) + Dimmer - An/Aus, Brightness + Farbtemperatur - An/Aus, Farbtemperatur und Brightness + HUE-Licht - Zum Schalten von Color-Leuchtmitteln über HUE-Wert, Brightness, Farbtemperatur, An/Aus (HUE kann auch fehlen) + RGB-Licht - RGB-Leuchtmitteln/Stripes welche Rot/Grün/ und Blau separat benötigen (Tasmota, WifiLight, etc.) + Brightness, Farbtemperatur + RGB-Licht-einzeln - RGB-Leuchtmitteln/Stripes welche HEX-Farbwerte benötigen (Tasmota, WifiLight, etc.) + Brightness, Farbtemperatur + Jalousien - Up, Stop, Down, Position + Fenster - Sensor open + Tür - Sensor open + Verschluss - Türschloss SET/ACTUAL/OPEN + Taste - Für Szenen oder Radiosender, etc. --> Nur Funktionsaufruf - Kein Taster wie MonoButton - True/False + Tastensensor - analog Taste + Thermostat - Aktuelle Raumtemperatur, Setpoint, etc. + Klimaanlage - Buttons zur Steuerung der Klimaanlage im unteren Bereich + Temperatur - Anzeige von Temperture - Datenpunkten, ananlog Info + Feuchtigkeit - Anzeige von Humidity - Datenpunkten, ananlog Info + Medien - Steuerung von Alexa - Über Alias-Manager im Verzeichnis Player automatisch anlegen (Geräte-Manager funktioniert nicht) + Wettervorhersage - Aktuelle Außen-Temperatur (Temp) und aktuelles Accu-Wheather-Icon (Icon) für Screensaver + +Interne Sonoff-Sensoren (über Tasmota): + ESP-Temperatur - wird in 0_userdata.0. abgelegt, kann als Alias importieert werden --> SetOption146 1 + Temperatur - Raumtemperatur - wird in 0_userdata.0. abgelegt, kann als Alias importieert werden + (!!! Achtung: der interne Sonoff-Sensor liefert keine exakten Daten, da das NSPanel-Board und der ESP selbst Hitze produzieren !!! + ggf. Offset einplanen oder besser einen externen Sensor über Zigbee etc. verwenden) + Timestamp - wird in 0_userdata.0. Zeitpunkt der letzten Sensorübertragung + +Tasmota-Status0 - (zyklische Ausführung) + liefert relevanten Tasmota-Informationen und kann bei Bedarf in "function get_tasmota_status0()" erweitert werden. Daten werden in 0_userdata.0. abgelegt + +Erforderliche Adapter: + Accu-Wheater: - Bei Nutzung der Wetterfunktionen (und zur Icon-Konvertierung) im Screensaver + Alexa2: - Bei Nutzung der dynamischen SpeakerList in der cardMedia + Geräte verwalten - Für Erstellung der Aliase + Alias-Manager - !!! ausschießlich für MEDIA-Alias + MQTT-Adapter - Für Kommunikation zwischen Skript und Tasmota + JavaScript-Adapter + +Upgrades in Konsole: + Tasmota BerryDriver : Backlog UpdateDriverVersion https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/tasmota/autoexec.be; Restart 1 + TFT EU STABLE Version : FlashNextion http://nspanel.pky.eu/lovelace-ui/github/nspanel-v3.5.0.tft +--------------------------------------------------------------------------------------- +*/ +var Icons = new IconsSelector(); +var timeoutSlider: any; +var manually_Update = false; + +const NSPanel_Path = '0_userdata.0.NSPanel.1.'; +const NSPanel_Alarm_Path = '0_userdata.0.NSPanel.'; //Neuer Pfad für gemeinsame Nutzung durch mehrere Panels (bei Nutzung der cardAlarm) +const Debug = false; + +// Variablen zur Steuerung der Wettericons auf dem Screensaver (Steuerung in 0_userdata.0.XPANELX.ScreensaverInfo) +// Wenn weatherForecastTimer auf true, dann Wechsel zwischen Datenpunkten und Wettervorhersage (30 Sekunden nach Minute (Zeit)) +// Wenn weatherForecastTimer auf false, dann Möglichkeit über weatherForecast, ob Datenpunkte oder Wettervorhersage (true = WeatherForecast/false = Datenpunkte) +var weatherForecast: boolean; //Änderung zum Video --> Einstellung siehe Wiki + +const HMIOff: RGB = { red: 68, green: 115, blue: 158 }; // Blau-Off - Original Entity Off +const HMIDark: RGB = { red: 29, green: 29, blue: 29 }; // Original Background Color +const Off: RGB = { red: 253, green: 128, blue: 0 }; // Orange-Off - schönere Farbübergänge +const On: RGB = { red: 253, green: 216, blue: 53 }; +const MSRed: RGB = { red: 251, green: 105, blue: 98 }; +const MSYellow: RGB = { red: 255, green: 235, blue: 156 }; +const MSGreen: RGB = { red: 121, green: 222, blue: 121 }; +const Red: RGB = { red: 255, green: 0, blue: 0 }; +const White: RGB = { red: 255, green: 255, blue: 255 }; +const Yellow: RGB = { red: 255, green: 255, blue: 0 }; +const Green: RGB = { red: 0, green: 255, blue: 0 }; +const Blue: RGB = { red: 0, green: 0, blue: 255 }; +const DarkBlue: RGB = { red: 0, green: 0, blue: 136 }; +const Gray: RGB = { red: 136, green: 136, blue: 136 }; +const Black: RGB = { red: 0, green: 0, blue: 0 }; +const colorSpotify: RGB = { red: 30, green: 215, blue: 96 }; +const colorAlexa: RGB = { red: 49, green: 196, blue: 243 }; +const colorRadio: RGB = { red: 255, green: 127, blue: 0 }; +const BatteryFull: RGB = { red: 96, green: 176, blue: 62 }; +const BatteryEmpty: RGB = { red: 179, green: 45, blue: 25 }; + +//Dynamische Indikatoren +const colorScale0: RGB = { red: 99, green: 190, blue: 123 }; +const colorScale1: RGB = { red: 129, green: 199, blue: 126 }; +const colorScale2: RGB = { red: 161, green: 208, blue: 127 }; +const colorScale3: RGB = { red: 129, green: 217, blue: 126 }; +const colorScale4: RGB = { red: 222, green: 226, blue: 131 }; +const colorScale5: RGB = { red: 254, green: 235, blue: 132 }; +const colorScale6: RGB = { red: 255, green: 210, blue: 129 }; +const colorScale7: RGB = { red: 251, green: 185, blue: 124 }; +const colorScale8: RGB = { red: 251, green: 158, blue: 117 }; +const colorScale9: RGB = { red: 248, green: 131, blue: 111 }; +const colorScale10: RGB = { red: 248, green: 105, blue: 107 }; + +//Screensaver Default Theme Colors +const scbackground: RGB = { red: 0, green: 0, blue: 0}; +const sctime: RGB = { red: 255, green: 255, blue: 255}; +const sctimeAMPM: RGB = { red: 255, green: 255, blue: 255}; +const scdate: RGB = { red: 255, green: 255, blue: 255}; +const sctMainIcon: RGB = { red: 255, green: 255, blue: 255}; +const sctMainText: RGB = { red: 255, green: 255, blue: 255}; +const sctForecast1: RGB = { red: 255, green: 255, blue: 255}; +const sctForecast2: RGB = { red: 255, green: 255, blue: 255}; +const sctForecast3: RGB = { red: 255, green: 255, blue: 255}; +const sctForecast4: RGB = { red: 255, green: 255, blue: 255}; +const sctF1Icon: RGB = { red: 255, green: 235, blue: 156}; +const sctF2Icon: RGB = { red: 255, green: 235, blue: 156}; +const sctF3Icon: RGB = { red: 255, green: 235, blue: 156}; +const sctF4Icon: RGB = { red: 255, green: 235, blue: 156}; +const sctForecast1Val: RGB = { red: 255, green: 255, blue: 255}; +const sctForecast2Val: RGB = { red: 255, green: 255, blue: 255}; +const sctForecast3Val: RGB = { red: 255, green: 255, blue: 255}; +const sctForecast4Val: RGB = { red: 255, green: 255, blue: 255}; +const scbar: RGB = { red: 255, green: 255, blue: 255}; +const sctMainIconAlt: RGB = { red: 255, green: 255, blue: 255}; +const sctMainTextAlt: RGB = { red: 255, green: 255, blue: 255}; +const sctTimeAdd: RGB = { red: 255, green: 255, blue: 255}; + +//Auto-Weather-Colors +const swClearNight: RGB = { red: 150, green: 150, blue: 100}; +const swCloudy: RGB = { red: 75, green: 75, blue: 75}; +const swExceptional: RGB = { red: 255, green: 50, blue: 50}; +const swFog: RGB = { red: 150, green: 150, blue: 150}; +const swHail: RGB = { red: 200, green: 200, blue: 200}; +const swLightning: RGB = { red: 200, green: 200, blue: 0}; +const swLightningRainy: RGB = { red: 200, green: 200, blue: 150}; +const swPartlycloudy: RGB = { red: 150, green: 150, blue: 150}; +const swPouring: RGB = { red: 50, green: 50, blue: 255}; +const swRainy: RGB = { red: 100, green: 100, blue: 255}; +const swSnowy: RGB = { red: 150, green: 150, blue: 150}; +const swSnowyRainy: RGB = { red: 150, green: 150, blue: 255}; +const swSunny: RGB = { red: 255, green: 255, blue: 0}; +const swWindy: RGB = { red: 150, green: 150, blue: 150}; + +var vwIconColor = []; + +//-- Anfang der Variablen für Seitengestaltung -- Aliase erforderlich ---------------- + + + +//-- ENDE der Variablen für Seitengestaltung -- Aliase erforderlich ------------------ + +export const config: Config = { + panelRecvTopic: 'mqtt.0.SmartHome.NSPanel_1.tele.RESULT', // anpassen + panelSendTopic: 'mqtt.0.SmartHome.NSPanel_1.cmnd.CustomSend', // anpassen + firstScreensaverEntity: { ScreensaverEntity: 'accuweather.0.Hourly.h0.PrecipitationProbability', ScreensaverEntityIcon: 'weather-pouring', ScreensaverEntityText: 'Regen', ScreensaverEntityUnitText: '%', ScreensaverEntityIconColor: {'val_min': 0, 'val_max': 100} }, + secondScreensaverEntity: { ScreensaverEntity: 'accuweather.0.Current.WindSpeed', ScreensaverEntityIcon: 'weather-windy', ScreensaverEntityText: "Wind", ScreensaverEntityUnitText: 'km/h', ScreensaverEntityIconColor: {'val_min': 0, 'val_max': 120} }, + thirdScreensaverEntity: { ScreensaverEntity: 'accuweather.0.Current.UVIndex', ScreensaverEntityIcon: 'solar-power', ScreensaverEntityText: 'UV', ScreensaverEntityUnitText: '', ScreensaverEntityIconColor: {'val_min': 0, 'val_max': 9} }, + fourthScreensaverEntity: { ScreensaverEntity: 'accuweather.0.Current.RelativeHumidity', ScreensaverEntityIcon: 'water-percent', ScreensaverEntityText: 'Luft', ScreensaverEntityUnitText: '%', ScreensaverEntityIconColor: {'val_min': 0, 'val_max': 100, 'val_best': 65} }, + alternativeScreensaverLayout: false, + autoWeatherColorScreensaverLayout: true, + //!!!! Achtung anpassen !!!! + mrIcon1ScreensaverEntity: { ScreensaverEntity: 'mqtt.0.SmartHome.NSPanel_1.stat.POWER1', ScreensaverEntityIcon: 'light-switch', ScreensaverEntityOnColor: On, ScreensaverEntityOffColor: Off }, + mrIcon2ScreensaverEntity: { ScreensaverEntity: 'mqtt.0.SmartHome.NSPanel_1.stat.POWER2', ScreensaverEntityIcon: 'lightbulb', ScreensaverEntityOnColor: On, ScreensaverEntityOffColor: Off }, + timeoutScreensaver: 20, + dimmode: 20, + active: 100, //Standard-Brightness TFT + screenSaverDoubleClick: true, + locale: 'de-DE', // en-US, de-DE, nl-NL, da-DK, es-ES, fr-FR, it-IT, ru-RU, etc. + timeFormat: '%H:%M', // currently not used + dateFormat: '%A, %d. %B %Y', // currently not used + weatherEntity: 'alias.0.Wetter', // Dieser Alias muss erstellt werden, damit die 4 kleineren Icons (Wetter oder DP) angezeigt werden können + defaultOffColor: Off, + defaultOnColor: On, + defaultColor: Off, + defaultBackgroundColor: Black, //New Parameter + temperatureUnit: '°C', + pages: [ + + ], + subPages: [ + + ], + button1Page: null, //Beispiel-Seite auf Button 1, wenn Rule2 definiert - Wenn nicht definiert --> button1Page: null, + button2Page: null //Beispiel-Seite auf Button 2, wenn Rule2 definiert - Wenn nicht definiert --> button1Page: null, +}; + +// _________________________________ Ab hier keine Konfiguration mehr _____________________________________ + +const request = require('request'); + +//---------------------Begin PageNavi +async function InitPageNavi() { + try { + if (!existsState(NSPanel_Path + 'PageNavi')) { + await createStateAsync(NSPanel_Path + 'PageNavi', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'PageNavi', { val: {"pagetype": "page","pageId": 0}, ack: true }); + } + } catch (err) { + console.log('function InitPageNavi: ' + err.message); + } +} +InitPageNavi(); + +//PageNavi +on({id: [].concat([NSPanel_Path + 'PageNavi']), change: "any"}, async function (obj) { + if (existsState(NSPanel_Path + 'PageNavi')) { + let vObj = JSON.parse(obj.state.val); + if (vObj.pagetype == 'page') { + GeneratePage(config.pages[vObj.pageId]); + } else if (vObj.pagetype == 'subpage') { + GeneratePage(config.subPages[vObj.pageId]); + } + } +}); + +//----------------------Begin Dimmode + +function ScreensaverDimmode(timeDimMode: DimMode) { + try { + if (Debug) console.log(rgb_dec565(HMIDark)) + if (Debug) console.log('Dimmode='+ timeDimMode.dimmodeOn) + if (timeDimMode.dimmodeOn != undefined ? timeDimMode.dimmodeOn : false) { + if (compareTime(timeDimMode.timeNight != undefined ? timeDimMode.timeNight : '22:00', timeDimMode.timeDay != undefined ? timeDimMode.timeDay : '07:00', 'not between', undefined)) { + SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessDay + '~' + config.active + '~' + rgb_dec565(config.defaultBackgroundColor) }); + if (Debug) console.log('Day Payload: ' + 'dimmode~' + timeDimMode.brightnessDay + '~' + config.active ) + } else { + SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessNight + '~' + config.active + '~' + rgb_dec565(config.defaultBackgroundColor) }); + if (Debug) console.log('Night Payload: ' + 'dimmode~' + timeDimMode.brightnessNight + '~' + config.active ) + } + } else { + SendToPanel({ payload: 'dimmode~' + config.dimmode + '~' + config.active + '~' + rgb_dec565(config.defaultBackgroundColor) }); + } + } catch (err) { + console.warn('function ScreensaverDimmode: ' + err.message); + } +} + +async function InitWeatherForecast() { + try { + //----Möglichkeit, im Screensaver zwischen Accu-Weather Forecast oder selbstdefinierten Werten zu wählen--------------------------------- + if (existsState(NSPanel_Path + "ScreensaverInfo.weatherForecast") == false || + existsState(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer") == false || + existsState(NSPanel_Path + "ScreensaverInfo.entityChangeTime") == false) { + await createStateAsync(NSPanel_Path + "ScreensaverInfo.weatherForecast", true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer", true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + "ScreensaverInfo.entityChangeTime", 60, { type: 'number' }); + }; + } catch (err) { + console.warn('function InitWeatherForecast: ' + err.message); + } +} + +InitWeatherForecast(); + +async function InitDimmode() { + try { + // Screensaver nachts auf dunkel ("brightnessNight: z.B. 2") oder aus ("brightnessNight:0") + if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay')) { + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', { type: 'number' }); + await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', { val: 8, ack: true }); + } + + if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_hourDay')) { + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourDay', { type: 'number' }); + await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourDay', { val: 7, ack: true }); + } + + if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight')) { + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', { type: 'number' }); + await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', { val: 1, ack: true }); + } + + if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_hourNight')) { + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourNight', { type: 'number' }); + await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourNight', { val: 22, ack: true }); + } + + const vTimeDay = getState(NSPanel_Path + 'NSPanel_Dimmode_hourDay').val; + const vTimeNight = getState(NSPanel_Path + 'NSPanel_Dimmode_hourNight').val; + + const timeDimMode = { + dimmodeOn: true, + brightnessDay: getState(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay').val, + brightnessNight: getState(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight').val, + timeDay: (vTimeDay < 10) ? `0${vTimeDay}:00` : `${vTimeDay}:00`, + timeNight: (vTimeNight < 10) ? `0${vTimeNight}:00` : `${vTimeNight}:00` + }; + + // timeDimMode Day + schedule({ hour: getState(NSPanel_Path + 'NSPanel_Dimmode_hourDay').val, minute: 0 }, () => { + ScreensaverDimmode(timeDimMode); + }); + + // timeDimMode Night + schedule({ hour: getState(NSPanel_Path + 'NSPanel_Dimmode_hourNight').val, minute: 0 }, () => { + ScreensaverDimmode(timeDimMode); + }); + + ScreensaverDimmode(timeDimMode); + } catch (err) { + console.warn('function InitDimmode: ' + err.message); + } +} + +InitDimmode(); + +//--------------------End Dimmode + +// Datenpunkte für Nachricht an Screensaver +const screensaverNotifyHeading = NSPanel_Path + 'ScreensaverInfo.popupNotifyHeading'; +const screensaverNotifyText = NSPanel_Path + 'ScreensaverInfo.popupNotifyText'; + +// Datenpunkte für Nachricht popupNotify Page +const popupNotifyHeading = NSPanel_Path + 'popupNotify.popupNotifyHeading'; +const popupNotifyHeadingColor = NSPanel_Path + 'popupNotify.popupNotifyHeadingColor'; +const popupNotifyText = NSPanel_Path + 'popupNotify.popupNotifyText'; +const popupNotifyTextColor = NSPanel_Path + 'popupNotify.popupNotifyTextColor'; +const popupNotifyInternalName = NSPanel_Path + 'popupNotify.popupNotifyInternalName'; // Wird mit Button-Action zurückgeschrieben +const popupNotifyButton1TextColor = NSPanel_Path + 'popupNotify.popupNotifyButton1TextColor'; +const popupNotifyButton1Text = NSPanel_Path + 'popupNotify.popupNotifyButton1Text'; +const popupNotifyButton2TextColor = NSPanel_Path + 'popupNotify.popupNotifyButton2TextColor'; +const popupNotifyButton2Text = NSPanel_Path + 'popupNotify.popupNotifyButton2Text'; +const popupNotifySleepTimeout = NSPanel_Path + 'popupNotify.popupNotifySleepTimeout'; // in sek. / wenn 0, dann bleibt die Nachricht stehen +const popupNotifyAction = NSPanel_Path + 'popupNotify.popupNotifyAction'; // Antwort aus dem Panel true/false +const popupNotifyLayout = NSPanel_Path + 'popupNotify.popupNotifyLayout'; +const popupNotifyFontIdText = NSPanel_Path + 'popupNotify.popupNotifyFontIdText'; 1 - 5 +const popupNotifyIcon = NSPanel_Path + 'popupNotify.popupNotifyIcon'; 1 - 5 +const popupNotifyIconColor = NSPanel_Path + 'popupNotify.popupNotifyIconColor'; 1 - 5 + +async function InitPopupNotify() { + try { + if (!existsState(screensaverNotifyHeading)) { + await createStateAsync(screensaverNotifyHeading, { type: 'string' }); + await setStateAsync(screensaverNotifyHeading, { val: '', ack: true }); + } + + if (!existsState(screensaverNotifyText)) { + await createStateAsync(screensaverNotifyText, { type: 'string' }); + await setStateAsync(screensaverNotifyText, { val: '', ack: true }); + } + + await createStateAsync(popupNotifyHeading, { type: 'string' }); + await createStateAsync(popupNotifyHeadingColor, { type: 'string' }); + await createStateAsync(popupNotifyText, { type: 'string' }); + await createStateAsync(popupNotifyTextColor, { type: 'string' }); + await createStateAsync(popupNotifyInternalName, { type: 'string' }); + await createStateAsync(popupNotifyButton1Text, { type: 'string' }); + await createStateAsync(popupNotifyButton1TextColor, { type: 'string' }); + await createStateAsync(popupNotifyButton2Text, { type: 'string' }); + await createStateAsync(popupNotifyButton2TextColor, { type: 'string' }); + await createStateAsync(popupNotifySleepTimeout, { type: 'number' }); + await createStateAsync(popupNotifyAction, { type: 'boolean' }); + await createStateAsync(popupNotifyLayout, { type: 'number' }); + await createStateAsync(popupNotifyFontIdText, { type: 'number' }); + await createStateAsync(popupNotifyIcon, { type: 'string' }); + await createStateAsync(popupNotifyIconColor, { type: 'string' }); + + // Notification to screensaver + on({ id: [screensaverNotifyHeading, screensaverNotifyText], change: 'ne', ack: false }, async (obj) => { + const heading = getState(screensaverNotifyHeading).val; + const text = getState(screensaverNotifyText).val; + + setIfExists(config.panelSendTopic, `notify~${heading}~${text}`); + + if (obj.id) { + await setStateAsync(obj.id, { val: obj.state.val, ack: true }); // ack new value + } + }); + + // popupNotify - Notification an separate Seite + on({ id: [popupNotifyInternalName], change: 'ne' }, async (obj) => { + + var notification : string = '' + + let v_popupNotifyHeadingColor = (getState(popupNotifyHeadingColor).val != null) ? getState(popupNotifyHeadingColor).val : '65504'// Farbe Headline - gelb 65504 + let v_popupNotifyButton1TextColor = (getState(popupNotifyButton1TextColor).val != null) ? getState(popupNotifyButton1TextColor).val : '63488'// Farbe Headline - gelb 65504 + let v_popupNotifyButton2TextColor = (getState(popupNotifyButton2TextColor).val != null) ? getState(popupNotifyButton2TextColor).val : '2016'// Farbe Headline - gelb 65504 + let v_popupNotifyTextColor = (getState(popupNotifyTextColor).val != null) ? getState(popupNotifyTextColor).val : '65535'// Farbe Headline - gelb 65504 + let v_popupNotifyIconColor = (getState(popupNotifyIconColor).val != null) ? getState(popupNotifyIconColor).val : '65535'// Farbe Headline - gelb 65504 + let v_popupNotifyFontIdText = (getState(popupNotifyFontIdText).val != null) ? getState(popupNotifyFontIdText).val : '1' + let v_popupNotifyIcon = (getState(popupNotifyIcon).val != null) ? getState(popupNotifyIcon).val : 'alert' + + notification = 'entityUpdateDetail' + '~' + + getState(popupNotifyInternalName).val + '~' + + getState(popupNotifyHeading).val + '~' + + v_popupNotifyHeadingColor + '~' + + getState(popupNotifyButton1Text).val + '~' + + v_popupNotifyButton1TextColor + '~' + + getState(popupNotifyButton2Text).val + '~' + + v_popupNotifyButton2TextColor + '~' + + getState(popupNotifyText).val + '~' + + v_popupNotifyTextColor + '~' + + getState(popupNotifySleepTimeout).val; + + if (getState(popupNotifyLayout).val == 2) { + notification = notification + '~' + + v_popupNotifyFontIdText + '~' + + Icons.GetIcon(v_popupNotifyIcon) + '~' + + v_popupNotifyIconColor; + } + + setIfExists(config.panelSendTopic, 'pageType~popupNotify'); + setIfExists(config.panelSendTopic, notification); + + }); + } catch (err) { + console.warn('function InitPopupNotify: ' + err.message); + } +} + +InitPopupNotify(); + +let subscriptions: any = {}; +let screensaverEnabled: boolean = false; +let pageId = 0; + +// Neu für Subpages +let activePage = undefined; + +//Uhrzeit an NSPanel senden +schedule('* * * * *', () => { + try { + SendTime(); + } catch (err) { + console.warn('schedule: ' + err.message); + } +}); + +//Wechsel zwischen Screensaver Enities und WeatherForecast +schedule('*/' + getState(NSPanel_Path + 'ScreensaverInfo.entityChangeTime').val + ' * * * * *', () => { + try { + //WeatherForcast true/false Umschaltung verzögert + if (getState(NSPanel_Path + "ScreensaverInfo.popupNotifyHeading").val == '' && getState(NSPanel_Path + "ScreensaverInfo.popupNotifyText").val == '' && getState(NSPanel_Path + "ScreensaverInfo.weatherForecast").val == true && getState(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer").val == true) { + setStateDelayed(NSPanel_Path + "ScreensaverInfo.weatherForecast", false, (getState(NSPanel_Path + 'ScreensaverInfo.entityChangeTime').val / 2 * 1000), false); + } else if (getState(NSPanel_Path + "ScreensaverInfo.popupNotifyHeading").val == '' && getState(NSPanel_Path + "ScreensaverInfo.popupNotifyText").val == '' && getState(NSPanel_Path + "ScreensaverInfo.weatherForecast").val == false && getState(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer").val == true) { + setStateDelayed(NSPanel_Path + "ScreensaverInfo.weatherForecast", true, (getState(NSPanel_Path + 'ScreensaverInfo.entityChangeTime').val / 2 * 1000), false); + } + } catch (err) { + console.warn('schedule: ' + err.message); + } +}); + +function InitHWButton1Color() { + try { + if (config.mrIcon1ScreensaverEntity.ScreensaverEntity != null || config.mrIcon1ScreensaverEntity.ScreensaverEntity != undefined) { + on({id: config.mrIcon1ScreensaverEntity.ScreensaverEntity, change: "ne"}, async function (obj) { + HandleScreensaverUpdate(); + }); + } + } catch (err) { + console.warn('function InitHWButton1Color: ' + err.message); + } +} +InitHWButton1Color(); + +function InitHWButton2Color() { + try { + if (config.mrIcon2ScreensaverEntity.ScreensaverEntity != null || config.mrIcon2ScreensaverEntity.ScreensaverEntity != undefined) { + on({id: config.mrIcon2ScreensaverEntity.ScreensaverEntity, change: "ne"}, async function (obj) { + HandleScreensaverUpdate(); + }); + } + } catch (err) { + console.warn('function InitHWButton2Color: ' + err.message); + } +} +InitHWButton2Color(); + +//Wechsel zwischen Datenpunkten und Weather-Forecast im Screensaver +on({id: [].concat([NSPanel_Path + "ScreensaverInfo.weatherForecast"]), change: "ne"}, async function (obj) { + weatherForecast = obj.state.val; + HandleScreensaverUpdate(); +}); + +schedule('0 * * * *', () => { + SendDate(); +}); + +// 3:30 Uhr Startup durchführen und aktuelle TFT-Version empfangen +schedule({ hour: 3, minute: 30 }, async () => { + await setStateAsync(config.panelSendTopic, 'pageType~pageStartup'); +}); + +// Updates vergleichen aktuell alle 12 Stunden +schedule('{"time":{"start":"00:00","end":"23:59","mode":"hours","interval":12},"period":{"days":1}}', () => { + get_tasmota_status0(); + get_panel_update_data(); + check_updates(); +}); + +// Mit Start auf Updates checken +get_locales(); +setState(config.panelSendTopic, 'pageType~pageStartup'); +get_tasmota_status0(); +get_panel_update_data(); +check_updates(); + +//------------------Begin Update Functions + +function get_locales() { + try { + if (Debug) console.log('Requesting locales'); + request({ + url: 'https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/ioBroker/ioBroker_NSPanel_locales.json', + headers: { + 'User-Agent': 'ioBroker' + } + }, async (error, response, result) => { + try { + if (result) { + await createStateAsync(NSPanel_Path + 'NSPanel_locales_json', { type: 'string', role: 'json' }); + await setStateAsync(NSPanel_Path + 'NSPanel_locales_json', { val: result, ack: true }); + } + } catch (err) { + console.log('get_locales: ' + err.message); + } + }); + } catch (err) { + console.error('error requesting locales in function get_locales: ' + err.message); + } +} + +async function check_updates() { + try { + const desired_display_firmware_version = 43; + const berry_driver_version = 4; + + if (Debug) console.log('Check-Updates'); + // Tasmota-Firmware-Vergleich + if (existsObject(NSPanel_Path + 'Tasmota_Firmware.currentVersion') && existsObject(NSPanel_Path + 'Tasmota_Firmware.onlineVersion')) { + if (getState(NSPanel_Path + 'Tasmota_Firmware.currentVersion').val !== getState(NSPanel_Path + 'Tasmota_Firmware.onlineVersion').val) { + if (existsState(NSPanel_Path + 'NSPanel_autoUpdate')) { + if (getState(NSPanel_Path + 'NSPanel_autoUpdate').val) { + if (Debug) console.log('Auto-Updates eingeschaltet - Update wird durchgeführt'); + // Tasmota Upgrade durchführen + update_tasmota_firmware(); + // Aktuelle Tasmota Version = Online Tasmota Version + + await setStateAsync(NSPanel_Path + 'Tasmota_Firmware.currentVersion', { val: getState(NSPanel_Path + 'Tasmota_Firmware.onlineVersion').val, ack: true }); + } else { + // Auf Tasmota-Updates hinweisen + if (Debug) console.log('Automatische Updates aus'); + + const InternalName = 'TasmotaFirmwareUpdate'; + const Headline = 'Tasmota-Firmware Update'; + const Text = ['Es ist eine neue Version der Tasmota-Firmware', '\r\n', 'verfügbar', '\r\n', '\r\n', 'Installierte Version: ' + String(getState((String(NSPanel_Path) + 'Tasmota_Firmware.currentVersion')).val), '\r\n', 'Verfügbare Version: ' + String(getState((String(NSPanel_Path) + 'Tasmota_Firmware.onlineVersion')).val), '\r\n', '\r\n', 'Upgrade durchführen?'].join(''); + const Button1 = 'Nein'; + const Button2 = 'Ja'; + const Timeout = 0; + + await setStateAsync(popupNotifyHeading, { val: Headline, ack: false }); + await setStateAsync(popupNotifyText, { val: [formatDate(getDateObject((new Date().getTime())), 'TT.MM.JJJJ SS:mm:ss'), '\r\n', '\r\n', Text].join(''), ack: false }); + await setStateAsync(popupNotifyButton1Text, { val: Button1, ack: false }); + await setStateAsync(popupNotifyButton2Text, { val: Button2, ack: false }); + await setStateAsync(popupNotifySleepTimeout, { val: Timeout, ack: false }); + await setStateAsync(popupNotifyInternalName, { val: InternalName, ack: false }); + } + } + } else { + if (Debug) console.log('Tasmota-Version auf NSPanel aktuell'); + } + } + + // Tasmota-Berry-Driver-Vergleich + if (existsObject(NSPanel_Path + 'Berry_Driver.currentVersion')) { + if (getState(NSPanel_Path + 'Berry_Driver.currentVersion').val < berry_driver_version) { + if (existsState(NSPanel_Path + 'NSPanel_autoUpdate')) { + if (getState(NSPanel_Path + 'NSPanel_autoUpdate').val) { + // Tasmota Berry-Driver Update durchführen + update_berry_driver_version(); + // Aktuelle Berry-Driver Version = Online Berry-Driver Version + await setStateAsync(NSPanel_Path + 'Berry_Driver.currentVersion', { val: getState(NSPanel_Path + 'Berry_Driver.onlineVersion').val, ack: true }); + + if (Debug) console.log('Berry-Driver automatisch aktualisiert'); + } else { + //Auf BerryDriver-Update hinweisen + if (Debug) console.log('Automatische Updates aus'); + + const InternalName = 'BerryDriverUpdate'; + const Headline = 'Berry-Driver Update'; + const Text = ['Es ist eine neue Version des Berry-Drivers', '\r\n', '(Tasmota) verfügbar', '\r\n', '\r\n', 'Installierte Version: ' + String(getState((String(NSPanel_Path) + 'Berry_Driver.currentVersion')).val), '\r\n', 'Verfügbare Version: ' + String(berry_driver_version), '\r\n', '\r\n', 'Upgrade durchführen?'].join(''); + const Button1 = 'Nein'; + const Button2 = 'Ja'; + const Timeout = 0; + + await setStateAsync(popupNotifyHeading, { val: Headline, ack: false }); + await setStateAsync(popupNotifyText, { val: [formatDate(getDateObject((new Date().getTime())), 'TT.MM.JJJJ SS:mm:ss'), '\r\n', '\r\n', Text].join(''), ack: false }); + await setStateAsync(popupNotifyButton1Text, { val: Button1, ack: false }); + await setStateAsync(popupNotifyButton2Text, { val: Button2, ack: false }); + await setStateAsync(popupNotifySleepTimeout, { val: Timeout, ack: false }); + await setStateAsync(popupNotifyInternalName, { val: InternalName, ack: false }); + } + } + } else { + if (Debug) console.log('Berry-Driver auf NSPanel aktuell'); + } + } + + // TFT-Firmware-Vergleich + if (existsObject(NSPanel_Path + 'Display_Firmware.currentVersion')) { + if (parseInt(getState(NSPanel_Path + 'Display_Firmware.currentVersion').val) < desired_display_firmware_version) { + if (existsState(NSPanel_Path + 'NSPanel_autoUpdate')) { + if (getState(NSPanel_Path + 'NSPanel_autoUpdate').val) { + // TFT-Firmware Update durchführen + update_tft_firmware(); + // Aktuelle TFT-Firmware Version = Online TFT-Firmware Version + await setStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { val: getState(NSPanel_Path + 'Display_Firmware.onlineVersion').val, ack: true }); + + if (Debug) console.log('Display_Firmware automatisch aktualisiert'); + } else { + // Auf TFT-Firmware hinweisen + if (Debug) console.log('Automatische Updates aus'); + + const InternalName = 'TFTFirmwareUpdate'; + const Headline = 'TFT-Firmware Update'; + const Text = ['Es ist eine neue Version der TFT-Firmware', '\r\n', 'verfügbar', '\r\n', '\r\n', 'Installierte Version: ' + String(getState((String(NSPanel_Path) + 'Display_Firmware.currentVersion')).val), '\r\n', 'Verfügbare Version: ' + String(desired_display_firmware_version), '\r\n', '\r\n', 'Upgrade durchführen?'].join(''); + const Button1 = 'Nein'; + const Button2 = 'Ja'; + const Timeout = 0; + + await setStateAsync(popupNotifyHeading, { val: Headline, ack: false }); + await setStateAsync(popupNotifyText, { val: [formatDate(getDateObject((new Date().getTime())), 'TT.MM.JJJJ SS:mm:ss'), '\r\n', '\r\n', Text].join(''), ack: false }); + await setStateAsync(popupNotifyButton1Text, { val: Button1, ack: false }); + await setStateAsync(popupNotifyButton2Text, { val: Button2, ack: false }); + await setStateAsync(popupNotifySleepTimeout, { val: Timeout, ack: false }); + await setStateAsync(popupNotifyInternalName, { val: InternalName, ack: false }); + } + } + } else { + if (Debug) console.log('Display_Firmware auf NSPanel aktuell'); + } + } + } catch (err) { + console.warn('function check_updates: ' + err.message); + } +} + +on({ id: NSPanel_Path + 'popupNotify.popupNotifyAction', change: 'any' }, async function (obj) { + try { + const val = obj.state ? obj.state.val : false; + + if (!val) { + manually_Update = false; + if (Debug) console.log('Es wurde Button1 gedrückt'); + } else if (val) { + if (manually_Update) { + const internalName = getState(NSPanel_Path + 'popupNotify.popupNotifyInternalName').val; + + if (internalName == 'TasmotaFirmwareUpdate') { + update_tasmota_firmware(); + } else if (internalName == 'BerryDriverUpdate') { + update_berry_driver_version(); + } else if (internalName == 'TFTFirmwareUpdate') { + update_tft_firmware(); + } + } + + if (Debug) console.log('Es wurde Button2 gedrückt'); + } + } catch (err) { + console.warn('Trigger popupNotifyAction: ' + err.message); + } +}); + +async function get_panel_update_data() { + try { + await createStateAsync(NSPanel_Path + 'NSPanel_autoUpdate', false, { read: true, write: true, name: 'Auto-Update', type: 'boolean', def: false }); + + await createStateAsync(NSPanel_Path + 'NSPanel_ipAddress', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'NSPanel_ipAddress', { val: get_current_tasmota_ip_address(), ack: true }); + + get_online_tasmota_firmware_version(); + get_current_berry_driver_version(); + get_online_berry_driver_version(); + check_version_tft_firmware(); + check_online_display_firmware(); + } catch (err) { + console.warn('function get_panel_update_data: ' + err.message); + } +} + +function get_current_tasmota_ip_address() { + try { + const infoObjId = config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'INFO2'; + const infoObj = JSON.parse(getState(infoObjId).val); + + if (Debug) console.log(`get_current_tasmota_ip_address: ${infoObj.Info2.IPAddress}`); + + return infoObj.Info2.IPAddress; + } catch (err) { + console.warn('function get_current_tasmota_ip_address: ' + err.message); + } +} + +function get_online_tasmota_firmware_version() { + try { + if (Debug) console.log('Requesting tasmota firmware version'); + request({ + url: 'https://api.github.com/repositories/80286288/releases/latest', + headers: { + 'User-Agent': 'ioBroker' + } + }, async (error, response, result) => { + try { + const Tasmota_JSON = JSON.parse(result); // JSON Resultat in Variable Schreiben + const TasmotaTagName = Tasmota_JSON.tag_name; // JSON nach "tag_name" filtern und in Variable schreiben + const TasmotaVersionOnline = TasmotaTagName.replace(/v/i, ''); // Aus Variable überflüssiges "v" filtern und in Release-Variable schreiben + + await createStateAsync(NSPanel_Path + 'Tasmota_Firmware.onlineVersion', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'Tasmota_Firmware.onlineVersion', { val: TasmotaVersionOnline, ack: true }); + } catch (err) { + console.log('get_online_tasmota_firmware_version: ' + err.message); + } + }); + } catch (err) { + console.warn('error requesting firmware in function get_online_tasmota_firmware_version: ' + err.message); + } +} + +function get_current_berry_driver_version() { + try { + if (Debug) console.log('Requesting current berry driver version'); + request({ + url: `http://${get_current_tasmota_ip_address()}/cm?cmnd=GetDriverVersion`, + headers: { + 'User-Agent': 'ioBroker' + } + }, async (error, response, result) => { + try { + await createStateAsync(NSPanel_Path + 'Berry_Driver.currentVersion', { type: 'number' }); + await setStateAsync(NSPanel_Path + 'Berry_Driver.currentVersion', { val: JSON.parse(result).nlui_driver_version, ack: true }); + } catch (err) { + console.warn('get_current_berry_driver_version: ' + err.message); + } + }); + } catch (err) { + console.warn('error requesting firmware in function get_current_berry_driver_version: ' + err.message); + } +} + +function get_tasmota_status0() { + try { + if (Debug) console.log('Requesting tasmota status0'); + request({ + url: `http://${get_current_tasmota_ip_address()}/cm?cmnd=Status0`, + headers: { + 'User-Agent': 'ioBroker' + } + }, async (error, response, result) => { + await createStateAsync(NSPanel_Path + 'Tasmota_Firmware.currentVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Uptime', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Version', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Hardware', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.AP', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.SSId', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.BSSId', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Channel', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Mode', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.RSSI', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Signal', { type: 'number' }); + + try { + const Tasmota_JSON = JSON.parse(result); + const tasmoVersion = Tasmota_JSON.StatusFWR.Version.indexOf('(') > -1 ? Tasmota_JSON.StatusFWR.Version.split('(')[0] : Tasmota_JSON.StatusFWR.Version; + + await setStateAsync(NSPanel_Path + 'Tasmota_Firmware.currentVersion', { val: tasmoVersion, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Uptime', { val: Tasmota_JSON.StatusPRM.Uptime, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Version', { val: Tasmota_JSON.StatusFWR.Version, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Hardware', { val: Tasmota_JSON.StatusFWR.Hardware, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.AP', { val: Tasmota_JSON.StatusSTS.Wifi.AP, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.SSId', { val: Tasmota_JSON.StatusSTS.Wifi.SSId, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.BSSId', { val: Tasmota_JSON.StatusSTS.Wifi.BSSId, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.Channel', { val: Tasmota_JSON.StatusSTS.Wifi.Channel, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.Mode', { val: Tasmota_JSON.StatusSTS.Wifi.Mode, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.RSSI', { val: Tasmota_JSON.StatusSTS.Wifi.RSSI, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.Signal', { val: Tasmota_JSON.StatusSTS.Wifi.Signal, ack: true }); + } catch (err) { + console.warn('get_tasmota_status0' + err.message); + } + }); + } catch (err) { + console.warn('error requesting firmware in function get_tasmota_status0: ' + err.message); + } +} + +function get_online_berry_driver_version() { + try { + if (Debug) console.log('Requesting online berry driver version'); + request({ + url: 'https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/tasmota/autoexec.be', + headers: { + 'User-Agent': 'ioBroker' + } + }, async (error, response, result) => { + if (result) { + try { + const BerryDriverVersionOnline = result.substring((result.indexOf('version_of_this_script = ') + 24), result.indexOf('version_of_this_script = ') + 27).replace(/\s+/g, ''); + await createStateAsync(NSPanel_Path + 'Berry_Driver.onlineVersion', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'Berry_Driver.onlineVersion', { val: BerryDriverVersionOnline, ack: true }); + } catch (err) { + console.log('get_online_berry_driver_version' + err.message); + } + } + }); + } catch (err) { + console.warn('error requesting firmware in function get_online_berry_driver_version: ' + err.message); + } +} + +function check_version_tft_firmware() { + try { + if (Debug) console.log('Requesting online TFT version'); + request({ + url: 'https://api.github.com/repos/joBr99/nspanel-lovelace-ui/releases/latest', + headers: { + 'User-Agent': 'ioBroker' + } + }, async (error, response, result) => { + if (result) { + try { + var NSPanel_JSON = JSON.parse(result); // JSON Resultat in Variable Schreiben + var NSPanelTagName = NSPanel_JSON.tag_name; // created_at; published_at; name ; draft ; prerelease + var NSPanelVersion = NSPanelTagName.replace(/v/i, ''); // Aus Variable überflüssiges "v" filtern und in Release-Variable schreiben + + await createStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { val: NSPanelVersion, ack: true }); + } catch (err) { + console.log('check_version_tft_firmware: ' + err.message); + } + } + }); + } catch (err) { + console.warn('error requesting firmware in function check_version_tft_firmware: ' + err.message); + } +} + +function check_online_display_firmware() { + try { + if (Debug) console.log('Requesting online firmware version'); + request({ + url: 'https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/apps/nspanel-lovelace-ui/nspanel-lovelace-ui.py', + headers: { + 'User-Agent': 'ioBroker' + } + }, async (error, response, result) => { + if (result) { + try { + let desired_display_firmware_version = result.substring((result.indexOf('desired_display_firmware_version =') + 34), result.indexOf('desired_display_firmware_version =') + 38).replace(/\s+/g, ''); + + await createStateAsync(NSPanel_Path + 'Display_Firmware.onlineVersion', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'Display_Firmware.onlineVersion', { val: desired_display_firmware_version, ack: true }); + } catch (err) { + console.warn('check_online_display_firmware' + err.message); + } + } + }); + } catch (err) { + console.warn('error requesting firmware in function check_online_display_firmware: ' + err.message); + } +} + +on({ id: config.panelRecvTopic }, async (obj) => { + if (obj.state.val.startsWith('\{"CustomRecv":')) { + try { + var json = JSON.parse(obj.state.val); + var split = json.CustomRecv.split(','); + if (split[0] == 'event' && split[1] == 'startup') { + await createStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'NSPanel_Version', { type: 'string' }); + + await setStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { val: split[2], ack: true }); + await setStateAsync(NSPanel_Path + 'NSPanel_Version', { val: split[3], ack: true }); + } + } catch (err) { + console.warn('error rceiving CustomRecv: ' + err.message); + } + } +}); + +function update_berry_driver_version() { + try { + request({ + url: `http://${get_current_tasmota_ip_address()}/cm?cmnd=Backlog UpdateDriverVersion https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/tasmota/autoexec.be; Restart 1`, + headers: { + 'User-Agent': 'ioBroker' + } + }, async function (error, response, result) { + + }); + } catch (err) { + console.warn('error at function update_berry_driver_version: ' + err.message); + } +} + +function update_tft_firmware() { + const tft_version: string = 'v3.5.0'; + const desired_display_firmware_url = `http://nspanel.pky.eu/lovelace-ui/github/nspanel-${tft_version}.tft`; + try { + request({ + url: `http://${get_current_tasmota_ip_address()}/cm?cmnd=FlashNextion ${desired_display_firmware_url}`, + headers: { + 'User-Agent': 'ioBroker' + } + }, async function (error, response, result) { + await createStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { val: tft_version, ack: true }); + }); + } catch (err) { + console.warn('error at function update_tft_firmware: ' + err.message); + } +} + +function update_tasmota_firmware() { + try { + request({ + url: `http://${get_current_tasmota_ip_address()}/cm?cmnd=Upgrade 1`, + headers: { + 'User-Agent': 'ioBroker' + } + }, async function (error, response, result) { + }); + } catch (err) { + console.warn('error at function update_tasmota_firmware: ' + err.message); + } +} +//------------------End Update Functions + +// Only monitor the extra nodes if present +var updateArray: string[] = []; + +if (config.firstScreensaverEntity !== null && config.firstScreensaverEntity.ScreensaverEntity != null && existsState(config.firstScreensaverEntity.ScreensaverEntity)) { + updateArray.push(config.firstScreensaverEntity.ScreensaverEntity) +} +if (config.secondScreensaverEntity !== null && config.secondScreensaverEntity.ScreensaverEntity != null && existsState(config.secondScreensaverEntity.ScreensaverEntity)) { + updateArray.push(config.secondScreensaverEntity.ScreensaverEntity) +} +if (config.thirdScreensaverEntity !== null && config.thirdScreensaverEntity.ScreensaverEntity != null && existsState(config.thirdScreensaverEntity.ScreensaverEntity)) { + updateArray.push(config.thirdScreensaverEntity.ScreensaverEntity) +} +if (config.fourthScreensaverEntity !== null && config.fourthScreensaverEntity.ScreensaverEntity != null && existsState(config.fourthScreensaverEntity.ScreensaverEntity)) { + updateArray.push(config.fourthScreensaverEntity.ScreensaverEntity) +} +if (updateArray.length > 0) { + on(updateArray, () => { + HandleScreensaverUpdate(); + }); +} + +on({ id: config.panelRecvTopic }, function (obj) { + try { + if (obj.state.val.startsWith('\{"CustomRecv":')) { + try { + var json = JSON.parse(obj.state.val); + + var split = json.CustomRecv.split(','); + HandleMessage(split[0], split[1], parseInt(split[2]), split); + } catch (err) { + console.warn(err.message); + } + } + } catch (err) { + console.warn('Trigger panelRecTopic: ' + err.message); + } +}); + +function SendToPanel(val: Payload | Payload[]): void { + try { + if (Array.isArray(val)) { + val.forEach(function (id, i) { + setState(config.panelSendTopic, id.payload); + if (Debug) console.log(id.payload); + }); + } else { + setState(config.panelSendTopic, val.payload); + } + } catch (err) { + console.warn('function SendToPanel: ' + err.message); + } +} + +on({ id: NSPanel_Alarm_Path + 'Alarm.AlarmState', change: 'ne' }, async (obj) => { + try { + if ((obj.state ? obj.state.val : '') == 'armed' || (obj.state ? obj.state.val : '') == 'disarmed' || (obj.state ? obj.state.val : '') == 'triggered') { + if (Debug) console.log(activePage); + if (NSPanel_Path == getState(NSPanel_Alarm_Path + 'Alarm.PANEL').val) { + GeneratePage(activePage); + } + } + } catch (err) { + console.warn('Trigger AlarmState: ' + err.message); + } +}); + +function HandleMessage(typ: string, method: string, page: number, words: Array): void { + try { + if (typ == 'event') { + switch (method) { + case 'startup': + screensaverEnabled = false; + UnsubscribeWatcher(); + HandleStartupProcess(); + pageId = 0; + GeneratePage(config.pages[0]); + break; + case 'sleepReached': + screensaverEnabled = true; + if (pageId < 0) + pageId = 0; + HandleScreensaver(); + break; + case 'pageOpenDetail': + screensaverEnabled = false; + UnsubscribeWatcher(); + let pageItem = findPageItem(words[3]); + if (pageItem !== undefined) + SendToPanel(GenerateDetailPage(words[2], pageItem)); + case 'buttonPress2': + screensaverEnabled = false; + HandleButtonEvent(words); + if (Debug) console.log(words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4]); + break; + case 'button1': + case 'button2': + screensaverEnabled = false; + HandleHardwareButton(method); + default: + break; + } + } + } catch (err) { + console.warn('function HandleMessage: ' + err.message); + } +} + +function findPageItem(searching: String): PageItem { + try { + + let pageItem = activePage.items.find(e => e.id === searching); + + if (pageItem !== undefined) { + return pageItem; + } + + config.subPages.every(sp => { + pageItem = sp.items.find(e => e.id === searching); + if (pageItem !== undefined) { + return false; + } + return true; + }); + + return pageItem; + } catch (err) { + console.warn('function findPageItem: ' + err.message); + } +} + +function GeneratePage(page: Page): void { + try { + activePage = page; + switch (page.type) { + case 'cardEntities': + SendToPanel(GenerateEntitiesPage(page)); + break; + case 'cardThermo': + SendToPanel(GenerateThermoPage(page)); + break; + case 'cardGrid': + SendToPanel(GenerateGridPage(page)); + break; + case 'cardMedia': + SendToPanel(GenerateMediaPage(page)); + break; + case 'cardAlarm': + SendToPanel(GenerateAlarmPage(page)); + break; + case 'cardQR': + SendToPanel(GenerateQRPage(page)); + break; + case 'cardPower': + SendToPanel(GeneratePowerPage(page)); + break; + } + } catch (err) { + console.warn('function GeneratePage: ' + err.message); + } +} + +function HandleHardwareButton(method: string): void { + try { + let page: (PageThermo | PageMedia | PageAlarm | PageEntities | PageGrid | PageQR | PagePower); + if (config.button1Page !== null && method == 'button1') { + page = config.button1Page; + pageId = -1; + } else if (config.button2Page !== null && method == 'button2') { + page = config.button2Page; + pageId = -2; + } else { + return; + } + + GeneratePage(page); + } catch (err) { + console.warn('function HandleHardwareButton: ' + err.message); + } +} + +function HandleStartupProcess(): void { + SendDate(); + SendTime(); + SendToPanel({ payload: 'timeout~' + config.timeoutScreensaver }); +} + +function SendDate(): void { + try { + const date = new Date(); + const options: any = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; + const _SendDate = date.toLocaleDateString(config.locale, options); + + SendToPanel({ payload: 'date~' + _SendDate }); + } catch (err) { + console.warn('function SendDate: ' + err.message); + } +} + +function SendTime(): void { + try { + const d = new Date(); + const hr = (d.getHours() < 10 ? '0' : '') + d.getHours(); + const min = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); + + SendToPanel({ payload: 'time~' + hr + ':' + min }); + } catch (err) { + console.warn('function SendTime: ' + err.message); + } +} + +function GenerateEntitiesPage(page: PageEntities): Payload[] { + try { + var out_msgs: Array = []; + out_msgs = [{ payload: 'pageType~cardEntities' }] + out_msgs.push({ payload: GeneratePageElements(page) }); + return out_msgs + } catch (err) { + console.warn('function GenerateEntitiesPage: ' + err.message); + } +} + +function GenerateGridPage(page: PageGrid): Payload[] { + try { + var out_msgs: Array = []; + out_msgs = [{ payload: 'pageType~cardGrid' }] + out_msgs.push({ payload: GeneratePageElements(page) }); + return out_msgs + } catch (err) { + console.warn('function GenerateGridPage: ' + err.message); + } +} + +function GeneratePageElements(page: Page): string { + try { + activePage = page; + let maxItems = 0; + switch (page.type) { + case 'cardThermo': + maxItems = 1; + break; + case 'cardAlarm': + maxItems = 1; + break; + case 'cardMedia': + maxItems = 1; + break; + case 'cardQR': + maxItems = 1; + break; + case 'cardEntities': + if (getState(NSPanel_Path + 'NSPanel_Version').val == 'eu') { + maxItems = 4; + } else { + maxItems = 5; + } + break; + case 'cardGrid': + maxItems = 6; + break; + } + + let pageData = 'entityUpd~' + page.heading + '~' + GetNavigationString(pageId); + + for (let index = 0; index < maxItems; index++) { + if (page.items[index] !== undefined) { + pageData += CreateEntity(page.items[index], index + 1, page.useColor); + } + } + return pageData; + } catch (err) { + console.warn('function GeneratePageElements: ' + err.message); + } +} + +function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = false): string { + try { + var iconId = '0'; + if (pageItem.id == 'delete') { + return '~delete~~~~~'; + } + + var name: string; + var type: string; + + // ioBroker + if (existsObject(pageItem.id) || pageItem.navigate === true) { + var iconColor = rgb_dec565(config.defaultColor); + + if (pageItem.navigate) { + type = 'button'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('gesture-tap-button'); + iconColor = GetIconColor(pageItem, true, useColors); + let buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; + return '~' + type + '~' + 'navigate.' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + pageItem.name + '~' + buttonText; + } + + let o = getObject(pageItem.id) + var val = null; + + if (existsState(pageItem.id + '.GET')) { + val = getState(pageItem.id + '.GET').val; + RegisterEntityWatcher(pageItem.id + '.GET'); + } else if (existsState(pageItem.id + '.SET')) { + val = getState(pageItem.id + '.SET').val; + RegisterEntityWatcher(pageItem.id + '.SET'); + } + + // Fallback if no name is given + name = pageItem.name !== undefined ? pageItem.name : o.common.name.de; + + switch (o.common.role) { + case 'socket': + case 'light': + type = 'light'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + var iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : o.common.role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + var optVal = '0'; + + if (val === true || val === 'true') { + optVal = '1'; + iconColor = GetIconColor(pageItem, true, useColors); + } else { + iconColor = GetIconColor(pageItem, false, useColors); + if (pageItem.icon !== undefined) { + if (pageItem.icon2 !== undefined) { + iconId = iconId2; + } + } + } + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'hue': + type = 'light'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lightbulb'); + var optVal = '0'; + + if (existsState(pageItem.id + '.ON_ACTUAL')) { + val = getState(pageItem.id + '.ON_ACTUAL').val; + RegisterEntityWatcher(pageItem.id + '.ON_ACTUAL'); + } + + if (val === true || val === 'true') { + optVal = '1'; + iconColor = GetIconColor(pageItem, existsState(pageItem.id + '.DIMMER') ? 100 - getState(pageItem.id + '.DIMMER').val : true, useColors); + } + + if (pageItem.interpolateColor != undefined && pageItem.interpolateColor == true) { + if (existsState(pageItem.id + '.HUE')) { + if (getState(pageItem.id + '.HUE').val != null) { + let huecolor = hsv2rgb(getState(pageItem.id + '.HUE').val, 1, 1); + let rgb = { red: Math.round(huecolor[0]), green: Math.round(huecolor[1]), blue: Math.round(huecolor[2]) }; + iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); + // RegisterDetailEntityWatcher(id + '.HUE'); + } + } + } + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'ct': + type = 'light'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lightbulb'); + var optVal = '0'; + + if (existsState(pageItem.id + '.ON')) { + val = getState(pageItem.id + '.ON').val; + RegisterEntityWatcher(pageItem.id + '.ON'); + } + + if (val === true || val === 'true') { + optVal = '1'; + iconColor = GetIconColor(pageItem, existsState(pageItem.id + '.DIMMER') ? 100 - getState(pageItem.id + '.DIMMER').val : true, useColors); + } + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'rgb': + type = 'light'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lightbulb'); + var optVal = '0'; + + if (existsState(pageItem.id + '.ON_ACTUAL')) { + val = getState(pageItem.id + '.ON_ACTUAL').val; + RegisterEntityWatcher(pageItem.id + '.ON_ACTUAL'); + } + + if (val === true || val === 'true') { + optVal = '1'; + iconColor = GetIconColor(pageItem, existsState(pageItem.id + '.DIMMER') ? 100 - getState(pageItem.id + '.DIMMER').val : true, useColors); + } + + if (existsState(pageItem.id + '.RED') && existsState(pageItem.id + '.GREEN') && existsState(pageItem.id + '.BLUE')) { + if (getState(pageItem.id + '.RED').val != null && getState(pageItem.id + '.GREEN').val != null && getState(pageItem.id + '.BLUE').val != null) { + let rgbRed = getState(pageItem.id + '.RED').val; + let rgbGreen = getState(pageItem.id + '.GREEN').val; + let rgbBlue = getState(pageItem.id + '.BLUE').val; + let rgb = { red: Math.round(rgbRed), green: Math.round(rgbGreen), blue: Math.round(rgbBlue) }; + iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); + } + } + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'rgbSingle': + type = 'light'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lightbulb'); + var optVal = '0'; + + if (existsState(pageItem.id + '.ON_ACTUAL')) { + val = getState(pageItem.id + '.ON_ACTUAL').val; + RegisterEntityWatcher(pageItem.id + '.ON_ACTUAL'); + } + + if (val === true || val === 'true') { + optVal = '1' + iconColor = GetIconColor(pageItem, existsState(pageItem.id + '.DIMMER') ? 100 - getState(pageItem.id + '.DIMMER').val : true, useColors); + } + + if (existsState(pageItem.id + '.RGB')) { + if (getState(pageItem.id + '.RGB').val != null) { + var hex = getState(pageItem.id + '.RGB').val; + var hexRed = parseInt(hex[1] + hex[2], 16); + var hexGreen = parseInt(hex[3] + hex[4], 16); + var hexBlue = parseInt(hex[5] + hex[6], 16); + let rgb = { red: Math.round(hexRed), green: Math.round(hexGreen), blue: Math.round(hexBlue) }; + iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); + } + } + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'dimmer': + type = 'light'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lightbulb'); + var optVal = '0'; + + if (existsState(pageItem.id + '.ON_ACTUAL')) { + val = getState(pageItem.id + '.ON_ACTUAL').val; + RegisterEntityWatcher(pageItem.id + '.ON_ACTUAL'); + } else if (existsState(pageItem.id + '.ON_SET')) { + val = getState(pageItem.id + '.ON_SET').val; + RegisterEntityWatcher(pageItem.id + '.ON_SET'); + } + + if (val === true || val === 'true') { + optVal = '1'; + iconColor = GetIconColor(pageItem, existsState(pageItem.id + '.ACTUAL') ? 100 - getState(pageItem.id + '.ACTUAL').val : true, useColors); + } + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'blind': + type = 'shutter'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('window-open'); + iconColor = GetIconColor(pageItem, existsState(pageItem.id + '.ACTUAL') ? getState(pageItem.id + '.ACTUAL').val : true, useColors); + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~'; + + case 'door': + case 'window': + type = 'text'; + + if (existsState(pageItem.id + '.ACTUAL')) { + if (getState(pageItem.id + '.ACTUAL').val) { + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); + iconColor = GetIconColor(pageItem, false, useColors); + var windowState = findLocale('window', 'opened'); + } else { + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); + //iconId = Icons.GetIcon('window-closed-variant'); + iconColor = GetIconColor(pageItem, true, useColors); + var windowState = findLocale('window', 'closed'); + } + + RegisterEntityWatcher(pageItem.id + '.ACTUAL'); + } + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState; + + case 'info': + + case 'humidity': + + case 'temperature': + + case 'value.temperature': + + case 'value.humidity': + + case 'sensor.door': + + case 'sensor.window': + + case 'thermostat': + type = 'text'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'value.temperature' || o.common.role == 'thermostat' ? Icons.GetIcon('thermometer') : Icons.GetIcon('information-outline'); + let unit = ''; + var optVal = '0'; + + if (existsState(pageItem.id + '.ON_ACTUAL')) { + optVal = getState(pageItem.id + '.ON_ACTUAL').val; + unit = pageItem.unit !== undefined ? pageItem.unit : GetUnitOfMeasurement(pageItem.id + '.ON_ACTUAL'); + RegisterEntityWatcher(pageItem.id + '.ON_ACTUAL'); + } else if (existsState(pageItem.id + '.ACTUAL')) { + optVal = getState(pageItem.id + '.ACTUAL').val; + unit = pageItem.unit !== undefined ? pageItem.unit : GetUnitOfMeasurement(pageItem.id + '.ACTUAL'); + RegisterEntityWatcher(pageItem.id + '.ACTUAL'); + } + + if (o.common.role == 'value.temperature') { + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('thermometer'); + } + + iconColor = GetIconColor(pageItem, parseInt(optVal), useColors); + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal + ' ' + unit; + + case 'buttonSensor': + case 'button': + type = 'button'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('gesture-tap-button'); + iconColor = GetIconColor(pageItem, true, useColors); + let buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; + + case 'lock': + type = 'button'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lock'); + iconColor = GetIconColor(pageItem, true, useColors); + + if (existsState(pageItem.id + '.ACTUAL')) { + if (getState(pageItem.id + '.ACTUAL').val) { + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lock'); + iconColor = GetIconColor(pageItem, true, useColors); + var lockState = findLocale('lock', 'UNLOCK'); + } else { + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lock-open-variant'); + iconColor = GetIconColor(pageItem, false, useColors); + var lockState = findLocale('lock', 'LOCK'); + } + lockState = pageItem.buttonText !== undefined ? pageItem.buttonText : lockState; + RegisterEntityWatcher(pageItem.id + '.ACTUAL'); + } + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState; + + case 'slider': + type = 'number'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('plus-minus-variant'); + + if (existsState(pageItem.id + '.SET')) { + val = getState(pageItem.id + '.SET').val; + RegisterEntityWatcher(pageItem.id + '.SET'); + } + + if (existsState(pageItem.id + '.ACTUAL')) { + val = getState(pageItem.id + '.ACTUAL').val; + RegisterEntityWatcher(pageItem.id + '.ACTUAL'); + } + + iconColor = GetIconColor(pageItem, false, useColors) + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; + + case 'volumeGroup': + case 'volume': + type = 'number'; + if (existsState(pageItem.id + '.SET')) { + val = getState(pageItem.id + '.SET').val; + RegisterEntityWatcher(pageItem.id + '.SET'); + } + if (existsState(pageItem.id + '.ACTUAL')) { + val = getState(pageItem.id + '.ACTUAL').val; + RegisterEntityWatcher(pageItem.id + '.ACTUAL'); + } + + iconColor = GetIconColor(pageItem, false, useColors) + if (existsState(pageItem.id + '.MUTE')) { + getState(pageItem.id + '.MUTE').val ? iconColor = GetIconColor(pageItem, false, useColors) : iconColor = GetIconColor(pageItem, true, useColors); + RegisterEntityWatcher(pageItem.id + '.MUTE'); + } + + if (val > 0 && val <= 33 && !getState(pageItem.id + '.MUTE').val) { + iconId = Icons.GetIcon('volume-low'); + } else if (val > 33 && val <= 66 && !getState(pageItem.id + '.MUTE').val) { + iconId = Icons.GetIcon('volume-medium'); + } else if (val > 66 && val <= 100 && !getState(pageItem.id + '.MUTE').val) { + iconId = Icons.GetIcon('volume-high'); + } else { + iconId = Icons.GetIcon('volume-mute'); + } + + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; + + case 'warning': + type = 'text'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('alert-outline'); + iconColor = getState(([pageItem.id, '.LEVEL'].join(''))).val; + let itemName = getState(([pageItem.id, '.TITLE'].join(''))).val; + let itemInfo = getState(([pageItem.id, '.INFO'].join(''))).val; + + return '~' + type + '~' + itemName + '~' + iconId + '~' + iconColor + '~' + itemName + '~' + itemInfo; + + default: + return '~delete~~~~~'; + } + } + return '~delete~~~~~'; + } catch (err) { + console.warn('function CreateEntity: ' + err.message); + } +} + +function findLocale(controlsObject: string, controlsState: string): string { + const locale = config.locale; + const strJson = getState(NSPanel_Path + 'NSPanel_locales_json').val; + + if (Debug) console.log(controlsObject + ' - ' + controlsState); + + try { + const obj = JSON.parse(strJson); + const strLocale = obj[controlsObject][controlsState][locale]; + + if (strLocale != undefined) { + return strLocale; + } else { + return controlsState; + } + + } catch (err) { + if (err.message.substring(0, 35) == 'Cannot read properties of undefined') { + if (Debug) console.log('function findLocale: missing translation: ' + controlsObject + ' - ' + controlsState); + } else { + console.warn('function findLocale: ' + err.message); + } + return controlsState; + } +} + +function GetIconColor(pageItem: PageItem, value: (boolean | number), useColors: boolean): number { + try { + // dimmer + if ((pageItem.useColor || useColors) && pageItem.interpolateColor && typeof (value) === 'number') { + let maxValue = pageItem.maxValueBrightness !== undefined ? pageItem.maxValueBrightness : 100; + let minValue = pageItem.minValueBrightness !== undefined ? pageItem.minValueBrightness : 0; + if (pageItem.maxValue !== undefined) maxValue = pageItem.maxValue; + if (pageItem.minValue !== undefined) minValue = pageItem.minValue; + value = value > maxValue ? maxValue : value; + value = value < minValue ? minValue : value; + + return rgb_dec565( + Interpolate( + pageItem.offColor !== undefined ? pageItem.offColor : config.defaultOffColor, + pageItem.onColor !== undefined ? pageItem.onColor : config.defaultOnColor, + scale(value, minValue, maxValue, 0, 1) + ) + ); + } + + if ((pageItem.useColor || useColors) && ((typeof (value) === 'boolean' && value) || value > (pageItem.minValueBrightness !== undefined ? pageItem.minValueBrightness : 0))) { + return rgb_dec565(pageItem.onColor !== undefined ? pageItem.onColor : config.defaultOnColor) + } + + return rgb_dec565(pageItem.offColor !== undefined ? pageItem.offColor : config.defaultOffColor); + } catch (err) { + console.warn('function GetIconColor: ' + err.message); + } +} + +function RegisterEntityWatcher(id: string): void { + try { + if (subscriptions.hasOwnProperty(id)) { + return; + } + + subscriptions[id] = (on({ id: id, change: 'any' }, (data) => { + if (pageId == -1 && config.button1Page != undefined) { + SendToPanel({ payload: GeneratePageElements(config.button1Page) }); + } + if (pageId == -2 && config.button2Page != undefined) { + SendToPanel({ payload: GeneratePageElements(config.button2Page) }); + } + if (activePage !== undefined) { + SendToPanel({ payload: GeneratePageElements(activePage) }); + } + })); + } catch (err) { + console.warn('function RegisterEntityWatcher: ' + err.message); + } +} + +function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: string): void { + try { + if (subscriptions.hasOwnProperty(id)) { + return; + } + + subscriptions[id] = (on({ id: id, change: 'any' }, () => { + SendToPanel(GenerateDetailPage(type, pageItem)); + })) + } catch (err) { + console.warn('function RegisterDetailEntityWatcher: ' + err.message); + } +} + +function GetUnitOfMeasurement(id: string): string { + try { + if (!existsObject(id)) + return ''; + + let obj = getObject(id); + if (typeof obj.common.unit !== 'undefined') { + return obj.common.unit + } + + if (typeof obj.common.alias !== 'undefined' && typeof obj.common.alias.id !== 'undefined') { + return GetUnitOfMeasurement(obj.common.alias.id); + } + + return ''; + } catch (err) { + console.warn('function GetUnitOfMeasurement: ' + err.message); + } +} + +function GenerateThermoPage(page: PageThermo): Payload[] { + try { + var id = page.items[0].id + var out_msgs: Array = []; + out_msgs.push({ payload: 'pageType~cardThermo' }); + + // ioBroker + if (existsObject(id)) { + let o = getObject(id); + let name = page.heading !== undefined ? page.heading : o.common.name.de; + let currentTemp = 0; + if (existsState(id + '.ACTUAL')) + currentTemp = (Math.round(parseFloat(getState(id + '.ACTUAL').val) * 10) / 10); + + let destTemp = 0; + if (existsState(id + '.SET')) { + destTemp = getState(id + '.SET').val.toFixed(2) * 10; + } + let statusStr: String = 'MANU'; + let status = ''; + if (existsState(id + '.MODE')) + status = getState(id + '.MODE').val; + + let minTemp = page.items[0].minValue !== undefined ? page.items[0].minValue : 50; //Min Temp 5°C + let maxTemp = page.items[0].maxValue !== undefined ? page.items[0].maxValue : 300; //Max Temp 30°C + let stepTemp = 5 // 0,5° Schritte + + //Attribute hinzufügen, wenn im Alias definiert + let i_list = Array.prototype.slice.apply($('[state.id="' + id + '.*"]')); + if ((i_list.length - 3) != 0) { + + var i = 0; + var bt = ['~~~~', '~~~~', '~~~~', '~~~~', '~~~~', '~~~~', '~~~~', '~~~~', '~~~~']; + + if (o.common.role == 'thermostat') { + + if (existsState(id + '.AUTOMATIC') && getState(id + '.AUTOMATIC').val != null) { + if (getState(id + '.AUTOMATIC').val) { + bt[i++] = Icons.GetIcon('alpha-a-circle') + '~' + rgb_dec565(On) + '~1~' + 'AUTT' + '~'; + statusStr = 'AUTO'; + } else { + bt[i++] = Icons.GetIcon('alpha-a-circle') + '~33840~1~' + 'AUTT' + '~'; + } + } + if (existsState(id + '.MANUAL') && getState(id + '.MANUAL').val != null) { + if (getState(id + '.MANUAL').val) { + bt[i++] = Icons.GetIcon('alpha-m-circle') + '~' + rgb_dec565(On) + '~1~' + 'MANT' + '~'; + statusStr = 'MANU'; + } else { + bt[i++] = Icons.GetIcon('alpha-m-circle') + '~33840~1~' + 'MANT' + '~'; + } + } + if (existsState(id + '.PARTY') && getState(id + '.PARTY').val != null) { + if (getState(id + '.PARTY').val) { + bt[i++] = Icons.GetIcon('party-popper') + '~' + rgb_dec565(On) + '~1~' + 'PART' + '~'; + statusStr = 'PARTY'; + } else { + bt[i++] = Icons.GetIcon('party-popper') + '~33840~1~' + 'PART' + '~'; + } + } + if (existsState(id + '.VACATION') && getState(id + '.VACATION').val != null) { + if (getState(id + '.VACATION').val) { + bt[i++] = Icons.GetIcon('palm-tree') + '~' + rgb_dec565(On) + '~1~' + 'VACT' + '~'; + statusStr = 'VAC'; + } else { + bt[i++] = Icons.GetIcon('palm-tree') + '~33840~1~' + 'VACT' + '~'; + } + } + if (existsState(id + '.BOOST') && getState(id + '.BOOST').val != null) { + if (getState(id + '.BOOST').val) { + bt[i++] = Icons.GetIcon('fast-forward-60') + '~' + rgb_dec565(On) + '~1~' + 'BOOT' + '~'; + statusStr = 'BOOST'; + } else { + bt[i++] = Icons.GetIcon('fast-forward-60') + '~33840~1~' + 'BOOT' + '~'; + } + } + + for (let i_index in i_list) { + let thermostatState = i_list[i_index].split('.'); + if ( + thermostatState[thermostatState.length - 1] != 'SET' && + thermostatState[thermostatState.length - 1] != 'ACTUAL' && + thermostatState[thermostatState.length - 1] != 'MODE' + ) { + i++; + + switch (thermostatState[thermostatState.length - 1]) { + case 'HUMIDITY': + if (existsState(id + '.HUMIDITY') && getState(id + '.HUMIDITY').val != null) { + if (parseInt(getState(id + '.HUMIDITY').val) < 40) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~65504~1~' + 'HUM' + '~'; + } else if (parseInt(getState(id + '.HUMIDITY').val) < 30) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~63488~1~' + 'HUM' + '~'; + } else if (parseInt(getState(id + '.HUMIDITY').val) >= 40) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~2016~1~' + 'HUM' + '~'; + } else if (parseInt(getState(id + '.HUMIDITY').val) > 65) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~65504~1~' + 'HUM' + '~'; + } else if (parseInt(getState(id + '.HUMIDITY').val) > 75) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~63488~1~' + 'HUM' + '~'; + } + } else i--; + break; + case 'LOWBAT': + if (existsState(id + '.LOWBAT') && getState(id + '.LOWBAT').val != null) { + if (getState(id + '.LOWBAT').val) { + bt[i - 1] = Icons.GetIcon('battery-low') + '~63488~1~' + 'LBAT' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('battery-high') + '~2016~1~' + 'LBAT' + '~'; + } + } else i--; + break; + case 'MAINTAIN': + if (existsState(id + '.MAINTAIN') && getState(id + '.MAINTAIN').val != null) { + if (getState(id + '.MAINTAIN').val >> .1) { + bt[i - 1] = Icons.GetIcon('account-wrench') + '~60897~1~' + 'MAIN' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('account-wrench') + '~33840~1~' + 'MAIN' + '~'; + } + } else i--; + break; + case 'UNREACH': + if (existsState(id + '.UNREACH') && getState(id + '.UNREACH').val != null) { + if (getState(id + '.UNREACH').val) { + bt[i - 1] = Icons.GetIcon('wifi-off') + '~63488~1~' + 'WLAN' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('wifi') + '~2016~1~' + 'WLAN' + '~'; + } + } else i--; + break; + case 'POWER': + if (existsState(id + '.POWER') && getState(id + '.POWER').val != null) { + if (getState(id + '.POWER').val) { + bt[i - 1] = Icons.GetIcon('power-standby') + '~2016~1~' + 'POW' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('power-standby') + '~33840~1~' + 'POW' + '~'; + } + } else i--; + break; + case 'ERROR': + if (existsState(id + '.ERROR') && getState(id + '.ERROR').val != null) { + if (getState(id + '.ERROR').val) { + bt[i - 1] = Icons.GetIcon('alert-circle') + '~63488~1~' + 'ERR' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('alert-circle') + '~33840~1~' + 'ERR' + '~'; + } + } else i--; + break; + case 'WORKING': + if (existsState(id + '.WORKING') && getState(id + '.WORKING').val != null) { + if (getState(id + '.WORKING').val) { + bt[i - 1] = Icons.GetIcon('briefcase-check') + '~2016~1~' + 'WORK' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('briefcase-check') + '~33840~1~' + 'WORK' + '~'; + } + } else i--; + break; + default: + i--; + break; + } + } + } + + for (let j = i; j < 9; j++) { + bt[j] = '~~~~'; + } + } + + if (o.common.role == 'airCondition') { + if (existsState(id + '.MODE') && getState(id + '.MODE').val != null) { + let Mode = getState(id + '.MODE').val + if (existsState(id + '.POWER') && getState(id + '.POWER').val != null) { + if (Mode != 0 || getState(id + '.POWER').val) { //0=ON oder .POWER = true + bt[0] = Icons.GetIcon('power-standby') + '~2016~1~' + 'POWER' + '~'; + statusStr = 'ON'; + } else { + bt[0] = Icons.GetIcon('power-standby') + '~35921~0~' + 'POWER' + '~'; + statusStr = 'OFF'; + } + } + if (Mode == 1) { //1=AUTO + bt[1] = Icons.GetIcon('air-conditioner') + '~1024~1~' + 'AUTO' + '~'; + statusStr = 'AUTO'; + } else { + bt[1] = Icons.GetIcon('air-conditioner') + '~35921~0~' + 'AUTO' + '~'; + } + if (Mode == 2) { //2=COOL + bt[2] = Icons.GetIcon('snowflake') + '~11487~1~' + 'COOL' + '~'; + statusStr = 'COOL'; + } else { + bt[2] = Icons.GetIcon('snowflake') + '~35921~0~' + 'COOL' + '~'; + } + if (Mode == 3) { //3=HEAT + bt[3] = Icons.GetIcon('fire') + '~64512~1~' + 'HEAT' + '~'; + statusStr = 'HEAT'; + } else { + bt[3] = Icons.GetIcon('fire') + '~35921~0~' + 'HEAT' + '~'; + } + if (Mode == 4) { //4=ECO + bt[4] = Icons.GetIcon('alpha-e-circle-outline') + '~2016~1~' + 'ECO' + '~'; + statusStr = 'ECO'; + } else { + bt[4] = Icons.GetIcon('alpha-e-circle-outline') + '~35921~0~' + 'ECO' + '~'; + } + if (Mode == 5) { //5=FANONLY + bt[5] = Icons.GetIcon('fan') + '~11487~1~' + 'FAN' + '~'; + statusStr = 'FAN ONLY'; + } else { + bt[5] = Icons.GetIcon('fan') + '~35921~0~' + 'FAN' + '~'; + } + if (Mode == 6) { //6=DRY + bt[6] = Icons.GetIcon('water-percent') + '~60897~1~' + 'DRY' + '~'; + statusStr = 'DRY'; + } else { + bt[6] = Icons.GetIcon('water-percent') + '~35921~0~' + 'DRY' + '~'; + } + if (existsState(id + '.SWING') && getState(id + '.SWING').val != null) { + if (getState(id + '.POWER').val && getState(id + '.SWING').val == 1) { //0=ON oder .SWING = true + bt[7] = Icons.GetIcon('swap-vertical-bold') + '~2016~1~' + 'SWING' + '~'; + } else { + bt[7] = Icons.GetIcon('swap-vertical-bold') + '~35921~0~' + 'SWING' + '~'; + } + } + } + } + } + + let icon_res = bt[0] + bt[1] + bt[2] + bt[3] + bt[4] + bt[5] + bt[6] + bt[7]; + + out_msgs.push({ + payload: 'entityUpd~' + + name + '~' // Heading + + GetNavigationString(pageId) + '~' // Page Navigation + + id + '~' // internalNameEntiy + + currentTemp + config.temperatureUnit + '~' // Ist-Temperatur (String) + + destTemp + '~' // Soll-Temperatur (numerisch ohne Komma) + + statusStr + '~' // Mode + + minTemp + '~' // Thermostat Min-Temperatur + + maxTemp + '~' // Thermostat Max-Temperatur + + stepTemp + '~' // Schritte für Soll (5°C) + + icon_res // Icons Status + + findLocale('thermostat', 'Currently') + '~' // Bezeicher vor Aktueller Raumtemperatur + + findLocale('thermostat', 'State') + '~' // Bezeicner vor + + '~' // Bezeichner vor HVAC -- Gibt es nicht mehr + + config.temperatureUnit + '~' // Bezeichner hinter Solltemp + + '' + '~' // iconTemperature dstTempTwoTempMode + + '' // dstTempTwoTempMode + }); + + } + + if (Debug) console.log(out_msgs); + return out_msgs + } catch (err) { + console.warn('function GenerateThermoPage: ' + err.message); + } +} + +function GenerateMediaPage(page: PageMedia): Payload[] { + try { + var id = page.items[0].id + + var out_msgs: Array = []; + + out_msgs.push({ payload: 'pageType~cardMedia' }); + if (existsObject(id)) { + let name = getState(id + '.ALBUM').val; + let title = getState(id + '.TITLE').val; + let author = getState(id + '.ARTIST').val; + + let vInstance = page.items[0].adapterPlayerInstance; + let v1Adapter = vInstance.split('.'); + let v2Adapter = v1Adapter[0]; + + //Alexa + neue Adpter/Player + let media_icon = Icons.GetIcon('playlist-music'); + + //Spotify-Premium + if (v2Adapter == 'spotify-premium') { + media_icon = Icons.GetIcon('spotify'); + name = getState(id + '.CONTEXT_DESCRIPTION').val; + let nameLenght = name.length; + if (name.substring(0,9) == 'Playlist:') { + let nameLenght = name.length; + name = name.slice(10, nameLenght); + } else if (name.substring(0,6) == 'Album:') { + let nameLenght = name.length; + name = name.slice(10, nameLenght); + } else if (name.substring(0,6) == 'Track') { + name = 'Spotify-Premium'; + } + if (nameLenght == 0) { + name = 'Spotify-Premium'; + } + author = getState(id + '.ARTIST').val + ' | ' + getState(id + '.ALBUM').val; + if (author.length > 30) { + author = getState(id + '.ARTIST').val; + } + if ((getState(id + '.ARTIST').val).length == 0) { + author = 'no music to control'; + } + } + + //Sonos + if (v2Adapter == 'sonos') { + media_icon = Icons.GetIcon('music'); + name = getState(id + '.CONTEXT_DESCRIPTION').val; + let nameLenght = name.length; + if (nameLenght == 0) { + name = 'Sonos Player'; + } + author = getState(id + '.ARTIST').val + ' | ' + getState(id + '.ALBUM').val; + if ((getState(id + '.ARTIST').val).length == 0) { + author = 'no music to control'; + } + } + + //Logitech Squeezebox RPC + if (v2Adapter == 'squeezeboxrpc') { + media_icon = Icons.GetIcon('dlna'); + let nameLenght = name.length; + if (nameLenght == 0) { + name = 'Squeezebox RPC'; + author = 'no music to control'; + } + } + + //Alexa2 + if (v2Adapter == 'alexa2') { + media_icon = Icons.GetIcon('playlist-music'); + let nameLenght = name.length; + if (nameLenght == 0) { + name = 'Alexa Player'; + author = 'no music to control'; + } + } + + let volume = getState(id + '.VOLUME').val; + var iconplaypause = Icons.GetIcon('pause'); //pause + var onoffbutton = 1374; + + //Für alle Player + if (getState(id + '.STATE').val) { + onoffbutton = 65535; + iconplaypause = Icons.GetIcon('pause'); //pause + } else { + iconplaypause = Icons.GetIcon('play'); //play + } + + //Ausnahme für squeezebox, da State = Power + if (getState(id + '.PAUSE').val === false && v2Adapter == 'squeezeboxrpc') { + onoffbutton = 65535; + iconplaypause = Icons.GetIcon('pause'); //pause + } else { + iconplaypause = Icons.GetIcon('play'); //play + } + + if (Debug) console.log(v2Adapter); + + let currentSpeaker = 'kein Speaker gefunden'; + + if (v2Adapter == 'alexa2') { + currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'Echo-Devices.', page.items[0].mediaDevice, '.Info.name'].join(''))).val; + } else if (v2Adapter == 'spotify-premium') { + currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'player.device.name'].join(''))).val; + } else if (v2Adapter == 'sonos') { + currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'root.', page.items[0].mediaDevice, '.members'].join(''))).val; + } else if (v2Adapter == 'squeezeboxrpc') { + if(existsObject(([page.items[0].adapterPlayerInstance, 'Playername'].join('')))) { + currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'Playername'].join(''))).val; + } + } + //------------------------------------------------------------------------------------------------------------- + // nachfolgend alle Alexa-Devices (ist Online / Player- und Commands-Verzeichnis vorhanden) auflisten und verketten + // Wenn Konstante alexaSpeakerList mind. einen Eintrag enthält, wird die Konstante verwendet - ansonsten Alle Devices aus dem Alexa Adapter + let speakerlist = ''; + if (page.items[0].speakerList.length > 0) { + for (let i_index in page.items[0].speakerList) { + speakerlist = speakerlist + page.items[0].speakerList[i_index] + '?'; + } + } else { + let i_list = Array.prototype.slice.apply($('[state.id="' + page.items[0].adapterPlayerInstance + 'Echo-Devices.*.Info.name"]')); + for (let i_index in i_list) { + let i = i_list[i_index]; + let deviceId = i; + deviceId = deviceId.split('.'); + if (getState(([page.items[0].adapterPlayerInstance, 'Echo-Devices.', deviceId[3], '.online'].join(''))).val && + existsObject(([page.items[0].adapterPlayerInstance, 'Echo-Devices.', deviceId[3], '.Player'].join(''))) && + existsObject(([page.items[0].adapterPlayerInstance, 'Echo-Devices.', deviceId[3], '.Commands'].join('')))) { + speakerlist = speakerlist + getState(i).val + '?'; + } + } + } + speakerlist = speakerlist.substring(0, speakerlist.length - 1); + //-------------------------------------------------------------------------------------------------------------- + + out_msgs.push({ + payload: 'entityUpd~' + //entityUpd + name + '~' + //heading + GetNavigationString(pageId) + '~' + //navigation + id + '~' + //internalNameEntiy + media_icon + '~' + //icon + title + '~' + //title + author + '~' + //author + volume + '~' + //volume + iconplaypause + '~' + //playpauseicon + currentSpeaker + '~' + //currentSpeaker + speakerlist + '~' + //speakerList-seperated-by-? + onoffbutton + }); //On/Off Button Color + } + if (Debug) console.log(out_msgs); + return out_msgs + } catch (err) { + console.warn('function GenerateMediaPage: ' + err.message); + } +} + +function GenerateAlarmPage(page: PageAlarm): Payload[] { + try { + activePage = page; + var id = page.items[0].id + + var out_msgs: Array = []; + out_msgs.push({ payload: 'pageType~cardAlarm' }); + var nsPath = NSPanel_Alarm_Path + 'Alarm.'; + + if (existsState(nsPath + 'AlarmPin') == false || existsState(nsPath + 'AlarmState') == false || existsState(nsPath + 'AlarmType') == false || existsState(nsPath + 'PIN_Failed') == false || existsState(nsPath + 'PANEL') == false) { + createState(nsPath + 'AlarmPin', '0000', { type: 'string' }, function () { setState(nsPath + 'AlarmPin', '0000') }); + createState(nsPath + 'AlarmState', 'disarmed', { type: 'string' }, function () { setState(nsPath + 'AlarmState', 'disarmed') }); + createState(nsPath + 'AlarmType', 'D1', { type: 'string' }, function () { setState(nsPath + 'AlarmType', 'D1') }); + createState(nsPath + 'PIN_Failed', 0, { type: 'number' }, function () { setState(nsPath + 'PIN_Failed', 0) }); + createState(nsPath + 'PANEL', NSPanel_Path, { type: 'string' }, function () { setState(nsPath + 'PANEL', NSPanel_Path) }); + } + + if (existsState(nsPath + 'AlarmPin') && existsState(nsPath + 'AlarmState') && existsState(nsPath + 'AlarmType')) { + //var entityPin = getState(nsPath + 'AlarmPin').val; + var entityState = getState(nsPath + 'AlarmState').val; + //var entityType = getState(nsPath + 'AlarmType').val; + var arm1: string, arm2: string, arm3: string, arm4: string; + var arm1ActionName: string, arm2ActionName: string, arm3ActionName: string, arm4ActionName: string; + var icon = '0'; + var iconcolor = 63488; + var numpadStatus = 'disable'; + var flashing = 'disable'; + + if (Debug) console.log(id); + + if (entityState == 'armed' || entityState == 'triggered') { + arm1 = 'Deaktivieren'; //arm1*~* + arm1ActionName = 'D1'; //arm1ActionName*~* + arm2 = ''; //arm2*~* + arm2ActionName = ''; //arm2ActionName*~* + arm3 = ''; //arm3*~* + arm3ActionName = ''; //arm3ActionName*~* + arm4 = ''; //arm4*~* + arm4ActionName = ''; //arm4ActionName*~* + } + + if (entityState == 'disarmed' || entityState == 'arming' || entityState == 'pending') { + arm1 = 'Vollschutz'; //arm1*~* + arm1ActionName = 'A1'; //arm1ActionName*~* + arm2 = 'Zuhause'; //arm2*~* + arm2ActionName = 'A2'; //arm2ActionName*~* + arm3 = 'Nacht'; //arm3*~* + arm3ActionName = 'A3'; //arm3ActionName*~* + arm4 = 'Besuch'; //arm4*~* + arm4ActionName = 'A4'; //arm4ActionName*~* + } + + if (entityState == 'armed') { + icon = Icons.GetIcon('shield-home'); //icon*~* + iconcolor = 63488; //iconcolor*~* + numpadStatus = 'enable'; //numpadStatus*~* + flashing = 'disable'; //flashing* + } + if (entityState == 'disarmed') { + icon = Icons.GetIcon('shield-off'); //icon*~* + iconcolor = 2016; //iconcolor*~* + numpadStatus = 'enable'; //numpadStatus*~* + flashing = 'disable'; //flashing* + } + if (entityState == 'arming' || entityState == 'pending') { + icon = Icons.GetIcon('shield'); //icon*~* + iconcolor = rgb_dec565({ red: 243, green: 179, blue: 0 }); //iconcolor*~* + numpadStatus = 'disable'; //numpadStatus*~* + flashing = 'enable' //flashing* + } + if (entityState == 'triggered') { + iconcolor = rgb_dec565({ red: 223, green: 76, blue: 30 }); //icon*~* + icon = Icons.GetIcon('bell-ring'); //iconcolor*~* + numpadStatus = 'enable'; //numpadStatus*~* + flashing = 'enable' //flashing* + } + + out_msgs.push({ + payload: 'entityUpd~' + //entityUpd~* + id + '~' + //internalNameEntity*~* + GetNavigationString(pageId) + '~' + //navigation*~* --> hiddenCards + arm1 + '~' + //arm1*~* + arm1ActionName + '~' + //arm1ActionName*~* + arm2 + '~' + //arm2*~* + arm2ActionName + '~' + //arm2ActionName*~* + arm3 + '~' + //arm3*~* + arm3ActionName + '~' + //arm3ActionName*~* + arm4 + '~' + //arm4*~* + arm4ActionName + '~' + //arm4ActionName*~* + icon + '~' + //icon*~* + iconcolor + '~' + //iconcolor*~* + numpadStatus + '~' + //numpadStatus*~* + flashing + }); //flashing* + + if (Debug) console.log(out_msgs); + return out_msgs + } + } catch (err) { + console.warn('function GenerateAlarmPage: ' + err.message); + } +} + +function GenerateQRPage(page: PageQR): Payload[] { + try { + activePage = page; + + var id = page.items[0].id + var out_msgs: Array = []; + out_msgs.push({ payload: 'pageType~cardQR' }); + + let o = getObject(id) + + var heading = page.heading !== undefined ? page.heading : o.common.name.de + var textQR = page.items[0].id + '.ACTUAL' !== undefined ? getState(page.items[0].id + '.ACTUAL').val : 'WIFI:T:undefined;S:undefined;P:undefined;H:undefined;' + var hiddenPWD = false; + if (page.items[0].hidePassword !== undefined && page.items[0].hidePassword == true) { + hiddenPWD = true + } + + const tempstr = textQR.split(';'); + for (let w = 0; w < tempstr.length - 1; w++) { + if (tempstr[w].substring(0, 1) == 'S') { + var optionalValue1 = tempstr[w].slice(2); + } + if (tempstr[w].substring(0, 1) == 'P') { + var optionalValue2 = tempstr[w].slice(2); + } + } + + var type1 = 'text'; + var internalName1 = 'SSID'; + var iconId1 = Icons.GetIcon('wifi'); + var displayName1 = 'SSID'; + var type2 = 'text'; + var internalName2 = 'Passwort'; + var iconId2 = Icons.GetIcon('key'); + var displayName2 = 'Passwort'; + + if (hiddenPWD) { + type2 = 'disable'; + iconId2 = ''; + displayName2 = ''; + } + + out_msgs.push({ + payload: 'entityUpd~' + //entityUpd + heading + '~' + //heading + GetNavigationString(pageId) + '~' + //navigation + textQR + '~' + //textQR + type1 + '~' + //type + internalName1 + '~' + //internalName + iconId1 + '~' + //iconId + 65535 + '~' + //iconColor + displayName1 + '~' + //displayName + optionalValue1 + '~' + //optionalValue + type2 + '~' + //type + internalName2 + '~' + //internalName + iconId2 + '~' + //iconId + 65535 + '~' + //iconColor + displayName2 + '~' + //displayName + optionalValue2 + }); //optionalValue + + //entityUpd,heading,navigation,textQR[,type,internalName,iconId,displayName,optionalValue]x2 + return out_msgs + + } catch (err) { + console.warn('function GenerateQRPage: ' + err.message); + } +} + +function GeneratePowerPage(page: PagePower): Payload[] { + try { + activePage = page; + + if (Debug) console.log(page.items[0].id); + + var demoMode = false; + + try { + var id = page.items[0].id + } catch (err) { + console.log("Kein PageItem definiert - cardPower Demo-Modus aktiv"); + demoMode = true; + } + + let heading = 'cardPower Example'; + if (demoMode != true) { + let o = getObject(id) + heading = page.heading !== undefined ? page.heading : o.common.name.de + } + + const obj = JSON.parse((getState(page.items[0].id + '.ACTUAL').val)); + + var out_msgs: Array = []; + out_msgs.push({ payload: 'pageType~cardPower' }); + + //Demo Data if no pageItem present + let array_icon_color = [White, MSGreen, MSYellow, MSGreen, MSYellow, MSGreen, MSRed]; + let array_icon = ['home', 'battery-charging-60', 'solar-power-variant', 'wind-turbine', 'shape', 'transmission-tower', 'car']; + let array_powerspeed = ['', '-1', '2', '4', '1', '1', '5']; + let array_powerstate = ['', '0,5 kW', '0,9 kW', '2,8 kW', '0,2 kW', '0,1 kW', '4,6 kW']; + + let arrayColorScale = [colorScale0, colorScale1, colorScale2, colorScale3, colorScale4, colorScale5, colorScale6, colorScale7, colorScale8, colorScale9, colorScale10] + + if (!demoMode) { + for (let obji = 0; obji < 6; obji++) { + array_icon_color[obji + 1] = arrayColorScale[obj[obji].iconColor]; + array_icon[obji + 1] = obj[obji].icon; + array_powerspeed[obji + 1] = obj[obji].speed; + array_powerstate[obji + 1] = obj[obji].value + ' ' + obj[obji].unit ; + } + } + + let power_string : any = ''; + + for (let i = 1; i < 7; i++ ) { + power_string = power_string + rgb_dec565(array_icon_color[i]) + '~'; // icon_color~ + power_string = power_string + Icons.GetIcon(array_icon[i]) + '~'; // icon~ + power_string = power_string + array_powerspeed[i] + '~'; // speed~ + power_string = power_string + array_powerstate[i] + '~'; // entity.state~ + } + + power_string = power_string.substring(0, power_string.length - 1); + + out_msgs.push({ + payload: 'entityUpd~' + //entityUpd~* + heading + '~' + //internalNameEntity*~* + GetNavigationString(pageId) + '~' + //navigation*~* + rgb_dec565(array_icon_color[0]) + '~' + // icon_color~ Mitte + Icons.GetIcon(array_icon[0]) + '~' + // icon~ Mitte + array_powerspeed[0] + '~' + // entity.state~ Mitte + power_string + }); + + return out_msgs + + } catch (err) { + console.warn('function GeneratePowerPage: ' + err.message); + } +} + +function setIfExists(id: string, value: any, type: string | null = null): boolean { + try { + if (type === null) { + if (existsState(id)) { + setState(id, value); + return true; + } + } else { + const obj = getObject(id); + if (existsState(id) && obj.common.type !== undefined && obj.common.type === type) { + setState(id, value); + return true; + } + } + + return false; + } catch (err) { + console.warn('function setIfExists: ' + err.message); + } +} + +function toggleState(id: string): boolean { + try { + const obj = getObject(id); + if (existsState(id) && obj.common.type !== undefined && obj.common.type === 'boolean') { + setIfExists(id, !getState(id).val); + return true; + } + return false; + } catch (err) { + console.warn('function toggleState: ' + err.message); + } +} + +function HandleButtonEvent(words): void { + try { + var id = words[2] + var buttonAction = words[3]; + + if (Debug) { + console.log(words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4] + ' - PageId: ' + pageId); + } + + if ((words[2]).substring(0, 8) == 'navigate') { + GeneratePage(eval((words[2]).substring(9, (words[2]).length))); + return; + } + + if (Debug) console.log(buttonAction); + + switch (buttonAction) { + case 'bUp': + if (pageId < 0) { // Prüfen, ob button1page oder button2page + pageId = 0; + } else { + pageId = Math.abs(pageNum); + } + UnsubscribeWatcher(); + GeneratePage(config.pages[pageId]); + break; + case 'bNext': + var pageNum = (((pageId + 1) % config.pages.length) + config.pages.length) % config.pages.length; + pageId = pageNum; + UnsubscribeWatcher(); + GeneratePage(config.pages[pageId]); + break; + case 'bPrev': + var pageNum = (((pageId - 1) % config.pages.length) + config.pages.length) % config.pages.length; + pageId = pageNum; + UnsubscribeWatcher(); + if (activePage != undefined && activePage.parent != undefined) { + //update pageID + for (let i = 0; i < config.pages.length; i++) { + if (config.pages[i] == activePage.parent) { + pageId = i; + break; + } + } + GeneratePage(activePage.parent); + } + else { + GeneratePage(config.pages[pageId]); + } + break; + case 'bExit': + if (config.screenSaverDoubleClick && words[2] == 'screensaver') { + if (words[4] == 2) { + setIfExists(NSPanel_Path + 'ScreensaverInfo.popupNotifyHeading', ''); + setIfExists(NSPanel_Path + 'ScreensaverInfo.popupNotifyText', ''); + GeneratePage(config.pages[pageId]); + } + } else { + if (Debug) console.log('bExit: ' + words[4] + ' - ' + pageId); + setIfExists(NSPanel_Path + 'ScreensaverInfo.popupNotifyHeading', ''); + setIfExists(NSPanel_Path + 'ScreensaverInfo.popupNotifyText', ''); + GeneratePage(activePage); + } + break; + case 'notifyAction': + if (words[4] == 'yes') { + setState(popupNotifyInternalName, { val: words[2], ack: true }); + setState(popupNotifyAction, { val: true, ack: true }); + } else if (words[4] == 'no') { + setState(popupNotifyInternalName, { val: words[2], ack: true }); + setState(popupNotifyAction, { val: false, ack: true }); + } + + setIfExists(config.panelSendTopic, 'exitPopup'); + + break; + case 'OnOff': + if (existsObject(id)) { + var action = false + if (words[4] == '1') + action = true; + let o = getObject(id); + switch (o.common.role) { + case 'socket': + case 'light': + setIfExists(id + '.SET', action); + break; + case 'dimmer': + setIfExists(id + '.ON_SET', action) ? true : setIfExists(id + '.ON_ACTUAL', action); + break; + case 'ct': + setIfExists(id + '.ON', action); + break; + case 'rgb': + case 'rgbSingle': + case 'hue': // Armilar + setIfExists(id + '.ON_ACTUAL', action); + } + } + break; + case 'button': + if (existsObject(id)) { + var action = false + if (words[4] == '1') + action = true; + let o = getObject(id); + switch (o.common.role) { + case 'lock': + case 'button': + toggleState(id + '.SET') ? true : toggleState(id + '.ON_SET'); + break; + case 'buttonSensor': + toggleState(id + '.ACTUAL'); + break; + case 'socket': + case 'light': + toggleState(id + '.SET') ? true : toggleState(id + '.ON_SET'); + break; + case 'dimmer': + toggleState(id + '.ON_SET') ? true : toggleState(id + '.ON_ACTUAL'); + break; + case 'ct': + toggleState(id + '.ON'); + break; + case 'rgb': + case 'rgbSingle': + case 'hue': // Armilar + toggleState(id + '.ON_ACTUAL'); + } + } + break; + case 'up': + setIfExists(id + '.OPEN', true); + break; + case 'stop': + setIfExists(id + '.STOP', true); + break; + case 'down': + setIfExists(id + '.CLOSE', true); + break; + case 'positionSlider': + (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); + timeoutSlider = setTimeout(async function () { + setIfExists(id + '.SET', parseInt(words[4])) ? true : setIfExists(id + '.ACTUAL', parseInt(words[4])); + }, 250); + break; + case 'tiltOpen': + setIfExists(id + '.TILT_OPEN', true); + break; + case 'tiltStop': + setIfExists(id + '.TILT_STOP', true); + break; + case 'tiltClose': + setIfExists(id + '.TILT_CLOSE', true); + break; + case 'tiltSlider': + (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); + timeoutSlider = setTimeout(async function () { + setIfExists(id + '.TILT_SET', parseInt(words[4])) ? true : setIfExists(id + '.TILT_ACTUAL', parseInt(words[4])); + }, 250); + break; + case 'brightnessSlider': + (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); + timeoutSlider = setTimeout(async function () { + if (existsObject(id)) { + let o = getObject(id); + let pageItem = findPageItem(id); + + switch (o.common.role) { + case 'dimmer': + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + let sliderPos = Math.trunc(scale(parseInt(words[4]), 0, 100, pageItem.maxValueBrightness, pageItem.minValueBrightness)) + setIfExists(id + '.SET', sliderPos) ? true : setIfExists(id + '.ACTUAL', sliderPos); + } else { + setIfExists(id + '.SET', parseInt(words[4])) ? true : setIfExists(id + '.ACTUAL', parseInt(words[4])); + } + break; + case 'rgb': + case 'ct': + case 'rgbSingle': + case 'hue': + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + let sliderPos = Math.trunc(scale(parseInt(words[4]), 0, 100, pageItem.maxValueBrightness, pageItem.minValueBrightness)) + setIfExists(id + '.DIMMER', sliderPos); + } else { + setIfExists(id + '.DIMMER', parseInt(words[4])); + } + break; + } + } + }, 250); + break; + case 'colorTempSlider': // Armilar - Slider tickt verkehrt - Hell = 0 / Dunkel = 100 -> Korrektur + (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); + timeoutSlider = setTimeout(async function () { + let pageItem = findPageItem(id); + if (pageItem.minValueColorTemp !== undefined && pageItem.minValueColorTemp !== undefined) { + let colorTempK = Math.trunc(scale(parseInt(words[4]), 0, 100, pageItem.minValueColorTemp, pageItem.maxValueColorTemp)); + setIfExists(id + '.TEMPERATURE', (colorTempK)); + } else { + setIfExists(id + '.TEMPERATURE', 100 - words[4]); + } + }, 250); + break; + case 'colorWheel': + let colorCoordinates = words[4].split('|'); + let rgb = pos_to_color(colorCoordinates[0], colorCoordinates[1]); + if (Debug) console.log(rgb); + if (Debug) console.log(getHue(rgb.red, rgb.green, rgb.blue)); + let o = getObject(id); + switch (o.common.role) { + case 'hue': + setIfExists(id + '.HUE', getHue(rgb.red, rgb.green, rgb.blue)); + break; + case 'rgb': + setIfExists(id + '.RED', rgb.red); + setIfExists(id + '.GREEN', rgb.green); + setIfExists(id + '.BLUE', rgb.blue); + break; + case 'rgbSingle': + let pageItem = findPageItem(id); + if (pageItem.colormode == "xy") { + //Für z.B. Deconz XY + setIfExists(id + ".RGB", rgb_to_cie(rgb.red, rgb.green, rgb.blue)); + if (Debug) console.log(rgb_to_cie(rgb.red, rgb.green, rgb.blue)); + } + else { + //Für RGB + setIfExists(id + ".RGB", ConvertRGBtoHex(rgb.red, rgb.green, rgb.blue)); + } + break; + } + break; + case 'tempUpd': + setIfExists(id + '.SET', parseInt(words[4]) / 10); + break; + case 'media-back': + setIfExists(id + '.PREV', true); + setTimeout(function(){ + GeneratePage(activePage); + },3000) + break; + case 'media-pause': + let pageItemTemp = findPageItem(id); + let adaInstanceSplit = pageItemTemp.adapterPlayerInstance.split('.'); + if (adaInstanceSplit[0] == 'squeezeboxrpc') { + let stateVal = getState(pageItemTemp.adapterPlayerInstance + 'state').val + if (stateVal == 0) { + setState(pageItemTemp.adapterPlayerInstance + 'state', 1) + } else if (stateVal == 1) { + setState(pageItemTemp.adapterPlayerInstance + 'state', 0) + } else if (stateVal == null) { + setState(pageItemTemp.adapterPlayerInstance + 'state', 1) + } + } else { + if (getState(id + '.STATE').val === true) { + setIfExists(id + '.PAUSE', true); + } else { + setIfExists(id + '.PLAY', true); + } + } + setTimeout(function(){ + GeneratePage(activePage); + },3000) + break; + case 'media-next': + setIfExists(id + '.NEXT', true); + setTimeout(function(){ + GeneratePage(activePage); + },3000) + break; + case 'volumeSlider': + setIfExists(id + '.VOLUME', parseInt(words[4])) + break; + case 'speaker-sel': + let pageItem = findPageItem(id); + let adapterInstance = pageItem.adapterPlayerInstance; + let adapter = adapterInstance.split('.') + let deviceAdapter = adapter[0]; + + switch (deviceAdapter) { + case 'spotify-premium': + var strDeviceID = spotifyGetDeviceID(words[4]); + setState(adapterInstance + 'devices.' + strDeviceID + ".useForPlayback", true); + break; + case 'alexa2': + let i_list = Array.prototype.slice.apply($('[state.id="' + adapterInstance + 'Echo-Devices.*.Info.name"]')); + for (let i_index in i_list) { + let i = i_list[i_index]; + if ((getState(i).val) === words[4]) { + let deviceId = i; + deviceId = deviceId.split('.'); + setIfExists(adapterInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Commands.textCommand', 'Schiebe meine Musik auf ' + words[4]); + pageItem.mediaDevice = deviceId[3]; + } + } + break; + case 'sonos': + break; + case 'chromecast': + break; + } + break; + case 'media-OnOff': + let pageItemTem = findPageItem(id); + let adaInstanceSpli = pageItemTem.adapterPlayerInstance.split('.'); + if (adaInstanceSpli[0] == 'squeezeboxrpc') { + let stateVal = getState(pageItemTem.adapterPlayerInstance + 'Power').val + if (stateVal === 0) { + setState(pageItemTem.adapterPlayerInstance + 'Power', 1) + setIfExists(id + '.STOP', false) + setIfExists(id + '.STATE', 1) + } else { + setState(pageItemTem.adapterPlayerInstance + 'Power', 0) + setIfExists(id + '.STOP', true) + setIfExists(id + '.STATE', 0) + } + } else { + setIfExists(id + '.STOP', true) + } + break; + case 'hvac_action': + if (words[4] == 'BOOT' || words[4] == 'PART' || words[4] == 'AUTT' || words[4] == 'MANT' || words[4] == 'VACT') { + + switch (words[4]) { + case 'BOOT': + setIfExists(words[2] + '.' + 'BOOST', !getState(words[2] + '.' + 'BOOST').val) + break; + case 'PART': + setIfExists(words[2] + '.' + 'PARTY', !getState(words[2] + '.' + 'PARTY').val) + break; + case 'AUTT': + setIfExists(words[2] + '.' + 'AUTOMATIC', !getState(words[2] + '.' + 'AUTOMATIC').val) + break; + case 'MANT': + setIfExists(words[2] + '.' + 'MANUAL', !getState(words[2] + '.' + 'MANUAL').val) + break; + case 'VACT': + setIfExists(words[2] + '.' + 'VACATION', !getState(words[2] + '.' + 'VACATION').val) + break; + } + let modes = ['BOOT', 'PART', 'AUTT', 'MANT', 'VACT'] + let modesDP = ['BOOST', 'PARTY', 'AUTOMATIC', 'MANUAL', 'VACATION'] + for (let mode=0; mode < 5; mode++) { + if (words[4] != modes[mode]) { + setIfExists(words[2] + '.' + modesDP[mode], false) + } + } + GeneratePage(config.pages[pageId]); + } else { + var HVACMode = 0; + switch (words[4]) { + case 'POWER': + HVACMode = 0; + setIfExists(words[2] + '.' + words[4], !getState(words[2] + '.' + words[4]).val) + if (getState(words[2] + '.' + words[4]).val) { + HVACMode = 1; + } + break; + case 'AUTO': + HVACMode = 1; + break; + case 'COOL': + HVACMode = 2; + break; + case 'HEAT': + HVACMode = 3; + break; + case 'ECO': + HVACMode = 4; + break; + case 'FAN': + HVACMode = 5; + break; + case 'DRY': + HVACMode = 6; + break; + case 'SWING': + HVACMode = getState(words[2] + '.MODE').val; + if (getState(words[2] + '.SWING').val == 0) { + setIfExists(words[2] + '.SWING', 1); + } else { + setIfExists(words[2] + '.' + 'SWING', 0); + } + break; + } + setIfExists(words[2] + '.' + 'MODE', HVACMode) + GeneratePage(config.pages[pageId]); + } + + break; + case 'number-set': + setIfExists(id + '.SET', parseInt(words[4])) ? true : setIfExists(id + '.ACTUAL', parseInt(words[4])); + break; + case 'A1': // Alarm-Page Alarm 1 aktivieren + if (words[4] != '') { + setIfExists(id + '.TYPE', 'A1'); + setIfExists(id + '.PIN', words[4]); + setIfExists(id + '.ACTUAL', 'arming'); + setIfExists(id + '.PANEL', NSPanel_Path); + } + setTimeout(function(){ + GeneratePage(activePage); + },250) + break; + case 'A2': // Alarm-Page Alarm 2 aktivieren + if (words[4] != '') { + setIfExists(id + '.TYPE', 'A2'); + setIfExists(id + '.PIN', words[4]); + setIfExists(id + '.ACTUAL', 'arming'); + setIfExists(id + '.PANEL', NSPanel_Path); + } + setTimeout(function(){ + GeneratePage(activePage); + },250) + break; + case 'A3': // Alarm-Page Alarm 3 aktivieren + if (words[4] != '') { + setIfExists(id + '.TYPE', 'A3'); + setIfExists(id + '.PIN', words[4]); + setIfExists(id + '.ACTUAL', 'arming'); + setIfExists(id + '.PANEL', NSPanel_Path); + } + setTimeout(function(){ + GeneratePage(activePage); + },250) + break; + case 'A4': // Alarm-Page Alarm 4 aktivieren + if (words[4] != '') { + setIfExists(id + '.TYPE', 'A4'); + setIfExists(id + '.PIN', words[4]); + setIfExists(id + '.ACTUAL', 'arming'); + setIfExists(id + '.PANEL', NSPanel_Path); + } + setTimeout(function(){ + GeneratePage(activePage); + },250) + break; + case 'D1': // Alarm-Page Alarm Deaktivieren + if (Debug) console.log('D1: ' + getState(id + '.PIN').val); + if (Debug) console.log(words[4]); + if (words[4] != '') { + if (getState(id + '.PIN').val == words[4]) { + setIfExists(id + '.PIN', '0000'); + setIfExists(id + '.TYPE', 'D1'); + setIfExists(id + '.ACTUAL', 'pending'); + setIfExists(id + '.PIN_Failed', 0); + } else { + setIfExists(id + '.PIN_Failed', getState(id + '.PIN_Failed').val + 1); + setIfExists(id + '.ACTUAL', 'triggered'); + } + setIfExists(id + '.PANEL', NSPanel_Path); + setTimeout(function(){ + GeneratePage(activePage); + },500) + } + break; + default: + break; + } + } catch (err) { + console.log('function HandleButtonEvent: ' + err.message); + } +} + +function GetNavigationString(pageId: number): string { + try { + + if (Debug) console.log(pageId); + + if (activePage.subPage) + return '1|0'; + + switch (pageId) { + case 0: + return '0|1'; + case config.pages.length - 1: + return '1|0'; + case -1: + return '2|0'; + case -2: + return '2|0'; + default: + return '1|1'; + } + } catch (err) { + console.log('function GetNavigationString: ' + err.message); + } +} + +function GenerateDetailPage(type: string, pageItem: PageItem): Payload[] { + try { + var out_msgs: Array = []; + let id = pageItem.id + + if (existsObject(id)) { + var o = getObject(id) + var val: (boolean | number) = 0; + let icon = Icons.GetIcon('lightbulb'); + var iconColor = rgb_dec565(config.defaultColor); + + if (type == 'popupLight') { + let switchVal = '0'; + let brightness = 0; + if (o.common.role == 'light' || o.common.role == 'socket') { + if (existsState(id + '.GET')) { + val = getState(id + '.GET').val; + RegisterDetailEntityWatcher(id + '.GET', pageItem, type); + } else if (existsState(id + '.SET')) { + val = getState(id + '.SET').val; + RegisterDetailEntityWatcher(id + '.SET', pageItem, type); + } + + icon = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + + if (val) { + switchVal = '1'; + iconColor = GetIconColor(pageItem, true, true); + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' // entityUpdateDetail + + id + '~' + + icon + '~' // iconId + + iconColor + '~' // iconColor + + switchVal + '~' // buttonState + + 'disable' + '~' // sliderBrightnessPos + + 'disable' + '~' // sliderColorTempPos + + 'disable' + '~' // colorMode + + '' + '~' // Color-Bezeichnung + + findLocale('lights', 'Temperature') + '~' // Temperature-Bezeichnung + + findLocale('lights', 'Brightness') + }); // Brightness-Bezeichnung + } + + // Dimmer + if (o.common.role == 'dimmer') { + if (existsState(id + '.ON_ACTUAL')) { + val = getState(id + '.ON_ACTUAL').val; + RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type); + } else if (existsState(id + '.ON_SET')) { + val = getState(id + '.ON_SET').val; + RegisterDetailEntityWatcher(id + '.ON_SET', pageItem, type); + } + + if (val === true) { + var iconColor = GetIconColor(pageItem, val, false); + switchVal = '1' + } + + if (existsState(id + '.ACTUAL')) { + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + brightness = Math.trunc(scale(getState(id + '.ACTUAL').val, pageItem.minValueBrightness, pageItem.maxValueBrightness, 100, 0)); + } else { + brightness = getState(id + '.ACTUAL').val; + } + } else { + console.warn('Alisas-Datenpunkt: ' + id + '.ACTUAL could not be read'); + } + + if (val === true) { + iconColor = GetIconColor(pageItem, 100 - brightness, true); + switchVal = '1'; + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + RegisterDetailEntityWatcher(id + '.ACTUAL', pageItem, type); + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + id + '~' + + icon + '~' //iconId + + iconColor + '~' //iconColor + + switchVal + '~' //buttonState + + brightness + '~' //sliderBrightnessPos + + 'disable' + '~' //sliderColorTempPos + + 'disable' + '~' //colorMod + + '' + '~' //Color-Bezeichnung + + findLocale('lights', 'Temperature') + '~' //Temperature-Bezeichnung + + findLocale('lights', 'Brightness') + }); //Brightness-Bezeichnung + + console.log('light.' + id) + + } + + // HUE-Licht + if (o.common.role == 'hue') { + + if (existsState(id + '.ON_ACTUAL')) { + val = getState(id + '.ON_ACTUAL').val; + RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type); + } + + if (existsState(id + '.DIMMER')) { + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + brightness = Math.trunc(scale(getState(id + '.DIMMER').val, pageItem.minValueBrightness, pageItem.maxValueBrightness, 100, 0)); + } else { + brightness = getState(id + '.DIMMER').val; + } + RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type); + } else { + console.warn('Alias-Datenpunkt: ' + id + '.DIMMER could not be read'); + } + + if (val === true) { + iconColor = GetIconColor(pageItem, 100 - brightness, true); + switchVal = '1'; + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + var colorMode = 'disable'; + if (existsState(id + '.HUE')) { + if (getState(id + '.HUE').val != null) { + colorMode = 'enable'; + let huecolor = hsv2rgb(getState(id + '.HUE').val, 1, 1); + let rgb = { red: Math.round(huecolor[0]), green: Math.round(huecolor[1]), blue: Math.round(huecolor[2]) } + iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); + //RegisterDetailEntityWatcher(id + '.HUE', pageItem, type); + } + } + + var colorTemp = 0; + if (existsState(id + '.TEMPERATURE')) { + if (getState(id + '.TEMPERATURE').val != null) { + if (pageItem.minValueColorTemp !== undefined && pageItem.minValueColorTemp !== undefined) { + colorTemp = Math.trunc(scale(getState(id + '.TEMPERATURE').val, pageItem.minValueColorTemp, pageItem.maxValueColorTemp, 0, 100)); + } else { + colorTemp = 100 - getState(id + '.TEMPERATURE').val; + } + //RegisterDetailEntityWatcher(id + '.TEMPERATURE', pageItem, type); + } + } else { + console.warn('Alias-Datenpunkt: ' + id + '.TEMPERATURE could not be read'); + } + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + id + '~' + + icon + '~' //iconId + + iconColor + '~' //iconColor + + switchVal + '~' //buttonState + + brightness + '~' //sliderBrightnessPos + + colorTemp + '~' //sliderColorTempPos + + colorMode + '~' //colorMode (if hue-alias without hue-datapoint, then disable) + + 'Color' + '~' //Color-Bezeichnung + + findLocale('lights', 'Temperature') + '~' //Temperature-Bezeichnung + + findLocale('lights', 'Brightness') + }); //Brightness-Bezeichnung + } + + // RGB-Licht + if (o.common.role == 'rgb') { + + if (existsState(id + '.ON_ACTUAL')) { + val = getState(id + '.ON_ACTUAL').val; + RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type); + } + + if (existsState(id + '.DIMMER')) { + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + brightness = Math.trunc(scale(getState(id + '.DIMMER').val, pageItem.minValueBrightness, pageItem.maxValueBrightness, 100, 0)); + } else { + brightness = getState(id + '.DIMMER').val; + } + RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type); + } else { + console.warn('Alias-Datenpunkt: ' + id + '.DIMMER could not be read'); + } + + if (val === true) { + iconColor = GetIconColor(pageItem, 100 - brightness, true); + switchVal = '1'; + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + var colorMode = 'disable'; + if (existsState(id + '.RED') && existsState(id + '.GREEN') && existsState(id + '.BLUE')) { + if (getState(id + '.RED').val != null && getState(id + '.GREEN').val != null && getState(id + '.BLUE').val != null) { + colorMode = 'enable'; + let rgb = { red: Math.round(getState(id + '.RED').val), green: Math.round(getState(id + '.GREEN').val), blue: Math.round(getState(id + '.BLUE').val) } + iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); + //RegisterDetailEntityWatcher(id + '.HUE', pageItem, type); + } + } + + var colorTemp = 0; + if (existsState(id + '.TEMPERATURE')) { + if (getState(id + '.TEMPERATURE').val != null) { + if (pageItem.minValueColorTemp !== undefined && pageItem.minValueColorTemp !== undefined) { + colorTemp = Math.trunc(scale(getState(id + '.TEMPERATURE').val, pageItem.minValueColorTemp, pageItem.maxValueColorTemp, 0, 100)); + } else { + colorTemp = 100 - getState(id + '.TEMPERATURE').val; + } + //RegisterDetailEntityWatcher(id + '.TEMPERATURE', pageItem, type); + } + } else { + console.warn('Alias-Datenpunkt: ' + id + '.TEMPERATURE could not be read'); + } + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + id + '~' + + icon + '~' //iconId + + iconColor + '~' //iconColor + + switchVal + '~' //buttonState + + brightness + '~' //sliderBrightnessPos + + colorTemp + '~' //sliderColorTempPos + + colorMode + '~' //colorMode (if hue-alias without hue-datapoint, then disable) + + 'Color' + '~' //Color-Bezeichnung + + findLocale('lights', 'Temperature') + '~' //Temperature-Bezeichnung + + findLocale('lights', 'Brightness') + }); //Brightness-Bezeichnung + } + + // RGB-Licht-einzeln (HEX) + if (o.common.role == 'rgbSingle') { + + if (existsState(id + '.ON_ACTUAL')) { + val = getState(id + '.ON_ACTUAL').val; + RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type); + } + + if (existsState(id + '.DIMMER')) { + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + brightness = Math.trunc(scale(getState(id + '.DIMMER').val, pageItem.minValueBrightness, pageItem.maxValueBrightness, 100, 0)); + } else { + brightness = getState(id + '.DIMMER').val; + } + RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type); + } else { + console.warn('Alias-Datenpunkt: ' + id + '.DIMMER could not be read'); + } + + if (val === true) { + iconColor = GetIconColor(pageItem, 100 - brightness, true); + switchVal = '1'; + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + var colorMode = 'disable'; + if (existsState(id + '.RGB')) { + if (getState(id + '.RGB').val != null) { + colorMode = 'enable'; + var hex = getState(id + '.RGB').val; + var hexRed = parseInt(hex[1] + hex[2], 16); + var hexGreen = parseInt(hex[3] + hex[4], 16); + var hexBlue = parseInt(hex[5] + hex[6], 16); + let rgb = { red: Math.round(hexRed), green: Math.round(hexGreen), blue: Math.round(hexBlue) } + iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); + //RegisterDetailEntityWatcher(id + '.HUE', pageItem, type); + } + } + + var colorTemp = 0; + if (existsState(id + '.TEMPERATURE')) { + if (getState(id + '.TEMPERATURE').val != null) { + if (pageItem.minValueColorTemp !== undefined && pageItem.minValueColorTemp !== undefined) { + colorTemp = Math.trunc(scale(getState(id + '.TEMPERATURE').val, pageItem.minValueColorTemp, pageItem.maxValueColorTemp, 0, 100)); + } else { + colorTemp = 100 - getState(id + '.TEMPERATURE').val; + } + //RegisterDetailEntityWatcher(id + '.TEMPERATURE', pageItem, type); + } + } else { + console.warn('Alias-Datenpunkt: ' + id + '.TEMPERATURE could not be read'); + } + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + id + '~' + + icon + '~' //iconId + + iconColor + '~' //iconColor + + switchVal + '~' //buttonState + + brightness + '~' //sliderBrightnessPos + + colorTemp + '~' //sliderColorTempPos + + colorMode + '~' //colorMode (if hue-alias without hue-datapoint, then disable) + + 'Color' + '~' //Color-Bezeichnung + + findLocale('lights', 'Temperature') + '~' //Temperature-Bezeichnung + + findLocale('lights', 'Brightness') + }); //Brightness-Bezeichnung + } + + // Farbtemperatur + if (o.common.role == 'ct') { + + if (existsState(id + '.ON')) { + val = getState(id + '.ON').val; + RegisterDetailEntityWatcher(id + '.ON', pageItem, type); + } + + if (existsState(id + '.DIMMER')) { + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + brightness = Math.trunc(scale(getState(id + '.DIMMER').val, pageItem.minValueBrightness, pageItem.maxValueBrightness, 100, 0)); + } else { + brightness = getState(id + '.DIMMER').val; + } + RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type); + } else { + console.warn('Alias-Datenpunkt: ' + id + '.DIMMER could not be read'); + } + + if (val === true) { + iconColor = GetIconColor(pageItem, 100 - brightness, true); + switchVal = '1'; + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + var colorMode = 'disable'; + + var colorTemp = 0; + if (existsState(id + '.TEMPERATURE')) { + if (getState(id + '.TEMPERATURE').val != null) { + if (pageItem.minValueColorTemp !== undefined && pageItem.minValueColorTemp !== undefined) { + colorTemp = Math.trunc(scale(getState(id + '.TEMPERATURE').val, pageItem.minValueColorTemp, pageItem.maxValueColorTemp, 0, 100)); + } else { + colorTemp = 100 - getState(id + '.TEMPERATURE').val; + } + //RegisterDetailEntityWatcher(id + '.TEMPERATURE', pageItem, type); + } + } else { + console.warn('Alias-Datenpunkt: ' + id + '.TEMPERATURE could not be read'); + } + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + id + '~' + + icon + '~' //iconId + + iconColor + '~' //iconColor + + switchVal + '~' //buttonState + + brightness + '~' //sliderBrightnessPos + + colorTemp + '~' //sliderColorTempPos + + colorMode + '~' //colorMode (if hue-alias without hue-datapoint, then disable) + + 'Color' + '~' //Color-Bezeichnung + + findLocale('lights', 'Temperature') + '~' //Temperature-Bezeichnung + + findLocale('lights', 'Brightness') + }); //Brightness-Bezeichnung + } + } + + if (type == 'popupShutter') { + icon = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('window-open'); + if (existsState(id + '.ACTUAL')) { + val = getState(id + '.ACTUAL').val; + RegisterDetailEntityWatcher(id + '.ACTUAL', pageItem, type); + } else if (existsState(id + '.SET')) { + val = getState(id + '.SET').val; + RegisterDetailEntityWatcher(id + '.SET', pageItem, type); + } + var tilt_position: any = 'disabled' + if (existsState(id + '.TILT_ACTUAL')) { + tilt_position = getState(id + '.TILT_ACTUAL').val; + RegisterDetailEntityWatcher(id + '.TILT_ACTUAL', pageItem, type); + } else if (existsState(id + '.TILT_SET')) { + tilt_position = getState(id + '.TILT_SET').val; + RegisterDetailEntityWatcher(id + '.TILT_SET', pageItem, type); + } + + let textSecondRow = ''; + let icon_id = icon; + let icon_up = Icons.GetIcon('arrow-up'); + let icon_stop = Icons.GetIcon('stop'); + let icon_down = Icons.GetIcon('arrow-down'); + let icon_up_status = getState(id + '.ACTUAL').val != 100 ? 'enable' : 'disable'; + let icon_stop_status = 'enable'; + let icon_down_status = getState(id + '.ACTUAL').val != 0 ? 'enable' : 'disable'; + let textTilt = ''; + let iconTiltLeft = ''; + let iconTiltStop = ''; + let iconTiltRight = ''; + let iconTiltLeftStatus = 'disable'; + let iconTiltStopStatus = 'disable'; + let iconTiltRightStatus = 'disable'; + let tilt_pos = 'disable'; + + if (existsState(id + '.TILT_SET')) { + textTilt = findLocale('blinds', 'Tilt'); + iconTiltLeft = Icons.GetIcon('arrow-top-right'); + iconTiltStop = Icons.GetIcon('stop'); + iconTiltRight = Icons.GetIcon('arrow-bottom-left'); + iconTiltLeftStatus = getState(id + '.TILT_ACTUAL').val != 100 ? 'enable' : 'disable'; + iconTiltStopStatus = 'enable'; + iconTiltRightStatus = getState(id + '.TILT_ACTUAL').val != 0 ? 'enable' : 'disable'; + tilt_pos = tilt_position; + } + + if (pageItem.secondRow != undefined) { + textSecondRow = pageItem.secondRow; + } + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + id + '~' //entity_id + + val + '~' //Shutterposition + + textSecondRow + '~' //pos_status 2.line + + findLocale('blinds', 'Position') + '~' //pos_translation + + icon_id + '~' //{icon_id}~ + + icon_up + '~' //{icon_up}~ + + icon_stop + '~' //{icon_stop}~ + + icon_down + '~' //{icon_down}~ + + icon_up_status + '~' //{icon_up_status}~ + + icon_stop_status + '~' //{icon_stop_status}~ + + icon_down_status + '~' //{icon_down_status}~ + + textTilt + '~' //{textTilt}~ + + iconTiltLeft + '~' //{iconTiltLeft}~ + + iconTiltStop + '~' //{iconTiltStop}~ + + iconTiltRight + '~' //{iconTiltRight}~ + + iconTiltLeftStatus + '~' //{iconTiltLeftStatus}~ + + iconTiltStopStatus + '~' //{iconTiltStopStatus}~ + + iconTiltRightStatus + '~' //{iconTiltRightStatus}~ + + tilt_pos //{tilt_pos}") + }); + } + } + + return out_msgs; + + } catch (err) { + console.log('function GenerateDetailPage: ' + err.message); + } +} + +function scale(number: number, inMin: number, inMax: number, outMin: number, outMax: number): number { + try { + return (outMax + outMin) - ((number - inMin) * (outMax - outMin) / (inMax - inMin) + outMin); + } catch (err) { + console.log('function scale: ' + err.message); + } +} + +function UnsubscribeWatcher(): void { + try { + for (const [key, value] of Object.entries(subscriptions)) { + unsubscribe(value); + delete subscriptions[key]; + } + } catch (err) { + console.log('function UnsubscribeWatcher: ' + err.message); + } +} + +function HandleScreensaver(): void { + SendToPanel({ payload: 'pageType~screensaver' }); + UnsubscribeWatcher(); + HandleScreensaverUpdate(); + HandleScreensaverColors(); +} + +function HandleScreensaverUpdate(): void { + try { + if (screensaverEnabled && config.weatherEntity != null && existsObject(config.weatherEntity)) { + var icon = getState(config.weatherEntity + '.ICON').val; + + let temperature = + existsState(config.weatherEntity + '.ACTUAL') ? getState(config.weatherEntity + '.ACTUAL').val : + existsState(config.weatherEntity + '.TEMP') ? getState(config.weatherEntity + '.TEMP').val : 'null'; + + if (config.alternativeScreensaverLayout) { + temperature = parseInt(Math.round(temperature).toFixed()); + } + + let payloadString = + 'weatherUpdate~' + Icons.GetIcon(GetAccuWeatherIcon(parseInt(icon))) + '~' + + temperature + ' ' + config.temperatureUnit + '~'; + + vwIconColor[0] = GetAccuWeatherIconColor(parseInt(icon)); + if (Debug) console.log(GetAccuWeatherIconColor(parseInt(icon))); + + if (weatherForecast) { + // Accu-Weather Forecast Tag 2 - Tag 5 -- Wenn weatherForecast = true + for (let i = 2; i < 6; i++) { + let TempMax = getState('accuweather.0.Summary.TempMax_d' + i).val; + let DayOfWeek = getState('accuweather.0.Summary.DayOfWeek_d' + i).val; + let WeatherIcon = GetAccuWeatherIcon(getState('accuweather.0.Summary.WeatherIcon_d' + i).val); + vwIconColor[i-1] = GetAccuWeatherIconColor(getState('accuweather.0.Summary.WeatherIcon_d' + i).val); + if (Debug) console.log(vwIconColor[i-1]); + payloadString += DayOfWeek + '~' + Icons.GetIcon(WeatherIcon) + '~' + TempMax + ' ' + config.temperatureUnit + '~'; + } + } else { + payloadString += GetScreenSaverEntityString(config.firstScreensaverEntity); + payloadString += GetScreenSaverEntityString(config.secondScreensaverEntity); + payloadString += GetScreenSaverEntityString(config.thirdScreensaverEntity); + payloadString += GetScreenSaverEntityString(config.fourthScreensaverEntity); + + const colorScale0: RGB = { red: 99, green: 190, blue: 123 }; + const colorScale1: RGB = { red: 129, green: 199, blue: 126 }; + const colorScale2: RGB = { red: 161, green: 208, blue: 127 }; + const colorScale3: RGB = { red: 129, green: 217, blue: 126 }; + const colorScale4: RGB = { red: 222, green: 226, blue: 131 }; + const colorScale5: RGB = { red: 254, green: 235, blue: 132 }; + const colorScale6: RGB = { red: 255, green: 210, blue: 129 }; + const colorScale7: RGB = { red: 251, green: 185, blue: 124 }; + const colorScale8: RGB = { red: 251, green: 158, blue: 117 }; + const colorScale9: RGB = { red: 248, green: 131, blue: 111 }; + const colorScale10: RGB = { red: 248, green: 105, blue: 107 }; + + if (config.firstScreensaverEntity.ScreensaverEntityIconColor != undefined) { + if (typeof getState(config.firstScreensaverEntity.ScreensaverEntity).val == 'boolean') { + vwIconColor[1] = (getState(config.firstScreensaverEntity.ScreensaverEntity).val == true) ? rgb_dec565(colorScale10) : rgb_dec565(colorScale0); + } else if (typeof config.firstScreensaverEntity.ScreensaverEntityIconColor == 'object') { + let iconvalmin = (config.firstScreensaverEntity.ScreensaverEntityIconColor.val_min != undefined) ? config.firstScreensaverEntity.ScreensaverEntityIconColor.val_min : 0 ; + let iconvalmax = (config.firstScreensaverEntity.ScreensaverEntityIconColor.val_max != undefined) ? config.firstScreensaverEntity.ScreensaverEntityIconColor.val_max : 100 ; + let iconvalbest = (config.firstScreensaverEntity.ScreensaverEntityIconColor.val_best != undefined) ? config.firstScreensaverEntity.ScreensaverEntityIconColor.val_best : iconvalmin ; + let valueScale = getState(config.firstScreensaverEntity.ScreensaverEntity).val; + + if (iconvalmin == 0 && iconvalmax == 1) { + vwIconColor[1] = (getState(config.firstScreensaverEntity.ScreensaverEntity).val == 1) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); + } else { + if (iconvalbest == iconvalmin) { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0) + } else { + if (valueScale < iconvalbest) { + valueScale = scale(valueScale,iconvalmin, iconvalbest, 0, 10) + } else if (valueScale > iconvalbest || iconvalbest != iconvalmin) { + valueScale = scale(valueScale,iconvalbest, iconvalmax, 10, 0) + } else { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0) + } + } + let valueScaletemp = (Math.round(valueScale)).toFixed(); + if (Debug) console.log(valueScaletemp); + switch (valueScaletemp) { + case '0': + vwIconColor[1] = rgb_dec565(colorScale0); + break; + case '1': + vwIconColor[1] = rgb_dec565(colorScale1); + break; + case '2': + vwIconColor[1] = rgb_dec565(colorScale2); + break; + case '3': + vwIconColor[1] = rgb_dec565(colorScale3); + break; + case '4': + vwIconColor[1] = rgb_dec565(colorScale4); + break; + case '5': + vwIconColor[1] = rgb_dec565(colorScale5); + break; + case '6': + vwIconColor[1] = rgb_dec565(colorScale6); + break; + case '7': + vwIconColor[1] = rgb_dec565(colorScale7); + break; + case '8': + vwIconColor[1] = rgb_dec565(colorScale8); + break; + case '9': + vwIconColor[1] = rgb_dec565(colorScale9); + break; + case '10': + vwIconColor[1] = rgb_dec565(colorScale10); + break; + } + } + if (config.firstScreensaverEntity.ScreensaverEntityIconColor.val_min == undefined) { + vwIconColor[1] = rgb_dec565(config.firstScreensaverEntity.ScreensaverEntityIconColor); + } + } else { + vwIconColor[1] = rgb_dec565(sctF1Icon); + } + } else { + vwIconColor[1] = rgb_dec565(sctF1Icon); + } + + if (config.secondScreensaverEntity.ScreensaverEntityIconColor != undefined) { + if (typeof getState(config.secondScreensaverEntity.ScreensaverEntity).val == 'boolean') { + vwIconColor[2] = (getState(config.secondScreensaverEntity.ScreensaverEntity).val == true) ? rgb_dec565(colorScale10) : rgb_dec565(colorScale0); + } else if (typeof config.secondScreensaverEntity.ScreensaverEntityIconColor == 'object') { + + let iconvalmin = (config.secondScreensaverEntity.ScreensaverEntityIconColor.val_min != undefined) ? config.secondScreensaverEntity.ScreensaverEntityIconColor.val_min : 0 ; + let iconvalmax = (config.secondScreensaverEntity.ScreensaverEntityIconColor.val_max != undefined) ? config.secondScreensaverEntity.ScreensaverEntityIconColor.val_max : 100 ; + let iconvalbest = (config.secondScreensaverEntity.ScreensaverEntityIconColor.val_best != undefined) ? config.secondScreensaverEntity.ScreensaverEntityIconColor.val_best : iconvalmin ; + let valueScale = getState(config.secondScreensaverEntity.ScreensaverEntity).val; + + if (iconvalmin == 0 && iconvalmax == 1) { + vwIconColor[2] = (getState(config.secondScreensaverEntity.ScreensaverEntity).val == 1) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); + } else { + if (iconvalbest == iconvalmin) { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0) + } else { + if (valueScale < iconvalbest) { + valueScale = scale(valueScale,iconvalmin, iconvalbest, 0, 10) + } else if (valueScale > iconvalbest || iconvalbest != iconvalmin) { + valueScale = scale(valueScale,iconvalbest, iconvalmax, 10, 0) + } else { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0) + } + } + let valueScaletemp = (Math.round(valueScale)).toFixed(); + if (Debug) console.log(valueScaletemp); + switch (valueScaletemp) { + case '0': + vwIconColor[2] = rgb_dec565(colorScale0); + break; + case '1': + vwIconColor[2] = rgb_dec565(colorScale1); + break; + case '2': + vwIconColor[2] = rgb_dec565(colorScale2); + break; + case '3': + vwIconColor[2] = rgb_dec565(colorScale3); + break; + case '4': + vwIconColor[2] = rgb_dec565(colorScale4); + break; + case '5': + vwIconColor[2] = rgb_dec565(colorScale5); + break; + case '6': + vwIconColor[2] = rgb_dec565(colorScale6); + break; + case '7': + vwIconColor[2] = rgb_dec565(colorScale7); + break; + case '8': + vwIconColor[2] = rgb_dec565(colorScale8); + break; + case '9': + vwIconColor[2] = rgb_dec565(colorScale9); + break; + case '10': + vwIconColor[2] = rgb_dec565(colorScale10); + break; + } + } + if (config.secondScreensaverEntity.ScreensaverEntityIconColor.val_min == undefined) { + vwIconColor[2] = rgb_dec565(config.secondScreensaverEntity.ScreensaverEntityIconColor); + } + } else { + vwIconColor[2] = rgb_dec565(sctF2Icon); + } + } else { + vwIconColor[2] = rgb_dec565(sctF2Icon); + } + + if (config.thirdScreensaverEntity.ScreensaverEntityIconColor != undefined) { + if (typeof getState(config.thirdScreensaverEntity.ScreensaverEntity).val == 'boolean') { + vwIconColor[3] = (getState(config.thirdScreensaverEntity.ScreensaverEntity).val == true) ? rgb_dec565(colorScale10) : rgb_dec565(colorScale0); + } else if (typeof config.thirdScreensaverEntity.ScreensaverEntityIconColor == 'object') { + + let iconvalmin = (config.thirdScreensaverEntity.ScreensaverEntityIconColor.val_min != undefined) ? config.thirdScreensaverEntity.ScreensaverEntityIconColor.val_min : 0 ; + let iconvalmax = (config.thirdScreensaverEntity.ScreensaverEntityIconColor.val_max != undefined) ? config.thirdScreensaverEntity.ScreensaverEntityIconColor.val_max : 100 ; + let iconvalbest = (config.thirdScreensaverEntity.ScreensaverEntityIconColor.val_best != undefined) ? config.thirdScreensaverEntity.ScreensaverEntityIconColor.val_best : iconvalmin ; + let valueScale = getState(config.thirdScreensaverEntity.ScreensaverEntity).val; + + if (iconvalmin == 0 && iconvalmax == 1) { + vwIconColor[3] = (getState(config.thirdScreensaverEntity.ScreensaverEntity).val == 1) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); + } else { + if (iconvalbest == iconvalmin) { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0) + } else { + if (valueScale < iconvalbest) { + valueScale = scale(valueScale,iconvalmin, iconvalbest, 0, 10) + } else if (valueScale > iconvalbest || iconvalbest != iconvalmin) { + valueScale = scale(valueScale,iconvalbest, iconvalmax, 10, 0) + } else { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0) + } + } + let valueScaletemp = (Math.round(valueScale)).toFixed(); + if (Debug) console.log(valueScaletemp); + switch (valueScaletemp) { + case '0': + vwIconColor[3] = rgb_dec565(colorScale0); + break; + case '1': + vwIconColor[3] = rgb_dec565(colorScale1); + break; + case '2': + vwIconColor[3] = rgb_dec565(colorScale2); + break; + case '3': + vwIconColor[3] = rgb_dec565(colorScale3); + break; + case '4': + vwIconColor[3] = rgb_dec565(colorScale4); + break; + case '5': + vwIconColor[3] = rgb_dec565(colorScale5); + break; + case '6': + vwIconColor[3] = rgb_dec565(colorScale6); + break; + case '7': + vwIconColor[3] = rgb_dec565(colorScale7); + break; + case '8': + vwIconColor[3] = rgb_dec565(colorScale8); + break; + case '9': + vwIconColor[3] = rgb_dec565(colorScale9); + break; + case '10': + vwIconColor[3] = rgb_dec565(colorScale10); + break; + } + } + if (config.thirdScreensaverEntity.ScreensaverEntityIconColor.val_min == undefined) { + vwIconColor[3] = rgb_dec565(config.thirdScreensaverEntity.ScreensaverEntityIconColor); + } + } else { + vwIconColor[3] = rgb_dec565(sctF2Icon); + } + } else { + vwIconColor[3] = rgb_dec565(sctF2Icon); + } + + if (config.fourthScreensaverEntity.ScreensaverEntityIconColor != undefined) { + if (typeof getState(config.fourthScreensaverEntity.ScreensaverEntity).val == 'boolean') { + vwIconColor[4] = (getState(config.fourthScreensaverEntity.ScreensaverEntity).val == true) ? rgb_dec565(colorScale10) : rgb_dec565(colorScale0); + } else if (typeof config.fourthScreensaverEntity.ScreensaverEntityIconColor == 'object') { + + let iconvalmin = (config.fourthScreensaverEntity.ScreensaverEntityIconColor.val_min != undefined) ? config.fourthScreensaverEntity.ScreensaverEntityIconColor.val_min : 0 ; + let iconvalmax = (config.fourthScreensaverEntity.ScreensaverEntityIconColor.val_max != undefined) ? config.fourthScreensaverEntity.ScreensaverEntityIconColor.val_max : 100 ; + let iconvalbest = (config.fourthScreensaverEntity.ScreensaverEntityIconColor.val_best != undefined) ? config.fourthScreensaverEntity.ScreensaverEntityIconColor.val_best : iconvalmin ; + let valueScale = getState(config.fourthScreensaverEntity.ScreensaverEntity).val; + + if (iconvalmin == 0 && iconvalmax == 1) { + vwIconColor[4] = (getState(config.fourthScreensaverEntity.ScreensaverEntity).val == 1) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); + } else { + if (iconvalbest == iconvalmin) { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0) + } else { + if (valueScale < iconvalbest) { + valueScale = scale(valueScale,iconvalmin, iconvalbest, 0, 10) + } else if (valueScale > iconvalbest || iconvalbest != iconvalmin) { + valueScale = scale(valueScale,iconvalbest, iconvalmax, 10, 0) + } else { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0) + } + } + let valueScaletemp = (Math.round(valueScale)).toFixed(); + if (Debug) console.log(valueScaletemp); + switch (valueScaletemp) { + case '0': + vwIconColor[4] = rgb_dec565(colorScale0); + break; + case '1': + vwIconColor[4] = rgb_dec565(colorScale1); + break; + case '2': + vwIconColor[4] = rgb_dec565(colorScale2); + break; + case '3': + vwIconColor[4] = rgb_dec565(colorScale3); + break; + case '4': + vwIconColor[4] = rgb_dec565(colorScale4); + break; + case '5': + vwIconColor[4] = rgb_dec565(colorScale5); + break; + case '6': + vwIconColor[4] = rgb_dec565(colorScale6); + break; + case '7': + vwIconColor[4] = rgb_dec565(colorScale7); + break; + case '8': + vwIconColor[4] = rgb_dec565(colorScale8); + break; + case '9': + vwIconColor[4] = rgb_dec565(colorScale9); + break; + case '10': + vwIconColor[4] = rgb_dec565(colorScale10); + break; + } + } + if (config.fourthScreensaverEntity.ScreensaverEntityIconColor.val_min == undefined) { + vwIconColor[4] = rgb_dec565(config.fourthScreensaverEntity.ScreensaverEntityIconColor); + } + } else { + vwIconColor[4] = rgb_dec565(sctF2Icon); + } + } else { + vwIconColor[4] = rgb_dec565(sctF2Icon); + } + } + + //AltLayout + if (config.alternativeScreensaverLayout) { + payloadString += parseInt(getState(config.fourthScreensaverEntity.ScreensaverEntity).val) + '~'; + payloadString += config.fourthScreensaverEntity.ScreensaverEntityUnitText + '~' + } else { + payloadString += '~~' + } + + let hwBtn1Col: any = config.mrIcon1ScreensaverEntity.ScreensaverEntityOffColor; + if (config.mrIcon1ScreensaverEntity.ScreensaverEntity != null) { + if (typeof (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val) == 'string') { + let hwBtn1: string = getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val; + if (hwBtn1 == 'ON') { + hwBtn1Col = config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor; + } + payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIcon) + '~' + rgb_dec565(hwBtn1Col) + '~'; + } else if (typeof (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val) == 'boolean') { + let hwBtn1: boolean = getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val; + if (hwBtn1) { + hwBtn1Col = config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor; + } + payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIcon) + '~' + rgb_dec565(hwBtn1Col) + '~'; + } + } else { + hwBtn1Col = Black; + payloadString += '~~'; + } + + let hwBtn2Col: any = config.mrIcon2ScreensaverEntity.ScreensaverEntityOffColor; + if (config.mrIcon2ScreensaverEntity.ScreensaverEntity != null) { + if (typeof (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val) == 'string') { + let hwBtn2: string = getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val; + if (hwBtn2 == 'ON') { + hwBtn2Col = config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor; + } + payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIcon) + '~' + rgb_dec565(hwBtn2Col) + '~'; + } else if (typeof (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val) == 'boolean') { + let hwBtn2: boolean = getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val; + if (hwBtn2) { + hwBtn2Col = config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor; + } + payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIcon) + '~' + rgb_dec565(hwBtn2Col) + '~'; + } + } else { + hwBtn2Col = Black; + payloadString += '~~'; + } + HandleScreensaverColors(); + + SendToPanel({ payload: payloadString }); + + } + } catch (err) { + console.log('HandleScreensaverUpdate: ' + err.message); + } +} + +function HandleScreensaverColors(): void { + try { + let vwIcon = []; + if (config.autoWeatherColorScreensaverLayout) { + vwIcon[0] = vwIconColor[0]; + vwIcon[1] = vwIconColor[1]; + vwIcon[2] = vwIconColor[2]; + vwIcon[3] = vwIconColor[3]; + vwIcon[4] = vwIconColor[4]; + } else { + if (weatherForecast) { + vwIcon[0] = rgb_dec565(sctMainIcon); + vwIcon[1] = rgb_dec565(sctF1Icon); + vwIcon[2] = rgb_dec565(sctF2Icon); + vwIcon[3] = rgb_dec565(sctF3Icon); + vwIcon[4] = rgb_dec565(sctF4Icon); + } else { + vwIcon[0] = rgb_dec565(sctMainIcon); + vwIcon[1] = vwIconColor[1]; + vwIcon[2] = vwIconColor[2]; + vwIcon[3] = vwIconColor[3]; + vwIcon[4] = vwIconColor[4]; + } + } + + let payloadString = 'color' + '~' + + rgb_dec565(scbackground) + '~' + //background + rgb_dec565(sctime) + '~' + //time + rgb_dec565(sctimeAMPM) + '~' + //timeAMPM~ + rgb_dec565(scdate) + '~' + //date~ + vwIcon[0] + '~' + //tMainIcon~ rgb_dec565(sctMainIcon) + rgb_dec565(sctMainText) + '~' + //tMainText~ + rgb_dec565(sctForecast1) + '~' + //tForecast1~ + rgb_dec565(sctForecast2) + '~' + //tForecast2~ + rgb_dec565(sctForecast3) + '~' + //tForecast3~ + rgb_dec565(sctForecast4) + '~' + //tForecast4~ + vwIcon[1] + '~' + //tF1Icon~ rgb_dec565(sctF1Icon) + vwIcon[2] + '~' + //tF2Icon~ rgb_dec565(sctF2Icon) + vwIcon[3] + '~' + //tF3Icon~ rgb_dec565(sctF3Icon) + vwIcon[4] + '~' + //tF4Icon~ rgb_dec565(sctF4Icon) + rgb_dec565(sctForecast1Val) + '~' + //tForecast1Val~ + rgb_dec565(sctForecast2Val) + '~' + //tForecast2Val~ + rgb_dec565(sctForecast3Val) + '~' + //tForecast3Val~ + rgb_dec565(sctForecast4Val) + '~' + //tForecast4Val~ + rgb_dec565(scbar) + '~' + //bar~ + rgb_dec565(sctMainIconAlt) + '~' + //tMainIconAlt + rgb_dec565(sctMainTextAlt) + '~' + //tMainTextAlt + rgb_dec565(sctTimeAdd); + //true; + + SendToPanel({ payload: payloadString }); + } catch (err) { + console.warn('HandleScreensaverColors: '+ err.message); + } +} + +function GetScreenSaverEntityString(configElement: ScreenSaverElement | null): string { + try { + if (configElement != null && configElement.ScreensaverEntity != null && existsState(configElement.ScreensaverEntity)) { + let u1 = getState(configElement.ScreensaverEntity).val; + + return configElement.ScreensaverEntityText + '~' + Icons.GetIcon(configElement.ScreensaverEntityIcon) + '~' + u1 + ' ' + configElement.ScreensaverEntityUnitText + '~'; + } + else { + return '~~~'; + } + } catch (err) { + console.warn('GetScreenSaverEntityString: '+ err.message); + } +} + +function GetAccuWeatherIcon(icon: number): string { + try { + switch (icon) { + case 24: // Ice + case 30: // Hot + case 31: // Cold + return 'window-open'; // exceptional + + case 7: // Cloudy + case 8: // Dreary (Overcast) + case 38: // Mostly Cloudy + return 'weather-cloudy'; // cloudy + + case 11: // fog + return 'weather-fog'; // fog + + case 25: // Sleet + return 'weather-hail'; // Hail + + case 15: // T-Storms + return 'weather-lightning'; // lightning + + case 16: // Mostly Cloudy w/ T-Storms + case 17: // Partly Sunny w/ T-Storms + case 41: // Partly Cloudy w/ T-Storms + case 42: // Mostly Cloudy w/ T-Storms + return 'weather-lightning-rainy'; // lightning-rainy + + case 33: // Clear + case 34: // Mostly Clear + case 37: // Hazy Moonlight + return 'weather-night'; + + case 3: // Partly Sunny + case 4: // Intermittent Clouds + case 6: // Mostly Cloudy + case 35: // Partly Cloudy + case 36: // Intermittent Clouds + return 'weather-partly-cloudy'; // partlycloudy + + case 18: // pouring + return 'weather-pouring'; // pouring + + case 12: // Showers + case 13: // Mostly Cloudy w/ Showers + case 14: // Partly Sunny w/ Showers + case 26: // Freezing Rain + case 39: // Partly Cloudy w/ Showers + case 40: // Mostly Cloudy w/ Showers + return 'weather-rainy'; // rainy + + case 19: // Flurries + case 20: // Mostly Cloudy w/ Flurries + case 21: // Partly Sunny w/ Flurries + case 22: // Snow + case 23: // Mostly Cloudy w/ Snow + case 43: // Mostly Cloudy w/ Flurries + case 44: // Mostly Cloudy w/ Snow + return 'weather-snowy'; // snowy + + case 29: // Rain and Snow + return 'weather-snowy-rainy'; // snowy-rainy + + case 1: // Sunny + case 2: // Mostly Sunny + case 5: // Hazy Sunshine + return 'weather-sunny'; // sunny + + case 32: // windy + return 'weather-windy'; // windy + + default: + return 'alert-circle-outline'; + } + } catch (err) { + console.warn('GetAccuWeatherIcon: '+ err.message); + } +} + +function GetAccuWeatherIconColor(icon: number): number { + try{ + switch (icon) { + case 24: // Ice + case 30: // Hot + case 31: // Cold + return rgb_dec565(swExceptional); // exceptional + + case 7: // Cloudy + case 8: // Dreary (Overcast) + case 38: // Mostly Cloudy + return rgb_dec565(swCloudy); // cloudy + + case 11: // fog + return rgb_dec565(swFog); // fog + + case 25: // Sleet + return rgb_dec565(swHail); // Hail + + case 15: // T-Storms + return rgb_dec565(swLightning); // lightning + + case 16: // Mostly Cloudy w/ T-Storms + case 17: // Partly Sunny w/ T-Storms + case 41: // Partly Cloudy w/ T-Storms + case 42: // Mostly Cloudy w/ T-Storms + return rgb_dec565(swLightningRainy); // lightning-rainy + + case 33: // Clear + case 34: // Mostly Clear + case 37: // Hazy Moonlight + return rgb_dec565(swClearNight); + + case 3: // Partly Sunny + case 4: // Intermittent Clouds + case 6: // Mostly Cloudy + case 35: // Partly Cloudy + case 36: // Intermittent Clouds + return rgb_dec565(swPartlycloudy); // partlycloudy + + case 18: // pouring + return rgb_dec565(swPouring); // pouring + + case 12: // Showers + case 13: // Mostly Cloudy w/ Showers + case 14: // Partly Sunny w/ Showers + case 26: // Freezing Rain + case 39: // Partly Cloudy w/ Showers + case 40: // Mostly Cloudy w/ Showers + return rgb_dec565(swRainy); // rainy + + case 19: // Flurries + case 20: // Mostly Cloudy w/ Flurries + case 21: // Partly Sunny w/ Flurries + case 22: // Snow + case 23: // Mostly Cloudy w/ Snow + case 43: // Mostly Cloudy w/ Flurries + case 44: // Mostly Cloudy w/ Snow + return rgb_dec565(swSnowy); // snowy + + case 29: // Rain and Snow + return rgb_dec565(swSnowyRainy); // snowy-rainy + + case 1: // Sunny + case 2: // Mostly Sunny + case 5: // Hazy Sunshine + return rgb_dec565(swSunny); // sunny + + case 32: // windy + return rgb_dec565(swWindy); // windy + + default: + return rgb_dec565(White); + } + } catch (err) { + console.warn('GetAccuWeatherIconColor: '+ err.message); + } +} + +//------------------Begin Read Internal Sensor Data +on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'SENSOR' }, async (obj) => { + try { + const Tasmota_Sensor = JSON.parse(obj.state.val); + + await createStateAsync(NSPanel_Path + 'Sensor.Time', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Sensor.TempUnit', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Sensor.ANALOG.Temperature', { type: 'number', 'unit': '°C' }); + await createStateAsync(NSPanel_Path + 'Sensor.ESP32.Temperature', { type: 'number', 'unit': '°C' }); + + await setStateAsync(NSPanel_Path + 'Sensor.Time', { val: Tasmota_Sensor.Time, ack: true }); + await setStateAsync(NSPanel_Path + 'Sensor.TempUnit', { val: '°' + Tasmota_Sensor.TempUnit, ack: true }); + await setStateAsync(NSPanel_Path + 'Sensor.ANALOG.Temperature', { val: parseFloat(Tasmota_Sensor.ANALOG.Temperature1), ack: true }); + await setStateAsync(NSPanel_Path + 'Sensor.ESP32.Temperature', { val: parseFloat(Tasmota_Sensor.ESP32.Temperature), ack: true }); + } catch (err) { + console.warn('error with reading senor-data: '+ err.message); + } +}); +//------------------End Read Internal Sensor Data + +function GetBlendedColor(percentage: number): RGB { + if (percentage < 50) { + return Interpolate(config.defaultOffColor, config.defaultOnColor, percentage / 50.0); + } + + return Interpolate(Red, White, (percentage - 50) / 50.0); +} + +function Interpolate(color1: RGB, color2: RGB, fraction: number): RGB { + var r: number = InterpolateNum(color1.red, color2.red, fraction); + var g: number = InterpolateNum(color1.green, color2.green, fraction); + var b: number = InterpolateNum(color1.blue, color2.blue, fraction); + return { red: Math.round(r), green: Math.round(g), blue: Math.round(b) }; +} + +function InterpolateNum(d1: number, d2: number, fraction: number): number { + return d1 + (d2 - d1) * fraction; +} + +function rgb_dec565(rgb: RGB): number { + //return ((Math.floor(rgb.red / 255 * 31) << 11) | (Math.floor(rgb.green / 255 * 63) << 5) | (Math.floor(rgb.blue / 255 * 31))); + return ((rgb.red >> 3) << 11) | ((rgb.green >> 2)) << 5 | ((rgb.blue) >> 3) +} + +/* Convert radians to degrees +rad - radians to convert, expects rad in range +/- PI per Math.atan2 +returns {number} degrees equivalent of rad +*/ +function rad2deg(rad) { + return (360 + 180 * rad / Math.PI) % 360; +} + +function ColorToHex(color) { + var hexadecimal = color.toString(16); + return hexadecimal.length == 1 ? '0' + hexadecimal : hexadecimal; +} + +function ConvertRGBtoHex(red: number, green: number, blue: Number) { + return '#' + ColorToHex(red) + ColorToHex(green) + ColorToHex(blue); +} + +/* Convert h,s,v values to r,g,b +hue - in range [0, 360] +saturation - in range 0 to 1 +value - in range 0 to 1 +returns {Array|number} [r, g,b] in range 0 to 255 + */ +function hsv2rgb(hue: number, saturation: number, value: number) { + hue /= 60; + let chroma = value * saturation; + let x = chroma * (1 - Math.abs((hue % 2) - 1)); + let rgb = hue <= 1 ? [chroma, x, 0] : + hue <= 2 ? [x, chroma, 0] : + hue <= 3 ? [0, chroma, x] : + hue <= 4 ? [0, x, chroma] : + hue <= 5 ? [x, 0, chroma] : + [chroma, 0, x]; + + return rgb.map(v => (v + value - chroma) * 255); +} + +function getHue(red: number, green: number, blue: number) { + + var min = Math.min(Math.min(red, green), blue); + var max = Math.max(Math.max(red, green), blue); + + if (min == max) { + return 0; + } + + var hue = 0; + if (max == red) { + hue = (green - blue) / (max - min); + + } else if (max == green) { + hue = 2 + (blue - red) / (max - min); + + } else { + hue = 4 + (red - green) / (max - min); + } + + hue = hue * 60; + if (hue < 0) hue = hue + 360; + + return Math.round(hue); +} + +function pos_to_color(x: number, y: number): RGB { + var r = 160 / 2; + var x = Math.round((x - r) / r * 100) / 100; + var y = Math.round((r - y) / r * 100) / 100; + + r = Math.sqrt(x * x + y * y); + let sat = 0 + if (r > 1) { + sat = 0; + } else { + sat = r; + } + + var hsv = rad2deg(Math.atan2(y, x)); + var rgb = hsv2rgb(hsv, sat, 1); + + return { red: Math.round(rgb[0]), green: Math.round(rgb[1]), blue: Math.round(rgb[2]) }; +} + +function rgb_to_cie(red, green, blue) +{ + //Apply a gamma correction to the RGB values, which makes the color more vivid and more the like the color displayed on the screen of your device + let vred = (red > 0.04045) ? Math.pow((red + 0.055) / (1.0 + 0.055), 2.4) : (red / 12.92); + let vgreen = (green > 0.04045) ? Math.pow((green + 0.055) / (1.0 + 0.055), 2.4) : (green / 12.92); + let vblue = (blue > 0.04045) ? Math.pow((blue + 0.055) / (1.0 + 0.055), 2.4) : (blue / 12.92); + + //RGB values to XYZ using the Wide RGB D65 conversion formula + let X = vred * 0.664511 + vgreen * 0.154324 + vblue * 0.162028; + let Y = vred * 0.283881 + vgreen * 0.668433 + vblue * 0.047685; + let Z = vred * 0.000088 + vgreen * 0.072310 + vblue * 0.986039; + + //Calculate the xy values from the XYZ values + let ciex = (X / (X + Y + Z)).toFixed(4); + let ciey = (Y / (X + Y + Z)).toFixed(4); + let cie = "[" + ciex + "," + ciey + "]" + + return cie; +} + +function spotifyGetDeviceID(vDeviceString) { + const availableDeviceIDs = getState("spotify-premium.0.devices.availableDeviceListIds").val; + const availableDeviceNames = getState("spotify-premium.0.devices.availableDeviceListString").val; + var arrayDeviceListIds = availableDeviceIDs.split(";"); + var arrayDeviceListSting = availableDeviceNames.split(";"); + var indexPos = arrayDeviceListSting.indexOf(vDeviceString); + var strDevID = arrayDeviceListIds[indexPos]; + return strDevID; +} + +type RGB = { + red: number, + green: number, + blue: number +}; + +type Payload = { + payload: string; +}; + +type Page = { + type: string, + heading: string, + items: PageItem[], + useColor: boolean, + subPage: boolean, + parent: Page, +}; + +interface PageEntities extends Page { + type: 'cardEntities', + items: PageItem[], +}; + +interface PageGrid extends Page { + type: 'cardGrid', + items: PageItem[], +}; + +interface PageThermo extends Page { + type: 'cardThermo', + items: PageItem[], +}; + +interface PageMedia extends Page { + type: 'cardMedia', + items: PageItem[], +}; + +interface PageAlarm extends Page { + type: 'cardAlarm', + items: PageItem[], +}; + +interface PageQR extends Page { + type: 'cardQR', + items: PageItem[], +}; + +interface PagePower extends Page { + type: 'cardPower', + items: PageItem[], +}; + +type PageItem = { + id: string, + icon: (string | undefined), + icon2: (string | undefined), + onColor: (RGB | undefined), + offColor: (RGB | undefined), + useColor: (boolean | undefined), + interpolateColor: (boolean | undefined), + minValueBrightness: (number | undefined), + maxValueBrightness: (number | undefined), + minValueColorTemp: (number | undefined), + maxValueColorTemp: (number | undefined), + minValue: (number | undefined), + maxValue: (number | undefined), + name: (string | undefined), + secondRow: (string | undefined), + buttonText: (string | undefined), + unit: (string | undefined), + navigate: (boolean | undefined), + colormode: (string | undefined), + adapterPlayerInstance: (string | undefined), + mediaDevice: (string | undefined), + targetPage: (string | undefined), + speakerList: (string[] | undefined), + hidePassword: (boolean | undefined) +} + +type DimMode = { + dimmodeOn: (boolean | undefined), + brightnessDay: (number | undefined), + brightnessNight: (number | undefined), + timeDay: (string | undefined), + timeNight: (string | undefined) +} + +type Config = { + panelRecvTopic: string, + panelSendTopic: string, + timeoutScreensaver: number, + dimmode: number, + active: number, + locale: string, + timeFormat: string, + dateFormat: string, + weatherEntity: string | null, + screenSaverDoubleClick: boolean, + temperatureUnit: string, + firstScreensaverEntity: ScreenSaverElement | null, + secondScreensaverEntity: ScreenSaverElement | null, + thirdScreensaverEntity: ScreenSaverElement | null, + fourthScreensaverEntity: ScreenSaverElement | null, + alternativeScreensaverLayout: boolean, + autoWeatherColorScreensaverLayout: boolean, + mrIcon1ScreensaverEntity: ScreenSaverMRElement | null, + mrIcon2ScreensaverEntity: ScreenSaverMRElement | null, + defaultColor: RGB, + defaultOnColor: RGB, + defaultOffColor: RGB, + defaultBackgroundColor: RGB, + pages: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PagePower)[], + subPages: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PagePower)[], + button1Page: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PagePower | null), + button2Page: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PagePower| null), +}; + +type ScreenSaverElement = { + ScreensaverEntity: string | null, + ScreensaverEntityIcon: string | null, + ScreensaverEntityText: string | null, + ScreensaverEntityUnitText: string | null, + ScreensaverEntityIconColor: any | null, +} + +type ScreenSaverMRElement = { + ScreensaverEntity: string | null, + ScreensaverEntityIcon: string | null, + ScreensaverEntityOnColor: RGB, + ScreensaverEntityOffColor: RGB, +}