diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 5f2c8dec..f9b01b59 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,109 +1,278 @@ /*----------------------------------------------------------------------- +TypeScript zur Steuerung des SONOFF NSPanel mit dem ioBroker +- abgestimmt auf TFT 36 / v2.9.0 / BerryDriver 4 / Tasmota 11.1.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) - -Mögliche Aliase: - Info - Werte aus Datenpunkt - 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 - Taste - Für Szenen oder Radiosender, etc. --> Nur Funktionsaufruf - Kein Taster wie MonoButton - True/False - ??? wahrscheinlich wäre Tastensensor besser geeignet, um Alias-Taste langfristig für einen MonoButton (Taster) zu verwenden ??? - Thermostat - Aktuelle Raumtemperatur, Setpoint, etc. - Feuchtigkeit - Anzeige von Humidity - Datenpunkten, ananlog Info - Medien - Steuerung von Alexa - Über Alias-Manager im Verzeichnis Player automatisch anlegen (Geräte-Manager funktioniert nicht) - Wetter - Aktuelle Außen-Temperatur und aktuelles Accu-Wheather-Icon für Screensaver +ioBroker-Unterstützung: https://forum.iobroker.net/topic/50888/sonoff-nspanel +ReleaseNotes: + Bugfixes und Erweiterungen seit letzter Verion: + - cardQR (für Gäste WLAN) + - cardThermo (Neues Design für Alias Thermostat und zusätzlich für Alias Klimaanlage) + - 08.05.2022 - Menüpfeile bei HardwareButtons (button1Page; button2Page) mit Navigation auf Page 0 + - 08.05.2022 - Standard-Brightness über neuen Parameter active einstellbar (Test mit 2.9.3) + - 08.05.2022 - Schalter (Licht, Dimmer, Hue, etc) in cardGrid lassen sich wieder schalten + Known-Bugs --> Bugfix folgt: + - Aktion auf Submenüs schaltet unmittelbar auf vorheriges Mainmenu + - Menü-Pfeile in Subpages (z.B. card QR, cardMedia, etc) + +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) + cardEtities 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 +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 + 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-v2.9.0.tft --------------------------------------------------------------------------------------- */ var Icons = new IconsSelector(); -var timeoutSlider; +var timeoutSlider: any; +const NSPanel_Path = "0_userdata.0.NSPanel.1." +const Debug = false; +var manually_Update = true; const Months = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]; const Days = ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"]; -const Red: RGB = { red: 255, green: 0, blue: 0 }; -const White: RGB = { red: 255, green: 255, blue: 255 }; -const Yellow: RGB = { red: 253, green: 216, blue: 53 }; -const Green: RGB = { red: 96, green: 176, blue: 62 } -const Brown: RGB = { red: 120, green: 80, blue: 59 } -const Gray: RGB = { red: 69, green: 69, blue: 69 } -const Off: RGB = { red: 68, green: 115, blue: 158 }; +//const Off: RGB = { red: 68, green: 115, blue: 158 }; //Blau-Off +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 BatteryFull: RGB = { red: 96, green: 176, blue: 62 } -const BatteryEmpty: RGB = { red: 179, green: 45, blue: 25 } +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 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 }; +//----------------------Begin Dimmode +//Screensaver nachts auf dunkel ("brightnessNight: z.B. 2") oder aus ("brightnessNight:0") +if (existsState(NSPanel_Path + "NSPanel_Dimmode_brightnessDay") == false || existsState(NSPanel_Path + "NSPanel_Dimmode_hourDay") == false || existsState(NSPanel_Path + "NSPanel_Dimmode_brightnessNight") == false || existsState(NSPanel_Path + "NSPanel_Dimmode_hourNight") == false) { + createState(NSPanel_Path + "NSPanel_Dimmode_brightnessDay", 8, {type: 'number'}, function() {setState(NSPanel_Path + "NSPanel_Dimmode_brightnessDay", 8)}); + createState(NSPanel_Path + "NSPanel_Dimmode_hourDay", 7, {type: 'number'}, function() {setState(NSPanel_Path + "NSPanel_Dimmode_hourDay", 7)}); + createState(NSPanel_Path + "NSPanel_Dimmode_brightnessNight", 1, {type: 'number'}, function() {setState(NSPanel_Path + "NSPanel_Dimmode_brightnessNight", 1)}); + createState(NSPanel_Path + "NSPanel_Dimmode_hourNight", 22, {type: 'number'}, function() {setState(NSPanel_Path + "NSPanel_Dimmode_hourNight", 22)}); +} +var vBrightnessDay = getState(NSPanel_Path + "NSPanel_Dimmode_brightnessDay").val; +var vBrightnessNight = getState(NSPanel_Path + "NSPanel_Dimmode_brightnessNight").val; +var vTimeDay = getState(NSPanel_Path + "NSPanel_Dimmode_hourDay").val; +if (vTimeDay < 10) { + var TimeDay = "0" + vTimeDay.toString() + ":00"; +} else { + var TimeDay = vTimeDay.toString() + ":00"; +} +var vTimeNight = getState(NSPanel_Path + "NSPanel_Dimmode_hourNight").val; +if (vTimeNight < 10) { + var TimeNight = "0" + vTimeNight.toString() + ":00"; +} else { + var TimeNight = vTimeNight.toString() + ":00"; +} +var timeDimMode = {dimmodeOn: true, brightnessDay: vBrightnessDay, brightnessNight: vBrightnessNight, timeDay: TimeDay, timeNight: TimeNight}; +//--------------------End Dimmode -//----Ability to choose between Accu-Weather Forcast or self-defined values in the screensaver--------------------------------- +//----Möglichkeit, im Screensaver zwischen Accu-Weather Forecast oder selbstdefinierten Werten zu wählen--------------------------------- var weatherForecast = true; //true = WheatherForecast 5 Days --- false = Config --> firstScreensaverEntity - fourthScreensaverEntity ... -//Alexa2-Instanz +//Alexa-Instanz var alexaInstanz = "alexa2.0" -var alexaDevice = "G0XXXXXXXXXXXXXX"; //Primär zu steuendes Device -//If alexaSpeakerList is defined, then entries are used, otherwise all relevant devices from the ioBroker Alexa2 adapter -const alexaSpeakerList = []; //Example ["Echo Spot Buero","Überall","Gartenhaus","Esszimmer","Heimkino"]; +var alexaDevice = "G0XXXXXXXXXXXXXXX"; //Primär zu steuerndes Device oder Gruppe aus alexa2-Adapter (Seriennummer) + +// Wenn alexaSpeakerList definiert, dann werden Einträge verwendet, sonst alle relevanten Devices aus Alexa-Instanz +// Speakerwechsel funktioniert nicht bei Radio/TuneIn sonden bei Playlists +//const alexaSpeakerList = []; //Beispiel ["Echo Spot Buero","Überall","Gartenhaus","Esszimmer","Heimkino"]; +const alexaSpeakerList = ["Echo Spot Buero","Überall","Gartenhaus","Esszimmer","Heimkino","Echo Dot Küche"]; //Datenpunkte für Nachricht an Screensaver -var popupNotifyHeading = "0_userdata.0.WzDisplay.popupNotifyHeading"; -var popupNotifyText = "0_userdata.0.WzDisplay.popupNotifyText"; +var screensaverNotifyHeading = NSPanel_Path + "ScreensaverInfo.popupNotifyHeading"; +var screensaverNotifyText = NSPanel_Path + "ScreensaverInfo.popupNotifyText"; +createState(screensaverNotifyHeading, {type: 'string'}); +createState(screensaverNotifyText, {type: 'string'}); + +//Datenpunkte für Nachricht popupNotify Page +var popupNotifyHeading = NSPanel_Path + "popupNotify.popupNotifyHeading"; +var popupNotifyText = NSPanel_Path + "popupNotify.popupNotifyText"; +var popupNotifyInternalName = NSPanel_Path + "popupNotify.popupNotifyInternalName"; // Wird mit Button-Action zurückgeschrieben +var popupNotifyButton1Text = NSPanel_Path + "popupNotify.popupNotifyButton1Text"; +var popupNotifyButton2Text = NSPanel_Path + "popupNotify.popupNotifyButton2Text"; +var popupNotifySleepTimeout = NSPanel_Path + "popupNotify.popupNotifySleepTimeout"; // in sek. / wenn 0, dann bleibt die Nachricht stehen +var popupNotifyAction = NSPanel_Path + "popupNotify.popupNotifyAction"; // Antwort aus dem Panel true/false +createState(popupNotifyHeading, {type: 'string'}); +createState(popupNotifyText, {type: 'string'}); +createState(popupNotifyInternalName, {type: 'string'}); +createState(popupNotifyButton1Text, {type: 'string'}); +createState(popupNotifyButton2Text, {type: 'string'}); +createState(popupNotifySleepTimeout, {type: 'number'}); +createState(popupNotifyAction, {type: 'boolean'}); var Test_Licht: PageEntities = { "type": "cardEntities", "heading": "Color Aliase", "useColor": true, + "subPage": false, "items": [ { id: "alias.0.NSPanel_1.TestRGBLichteinzeln", name: "RGB-Licht Hex-Color", interpolateColor: true}, //{ id: "alias.0.NSPanel_1.TestFarbtemperatur", name: "Farbtemperatur", interpolateColor: true}, - { id: "alias.0.NSPanel_1.TestRGBLicht", name: "RGB-Licht", minValueBrightness: 0, maxValueBrightness: 70, interpolateColor: true}, + { id: "alias.0.NSPanel_1.TestRGBLicht", name: "RGB-Licht", minValueBrightness: 0, maxValueBrightness: 100, interpolateColor: true}, { id: "alias.0.NSPanel_1.TestCTmitHUE", name: "HUE-Licht-CT", minValueBrightness: 0, maxValueBrightness: 70, minValueColorTemp: 500, maxValueColorTemp: 6500, interpolateColor: true}, { id: "alias.0.NSPanel_1.TestHUELicht", name: "HUE-Licht-Color", minValueColorTemp: 500, maxValueColorTemp: 6500, interpolateColor: true} ] }; -var Wohnen: PageEntities = +var Test_Funktionen: PageEntities = { "type": "cardEntities", - "heading": "Haus", + "heading": "Sonstige Aliase", "useColor": true, + "subPage": false, "items": [ - { id: "alias.0.Stern", name: "Sternsteckdose"}, - { id: "alias.0.Erker"}, - { id: "alias.0.Küche", interpolateColor: true }, - { id: "alias.0.Wand" } + { id: "alias.0.NSPanel_1.TestLautstärke", offColor: MSRed /*if mute=true*/, onColor: MSGreen ,name: "Echo Spot Büro", minValue: 0, maxValue: 100}, + { id: "alias.0.NSPanel_1.TestTemperatur",name: "Temperatur außen", icon: "thermometer", onColor: White}, + { id: "alias.0.NSPanel_1.TestFeuchtigkeit", name: "Luftfeuchte außen", icon: "water-percent", unit: "%H", onColor: White}, + { id: "alias.0.NSPanel_1.TestInfo", name: "Windstärke", icon: "wind-power-outline", offColor: MSRed, onColor: MSGreen, unit: "bft", minValue: 0, maxValue: 12, interpolateColor: true, useColor: true} ] }; -var Strom: PageEntities = +var Buero_Seite_1: PageEntities = { "type": "cardEntities", - "heading": "Strom", + "heading": "Büro", "useColor": true, + "subPage": false, "items": [ - { id: "alias.0.Netz", icon: "flash", interpolateColor: true, offColor: BatteryFull, onColor: Red, minValue: -1000, maxValue: 1000 }, - { id: "alias.0.Hausverbrauch", icon: "flash", interpolateColor: true, offColor: BatteryFull, onColor: Red, maxValue: 1000 }, - { id: "alias.0.Pv", icon: "solar-power", interpolateColor: true, offColor: Off, onColor: BatteryFull, maxValue: 1000 }, - { id: "alias.0.Batterie", icon: "battery-medium", interpolateColor: true, offColor: BatteryEmpty, onColor: BatteryFull } + { id: "alias.0.NSPanel_1.Schreibtischlampe", interpolateColor: true}, + { id: "alias.0.NSPanel_1.Deckenbeleuchtung", interpolateColor: true}, + { id: "alias.0.NSPanel_1.Testlampe2", name: "Filamentlampe", minValueBrightness: 0, maxValueBrightness: 70, interpolateColor: true}, + { id: "alias.0.NSPanel_1.Luftreiniger", icon: "power", offColor: MSRed, onColor: MSGreen} ] }; -var Müll: PageEntities = +var Fenster_1: PageEntities = { "type": "cardEntities", - "heading": "Müllkalender", + "heading": "Fenster und Türen", "useColor": true, + "subPage": false, "items": [ - { id: "alias.0.WzNsPanel.Müll.Bio_Tonne" ,unit:"Tage", icon: "trash-can",onColor: Brown}, - { id: "alias.0.WzNsPanel.Müll.Graue_Tonne" ,unit:"Tage",icon: "trash-can",onColor: Gray}, - { id: "alias.0.WzNsPanel.Müll.Grüne_Tonne" ,unit:"Tage",icon: "trash-can",onColor: Green}, - { id: "alias.0.WzNsPanel.Müll.Gelbe_Tonne" ,unit:"Tage",icon: "trash-can",onColor: Yellow} + { id: "alias.0.NSPanel_1.TestFenster", offColor: MSRed, onColor: MSGreen, name: "Büro Fenster"}, + { id: "alias.0.NSPanel_1.Haustuer", offColor: MSRed, onColor: MSGreen, name: "Haustür"}, + { id: "alias.0.NSPanel_1.TestBlind", onColor: White, name: "IKEA Fyrtur"}, + { id: "alias.0.NSPanel_1.TestDoorlock", offColor: MSRed, onColor: MSGreen, name: "Türschloss"}, + ] +}; + +var Button_1: PageEntities = +{ + "type": "cardEntities", + "heading": "Button Aliase", + "useColor": true, + "subPage": false, + "items": [ + { id: "alias.0.NSPanel_1.TestTastensensor", name: "Tastensensor (FFN)"}, + { id: "alias.0.NSPanel_1.Radio.NDR2", icon: "radio", name: "Taste (NDR2)", onColor: colorRadio}, + ] +}; + +var Subpages_1: PageEntities = +{ + "type": "cardEntities", + "heading": "Test Subpages", + "useColor": true, + "subPage": false, + "items": [ + { navigate: true, id: "Abfall", onColor: White, name: "Abfallkalender"}, + { navigate: true, id: "WLAN", onColor: White, name: "Gäste WLAN"}, + ] +}; + +//Subpage 1 von Subpages_1 +var Abfall: PageEntities = +{ + "type": "cardEntities", + "heading": "Abfallkalender", + "useColor": true, + "subPage": true, + "items": [ + { id: "alias.0.NSPanel_1.Abfall.event1",icon: "trash-can"}, + { id: "alias.0.NSPanel_1.Abfall.event2",icon: "trash-can"}, + { id: "alias.0.NSPanel_1.Abfall.event3",icon: "trash-can"}, + { id: "alias.0.NSPanel_1.Abfall.event4",icon: "trash-can"} + ] +}; + +var Buero_Seite_2: PageGrid = +{ + "type": "cardGrid", + "heading": "Büro 2", + "useColor": true, + "subPage": false, + "items": [ + { id: "alias.0.NSPanel_1.Schreibtischlampe", name: "Schreibtisch"}, + { id: "alias.0.NSPanel_1.Deckenbeleuchtung", name: "Deckenlampe"}, + { id: "alias.0.NSPanel_1.TestFenster", offColor: MSRed, onColor: MSGreen, name: "Büro Fenster"}, + { id: "alias.0.NSPanel_1.Luftreiniger", icon: "power", offColor: MSRed, onColor: MSGreen}, + { id: "alias.0.NSPanel_1.TestBlind", icon: "projector-screen", onColor: White, name: "Beamer"}, + { id: "alias.0.NSPanel_1.Radio.Bob", icon: "play", onColor: White, name: "TuneIn"} ] }; @@ -112,43 +281,143 @@ var Alexa: PageMedia = "type": "cardMedia", "heading": "Alexa", "useColor": true, + "subPage": false, "items": [{ id: "alias.0.NSPanel_1.Alexa.PlayerBuero" }] }; +var Buero_Themostat: PageThermo = +{ + "type": "cardThermo", + "heading": "Test Thermostat", + "useColor": true, + "subPage": false, + "items": [{ id: "alias.0.NSPanel_1.Thermostat_Büro", minValue: 50, maxValue: 300 }] +}; + +var Buero_Klimaanlage: PageThermo = +{ + "type": "cardThermo", + "heading": "Test Klimaanlage", + "useColor": true, + "subPage": false, + "items": [{ id: "alias.0.NSPanel_1.TestKlimaanlage", minValue: 170, maxValue: 250}] +}; + +//Subpage 2 von Subpages_1 +var WLAN: PageQR = +{ + "type": "cardQR", + "heading": "Gäste WLAN", + "useColor": true, + "subPage": true, + "items": [{ id: "alias.0.NSPanel_1.Guest_Wifi" }] +}; + +var Buero_Alarm: PageAlarm = +{ + "type": "cardAlarm", + "heading": "Alarm", + "useColor": true, + "subPage": false, + "items": [{ id: "alias.0.NSPanel_1.Alarm" }] +}; + var button1Page: PageGrid = { "type": "cardGrid", "heading": "Radio", "useColor": true, + "subPage": false, "items": [ - { id: "alias.0.Radio.NJoy" }, - { id: "alias.0.Radio.Delta_Radio" }, - { id: "alias.0.Radio.NDR2" }, + { id: "alias.0.NSPanel_1.Radio.FFN", icon: "radio", name: "FFN", onColor: colorRadio}, + { id: "alias.0.NSPanel_1.Radio.Antenne" , icon: "radio", name: "Antenne Nds.", onColor: colorRadio}, + { id: "alias.0.NSPanel_1.Radio.NDR2", icon: "radio", name: "NDR2", onColor: colorRadio}, + { id: "alias.0.NSPanel_1.Radio.Bob", icon: "radio", name: "Radio BOB", onColor: colorRadio}, + { id: "alias.0.NSPanel_1.Radio.Spotify", icon: "spotify", name: "Party Playlist", onColor: colorSpotify}, + { id: "alias.0.NSPanel_1.Radio.Alexa", icon: "playlist-music", name: "Playlist 2021", onColor: colorAlexa} ] }; - var button2Page: PageEntities = { "type": "cardEntities", - "heading": "Knopf2", + "heading": "Büro", "useColor": true, + "subPage": false, "items": [ - { id: "alias.0.Schlafen" }, - { id: "alias.0.Stern" } + { id: "alias.0.NSPanel_1.Schreibtischlampe"}, + { id: "alias.0.NSPanel_1.Deckenbeleuchtung"} + ] +}; + +//Subpages 2 (+ Info) +var Service: PageEntities = +{ + "type": "cardEntities", + "heading": "NSPanel Service", + "useColor": true, + "subPage": false, + "items": [ + { id: "alias.0.NSPanel_1.NSPanel_AutoUpdate", name: "Auto-Updates" ,icon: "update", offColor: MSRed, onColor: MSGreen}, + { navigate: true, id: "NSPanel_Infos", icon: "information-outline", onColor: White, name: "NSPanel Infos"}, + { navigate: true, id: "NSPanel_Firmware_Updates", icon: "update", onColor: White, name: "Manuelle-Updates"}, + { navigate: true, id: "NSPanel_Einstellungen", icon: "wrench-outline", onColor: White, name: "Einstellungen"} + ] +}; + +//Subpage 1 von Subpages_2 +var NSPanel_Infos: PageEntities = +{ + "type": "cardEntities", + "heading": "NSPanel Infos", + "useColor": true, + "subPage": true, + "items": [ + { id: "alias.0.NSPanel_1.NSPanel_Hardware", name: "Hardware", icon: "memory", offColor: MSYellow, onColor: MSYellow, useColor: true}, + { id: "alias.0.NSPanel_1.NSPanel_ESP_Temp", name: "ESP Temperatur", icon: "thermometer", unit: "°C", offColor: MSYellow, onColor: MSYellow, useColor: true}, + { id: "alias.0.NSPanel_1.NSPanel_UpTime", name: "Uptime", icon: "timeline-clock-outline", offColor: MSYellow, onColor: MSYellow, useColor: true}, + { id: "alias.0.NSPanel_1.NSPanel_RSSI", name: "Wifi-Signal", icon: "signal-distance-variant", unit: "dBm", offColor: MSYellow, onColor: MSYellow, useColor: true} + ] +}; + +//Subpage 2 von Subpages_2 +var NSPanel_Einstellungen: PageEntities = +{ + "type": "cardEntities", + "heading": "Screensaver", + "useColor": true, + "subPage": true, + "items": [ + { id: "alias.0.NSPanel_1.Dimmode_BrightnessDay", name: "Brightness Tag", icon: "brightness-5", offColor: MSYellow, onColor: MSYellow, useColor: true, minValue: 5, maxValue: 10}, + { id: "alias.0.NSPanel_1.Dimmode_BrightnessNight", name: "Brightness Nacht", icon: "brightness-4", offColor: MSYellow, onColor: MSYellow, useColor: true, minValue: 0, maxValue: 4}, + { id: "alias.0.NSPanel_1.Dimmode_HourDay", name: "Stunde Tag", icon: "sun-clock", offColor: MSYellow, onColor: MSYellow, useColor: true, minValue: 0, maxValue: 23}, + { id: "alias.0.NSPanel_1.Dimmode_HourNight", name: "Stunde Nacht", icon: "sun-clock-outline", offColor: MSYellow, onColor: MSYellow, useColor: true, minValue: 0, maxValue: 23} + ] +}; + +//Subpage 3 von Subpages_2 +var NSPanel_Firmware_Updates: PageEntities = +{ + "type": "cardEntities", + "heading": "Firmware-Updates", + "useColor": true, + "subPage": true, + "items": [ + { id: "alias.0.NSPanel_1.Tasmota_Version", name: "Tasmota Firmware", useColor: true}, + { id: "alias.0.NSPanel_1.TFT_Firmware", name: "TFT-Firmware", useColor: true}, ] }; export const config: Config = { - panelRecvTopic: "mqtt.0.tele.WzDisplay.RESULT", - panelSendTopic: "mqtt.0.cmnd.WzDisplay.CustomSend", - firstScreensaverEntity: { ScreensaverEntity: "alias.0.Wetter.HUMIDITY", ScreensaverEntityIcon: "water-percent", ScreensaverEntityText: "Luft", ScreensaverEntityUnitText: "%" }, - secondScreensaverEntity: { ScreensaverEntity: "alias.0.Wetter.PRECIPITATION_CHANCE", ScreensaverEntityIcon: "weather-pouring", ScreensaverEntityText: "Regen", ScreensaverEntityUnitText: "%" }, - thirdScreensaverEntity: { ScreensaverEntity: "alias.0.Batterie.ACTUAL", ScreensaverEntityIcon: "battery-medium", ScreensaverEntityText: "Batterie", ScreensaverEntityUnitText: "%" }, - fourthScreensaverEntity: { ScreensaverEntity: "alias.0.Pv.ACTUAL", ScreensaverEntityIcon: "solar-power", ScreensaverEntityText: "PV", ScreensaverEntityUnitText: "W" }, + panelRecvTopic: "mqtt.0.SmartHome.NSPanel_1.tele.RESULT", //anpassen + panelSendTopic: "mqtt.0.SmartHome.NSPanel_1.cmnd.CustomSend", //anpassen + firstScreensaverEntity: { ScreensaverEntity: "hmip.0.devices.3014F711A000185BE9922BCF.channels.1.humidity", ScreensaverEntityIcon: "water-percent", ScreensaverEntityText: "Luft", ScreensaverEntityUnitText: "%" }, + secondScreensaverEntity: { ScreensaverEntity: "accuweather.0.Daily.Day1.Day.PrecipitationProbability", ScreensaverEntityIcon: "weather-pouring", ScreensaverEntityText: "Regen", ScreensaverEntityUnitText: "%" }, + thirdScreensaverEntity: { ScreensaverEntity: "0_userdata.0.Wetter.Windstaerke_homaticIP", ScreensaverEntityIcon: "weather-windy", ScreensaverEntityText: "Wind", ScreensaverEntityUnitText: "bft" }, + fourthScreensaverEntity: { ScreensaverEntity: "accuweather.0.Current.UVIndex", ScreensaverEntityIcon: "solar-power", ScreensaverEntityText: "UV", ScreensaverEntityUnitText: "" }, timeoutScreensaver: 15, dimmode: 8, - active: 100, + active: 100, //Standard-Brightness TFT screenSaverDoubleClick: false, locale: "de_DE", timeFormat: "%H:%M", @@ -159,28 +428,58 @@ export const config: Config = { defaultColor: Off, temperatureUnit: "°C", pages: [ - //Test_Licht, - Wohnen, - Strom, - Müll, + Buero_Seite_2, + Buero_Seite_1, + Buero_Klimaanlage, + //WLAN, + Button_1, + Test_Licht, + Test_Funktionen, + Fenster_1, + Subpages_1, Alexa, - { - "type": "cardThermo", - "heading": "Thermostat", - "useColor": true, - "items": [{ id: "alias.0.WzNsPanel", name: "Wohnzimmer" }] - } + Buero_Themostat, + Buero_Alarm, + Service ], button1Page: button1Page, button2Page: button2Page }; -// _________________________________ End configuration _____________________________________ +// _________________________________ Ab hier keine Konfiguration mehr _____________________________________ + +//Notification an Screensaver +on({id: [screensaverNotifyHeading, screensaverNotifyText], change: "ne"}, async function (obj) { + setState(config.panelSendTopic,(['notify~',getState(screensaverNotifyHeading).val,'~',getState(screensaverNotifyText).val].join(''))); +}); + +//popupNotify - Notification an separate Seite +on({id: [popupNotifyInternalName, popupNotifyHeading, popupNotifyText, popupNotifyButton1Text, popupNotifyButton2Text, popupNotifySleepTimeout], change: "ne"}, async function (obj) { + var notification = "entityUpdateDetail" + "~" + + getState(popupNotifyInternalName).val + "~" + + getState(popupNotifyHeading).val + "~" + + "65504" + "~" //Farbe Headline - gelb + + getState(popupNotifyButton1Text).val + "~" + + "63488" + "~" //Farbe Button1 - rot + + getState(popupNotifyButton2Text).val + "~" + + "2016" + "~" //Farbe Button2 - grün + + getState(popupNotifyText).val + "~" + + "65535" + "~" //Farbe Text - weiß + + getState(popupNotifySleepTimeout).val; + clearTimeout(timer); + var timer = setTimeout(function() { + setState(config.panelSendTopic, "pageType~popupNotify"); + setState(config.panelSendTopic, notification); + }, 500); +}); var subscriptions: any = {}; var screensaverEnabled : boolean = false; var pageId = 0; +//Neu für Subpages +var subPage_open = false; + schedule("* * * * *", function () { SendTime(); }); @@ -188,8 +487,288 @@ schedule("0 * * * *", function () { SendDate(); }); +//3:30 Uhr Startup durchführen und aktuelle TFT-Version empfangen +schedule({hour: 3, minute: 30}, function () { + setState(config.panelSendTopic, 'pageType~pageStartup'); +}); + +//´timeDimMode Day +schedule({hour: getState(NSPanel_Path+ "NSPanel_Dimmode_hourDay").val, minute: 0}, function () { + ScreensaverDimmode(); +}); + +//´timeDimMode Night +schedule({hour: getState(NSPanel_Path+ "NSPanel_Dimmode_hourNight").val, minute: 0}, function () { + ScreensaverDimmode(); +}); + +//Updates vergleichen aktuell alle 30 Minuten +schedule("*/30 * * * *", function () { + get_tasmota_status0(); + get_panel_update_data(); + check_updates(); +}); + +//Mit Start auf Updates checken +setState(config.panelSendTopic, 'pageType~pageStartup'); +get_tasmota_status0() +get_panel_update_data(); +check_updates(); + +//------------------Begin Update Functions +function check_updates() { + + const desired_display_firmware_version = 36; + 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 + setState(NSPanel_Path + "Tasmota_Firmware.currentVersion", getState(NSPanel_Path + "Tasmota_Firmware.onlineVersion").val); + } else { + //Auf Tasmota-Updates hinweisen + if (Debug) console.log("Automatische Updates aus"); + let Path = NSPanel_Path + 'popupNotify.'; + let InternalName = 'TasmotaFirmwareUpdate'; + let Headline = 'Tasmota-Firmware Update'; + let 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(''); + let Button1 = 'Nein'; + let Button2 = 'Ja'; + let Timeout = 0; + setStateDelayed((String(Path) + 'popupNotifyHeading'), Headline, false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifyText'), ([formatDate(getDateObject((new Date().getTime())), "TT.MM.JJJJ SS:mm:ss"),'\r\n','\r\n',Text].join('')), false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifyButton1Text'), Button1, false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifyButton2Text'), Button2, false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifySleepTimeout'), Timeout, false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifyInternalName'), InternalName, false, parseInt(((0) || "").toString(), 60000), 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 + setState(NSPanel_Path + "Berry_Driver.currentVersion", getState(NSPanel_Path + "Berry_Driver.onlineVersion").val); + if (Debug) console.log("Berry-Driver automatisch aktualisiert"); + } else { + //Auf BerryDriver-Update hinweisen + if (Debug) console.log("Automatische Updates aus"); + let Path = NSPanel_Path + 'popupNotify.'; + let InternalName = 'BerryDriverUpdate'; + let Headline = 'Berry-Driver Update'; + let 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(''); + let Button1 = 'Nein'; + let Button2 = 'Ja'; + let Timeout = 0; + setStateDelayed((String(Path) + 'popupNotifyHeading'), Headline, false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifyText'), ([formatDate(getDateObject((new Date().getTime())), "TT.MM.JJJJ SS:mm:ss"),'\r\n','\r\n',Text].join('')), false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifyButton1Text'), Button1, false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifyButton2Text'), Button2, false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifySleepTimeout'), Timeout, false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifyInternalName'), InternalName, false, parseInt(((0) || "").toString(), 60000), 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 + setState(NSPanel_Path + "Display_Firmware.currentVersion", getState(NSPanel_Path + "Display_Firmware.onlineVersion").val); + + if (Debug) console.log("Display_Firmware automatisch aktualisiert"); + } else { + //Auf TFT-Firmware hinweisen + if (Debug) console.log("Automatische Updates aus"); + let Path = NSPanel_Path + 'popupNotify.'; + let InternalName = 'TFTFirmwareUpdate'; + let Headline = 'TFT-Firmware Update'; + let 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(''); + let Button1 = 'Nein'; + let Button2 = 'Ja'; + let Timeout = 0; + setStateDelayed((String(Path) + 'popupNotifyHeading'), Headline, false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifyText'), ([formatDate(getDateObject((new Date().getTime())), "TT.MM.JJJJ SS:mm:ss"),'\r\n','\r\n',Text].join('')), false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifyButton1Text'), Button1, false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifyButton2Text'), Button2, false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifySleepTimeout'), Timeout, false, parseInt(((0) || "").toString(), 60000), false); + setStateDelayed((String(Path) + 'popupNotifyInternalName'), InternalName, false, parseInt(((0) || "").toString(), 60000), false); + } + } + } else { + if (Debug) console.log("Display_Firmware auf NSPanel aktuell"); + } + } +} + +on({id: [].concat([NSPanel_Path + 'popupNotify.popupNotifyAction']), change: "any"}, async function (obj) { + if ((obj.state ? obj.state.val : "") == false) { + manually_Update = false + if (Debug) console.log('Es wurde Button1 gedrückt'); + } else if ((obj.state ? obj.state.val : "") == true) { + if (manually_Update) { + if (getState(NSPanel_Path + "popupNotify.popupNotifyInternalName").val = "TasmotaFirmwareUpdate") { + update_tasmota_firmware(); + } else if (getState(NSPanel_Path + "popupNotify.popupNotifyInternalName").val = "BerryDriverUpdate") { + update_berry_driver_version(); + } else if (getState(NSPanel_Path + "popupNotify.popupNotifyInternalName").val = "TFTFirmwareUpdate") { + update_tft_firmware(); + } + } + if (Debug) console.log('Es wurde Button2 gedrückt'); + } +}); + +function get_panel_update_data() { + createState(NSPanel_Path + "NSPanel_autoUpdate", false, {read: true, write: true, name: "Auto-Updater", type: "boolean", def: false}); + createState(NSPanel_Path + "NSPanel_ipAddress"); + setIfExists(NSPanel_Path + "NSPanel_ipAddress", get_current_tasmota_ip_address()); + get_online_tasmota_firmware_version(); + get_current_berry_driver_version(); + get_online_berry_driver_version(); + check_version_tft_firmware(); + check_online_display_firmware(); +} + +function get_current_tasmota_ip_address() { + let mqttInfo2 = config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 6) + "INFO2"; + let Tasmota_Info2 = JSON.parse(getState(mqttInfo2).val); + return Tasmota_Info2.Info2.IPAddress; +} + +function get_online_tasmota_firmware_version() { + exec('curl -X GET -k \'https://api.github.com/repositories/80286288/releases/latest\'', function (error, result, stderr){ //GitAPI aufruf für JSON Inhalt von Latest Tasmota Release + var Tasmota_JSON = JSON.parse(result) //JSON Resultat in Variable Schreiben + var TasmotaTagName = Tasmota_JSON.tag_name //JSON nach "tag_name" filtern und in Variable schreiben + var TasmotaVersionOnline = TasmotaTagName.replace(/v/i, ""); //Aus Variable überflüssiges "v" filtern und in Release-Variable schreiben + createState(NSPanel_Path + "Tasmota_Firmware.onlineVersion"); + setIfExists(NSPanel_Path + "Tasmota_Firmware.onlineVersion", TasmotaVersionOnline); + }); +} + +function get_current_berry_driver_version() { + require("request")((['http://',get_current_tasmota_ip_address(),'/cm?cmnd=GetDriverVersion'].join('')), async function (error, response, result) { + createState(NSPanel_Path + "Berry_Driver.currentVersion"); + setIfExists(NSPanel_Path + 'Berry_Driver.currentVersion', getAttr(result, 'nlui_driver_version')); + }); +} + +function get_tasmota_status0() { + require("request")((['http://',get_current_tasmota_ip_address(),'/cm?cmnd=Status0'].join('')), async function (error, response, result) { + createState(NSPanel_Path + "Tasmota_Firmware.currentVersion"); + createState(NSPanel_Path + "Tasmota.Uptime"); + createState(NSPanel_Path + "Tasmota.Version"); + createState(NSPanel_Path + "Tasmota.Hardware"); + createState(NSPanel_Path + "Tasmota.Wifi.AP"); + createState(NSPanel_Path + "Tasmota.Wifi.SSId"); + createState(NSPanel_Path + "Tasmota.Wifi.BSSId"); + createState(NSPanel_Path + "Tasmota.Wifi.Channel"); + createState(NSPanel_Path + "Tasmota.Wifi.Mode"); + createState(NSPanel_Path + "Tasmota.Wifi.RSSI"); + createState(NSPanel_Path + "Tasmota.Wifi.Signal"); + + var Tasmota_JSON = JSON.parse(result) + let tasmoVersion = Tasmota_JSON.StatusFWR.Version.split("("); + setIfExists(NSPanel_Path + "Tasmota_Firmware.currentVersion", tasmoVersion[0]); + setIfExists(NSPanel_Path + "Tasmota.Uptime", Tasmota_JSON.StatusPRM.Uptime); + setIfExists(NSPanel_Path + "Tasmota.Version", Tasmota_JSON.StatusFWR.Version); + setIfExists(NSPanel_Path + "Tasmota.Hardware", Tasmota_JSON.StatusFWR.Hardware); + setIfExists(NSPanel_Path + "Tasmota.Wifi.AP", Tasmota_JSON.StatusSTS.Wifi.AP); + setIfExists(NSPanel_Path + "Tasmota.Wifi.SSId", Tasmota_JSON.StatusSTS.Wifi.SSId); + setIfExists(NSPanel_Path + "Tasmota.Wifi.BSSId", Tasmota_JSON.StatusSTS.Wifi.BSSId); + setIfExists(NSPanel_Path + "Tasmota.Wifi.Channel", Tasmota_JSON.StatusSTS.Wifi.Channel); + setIfExists(NSPanel_Path + "Tasmota.Wifi.Mode", Tasmota_JSON.StatusSTS.Wifi.Mode); + setIfExists(NSPanel_Path + "Tasmota.Wifi.RSSI", Tasmota_JSON.StatusSTS.Wifi.RSSI); + setIfExists(NSPanel_Path + "Tasmota.Wifi.Signal", Tasmota_JSON.StatusSTS.Wifi.Signal); + }); +} + +function get_online_berry_driver_version() { + exec('curl https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/tasmota/autoexec.be', function (error, result, stderr){ + if (result) { + let BerryDriverVersionOnline = result.substring((result.indexOf("version_of_this_script = ") + 24), result.indexOf("version_of_this_script = ") + 27).replace(/\s+/g, ''); + createState(NSPanel_Path + "Berry_Driver.onlineVersion"); + setIfExists(NSPanel_Path + 'Berry_Driver.onlineVersion', BerryDriverVersionOnline); + } + }); +} + +function check_version_tft_firmware() { + exec('curl -X GET -k \'https://api.github.com/repos/joBr99/nspanel-lovelace-ui/releases/latest\'', function (error, result, stderr){ //GitAPI aufruf für JSON Inhalt von Latest Tasmota Release + 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 + createState(NSPanel_Path + "TFT_Firmware.onlineVersion"); + setIfExists(NSPanel_Path + 'TFT_Firmware.onlineVersion', NSPanelVersion); + }); +} + +function check_online_display_firmware() { + exec('curl https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/apps/nspanel-lovelace-ui/nspanel-lovelace-ui.py', function (error, result, stderr){ + if (result) { + let desired_display_firmware_version = result.substring((result.indexOf("desired_display_firmware_version =") + 34), result.indexOf("desired_display_firmware_version =") + 38).replace(/\s+/g, ''); + createState(NSPanel_Path + "Display_Firmware.onlineVersion"); + setIfExists(NSPanel_Path + 'Display_Firmware.onlineVersion', desired_display_firmware_version); + } + }); +} + +on({ id: config.panelRecvTopic }, function (obj) { + if (obj.state.val.startsWith('\{"CustomRecv":')) { + var json = JSON.parse(obj.state.val); + var split = json.CustomRecv.split(","); + if (split[0] == "event" && split[1] == "startup") { + createState(NSPanel_Path + 'Display_Firmware.currentVersion',{ type:'string'}); + createState(NSPanel_Path + 'NSPanel_Version',{ type:'string'}); + setIfExists(NSPanel_Path + 'Display_Firmware.currentVersion',split[2]); + setIfExists(NSPanel_Path + 'NSPanel_Version',split[3]); + } + } +}); + +function update_berry_driver_version() { + require("request")((['http://',get_current_tasmota_ip_address(),'/cm?cmnd=Backlog UpdateDriverVersion https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/tasmota/autoexec.be; Restart 1'].join('')), async function (error, response, result) { + }); +} + +function update_tft_firmware() { + const tft_version : string = "v2.9.0"; + var desired_display_firmware_url = "http://nspanel.pky.eu/lovelace-ui/github/nspanel-" + tft_version + ".tft" + require("request")((['http://',get_current_tasmota_ip_address(),'/cm?cmnd=FlashNextion ', desired_display_firmware_url].join('')), async function (error, response, result) { + createState(NSPanel_Path + "TFT_Firmware.onlineVersion"); + setIfExists(NSPanel_Path + 'TFT_Firmware.onlineVersion', tft_version); + }); +} + +function update_tasmota_firmware() { + require("request")((['http://',get_current_tasmota_ip_address(),'/cm?cmnd=Upgrade 1'].join('')), async function (error, response, result) { + }); +} +//------------------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) } @@ -202,12 +781,12 @@ if (config.thirdScreensaverEntity !== null && config.thirdScreensaverEntity.Scre if (config.fourthScreensaverEntity !== null && config.fourthScreensaverEntity.ScreensaverEntity != null && existsState(config.fourthScreensaverEntity.ScreensaverEntity)) { updateArray.push(config.fourthScreensaverEntity.ScreensaverEntity) } - if (updateArray.length > 0) { on(updateArray, function () { HandleScreensaverUpdate(); }) } + on({ id: config.panelRecvTopic }, function (obj) { if (obj.state.val.startsWith('\{"CustomRecv":')) { var json = JSON.parse(obj.state.val); @@ -221,12 +800,20 @@ function SendToPanel(val: Payload | Payload[]): void { 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); } + +on({id: [].concat([NSPanel_Path + 'Alarm.AlarmState']), change: "ne"}, async function (obj) { + if ((obj.state ? obj.state.val : "") == 'armed' || (obj.state ? obj.state.val : "") == 'disarmed' || (obj.state ? obj.state.val : "") == 'triggered') { + GeneratePage(config.pages[8]); //----------- muss noch dynamisch gefunden werden ------------------------------------------- + } +}); + function HandleMessage(typ: string, method: string, page: number, words: Array): void { if (typ == "event") { switch (method) { @@ -239,7 +826,7 @@ function HandleMessage(typ: string, method: string, page: number, words: Arraypage)); break; + case "cardAlarm": + SendToPanel(GenerateAlarmPage(page)); + break; + case "cardQR": + SendToPanel(GenerateQRPage(page)); + break; } } function HandleHardwareButton(method: string): void { - let page: (PageThermo | PageMedia | PageEntities | PageGrid); + let page: (PageThermo | PageMedia | PageAlarm | PageEntities | PageGrid | PageQR); if (config.button1Page !== null && method == "button1") { page = config.button1Page; pageId = -1; @@ -300,7 +894,7 @@ function HandleStartupProcess(): void { SendDate(); SendTime(); SendToPanel({ payload: "timeout~" + config.timeoutScreensaver }); - SendToPanel({ payload: "dimmode~" + config.dimmode + "~" + config.active }); + SendToPanel({ payload: "dimmode~" + config.dimmode + "~" + config.active}); } function SendDate(): void { @@ -327,6 +921,18 @@ function SendTime(): void { SendToPanel({ payload: "time~" + hr + ":" + min }); } +function ScreensaverDimmode() { + if (timeDimMode.dimmodeOn != undefined ? timeDimMode.dimmodeOn : false) { + if (compareTime(timeDimMode.timeNight != undefined ? timeDimMode.timeNight : "23:00", timeDimMode.timeDay != undefined ? timeDimMode.timeDay : "06:00", "not between", null)) { + SendToPanel({ payload: "dimmode~" + timeDimMode.brightnessDay + "~" + config.active }); + } else { + SendToPanel({ payload: "dimmode~" + timeDimMode.brightnessNight + "~" + config.active }); + } + } else { + SendToPanel({ payload: "dimmode~" + config.dimmode + "~" + config.active }); + } +} + function GenerateEntitiesPage(page: PageEntities): Payload[] { var out_msgs: Array = []; out_msgs = [{ payload: "pageType~cardEntities" }] @@ -347,9 +953,15 @@ function GeneratePageElements(page: Page): string { case "cardThermo": maxItems = 1; break; + case "cardAlarm": + maxItems = 1; + break; case "cardMedia": maxItems = 1; break; + case "cardQR": + maxItems = 1; + break; case "cardEntities": maxItems = 4; break; @@ -357,14 +969,25 @@ function GeneratePageElements(page: Page): string { maxItems = 6; break; } - let pageData = "entityUpd~" + page.heading + "~" + GetNavigationString(pageId) + + let pageData = "entityUpd~" + page.heading + "~" + GetNavigationString(pageId); + +//--------------------------------------Subpage---------------- + if (page.subPage) { + subPage_open = true; + pageData = "entityUpd~" + page.heading + "~" + "1|0"; + } +//--------------------------------------------------------- for (let index = 0; index < maxItems; index++) { if (page.items[index] !== undefined) { pageData += CreateEntity(page.items[index], index + 1, page.useColor); } +/* else { - pageData += CreateEntity({ id: "delete" }, index + 1); + pageData += CreateEntity({ id: "delete" }, index + 1); + //muss das wirklich? Wo erforderlich wird es mitgegeben! } +*/ } return pageData; } @@ -376,11 +999,21 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } var name: string; var type: string; + // ioBroker - if (existsObject(pageItem.id)) { + 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; - name = pageItem.name !== undefined ? pageItem.name : o.common.name.de if (existsState(pageItem.id + ".GET")) { val = getState(pageItem.id + ".GET").val; @@ -390,13 +1023,15 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = val = getState(pageItem.id + ".SET").val; RegisterEntityWatcher(pageItem.id + ".SET"); } - var iconColor = rgb_dec565(config.defaultColor); + + name = pageItem.name !== undefined ? pageItem.name : o.common.name.de switch (o.common.role) { - case "socket": + 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"); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == "socket" ? Icons.GetIcon("power-socket-de") : Icons.GetIcon("lightbulb"); var optVal = "0" if (val === true || val === "true") { @@ -429,7 +1064,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = 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", pageItem, type); + //RegisterDetailEntityWatcher(id + ".HUE"); } } @@ -509,7 +1144,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } return "~" + type + "~" + pageItem.id + "~" + iconId + "~" + iconColor + "~" + name + "~" + optVal; - + case "dimmer": type = "light" iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon("lightbulb"); @@ -528,15 +1163,15 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } 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")) { @@ -553,12 +1188,19 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = 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.door": + case "sensor.window": case "thermostat": @@ -585,18 +1227,92 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = 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"); - let buttonText = pageItem.name !== undefined ? pageItem.name : "PRESS"; iconColor = GetIconColor(pageItem, true, useColors); - return "~" + type + "~" + pageItem.id + "~" + iconId + "~" + + iconColor + "~" + name + "~" + buttonText; + 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 = "UNLOCK" + } else { + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon("lock-open-variant"); + iconColor = GetIconColor(pageItem, false, useColors); + var lockState = "LOCK" + } + 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~~~~~" } @@ -617,7 +1333,7 @@ function GetIconColor(pageItem: PageItem, value: (boolean | number), useColors: )); } - if ((pageItem.useColor || useColors) && ((typeof (value) === "boolean" && value) || value > (pageItem.minValueBrightness !== undefined ? pageItem.minValueBrightness : 0) || value > (pageItem.minValue !== undefined ? pageItem.minValue : 0))) { + 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) } @@ -638,7 +1354,6 @@ function RegisterEntityWatcher(id: string): void { })) } - function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: string): void { if (subscriptions.hasOwnProperty(id)) { return; @@ -671,166 +1386,232 @@ function GenerateThermoPage(page: PageThermo): Payload[] { // ioBroker if (existsObject(id)) { let o = getObject(id) - let name = page.items[0].name !== undefined ? page.items[0].name : o.common.name.de + 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)*10; + 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 = 180 //Min Temp 5°C - let maxTemp = 300 //Max Temp 30°C + + 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 - //Dynamically add attributes if defined in alias - var thermButton = 0; + //Attribute hinzufügen, wenn im Alias definiert let i_list = Array.prototype.slice.apply($('[state.id="' + id + '.*"]')); if ((i_list.length - 3) != 0) { - console.log(i_list.length -3) - if ((i_list.length -3)%2 == 0) { - if ((i_list.length - 3) == 2) { - thermButton = 6; - } else { - thermButton = 5; - } - } else { - if ((i_list.length - 3) == 1) { - thermButton = 2; - } else if ((i_list.length - 3) == 3) { - thermButton = 1; - } else { - thermButton = 0; - } - } - + var i = 0; - var bt = ["","","","","","","","",""]; - for (i = 0; i < thermButton; i++) { - bt[i] = "~~~~"; - } - 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~bt" + (i-1) + "~"; - } else if (parseInt(getState(id + ".HUMIDITY").val) < 30) { - bt[i-1] = Icons.GetIcon("water-percent") + "~63488~1~bt" + (i-1) + "~"; - } else if (parseInt(getState(id + ".HUMIDITY").val) > 65) { - bt[i-1] = Icons.GetIcon("water-percent") + "~65504~1~bt" + (i-1) + "~"; - } else if (parseInt(getState(id + ".HUMIDITY").val) > 75) { - bt[i-1] = Icons.GetIcon("water-percent") + "~63488~1~bt" + (i-1) + "~"; - } - } 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~bt" + (i-1) + "~"; - } else { - bt[i-1] = Icons.GetIcon("battery-high") + "~2016~1~bt" + (i-1) + "~"; - } - } 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("fire") + "~60897~1~bt" + (i-1) + "~"; - } else { - bt[i-1] = Icons.GetIcon("fire") + "~33840~0~bt" + (i-1) + "~"; - } - } 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~bt" + (i-1) + "~"; - } else { - bt[i-1] = Icons.GetIcon("wifi") + "~2016~1~bt" + (i-1) + "~"; - } - } 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~bt" + (i-1) + "~"; - } else { - bt[i-1] = Icons.GetIcon("power-standby") + "~33840~1~bt" + (i-1) + "~"; - } - } 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~bt" + (i-1) + "~"; - } else { - bt[i-1] = Icons.GetIcon("alert-circle") + "~33840~1~bt" + (i-1) + "~"; - } - } 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~bt" + (i-1) + "~"; - } else { - bt[i-1] = Icons.GetIcon("briefcase-check") + "~33840~1~bt" + (i-1) + "~"; - } - } else i--; - break; - case "BOOST": - if (existsState(id + ".BOOST") && getState(id + ".BOOST").val != null) { - if (getState(id + ".BOOST").val) { - bt[i-1] = Icons.GetIcon("fast-forward-60") + "~2016~1~bt" + (i-1) + "~"; - } else { - bt[i-1] = Icons.GetIcon("fast-forward-60") + "~33840~1~bt" + (i-1) + "~"; - } - } else i--; - break; - case "PARTY": - if (existsState(id + ".PARTY") && getState(id + ".PARTY").val != null) { - if (getState(id + ".PARTY").val) { - bt[i-1] = Icons.GetIcon("party-popper") + "~2016~1~bt" + (i-1) + "~"; - } else { - bt[i-1] = Icons.GetIcon("party-popper") + "~33840~1~bt" + (i-1) + "~"; - } - } else i--; - break; - default: - i--; - break; + var bt = ["~~~~","~~~~","~~~~","~~~~","~~~~","~~~~","~~~~","~~~~","~~~~"]; + + if (o.common.role == "thermostat") { + 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~" + "HUMIDITY" + "~"; + } else if (parseInt(getState(id + ".HUMIDITY").val) < 30) { + bt[i-1] = Icons.GetIcon("water-percent") + "~63488~1~" + "HUMIDITY" + "~"; + } else if (parseInt(getState(id + ".HUMIDITY").val) >= 40) { + bt[i-1] = Icons.GetIcon("water-percent") + "~2016~1~" + "HUMIDITY" + "~"; + } else if (parseInt(getState(id + ".HUMIDITY").val) > 65) { + bt[i-1] = Icons.GetIcon("water-percent") + "~65504~1~" + "HUMIDITY" + "~"; + } else if (parseInt(getState(id + ".HUMIDITY").val) > 75) { + bt[i-1] = Icons.GetIcon("water-percent") + "~63488~1~" + "HUMIDITY" + "~"; + } + } 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~" + "LOWBAT" + "~"; + } else { + bt[i-1] = Icons.GetIcon("battery-high") + "~2016~1~" + "LOWBAT" + "~"; + } + } 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("fire") + "~60897~1~" + "MAINTAIN" + "~"; + } else { + bt[i-1] = Icons.GetIcon("fire") + "~33840~0~" + "MAINTAIN" + "~"; + } + } 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~" + "UNREACH" + "~"; + } else { + bt[i-1] = Icons.GetIcon("wifi") + "~2016~1~" + "UNREACH" + "~"; + } + } 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~" + "POWER" + "~"; + } else { + bt[i-1] = Icons.GetIcon("power-standby") + "~33840~1~" + "POWER" + "~"; + } + } 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~" + "ERROR" + "~"; + } else { + bt[i-1] = Icons.GetIcon("alert-circle") + "~33840~1~" + "ERROR" + "~"; + } + } 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~" + "WORKING" + "~"; + } else { + bt[i-1] = Icons.GetIcon("briefcase-check") + "~33840~1~" + "WORKING" + "~"; + } + } else i--; + break; + case "BOOST": + if (existsState(id + ".BOOST") && getState(id + ".BOOST").val != null) { + if (getState(id + ".BOOST").val) { + bt[i-1] = Icons.GetIcon("fast-forward-60") + "~2016~1~" + "BOOST" + "~"; + } else { + bt[i-1] = Icons.GetIcon("fast-forward-60") + "~33840~1~" + "BOOST" + "~"; + } + } else i--; + break; + case "PARTY": + if (existsState(id + ".PARTY") && getState(id + ".PARTY").val != null) { + if (getState(id + ".PARTY").val) { + bt[i-1] = Icons.GetIcon("party-popper") + "~2016~1~" + "PARTY" + "~"; + } else { + bt[i-1] = Icons.GetIcon("party-popper") + "~33840~1~" + "PARTY" + "~"; + } + } else i--; + break; + default: + i--; + break; + } } } + for (let j = i; j < 9; j++) { + bt[j] = "~~~~"; + } } - 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] + bt[8]; + + 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 + "~" + GetNavigationString(pageId) + "~" + id + "~" + currentTemp + "~" + destTemp + "~" + status + "~" + minTemp + "~" + maxTemp + "~" + stepTemp + "~" +icon_res}) + + out_msgs.push({ payload: "entityUpd~" + + name + "~" //Heading + + GetNavigationString(pageId) + "~" //Page Navigation + + id + "~" //internalNameEntiy + + currentTemp + "°C" + "~" //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 + + "Aktuell" + "~" //Bezeicher vor Aktueller Raumtemperatur + + "Status" + "~" //Bezeicner vor + + "HVAC" + "~" //Bezeichner vor HVAC + + "°C"}) //Bezeichner Hinter Solltemp + } + + if (Debug) console.log(out_msgs); return out_msgs } + function GenerateMediaPage(page: PageMedia): Payload[] { 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 name = getState(id + ".ALBUM").val; let media_icon = Icons.GetIcon("playlist-music"); let title = getState(id + ".TITLE").val; let author = getState(id + ".ARTIST").val; @@ -844,7 +1625,6 @@ function GenerateMediaPage(page: PageMedia): Payload[] { iconplaypause = Icons.GetIcon("play"); //play } let currentSpeaker = getState(([alexaInstanz,'.Echo-Devices.',alexaDevice,'.Info.name'].join(''))).val; - //console.log(id); //------------------------------------------------------------------------------------------------------------- // nachfolgend alle Alexa-Devices (ist Online / Player- und Commands-Verzeichnis vorhanden) auflisten und verketten @@ -853,14 +1633,14 @@ function GenerateMediaPage(page: PageMedia): Payload[] { if (alexaSpeakerList.length > 0) { for (let i_index in alexaSpeakerList) { speakerlist = speakerlist + alexaSpeakerList[i_index] + "?"; - } + } } else { let i_list = Array.prototype.slice.apply($('[state.id="' + alexaInstanz + '.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(([alexaInstanz,'.Echo-Devices.',deviceId[3],'.online'].join(''))).val && + if (getState(([alexaInstanz,'.Echo-Devices.',deviceId[3],'.online'].join(''))).val && existsObject(([alexaInstanz,'.Echo-Devices.',deviceId[3],'.Player'].join(''))) && existsObject(([alexaInstanz,'.Echo-Devices.',deviceId[3],'.Commands'].join('')))) { speakerlist = speakerlist + getState(i).val + "?"; @@ -869,19 +1649,164 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } speakerlist = speakerlist.substring(0,speakerlist.length-1); //-------------------------------------------------------------------------------------------------------------- - out_msgs.push({ payload: "entityUpd~" + - name + "~" + - id + "~" + - id + "~" + //???? - media_icon + "~" + - title + "~" + - author + "~" + - volume + "~" + - iconplaypause + "~" + - currentSpeaker + "~" + - speakerlist + "~" + - onoffbutton}); + + 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 +} + +function GenerateAlarmPage(page: PageAlarm): Payload[] { + var id = page.items[0].id + var out_msgs: Array = []; + out_msgs.push({ payload: "pageType~cardAlarm" }); + var nsPath = NSPanel_Path + "Alarm." + + if (existsState(nsPath + "AlarmPin") == false || existsState(nsPath + "AlarmState") == false || existsState(nsPath + "AlarmType") == 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", "0", {type: 'string'}, function() {setState(nsPath + "AlarmType", "0")}); + } + + 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 + } +} + +function GenerateQRPage(page: PageQR): Payload[] { + 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 + let minTemp = page.items[0].minValue !== undefined ? page.items[0].minValue : 50; + var textQR = page.items[0].id + ".ACTUAL" !== undefined ? getState(page.items[0].id + ".ACTUAL").val : "WIFI:T:undefined;S:undefined;P:undefined;H:undefined;" + + 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" + + 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 } @@ -905,17 +1830,35 @@ function setIfExists(id: string, value: any, type: string | null = null): boolea function toggleState(id: string): boolean { let obj = getObject(id); if (existsState(id) && obj.common.type !== undefined && obj.common.type === "boolean") { - setState(id, !getState(id).val); + setIfExists(id, !getState(id).val); return true; } return false; } function HandleButtonEvent(words): void { - let id = words[2] - let buttonAction = words[3]; + 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; + } 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); pageId = Math.abs(pageNum); @@ -927,22 +1870,42 @@ function HandleButtonEvent(words): void { pageId = Math.abs(pageNum); UnsubscribeWatcher(); GeneratePage(config.pages[pageId]); + +//-------------Subpage + if (subPage_open) { + subPage_open = false; + HandleButtonEvent(['event','buttonPress2','cardEntities','bNext']) + } +//-------------------------------- break; case "bExit": if (config.screenSaverDoubleClick) { - if (words[4] == 2) + if (words[4] == 2) { GeneratePage(config.pages[pageId]); - } - else + } + } else { + if (Debug) console.log("bExit: " + words[4] + " - "+ pageId) GeneratePage(config.pages[pageId]); + } + break; + case "notifyAction": + if (words[4] == "yes") { + setIfExists(popupNotifyInternalName, words[2]); + setIfExists(popupNotifyAction , true); + } else if (words[4] == "no") { + setIfExists(popupNotifyInternalName, words[2]); + setIfExists(popupNotifyAction , false) + } + setIfExists(config.panelSendTopic, "exitPopup") break; case "OnOff": if (existsObject(id)) { var action = false if (words[4] == "1") - action = true + action = true; let o = getObject(id) switch (o.common.role) { + case "socket": case "light": setIfExists(id + ".SET", action); break; @@ -969,13 +1932,40 @@ function HandleButtonEvent(words): void { setIfExists(id + ".CLOSE", true) break; case "button": - toggleState(id + ".SET") ? true : toggleState(id + ".ON_SET") + 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 "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])); - //console.log("PositionSlider feuert"); }, 250); break; case "brightnessSlider": @@ -984,14 +1974,12 @@ function HandleButtonEvent(words): void { if (existsObject(id)) { let o = getObject(id); let pageItem = config.pages[pageId].items.find(e => e.id === id); - //console.log(o.common.role); 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])); setIfExists(id + ".SET", parseInt(words[4])) ? true : setIfExists(id + ".ACTUAL", parseInt(words[4])); } break; @@ -1025,8 +2013,8 @@ function HandleButtonEvent(words): void { case "colorWheel": let colorCoordinates = words[4].split('|'); let rgb = pos_to_color(colorCoordinates[0], colorCoordinates[1]); - //console.log(rgb); - //console.log(getHue(rgb.red, rgb.green, rgb.blue)); + 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": @@ -1041,6 +2029,9 @@ function HandleButtonEvent(words): void { setIfExists(id + ".RGB", ConvertRGBtoHex(rgb.red, rgb.green, rgb.blue)); } break; + case "tempUpd": + setIfExists(id + ".SET", parseInt(words[4]) / 10) + break; case "media-back": setIfExists(id + ".PREV", true) break; @@ -1049,7 +2040,7 @@ function HandleButtonEvent(words): void { setIfExists(id + ".PAUSE", true) } else { setIfExists(id + ".PLAY", true) - } + } break; case "media-next": setIfExists(id + ".NEXT", true) @@ -1072,21 +2063,126 @@ function HandleButtonEvent(words): void { case "media-OnOff": setIfExists(id + ".STOP", true) break; - case "tempUpd": - setIfExists(id + ".SET", parseInt(words[4]) / 10) + case "hvac_action": + if (words[4] == "BOOST" || words[4] == "PARTY") { + setIfExists(words[2] + "." + words[4], !getState(words[2] + "." + words[4]).val) + } + 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"); + setTimeout(function(){ + GeneratePage(config.pages[pageId]); + },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"); + setTimeout(function(){ + GeneratePage(config.pages[pageId]); + },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"); + setTimeout(function(){ + GeneratePage(config.pages[pageId]); + },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"); + setTimeout(function(){ + GeneratePage(config.pages[pageId]); + },250) + } + break; + case "D1": //Alarm-Page Alarm Deaktivieren + if (Debug) console.log("D1: " + getState(id + ".PIN").val); + if (words[4] != "") { + if (getState(id + ".PIN").val == words[4]) { + setIfExists(id + ".PIN", "0000"); + setIfExists(id + ".TYPE", "D1"); + setIfExists(id + ".ACTUAL", "pending"); + setTimeout(function(){ + GeneratePage(config.pages[pageId]); + },250) + } + } + break; default: break; } } + function GetNavigationString(pageId: number): string { + if (Debug) console.log(pageId); + if (Debug) console.log(subPage_open); + switch (pageId) { case 0: return "0|1"; case config.pages.length - 1: return "1|0"; case -1: - return "0|0"; + return "2|0"; + case -2: + return "2|0"; default: return "1|1"; } @@ -1105,7 +2201,7 @@ function GenerateDetailPage(type: string, pageItem: PageItem): Payload[] { if (type == "popupLight") { let switchVal = "0" let brightness = 0; - if (o.common.role == "light") { + if (o.common.role == "light" || o.common.role == "socket") { if (existsState(id + ".GET")) { val = getState(id + ".GET").val; RegisterDetailEntityWatcher(id + ".GET", pageItem, type); @@ -1115,12 +2211,25 @@ function GenerateDetailPage(type: string, pageItem: PageItem): Payload[] { 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, false); + iconColor = GetIconColor(pageItem, true, true); + } else { + iconColor = GetIconColor(pageItem, false, true); } - out_msgs.push({ payload: "entityUpdateDetail~" + icon + "~" + + iconColor + "~" + switchVal + ",disable,disable,disable" + "~Color~Temperature~Brightness" }) + out_msgs.push({ payload: "entityUpdateDetail" + "~" //entityUpdateDetail + + icon + "~" //iconId + + iconColor + "~" //iconColor + + switchVal + "~" //buttonState + + "disable" + "~" //sliderBrightnessPos + + "disable" + "~" //sliderColorTempPos + + "disable" + "~" //colorMode + + "Color" + "~" //Color-Bezeichnung + + "Temperature" + "~" //Temperature-Bezeichnung + + "Brightness" }) //Brightness-Bezeichnung } //Dimmer @@ -1157,12 +2266,20 @@ function GenerateDetailPage(type: string, pageItem: PageItem): Payload[] { } RegisterDetailEntityWatcher(id + ".ACTUAL", pageItem, type); - - let colorTemp = "disable" - let colorMode = "disable" - out_msgs.push({ payload: "entityUpdateDetail~" + icon + "~" + iconColor + "~" + switchVal + "~" + brightness + "~" + colorTemp + "~" + colorMode + "~Color~Temperature~Brightness" }) + out_msgs.push({ payload: "entityUpdateDetail" + "~" //entityUpdateDetail + + icon + "~" //iconId + + iconColor + "~" //iconColor + + switchVal + "~" //buttonState + + brightness + "~" //sliderBrightnessPos + + "disable" + "~" //sliderColorTempPos + + "disable" + "~" //colorMod + + "Color" + "~" //Color-Bezeichnung + + "Temperature" + "~" //Temperature-Bezeichnung + + "Brightness" }) //Brightness-Bezeichnung + } + //HUE-Licht if (o.common.role == "hue") { @@ -1214,7 +2331,16 @@ function GenerateDetailPage(type: string, pageItem: PageItem): Payload[] { console.warn("Alias-Datenpunkt: " + id + ".TEMPERATURE could not be read"); } - out_msgs.push({ payload: "entityUpdateDetail~" + icon + "~" + iconColor + "~" + switchVal + "~" + brightness + "~" + colorTemp + "~" + colorMode + "~Color~Temperature~Brightness" }) + out_msgs.push({ payload: "entityUpdateDetail" + "~" //entityUpdateDetail + + icon + "~" //iconId + + iconColor + "~" //iconColor + + switchVal + "~" //buttonState + + brightness + "~" //sliderBrightnessPos + + colorTemp + "~" //sliderColorTempPos + + colorMode + "~" //colorMode (if hue-alias without hue-datapoint, then disable) + + "Color" + "~" //Color-Bezeichnung + + "Temperature" + "~" //Temperature-Bezeichnung + + "Brightness" }) //Brightness-Bezeichnung } //RGB-Licht @@ -1267,7 +2393,16 @@ function GenerateDetailPage(type: string, pageItem: PageItem): Payload[] { console.warn("Alias-Datenpunkt: " + id + ".TEMPERATURE could not be read"); } - out_msgs.push({ payload: "entityUpdateDetail~" + icon + "~" + iconColor + "~" + switchVal + "~" + brightness + "~" + colorTemp + "~" + colorMode + "~Color~Temperature~Brightness" }) + out_msgs.push({ payload: "entityUpdateDetail" + "~" //entityUpdateDetail + + icon + "~" //iconId + + iconColor + "~" //iconColor + + switchVal + "~" //buttonState + + brightness + "~" //sliderBrightnessPos + + colorTemp + "~" //sliderColorTempPos + + colorMode + "~" //colorMode (if hue-alias without hue-datapoint, then disable) + + "Color" + "~" //Color-Bezeichnung + + "Temperature" + "~" //Temperature-Bezeichnung + + "Brightness" }) //Brightness-Bezeichnung } //RGB-Licht-einzeln (HEX) @@ -1324,7 +2459,16 @@ function GenerateDetailPage(type: string, pageItem: PageItem): Payload[] { console.warn("Alias-Datenpunkt: " + id + ".TEMPERATURE could not be read"); } - out_msgs.push({ payload: "entityUpdateDetail~" + icon + "~" + iconColor + "~" + switchVal + "~" + brightness + "~" + colorTemp + "~" + colorMode + "~Color~Temperature~Brightness" }) + out_msgs.push({ payload: "entityUpdateDetail" + "~" //entityUpdateDetail + + icon + "~" //iconId + + iconColor + "~" //iconColor + + switchVal + "~" //buttonState + + brightness + "~" //sliderBrightnessPos + + colorTemp + "~" //sliderColorTempPos + + colorMode + "~" //colorMode (if hue-alias without hue-datapoint, then disable) + + "Color" + "~" //Color-Bezeichnung + + "Temperature" + "~" //Temperature-Bezeichnung + + "Brightness" }) //Brightness-Bezeichnung) } //Farbtemperatur @@ -1369,12 +2513,22 @@ function GenerateDetailPage(type: string, pageItem: PageItem): Payload[] { console.warn("Alias-Datenpunkt: " + id + ".TEMPERATURE could not be read"); } - out_msgs.push({ payload: "entityUpdateDetail~" + icon + "~" + iconColor + "~" + switchVal + "~" + brightness + "~" + colorTemp + "~" + colorMode + "~Color~Temperature~Brightness" }) + out_msgs.push({ payload: "entityUpdateDetail" + "~" //entityUpdateDetail + + icon + "~" //iconId + + iconColor + "~" //iconColor + + switchVal + "~" //buttonState + + brightness + "~" //sliderBrightnessPos + + colorTemp + "~" //sliderColorTempPos + + colorMode + "~" //colorMode (if hue-alias without hue-datapoint, then disable) + + "Color" + "~" //Color-Bezeichnung + + "Temperature" + "~" //Temperature-Bezeichnung + + "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); @@ -1382,7 +2536,10 @@ function GenerateDetailPage(type: string, pageItem: PageItem): Payload[] { val = getState(id + ".SET").val; RegisterDetailEntityWatcher(id + ".SET", pageItem, type); } - out_msgs.push({ payload: "entityUpdateDetail~" + val + "~~Position" }) + out_msgs.push({ payload: "entityUpdateDetail" + "~" //entityUpdateDetail + + val + "~" //Shutterposition + + "" + "~" + + "Position"}) //Position-Bezeichnung } } return out_msgs @@ -1408,15 +2565,16 @@ function HandleScreensaver(): void { function HandleScreensaverUpdate(): void { if (screensaverEnabled && config.weatherEntity != null && existsObject(config.weatherEntity)) { var icon = getState(config.weatherEntity + ".ICON").val; - + let temperature: string = existsState(config.weatherEntity + ".ACTUAL") ? getState(config.weatherEntity + ".ACTUAL").val : existsState(config.weatherEntity + ".TEMP") ? getState(config.weatherEntity + ".TEMP").val : "null"; - + let payloadString = "weatherUpdate~" + Icons.GetIcon(GetAccuWeatherIcon(parseInt(icon))) + "~" + temperature + " " + config.temperatureUnit + "~" - + +/*-------------------------------------------------------------------------------------------------------------------------------------*/ if (weatherForecast == true) { // Accu-Weather Forecast Tag 2 - Tag 5 -- Wenn weatherForecast = true for (let i = 2; i < 6; i++) { @@ -1433,7 +2591,7 @@ function HandleScreensaverUpdate(): void { payloadString += GetScreenSaverEntityString(config.thirdScreensaverEntity); payloadString += GetScreenSaverEntityString(config.fourthScreensaverEntity); } - +/*-------------------------------------------------------------------------------------------------------------------------------------*/ SendToPanel({ payload: payloadString }); } } @@ -1523,6 +2681,21 @@ function GetAccuWeatherIcon(icon: number): string { } } +//------------------Begin Read Internal Sensor Data +on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 6) + "SENSOR" }, function (obj) { + let mqttSensor = config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 6) + "SENSOR"; + let Tasmota_Sensor = JSON.parse(getState(mqttSensor).val); + createState(NSPanel_Path + 'Sensor.Time'); + createState(NSPanel_Path + 'Sensor.TempUnit'); + createState(NSPanel_Path + 'Sensor.ANALOG.Temperature'); + createState(NSPanel_Path + 'Sensor.ESP32.Temperature'); + setIfExists(NSPanel_Path + 'Sensor.Time', Tasmota_Sensor.Time); + setIfExists(NSPanel_Path + 'Sensor.TempUnit', "°" + Tasmota_Sensor.TempUnit); + setIfExists(NSPanel_Path + 'Sensor.ANALOG.Temperature', Tasmota_Sensor.ANALOG.Temperature1); + setIfExists(NSPanel_Path + 'Sensor.ESP32.Temperature', Tasmota_Sensor.ESP32.Temperature); +}); +//------------------End Read Internal Sensor Data + function GetBlendedColor(percentage: number): RGB { if (percentage < 50) return Interpolate(config.defaultOffColor, config.defaultOnColor, percentage / 50.0); @@ -1544,6 +2717,10 @@ 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))); } +/* 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; } @@ -1557,6 +2734,12 @@ 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; @@ -1567,29 +2750,37 @@ function hsv2rgb(hue: number, saturation: number, value: number) { 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 { +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; @@ -1601,8 +2792,10 @@ function pos_to_color(x: number, y: number): RGB { } 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]) }; } @@ -1620,14 +2813,15 @@ type Page = { type: string, heading: string, items: PageItem[], - useColor: boolean + useColor: boolean, + subPage: boolean, }; interface PageEntities extends Page { type: "cardEntities", items: PageItem[], - }; + interface PageGrid extends Page { type: "cardGrid", items: PageItem[], @@ -1643,6 +2837,16 @@ interface PageMedia extends Page { items: PageItem[], }; +interface PageAlarm extends Page { + type: "cardAlarm", + items: PageItem[], +}; + +interface PageQR extends Page { + type: "cardQR", + items: PageItem[], +}; + type PageItem = { id: string, icon: (string | undefined), @@ -1657,7 +2861,17 @@ type PageItem = { minValue: (number | undefined), maxValue: (number | undefined), name: (string | undefined), - unit: (string | undefined) + buttonText: (string | undefined), + unit: (string | undefined), + navigate: (boolean | undefined), +} + +type DimMode = { + dimmodeOn: (boolean | undefined), + brightnessDay: (number | undefined), + brightnessNight: (number | undefined), + timeDay: (string | undefined), + timeNight: (string | undefined) } type Config = { @@ -1665,7 +2879,7 @@ type Config = { panelSendTopic: string, timeoutScreensaver: number, dimmode: number, - //brightnessScreensaver: + active: number, locale: string, timeFormat: string, dateFormat: string, @@ -1679,9 +2893,9 @@ type Config = { defaultColor: RGB, defaultOnColor: RGB, defaultOffColor: RGB, - pages: (PageThermo | PageMedia | PageEntities | PageGrid)[], - button1Page: (PageThermo | PageMedia | PageEntities | PageGrid | null), - button2Page: (PageThermo | PageMedia | PageEntities | PageGrid | null), + pages: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid)[], + button1Page: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | null), + button2Page: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | null), }; type ScreenSaverElement = {