From 1cb974494fcdaf58aafdbd62456fc648e671e255 Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Mon, 25 Dec 2023 14:57:04 +0100 Subject: [PATCH 01/99] Update NsPanelTs.ts Fix Log output payload -> Json.stringify --- ioBroker/NsPanelTs.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 25fe92c2..543b5fba 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -3008,7 +3008,7 @@ function findPageItem(searching: String): PageItem { let pageItem = activePage.items.find(e => e.id === searching); if (pageItem !== undefined) { - if (Debug) log('findPageItem -> pageItem ' + pageItem, 'info'); + if (Debug) log('findPageItem -> pageItem ' + JSON.stringify(pageItem), 'info'); return pageItem; } @@ -3018,7 +3018,7 @@ function findPageItem(searching: String): PageItem { return pageItem === undefined; }); - if (Debug) log('findPageItem -> pageItem SubPage ' + pageItem, 'info'); + if (Debug) log('findPageItem -> pageItem SubPage ' + JSON.stringifyy(pageItem), 'info'); return pageItem; } catch (err) { @@ -5320,7 +5320,7 @@ function GenerateMediaPage(page: PageMedia): Payload[] { }); } if (Debug) { - log('GenerateMediaPage payload: ' + out_msgs, 'info'); + log('GenerateMediaPage payload: ' + JSON.stringify(out_msgs), 'info'); } return out_msgs } catch (err) { @@ -5476,7 +5476,7 @@ function GenerateAlarmPage(page: PageAlarm): Payload[] { }); if (Debug) { - log('GenerateAlarmPage payload: ' + out_msgs, 'info'); + log('GenerateAlarmPage payload: ' + JSON.stringify(out_msgs), 'info'); } return out_msgs; } @@ -5556,7 +5556,7 @@ function GenerateUnlockPage(page: PageUnlock): Payload[] { }); if (Debug) { - log('GenerateUnlockPage payload: ' + out_msgs, 'info'); + log('GenerateUnlockPage payload: ' + JSON.stringify(out_msgs), 'info'); } return out_msgs; @@ -5671,7 +5671,7 @@ function GenerateQRPage(page: PageQR): Payload[] { }); if (Debug) { - log('GenerateQRPage payload: ' + out_msgs, 'info'); + log('GenerateQRPage payload: ' + JSON.stingify(out_msgs), 'info'); } return out_msgs; @@ -5816,7 +5816,7 @@ function GeneratePowerPage(page: PagePower): Payload[] { // 1st to 6th Item power_string }); - if (Debug) log('GeneratePowerPage payload: ' + out_msgs, 'info'); + if (Debug) log('GeneratePowerPage payload: ' + JSON.stringify(out_msgs), 'info'); return out_msgs; } catch (err) { @@ -5848,7 +5848,7 @@ function GenerateChartPage(page: PageChart): Payload[] { txt }); - if (Debug) log('GenerateChartPage payload: ' + out_msgs, 'info'); + if (Debug) log('GenerateChartPage payload: ' + JSON.stringify(out_msgs), 'info'); return out_msgs; } catch (err) { @@ -7935,6 +7935,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): } } } + if (Debug) log('GenerateDetailPage -> payload: ' + JSON.stringify(out_msgs), 'info'); return out_msgs; } catch (err) { From b35122868f22eba39799d927b0cecb81919f7b12 Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Tue, 26 Dec 2023 00:45:48 +0100 Subject: [PATCH 02/99] Update NsPanelTs.ts --- ioBroker/NsPanelTs.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 543b5fba..cfa27daf 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -3018,7 +3018,7 @@ function findPageItem(searching: String): PageItem { return pageItem === undefined; }); - if (Debug) log('findPageItem -> pageItem SubPage ' + JSON.stringifyy(pageItem), 'info'); + if (Debug) log('findPageItem -> pageItem SubPage ' + JSON.stringify(pageItem), 'info'); return pageItem; } catch (err) { @@ -5671,7 +5671,7 @@ function GenerateQRPage(page: PageQR): Payload[] { }); if (Debug) { - log('GenerateQRPage payload: ' + JSON.stingify(out_msgs), 'info'); + log('GenerateQRPage payload: ' + JSON.stringify(out_msgs), 'info'); } return out_msgs; From aeaa995a0a6e424ddd8ede248f2596b380a96a44 Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Tue, 26 Dec 2023 00:51:23 +0100 Subject: [PATCH 03/99] v4.3.3.26 - Update NSPanel.ts Fix Log output payload -> Json.stringify --- ioBroker/NsPanelTs.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index cfa27daf..ae7e057c 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.25 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne +TypeScript v4.3.3.26 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -82,6 +82,7 @@ ReleaseNotes: - 17.12.2023 - v4.3.3.23 Optimization of the blind control (enable or disable Up/Stop/Down) - 18.12.2023 - v4.3.3.24 Hotfix Update Message / Add Icon Colors to Entity Button - 21.12.2023 - v4.3.3.25 Add switch of cardQR by hidePassword: true + - 26.12.2023 - v4.3.3.26 Fix Log output payload -> Json.stringify Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -958,7 +959,7 @@ export const config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.25'; +const scriptVersion: string = 'v4.3.3.26'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; From 93aafe259b25ed785996c23ed1eac2addb56db15 Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Thu, 28 Dec 2023 09:46:05 +0100 Subject: [PATCH 04/99] Update NsPanelTs.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ablösung pageItem.id durch placeId --- ioBroker/NsPanelTs.ts | 85 +++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index ae7e057c..6680f5ee 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -3233,7 +3233,7 @@ function GeneratePageElements(page: Page): string { for (let index = 0; index < maxItems; index++) { if (page.items[index] !== undefined) { - pageData += CreateEntity(page.items[index], index + 1, page.useColor); + pageData += CreateEntity(page.items[index], index, page.useColor); } } if (Debug) log('GeneratePageElements pageData ' + pageData, 'info'); @@ -3543,8 +3543,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role socket/light ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role socket/light ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'hue': type = 'light'; @@ -3573,8 +3573,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role hue ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role hue ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'ct': type = 'light'; @@ -3593,8 +3593,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role ct ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role ct ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'rgb': type = 'light'; @@ -3623,8 +3623,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role rgb ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role rgb ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'cie': case 'rgbSingle': @@ -3655,8 +3655,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role cie/rgbSingle ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role cie/rgbSingle ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'dimmer': type = 'light'; @@ -3675,8 +3675,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role dimmer ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role dimmer ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'blind': type = 'shutter'; @@ -3708,9 +3708,9 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; let value = icon_up + '|' + icon_stop + '|' + icon_down + '|' + icon_up_status + '|' + icon_stop_status + '|' + icon_down_status - if (Debug) log('CreateEntity Icon role blind ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + value, 'info'); + if (Debug) log('CreateEntity Icon role blind ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + value, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + value; + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + value; case 'gate': type = 'text'; @@ -3730,8 +3730,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } - if (Debug) log('CreateEntity Icon role gate ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState; + if (Debug) log('CreateEntity Icon role gate ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState; case 'door': case 'window': @@ -3751,8 +3751,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role door/window ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState; + if (Debug) log('CreateEntity Icon role door/window ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState; case 'motion': type = 'text'; @@ -3766,8 +3766,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconId = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : Icons.GetIcon('motion-sensor'); } - if (Debug) log('CreateEntity Icon role motion ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role motion ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'info': @@ -3841,8 +3841,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } if (Debug) log('CreateEntity Icon role info, humidity, temperature, value.temperature, value.humidity, sensor.door, sensor.window, thermostat', 'info'); - if (Debug) log('CreateEntity ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal+ ' ' + unit, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal + ' ' + unit; + if (Debug) log('CreateEntity ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal+ ' ' + unit, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal + ' ' + unit; case 'buttonSensor': @@ -3851,8 +3851,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconColor = GetIconColor(pageItem, true, useColors); let inSelText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; - if (Debug) log('CreateEntity Icon role buttonSensor ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText; + if (Debug) log('CreateEntity Icon role buttonSensor ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText; case 'button': type = 'button'; @@ -3865,8 +3865,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; - if (Debug) log('CreateEntity Icon role button ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; + if (Debug) log('CreateEntity Icon role button ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; case 'value.time': case 'level.timer': type = 'timer'; @@ -3879,8 +3879,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = RegisterEntityWatcher(pageItem.id + '.STATE'); } - if (Debug) log('CreateEntity Icon role level.timer ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText; + if (Debug) log('CreateEntity Icon role level.timer ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText; case 'value.alarmtime': type = 'timer'; @@ -3897,8 +3897,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = name = ('0' + String(Math.floor(timer_actual / 60))).slice(-2) + ':' + ('0' + String(timer_actual % 60)).slice(-2); } - if (Debug) log('CreateEntity Icon role value.alarmtime ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText + ' ' + val, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText; + if (Debug) log('CreateEntity Icon role value.alarmtime ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText + ' ' + val, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText; case 'level.mode.fan': @@ -3918,8 +3918,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role level.mode.fan ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role level.mode.fan ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'lock': type = 'button'; @@ -3940,8 +3940,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = lockState = pageItem.buttonText !== undefined ? pageItem.buttonText : lockState; } - if (Debug) log('CreateEntity Icon role lock ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState; + if (Debug) log('CreateEntity Icon role lock ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState; case 'slider': type = 'number'; @@ -3949,8 +3949,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconColor = GetIconColor(pageItem, false, useColors); - if (Debug) log('CreateEntity Icon role slider ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; + if (Debug) log('CreateEntity Icon role slider ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; case 'volumeGroup': case 'volume': @@ -3971,8 +3971,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconId = Icons.GetIcon('volume-mute'); } - if (Debug) log('CreateEntity Icon role volumeGroup/volume ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; + if (Debug) log('CreateEntity Icon role volumeGroup/volume ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; case 'warning': type = 'text'; @@ -3988,7 +3988,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconId = itemInfo; } - if (Debug) log('CreateEntity Icon role warning ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + itemName + '~' + itemInfo, 'info'); + if (Debug) log('CreateEntity Icon role warning ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + itemName + '~' + itemInfo, 'info'); return '~' + type + '~' + itemName + '~' + iconId + '~' + iconColor + '~' + itemName + '~' + itemInfo; case 'timeTable': @@ -5919,6 +5919,11 @@ function HandleButtonEvent(words: any): void { let tempid = words[2].split('?'); let id = tempid[0]; let buttonAction = words[3]; + let pageItemID: string = ''; + + if (!isNaN(id)) {pageItemID = activePage.items[id].id}; + + log('HandleButtonEvent activePage: '+ activePage.items.length + ' id: ' + id + ' tempid: ' + tempid + ' pageItemId: ' + pageItemID); if (Debug) { log('HandleButtonEvent übergebene Werte ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4] + ' - PageId: ' + pageId, 'info'); From f807406a97be430ead573f64a5bdcc25bcc52629 Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Thu, 28 Dec 2023 10:23:02 +0100 Subject: [PATCH 05/99] Update NsPanelTs.ts --- ioBroker/NsPanelTs.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 6680f5ee..5ff6196b 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -5921,9 +5921,13 @@ function HandleButtonEvent(words: any): void { let buttonAction = words[3]; let pageItemID: string = ''; - if (!isNaN(id)) {pageItemID = activePage.items[id].id}; + if (!isNaN(id)) { + pageItemID = activePage.items[id].id; + log('HandleButtonEvent activePage: ' + activePage.items.length + ' id: ' + id + ' tempid: ' + tempid + ' pageItemId: ' + pageItemID); + id = pageItemID + }; - log('HandleButtonEvent activePage: '+ activePage.items.length + ' id: ' + id + ' tempid: ' + tempid + ' pageItemId: ' + pageItemID); + if (Debug) { log('HandleButtonEvent übergebene Werte ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4] + ' - PageId: ' + pageId, 'info'); From 9082ed20f30c3467bbc19d0d729e97b1e7907b77 Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Thu, 28 Dec 2023 14:40:09 +0100 Subject: [PATCH 06/99] v4.3.3.27 Update NSPanel.ts - Fix Payload (pageItem.id -> placeId) by Function CreateEntity - Fix Fallback PageItem.name by Function CreateEntity --- ioBroker/NsPanelTs.ts | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 5ff6196b..b74c08e5 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.26 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne +TypeScript v4.3.3.27 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -83,6 +83,8 @@ ReleaseNotes: - 18.12.2023 - v4.3.3.24 Hotfix Update Message / Add Icon Colors to Entity Button - 21.12.2023 - v4.3.3.25 Add switch of cardQR by hidePassword: true - 26.12.2023 - v4.3.3.26 Fix Log output payload -> Json.stringify + - 28.12.2023 - v4.3.3.27 Fix Payload (pageItem.id -> placeId) by Function CreateEntity + - 28.12.2023 - v4.3.3.27 Fix Fallback PageItem.name by Function CreateEntity Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -959,7 +961,7 @@ export const config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.26'; +const scriptVersion: string = 'v4.3.3.27'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -3279,16 +3281,26 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } // Fallback if no name is given - name = pageItem.name !== undefined ? pageItem.name : o.common.name.de; +// name = pageItem.name !== undefined ? pageItem.name : o.common.name.de; + name = pageItem.name !== undefined ? pageItem.name : o.common.name.de == undefined ? o.common.name : o.common.name.de; let prefix = pageItem.prefixName !== undefined ? pageItem.prefixName : ''; let suffix = pageItem.suffixName !== undefined ? pageItem.suffixName : ''; + // If name is used with changing values + if ((name || '').indexOf('getState(') != -1) { + let dpName: string = name.slice(10, name.length -6); + name = getState(dpName).val; + RegisterEntityWatcher(dpName); + } + +/* // If name is used with changing values if (name.indexOf('getState(') != -1) { let dpName: string = name.slice(10, name.length -6); name = getState(dpName).val; RegisterEntityWatcher(dpName); } +*/ name = prefix + name + suffix; if (existsState(pageItem.id + '.GET')) { @@ -5923,12 +5935,12 @@ function HandleButtonEvent(words: any): void { if (!isNaN(id)) { pageItemID = activePage.items[id].id; - log('HandleButtonEvent activePage: ' + activePage.items.length + ' id: ' + id + ' tempid: ' + tempid + ' pageItemId: ' + pageItemID); + if (Debug) { + log('HandleButtonEvent activePage: ' + activePage.items.length + ' id: ' + id + ' tempid: ' + tempid + ' pageItemId: ' + pageItemID); + } id = pageItemID }; - - if (Debug) { log('HandleButtonEvent übergebene Werte ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4] + ' - PageId: ' + pageId, 'info'); } From 8f3c74165d6473f41cae48a03c525a023872d641 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Fri, 29 Dec 2023 12:27:21 +0100 Subject: [PATCH 07/99] v4.3.3.26 - Downgrade NsPanelTs.ts Bug with inSel-Popup in v4.3.3.27 --- ioBroker/NsPanelTs.ts | 107 +++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 64 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index b74c08e5..ae7e057c 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.27 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne +TypeScript v4.3.3.26 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -83,8 +83,6 @@ ReleaseNotes: - 18.12.2023 - v4.3.3.24 Hotfix Update Message / Add Icon Colors to Entity Button - 21.12.2023 - v4.3.3.25 Add switch of cardQR by hidePassword: true - 26.12.2023 - v4.3.3.26 Fix Log output payload -> Json.stringify - - 28.12.2023 - v4.3.3.27 Fix Payload (pageItem.id -> placeId) by Function CreateEntity - - 28.12.2023 - v4.3.3.27 Fix Fallback PageItem.name by Function CreateEntity Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -961,7 +959,7 @@ export const config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.27'; +const scriptVersion: string = 'v4.3.3.26'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -3235,7 +3233,7 @@ function GeneratePageElements(page: Page): string { for (let index = 0; index < maxItems; index++) { if (page.items[index] !== undefined) { - pageData += CreateEntity(page.items[index], index, page.useColor); + pageData += CreateEntity(page.items[index], index + 1, page.useColor); } } if (Debug) log('GeneratePageElements pageData ' + pageData, 'info'); @@ -3281,26 +3279,16 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } // Fallback if no name is given -// name = pageItem.name !== undefined ? pageItem.name : o.common.name.de; - name = pageItem.name !== undefined ? pageItem.name : o.common.name.de == undefined ? o.common.name : o.common.name.de; + name = pageItem.name !== undefined ? pageItem.name : o.common.name.de; let prefix = pageItem.prefixName !== undefined ? pageItem.prefixName : ''; let suffix = pageItem.suffixName !== undefined ? pageItem.suffixName : ''; - // If name is used with changing values - if ((name || '').indexOf('getState(') != -1) { - let dpName: string = name.slice(10, name.length -6); - name = getState(dpName).val; - RegisterEntityWatcher(dpName); - } - -/* // If name is used with changing values if (name.indexOf('getState(') != -1) { let dpName: string = name.slice(10, name.length -6); name = getState(dpName).val; RegisterEntityWatcher(dpName); } -*/ name = prefix + name + suffix; if (existsState(pageItem.id + '.GET')) { @@ -3555,8 +3543,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role socket/light ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role socket/light ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'hue': type = 'light'; @@ -3585,8 +3573,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role hue ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role hue ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'ct': type = 'light'; @@ -3605,8 +3593,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role ct ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role ct ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'rgb': type = 'light'; @@ -3635,8 +3623,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role rgb ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role rgb ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'cie': case 'rgbSingle': @@ -3667,8 +3655,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role cie/rgbSingle ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role cie/rgbSingle ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'dimmer': type = 'light'; @@ -3687,8 +3675,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role dimmer ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role dimmer ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'blind': type = 'shutter'; @@ -3720,9 +3708,9 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; let value = icon_up + '|' + icon_stop + '|' + icon_down + '|' + icon_up_status + '|' + icon_stop_status + '|' + icon_down_status - if (Debug) log('CreateEntity Icon role blind ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + value, 'info'); + if (Debug) log('CreateEntity Icon role blind ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + value, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + value; + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + value; case 'gate': type = 'text'; @@ -3742,8 +3730,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } - if (Debug) log('CreateEntity Icon role gate ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState; + if (Debug) log('CreateEntity Icon role gate ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState; case 'door': case 'window': @@ -3763,8 +3751,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role door/window ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState; + if (Debug) log('CreateEntity Icon role door/window ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState; case 'motion': type = 'text'; @@ -3778,8 +3766,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconId = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : Icons.GetIcon('motion-sensor'); } - if (Debug) log('CreateEntity Icon role motion ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role motion ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'info': @@ -3853,8 +3841,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } if (Debug) log('CreateEntity Icon role info, humidity, temperature, value.temperature, value.humidity, sensor.door, sensor.window, thermostat', 'info'); - if (Debug) log('CreateEntity ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal+ ' ' + unit, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal + ' ' + unit; + if (Debug) log('CreateEntity ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal+ ' ' + unit, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal + ' ' + unit; case 'buttonSensor': @@ -3863,8 +3851,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconColor = GetIconColor(pageItem, true, useColors); let inSelText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; - if (Debug) log('CreateEntity Icon role buttonSensor ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText; + if (Debug) log('CreateEntity Icon role buttonSensor ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText; case 'button': type = 'button'; @@ -3877,8 +3865,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; - if (Debug) log('CreateEntity Icon role button ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; + if (Debug) log('CreateEntity Icon role button ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; case 'value.time': case 'level.timer': type = 'timer'; @@ -3891,8 +3879,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = RegisterEntityWatcher(pageItem.id + '.STATE'); } - if (Debug) log('CreateEntity Icon role level.timer ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText; + if (Debug) log('CreateEntity Icon role level.timer ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText; case 'value.alarmtime': type = 'timer'; @@ -3909,8 +3897,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = name = ('0' + String(Math.floor(timer_actual / 60))).slice(-2) + ':' + ('0' + String(timer_actual % 60)).slice(-2); } - if (Debug) log('CreateEntity Icon role value.alarmtime ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText + ' ' + val, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText; + if (Debug) log('CreateEntity Icon role value.alarmtime ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText + ' ' + val, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText; case 'level.mode.fan': @@ -3930,8 +3918,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role level.mode.fan ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role level.mode.fan ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'lock': type = 'button'; @@ -3952,8 +3940,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = lockState = pageItem.buttonText !== undefined ? pageItem.buttonText : lockState; } - if (Debug) log('CreateEntity Icon role lock ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState; + if (Debug) log('CreateEntity Icon role lock ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState; case 'slider': type = 'number'; @@ -3961,8 +3949,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconColor = GetIconColor(pageItem, false, useColors); - if (Debug) log('CreateEntity Icon role slider ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; + if (Debug) log('CreateEntity Icon role slider ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; case 'volumeGroup': case 'volume': @@ -3983,8 +3971,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconId = Icons.GetIcon('volume-mute'); } - if (Debug) log('CreateEntity Icon role volumeGroup/volume ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); - return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; + if (Debug) log('CreateEntity Icon role volumeGroup/volume ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); + return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; case 'warning': type = 'text'; @@ -4000,7 +3988,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconId = itemInfo; } - if (Debug) log('CreateEntity Icon role warning ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + itemName + '~' + itemInfo, 'info'); + if (Debug) log('CreateEntity Icon role warning ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + itemName + '~' + itemInfo, 'info'); return '~' + type + '~' + itemName + '~' + iconId + '~' + iconColor + '~' + itemName + '~' + itemInfo; case 'timeTable': @@ -5931,15 +5919,6 @@ function HandleButtonEvent(words: any): void { let tempid = words[2].split('?'); let id = tempid[0]; let buttonAction = words[3]; - let pageItemID: string = ''; - - if (!isNaN(id)) { - pageItemID = activePage.items[id].id; - if (Debug) { - log('HandleButtonEvent activePage: ' + activePage.items.length + ' id: ' + id + ' tempid: ' + tempid + ' pageItemId: ' + pageItemID); - } - id = pageItemID - }; if (Debug) { log('HandleButtonEvent übergebene Werte ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4] + ' - PageId: ' + pageId, 'info'); From 50209418d739ce1d9d89460877b42fa775cf9b32 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Sat, 30 Dec 2023 11:23:09 +0100 Subject: [PATCH 08/99] v4.3.3.28 - Update NsPanelTs.ts - short ID's - Fix windows open/close in createEntity --- ioBroker/NsPanelTs.ts | 259 +++++++++++++++++++++++++----------------- 1 file changed, 156 insertions(+), 103 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index ae7e057c..61269597 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.26 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne +TypeScript v4.3.3.28 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -83,6 +83,9 @@ ReleaseNotes: - 18.12.2023 - v4.3.3.24 Hotfix Update Message / Add Icon Colors to Entity Button - 21.12.2023 - v4.3.3.25 Add switch of cardQR by hidePassword: true - 26.12.2023 - v4.3.3.26 Fix Log output payload -> Json.stringify + - 28.12.2023 - v4.3.3.27 Fix Payload (pageItem.id -> placeId) by Function CreateEntity + - 28.12.2023 - v4.3.3.27 Fix Fallback PageItem.name by Function CreateEntity + - 30.12.2023 - v4.3.3.28 Fix short ID's Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -959,7 +962,7 @@ export const config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.26'; +const scriptVersion: string = 'v4.3.3.28'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -1169,12 +1172,18 @@ async function CheckMQTTPorts() { portArray[i] = adapterInstancePort.trim(); } let mqttInstance = adapterArray.indexOf(instanceName); - for (let j: number = 1; j < portArray.length; j++) { - if (portArray[j] == portArray[mqttInstance] && adapterArray[j] == adapterArray[mqttInstance]) { - log('- MQTT-Port-Check OK: Instance of Adapter: ' + adapterArray[j] + ' is running on Port:' + portArray[j], 'info'); - } else if (portArray[j] == portArray[mqttInstance] && adapterArray[j] != adapterArray[mqttInstance]) { - log('Instance of Adapter: ' + adapterArray[j] + ' is running on same Port:' + portArray[j] + ' as ' + adapterArray[mqttInstance], 'warn'); - log('Please Change Port of Instance: ' + adapterArray[j], 'warn'); + + const mqttConfig = getObject(`system.adapter.${adapterArray[mqttInstance]}`) + if (mqttConfig && mqttConfig.native && mqttConfig.native.type == 'client') { + log('- MQTT-Port-Check OK: Instance of Adapter: ' +adapterArray[mqttInstance] + ' is running as client!','info'); + } else { + for (let j: number = 1; j < portArray.length; j++) { + if (portArray[j] == portArray[mqttInstance] && adapterArray[j] == adapterArray[mqttInstance]) { + log('- MQTT-Port-Check OK: Instance of Adapter: ' + adapterArray[j] + ' is running on Port:' + portArray[j], 'info'); + } else if (portArray[j] == portArray[mqttInstance] && adapterArray[j] != adapterArray[mqttInstance]) { + log('Instance of Adapter: ' + adapterArray[j] + ' is running on same Port:' + portArray[j] + ' as ' + adapterArray[mqttInstance], 'warn'); + log('Please Change Port of Instance: ' + adapterArray[j], 'warn'); + } } } log('End MQTT-Port-Check ---------------------------------------','info'); @@ -2968,13 +2977,21 @@ function HandleMessage(typ: string, method: string, page: number, words: Array pageOpenDetail ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4], 'info'); + } + let tempId: PageItem['id']; let tempPageItem = words[3].split('?'); - let pageItem = findPageItem(tempPageItem[0]); + let placeId = undefined; + if (!isNaN(parseInt(tempPageItem[0]))){ + tempId = activePage.items[tempPageItem[0]].id; + placeId = tempPageItem[0] + } else { + tempId = tempPageItem[0]; + } + let pageItem: PageItem = findPageItem(tempId); if (pageItem !== undefined) { - if (Debug) { - log('HandleMessage -> pageOpenDetail ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4], 'info'); - } - SendToPanel(GenerateDetailPage(words[2], tempPageItem[1], pageItem)); + SendToPanel(GenerateDetailPage(words[2], tempPageItem[1], pageItem, placeId)); } break; case 'buttonPress2': @@ -3233,7 +3250,7 @@ function GeneratePageElements(page: Page): string { for (let index = 0; index < maxItems; index++) { if (page.items[index] !== undefined) { - pageData += CreateEntity(page.items[index], index + 1, page.useColor); + pageData += CreateEntity(page.items[index], index, page.useColor); } } if (Debug) log('GeneratePageElements pageData ' + pageData, 'info'); @@ -3279,12 +3296,12 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } // Fallback if no name is given - name = pageItem.name !== undefined ? pageItem.name : o.common.name.de; + name = pageItem.name !== undefined ? pageItem.name : o.common.name.de == undefined ? o.common.name : o.common.name.de; let prefix = pageItem.prefixName !== undefined ? pageItem.prefixName : ''; let suffix = pageItem.suffixName !== undefined ? pageItem.suffixName : ''; // If name is used with changing values - if (name.indexOf('getState(') != -1) { + if ((name || '').indexOf('getState(') != -1) { let dpName: string = name.slice(10, name.length -6); name = getState(dpName).val; RegisterEntityWatcher(dpName); @@ -3365,17 +3382,17 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = case 'door': case 'window': - iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); - iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : o.common.role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); + iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : o.common.role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : existsState(pageItem.id + '.BUTTONTEXT') ? getState(pageItem.id + '.BUTTONTEXT').val : 'PRESS'; if (existsState(pageItem.id + '.COLORDEC')) { iconColor = getState(pageItem.id + '.COLORDEC').val; } else { if (val === true || val === 'true') { - iconColor = GetIconColor(pageItem, false, useColors); - } else { iconColor = GetIconColor(pageItem, true, useColors); + } else { + iconColor = GetIconColor(pageItem, false, useColors); } } if (val === true || val === 'true') { iconId = iconId2 }; @@ -3543,8 +3560,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role socket/light ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role socket/light ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'hue': type = 'light'; @@ -3573,8 +3590,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role hue ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role hue ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'ct': type = 'light'; @@ -3593,8 +3610,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role ct ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role ct ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'rgb': type = 'light'; @@ -3623,8 +3640,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role rgb ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role rgb ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'cie': case 'rgbSingle': @@ -3655,8 +3672,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role cie/rgbSingle ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role cie/rgbSingle ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'dimmer': type = 'light'; @@ -3675,8 +3692,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role dimmer ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role dimmer ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'blind': type = 'shutter'; @@ -3708,9 +3725,9 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; let value = icon_up + '|' + icon_stop + '|' + icon_down + '|' + icon_up_status + '|' + icon_stop_status + '|' + icon_down_status - if (Debug) log('CreateEntity Icon role blind ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + value, 'info'); + if (Debug) log('CreateEntity Icon role blind ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + value, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + value; + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + value; case 'gate': type = 'text'; @@ -3730,8 +3747,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } - if (Debug) log('CreateEntity Icon role gate ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState; + if (Debug) log('CreateEntity Icon role gate ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState; case 'door': case 'window': @@ -3741,18 +3758,18 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = if (existsState(pageItem.id + '.ACTUAL')) { if (getState(pageItem.id + '.ACTUAL').val) { iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); - iconColor = GetIconColor(pageItem, false, useColors); + iconColor = GetIconColor(pageItem, true, useColors); windowState = findLocale('window', 'opened'); } else { iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); iconId = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : iconId; - iconColor = GetIconColor(pageItem, true, useColors); + iconColor = GetIconColor(pageItem, false, useColors); windowState = findLocale('window', 'closed'); } } - if (Debug) log('CreateEntity Icon role door/window ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState; + if (Debug) log('CreateEntity Icon role door/window ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState; case 'motion': type = 'text'; @@ -3766,8 +3783,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconId = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : Icons.GetIcon('motion-sensor'); } - if (Debug) log('CreateEntity Icon role motion ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role motion ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'info': @@ -3841,8 +3858,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } if (Debug) log('CreateEntity Icon role info, humidity, temperature, value.temperature, value.humidity, sensor.door, sensor.window, thermostat', 'info'); - if (Debug) log('CreateEntity ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal+ ' ' + unit, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal + ' ' + unit; + if (Debug) log('CreateEntity ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal+ ' ' + unit, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal + ' ' + unit; case 'buttonSensor': @@ -3851,8 +3868,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconColor = GetIconColor(pageItem, true, useColors); let inSelText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; - if (Debug) log('CreateEntity Icon role buttonSensor ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText; + if (Debug) log('CreateEntity Icon role buttonSensor ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText; case 'button': type = 'button'; @@ -3865,8 +3882,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; - if (Debug) log('CreateEntity Icon role button ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; + if (Debug) log('CreateEntity Icon role button ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; case 'value.time': case 'level.timer': type = 'timer'; @@ -3879,8 +3896,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = RegisterEntityWatcher(pageItem.id + '.STATE'); } - if (Debug) log('CreateEntity Icon role level.timer ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText; + if (Debug) log('CreateEntity Icon role level.timer ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText; case 'value.alarmtime': type = 'timer'; @@ -3897,8 +3914,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = name = ('0' + String(Math.floor(timer_actual / 60))).slice(-2) + ':' + ('0' + String(timer_actual % 60)).slice(-2); } - if (Debug) log('CreateEntity Icon role value.alarmtime ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText + ' ' + val, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText; + if (Debug) log('CreateEntity Icon role value.alarmtime ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText + ' ' + val, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText; case 'level.mode.fan': @@ -3918,8 +3935,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } - if (Debug) log('CreateEntity Icon role level.mode.fan ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + if (Debug) log('CreateEntity Icon role level.mode.fan ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; case 'lock': type = 'button'; @@ -3940,8 +3957,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = lockState = pageItem.buttonText !== undefined ? pageItem.buttonText : lockState; } - if (Debug) log('CreateEntity Icon role lock ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState; + if (Debug) log('CreateEntity Icon role lock ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState; case 'slider': type = 'number'; @@ -3949,8 +3966,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconColor = GetIconColor(pageItem, false, useColors); - if (Debug) log('CreateEntity Icon role slider ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; + if (Debug) log('CreateEntity Icon role slider ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; case 'volumeGroup': case 'volume': @@ -3971,8 +3988,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconId = Icons.GetIcon('volume-mute'); } - if (Debug) log('CreateEntity Icon role volumeGroup/volume ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); - return '~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; + if (Debug) log('CreateEntity Icon role volumeGroup/volume ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; case 'warning': type = 'text'; @@ -3988,7 +4005,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = iconId = itemInfo; } - if (Debug) log('CreateEntity Icon role warning ~' + type + '~' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + itemName + '~' + itemInfo, 'info'); + if (Debug) log('CreateEntity Icon role warning ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + itemName + '~' + itemInfo, 'info'); return '~' + type + '~' + itemName + '~' + iconId + '~' + iconColor + '~' + itemName + '~' + itemInfo; case 'timeTable': @@ -4141,14 +4158,16 @@ function RegisterEntityWatcher(id: string): void { } } -function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: string): void { +function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: string, placeId: number): void { try { if (subscriptions.hasOwnProperty(id)) { return; } + + if (Debug) log('id: ' + id + ' - pageItem: ' + JSON.stringify(pageItem) + ' - type: ' + type + ' - placeId: ' + placeId, 'info'); subscriptions[id] = (on({ id: id, change: 'any' }, () => { - SendToPanel(GenerateDetailPage(type, undefined, pageItem)); + SendToPanel(GenerateDetailPage(type, undefined, pageItem, placeId)); })) } catch (err) { log('error at function RegisterDetailEntityWatcher: ' + err.message, 'warn'); @@ -5919,6 +5938,15 @@ function HandleButtonEvent(words: any): void { let tempid = words[2].split('?'); let id = tempid[0]; let buttonAction = words[3]; + let pageItemID: string = ''; + + if (!isNaN(id)) { + pageItemID = activePage.items[id].id; + if (Debug) { + log('HandleButtonEvent activePage: ' + activePage.items.length + ' id: ' + id + ' tempid: ' + tempid + ' pageItemId: ' + pageItemID); + } + id = pageItemID + }; if (Debug) { log('HandleButtonEvent übergebene Werte ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4] + ' - PageId: ' + pageId, 'info'); @@ -6987,33 +7015,35 @@ function GetNavigationString(pageId: number): string { } } -function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): Payload[] { - if (Debug) log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); +function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, placeId: number): Payload[] { + log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); try { let out_msgs: Array = []; let id = pageItem.id; if (existsObject(id)) { + let o = getObject(id); let val: (boolean | number) = 0; let icon = Icons.GetIcon('lightbulb'); let iconColor = rgb_dec565(config.defaultColor); if (type == 'popupLight') { + let switchVal = '0'; let brightness = 0; if (o.common.role == 'light' || o.common.role == 'socket') { if (existsState(id + '.GET')) { val = getState(id + '.GET').val; - RegisterDetailEntityWatcher(id + '.GET', pageItem, type); + RegisterDetailEntityWatcher(id + '.GET', pageItem, type, placeId); } else if (existsState(id + '.SET')) { if(pageItem.monobutton != undefined && pageItem.monobutton == true){ val = getState(id + ".STATE").val; - RegisterDetailEntityWatcher(id + ".STATE", pageItem, type); + RegisterDetailEntityWatcher(id + ".STATE", pageItem, type, placeId); } else { val = getState(id + '.SET').val; - RegisterDetailEntityWatcher(id + '.SET', pageItem, type); + RegisterDetailEntityWatcher(id + '.SET', pageItem, type, placeId); } } @@ -7031,9 +7061,11 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): effect_supported = 'enable'; } + let tempId = placeId != undefined ? placeId : id; + out_msgs.push({ payload: 'entityUpdateDetail' + '~' // entityUpdateDetail - + id + '~' + + tempId + '~' + icon + '~' // iconId + iconColor + '~' // iconColor + switchVal + '~' // buttonState @@ -7051,10 +7083,10 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): if (o.common.role == 'dimmer') { if (existsState(id + '.ON_ACTUAL')) { val = getState(id + '.ON_ACTUAL').val; - RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type); + RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type, placeId); } else if (existsState(id + '.ON_SET')) { val = getState(id + '.ON_SET').val; - RegisterDetailEntityWatcher(id + '.ON_SET', pageItem, type); + RegisterDetailEntityWatcher(id + '.ON_SET', pageItem, type, placeId); } if (val === true) { @@ -7079,16 +7111,18 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): iconColor = GetIconColor(pageItem, false, true); } - RegisterDetailEntityWatcher(id + '.ACTUAL', pageItem, type); + RegisterDetailEntityWatcher(id + '.ACTUAL', pageItem, type, placeId); let effect_supported = 'disable'; if (pageItem.modeList != undefined) { effect_supported = 'enable'; } + let tempId = placeId != undefined ? placeId : id; + out_msgs.push({ payload: 'entityUpdateDetail' + '~' //entityUpdateDetail - + id + '~' + + tempId + '~' + icon + '~' //iconId + iconColor + '~' //iconColor + switchVal + '~' //buttonState @@ -7107,7 +7141,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): if (existsState(id + '.ON_ACTUAL')) { val = getState(id + '.ON_ACTUAL').val; - RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type); + RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type, placeId); } if (existsState(id + '.DIMMER')) { @@ -7116,7 +7150,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): } else { brightness = getState(id + '.DIMMER').val; } - RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type); + RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type, placeId); } else { log('function GenerateDetailPage role:hue -> Alias-Datenpunkt: ' + id + '.DIMMER could not be read', 'warn'); } @@ -7156,9 +7190,11 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): effect_supported = 'enable'; } + let tempId = placeId != undefined ? placeId : id; + out_msgs.push({ payload: 'entityUpdateDetail' + '~' //entityUpdateDetail - + id + '~' + + tempId + '~' + icon + '~' //iconId + iconColor + '~' //iconColor + switchVal + '~' //buttonState @@ -7177,7 +7213,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): if (existsState(id + '.ON_ACTUAL')) { val = getState(id + '.ON_ACTUAL').val; - RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type); + RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type, placeId); } if (existsState(id + '.DIMMER')) { @@ -7186,7 +7222,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): } else { brightness = getState(id + '.DIMMER').val; } - RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type); + RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type, placeId); } else { log('function GenerateDetailPage role:rgb -> Alias-Datenpunkt: ' + id + '.DIMMER could not be read', 'warn'); } @@ -7224,10 +7260,12 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): if (pageItem.modeList != undefined) { effect_supported = 'enable'; } + + let tempId = placeId != undefined ? placeId : id; out_msgs.push({ payload: 'entityUpdateDetail' + '~' //entityUpdateDetail - + id + '~' + + tempId + '~' + icon + '~' //iconId + iconColor + '~' //iconColor + switchVal + '~' //buttonState @@ -7246,7 +7284,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): if (existsState(id + '.ON_ACTUAL')) { val = getState(id + '.ON_ACTUAL').val; - RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type); + RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type, placeId); } if (existsState(id + '.DIMMER')) { @@ -7255,7 +7293,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): } else { brightness = getState(id + '.DIMMER').val; } - RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type); + RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type, placeId); } else { log('function GenerateDetailPage role:rgbSingle -> Alias-Datenpunkt: ' + id + '.DIMMER could not be read', 'warn'); } @@ -7299,9 +7337,11 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): effect_supported = 'enable'; } + let tempId = placeId != undefined ? placeId : id; + out_msgs.push({ payload: 'entityUpdateDetail' + '~' //entityUpdateDetail - + id + '~' + + tempId + '~' + icon + '~' //iconId + iconColor + '~' //iconColor + switchVal + '~' //buttonState @@ -7320,7 +7360,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): if (existsState(id + '.ON')) { val = getState(id + '.ON').val; - RegisterDetailEntityWatcher(id + '.ON', pageItem, type); + RegisterDetailEntityWatcher(id + '.ON', pageItem, type, placeId); } if (existsState(id + '.DIMMER')) { @@ -7329,7 +7369,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): } else { brightness = getState(id + '.DIMMER').val; } - RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type); + RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type, placeId); } else { log('function GenerateDetailPage role:ct -> Alias-Datenpunkt: ' + id + '.DIMMER could not be read', 'warn'); } @@ -7361,9 +7401,11 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): effect_supported = 'enable'; } + let tempId = placeId != undefined ? placeId : id; + out_msgs.push({ payload: 'entityUpdateDetail' + '~' //entityUpdateDetail - + id + '~' + + tempId + '~' + icon + '~' //iconId + iconColor + '~' //iconColor + switchVal + '~' //buttonState @@ -7383,7 +7425,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): 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); + RegisterDetailEntityWatcher(id + '.ACTUAL', pageItem, type, placeId); } else if (existsState(id + '.SET')) { val = getState(id + '.SET').val; //RegisterDetailEntityWatcher(id + '.SET', pageItem, type); @@ -7391,7 +7433,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): let tilt_position: any = 'disabled' if (existsState(id + '.TILT_ACTUAL')) { tilt_position = getState(id + '.TILT_ACTUAL').val; - RegisterDetailEntityWatcher(id + '.TILT_ACTUAL', pageItem, type); + RegisterDetailEntityWatcher(id + '.TILT_ACTUAL', pageItem, type, placeId); } else if (existsState(id + '.TILT_SET')) { tilt_position = getState(id + '.TILT_SET').val; //RegisterDetailEntityWatcher(id + '.TILT_SET', pageItem, type); @@ -7451,9 +7493,11 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): textSecondRow = pageItem.secondRow; } + let tempId = placeId != undefined ? placeId : id; + out_msgs.push({ payload: 'entityUpdateDetail' + '~' //entityUpdateDetail - + id + '~' //entity_id + + tempId + '~' //entity_id + val + '~' //Shutterposition + textSecondRow + '~' //pos_status 2.line + findLocale('blinds', 'Position') + '~' //pos_translation @@ -7483,7 +7527,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): let payloadParameters1 = '~~~~' if (pageItem.popupThermoMode1 != undefined) { - RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias[0], pageItem, type); + RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias[0], pageItem, type, placeId); payloadParameters1 = pageItem.popUpThermoName[0] + '~' //{heading}~ Mode 1 + 'modus1' + '~' //{id}~ Mode 1 + getState(pageItem.id + "." + pageItem.setThermoAlias[0]).val + '~' //{ACTUAL}~ Mode 1 @@ -7492,7 +7536,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): let payloadParameters2 = '~~~~' if (pageItem.popupThermoMode2 != undefined) { - RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias[1], pageItem, type); + RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias[1], pageItem, type, placeId); payloadParameters2 = pageItem.popUpThermoName[1] + '~' //{heading}~ Mode 2 + 'modus2' + '~' //{id}~ Mode 2 + getState(pageItem.id + "." + pageItem.setThermoAlias[1]).val + '~' //{ACTUAL}~ Mode 2 @@ -7501,7 +7545,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): let payloadParameters3 = '~~~~' if (pageItem.popupThermoMode3 != undefined) { - RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias[2], pageItem, type); + RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias[2], pageItem, type, placeId); payloadParameters3 = pageItem.popUpThermoName[2] + '~' //{heading}~ Mode 3 + 'modus3' + '~' //{id}~ Mode 3 + getState(pageItem.id + "." + pageItem.setThermoAlias[2]).val + '~' //{ACTUAL}~ Mode 3 @@ -7524,12 +7568,12 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): let timer_actual: number = 0; if (existsState(id + '.ACTUAL')) { - RegisterDetailEntityWatcher(id + '.ACTUAL', pageItem, type); + RegisterDetailEntityWatcher(id + '.ACTUAL', pageItem, type, placeId); timer_actual = getState(id + '.ACTUAL').val; } if (existsState(id + '.STATE')) { - RegisterDetailEntityWatcher(id + '.STATE', pageItem, type); + RegisterDetailEntityWatcher(id + '.STATE', pageItem, type, placeId); } let editable = 1; @@ -7587,9 +7631,11 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): } } + let tempId = placeId != undefined ? placeId : id; + out_msgs.push({ payload: 'entityUpdateDetail' + '~' //entityUpdateDetail - + id + '~~' //{entity_id} + + tempId + '~~' //{entity_id} + rgb_dec565(White) + '~' //{icon_color}~ + id + '~' + min_remaining + '~' @@ -7611,10 +7657,10 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): if (o.common.role == 'level.mode.fan') { if (existsState(id + '.SET')) { val = getState(id + '.SET').val; - RegisterDetailEntityWatcher(id + '.SET', pageItem, type); + RegisterDetailEntityWatcher(id + '.SET', pageItem, type, placeId); } if (existsState(id + '.MODE')) { - RegisterDetailEntityWatcher(id + '.MODE', pageItem, type); + RegisterDetailEntityWatcher(id + '.MODE', pageItem, type, placeId); } icon = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : 'fan'; @@ -7631,10 +7677,12 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): let modeList = pageItem.modeList.join('?'); let actualMode = pageItem.modeList[getState(id + '.MODE').val]; - + + let tempId = placeId != undefined ? placeId : id; + out_msgs.push({ payload: 'entityUpdateDetail' + '~' // entityUpdateDetail - + id + '~' + + tempId + '~' + icon + '~' // iconId + iconColor + '~' // iconColor + switchVal + '~' // buttonState @@ -7863,9 +7911,11 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): mode = 'favorites'; } + let tempId = placeId != undefined ? placeId : id; + out_msgs.push({ payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail - + id + '?' + optional + '~~' //{entity_id} + + tempId + '?' + optional + '~~' //{entity_id} + rgb_dec565(HMIOn) + '~' //{icon_color}~ + mode + '~' + actualState + '~' @@ -7879,7 +7929,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): if (pageItem.inSel_ChoiceState || pageItem.inSel_ChoiceState == undefined) { if (existsObject(pageItem.id + '.VALUE')) { actualValue = formatInSelText(pageItem.modeList[getState(pageItem.id + '.VALUE').val]); - RegisterDetailEntityWatcher(id + '.VALUE', pageItem, type); + RegisterDetailEntityWatcher(id + '.VALUE', pageItem, type, placeId); } } @@ -7889,9 +7939,11 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): } let valueList = pageItem.modeList != undefined ? tempModeList.join('?') : ''; + let tempId = placeId != undefined ? placeId : id; + out_msgs.push({ payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail2 - + id + '~~' //{entity_id} + + tempId + '~~' //{entity_id} + rgb_dec565(White) + '~' //{icon_color}~ + 'insel' + '~' + actualValue + '~' @@ -7912,7 +7964,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): if (pageItem.inSel_ChoiceState || pageItem.inSel_ChoiceState == undefined) { if (existsObject(pageItem.id + '.VALUE')) { actualValue = formatInSelText(pageItem.modeList[getState(pageItem.id + '.VALUE').val]); - RegisterDetailEntityWatcher(id + '.VALUE', pageItem, type); + RegisterDetailEntityWatcher(id + '.VALUE', pageItem, type, placeId); } } @@ -7923,10 +7975,11 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem): let valueList = pageItem.modeList != undefined ? tempModeList.join('?') : ''; //log(valueList); + let tempId = placeId != undefined ? placeId : id; out_msgs.push({ payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail2 - + id + '~~' //{entity_id} + + tempId + '~~' //{entity_id} + rgb_dec565(White) + '~' //{icon_color}~ + 'insel' + '~' + actualValue + '~' From d4067c5ddbdcf4548e2852832f4eaad1a39e4920 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Sat, 30 Dec 2023 11:56:31 +0100 Subject: [PATCH 09/99] v4.3.3.28 - Update NsPanelTs.ts - Fix short ID's in v4.3.3.27 - Fix window Icons in CreateEntity - Add MQTT-Client Check --- ioBroker/NsPanelTs.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 61269597..8f184bab 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -84,8 +84,10 @@ ReleaseNotes: - 21.12.2023 - v4.3.3.25 Add switch of cardQR by hidePassword: true - 26.12.2023 - v4.3.3.26 Fix Log output payload -> Json.stringify - 28.12.2023 - v4.3.3.27 Fix Payload (pageItem.id -> placeId) by Function CreateEntity - - 28.12.2023 - v4.3.3.27 Fix Fallback PageItem.name by Function CreateEntity - - 30.12.2023 - v4.3.3.28 Fix short ID's + - 28.12.2023 - v4.3.3.27 Fix Fallback PageItem.name by Function CreateEntity --> Many Bugs + - 30.12.2023 - v4.3.3.28 Fix short ID's in v4.3.3.27 + - 30.12.2023 - v4.3.3.28 Fix window Icons in CreateEntity + - 30.12.2023 - v4.3.3.28 Add MQTT-Client Check Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined From 14bc7dedec1692431556cfe281e9ceb695203124 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Sat, 30 Dec 2023 14:15:54 +0100 Subject: [PATCH 10/99] v4.3.3.28 - Update NsPanelTs.ts - Fix short ID's in v4.3.3.27 - Fix window Icons in CreateEntity - Add MQTT-Client Check --- ioBroker/NsPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 8f184bab..3c9e5e29 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -7018,7 +7018,7 @@ function GetNavigationString(pageId: number): string { } function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, placeId: number): Payload[] { - log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); + if (Debug) log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); try { let out_msgs: Array = []; let id = pageItem.id; From c489f07c0a3012c178197139c79f9b15023b75aa Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Sun, 31 Dec 2023 11:33:40 +0100 Subject: [PATCH 11/99] v4.3.3.28 - Update NsPanelTs.ts - Fix short ID's in v4.3.3.27 - Fix window Icons in CreateEntity - Add MQTT-Client Check --- ioBroker/NsPanelTs.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 3c9e5e29..381add65 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -7637,9 +7637,9 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, out_msgs.push({ payload: 'entityUpdateDetail' + '~' //entityUpdateDetail - + tempId + '~~' //{entity_id} + + tempId + '~~' //{entity_id} + rgb_dec565(White) + '~' //{icon_color}~ - + id + '~' + + tempId + '~' + min_remaining + '~' + sec_remaining + '~' + editable + '~' From 5c3f366e5332ce3e9f5330bc0e4e7873055703f0 Mon Sep 17 00:00:00 2001 From: ticaki Date: Mon, 1 Jan 2024 21:53:13 +0100 Subject: [PATCH 12/99] fix types --- ioBroker/NsPanelTs.ts | 1159 +++++++++++++++++++++-------------------- 1 file changed, 596 insertions(+), 563 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 381add65..8c70cdfd 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -770,157 +770,145 @@ let NSPanel_Service_SubPage = ***********************************************************************/ export const config = { - // Seiteneinteilung / Page division // Hauptseiten / Mainpages pages: [ - - NSPanel_Service, //Auto-Alias Service Page - //Unlock_Service //Auto-Alias Service Page (Service Pages used with cardUnlock) + NSPanel_Service, //Auto-Alias Service Page + //Unlock_Service //Auto-Alias Service Page (Service Pages used with cardUnlock) ], - // Unterseiten / Subpages subPages: [ - - NSPanel_Service_SubPage, //Auto-Alias Service Page (only used with cardUnlock) - NSPanel_Infos, //Auto-Alias Service Page - NSPanel_Wifi_Info_1, //Auto-Alias Service Page - NSPanel_Wifi_Info_2, //Auto-Alias Service Page - NSPanel_Sensoren, //Auto-Alias Service Page - NSPanel_Hardware, //Auto-Alias Service Page - NSPanel_IoBroker, //Auot-Alias Service Page - NSPanel_Einstellungen, //Auto-Alias Service Page - NSPanel_Screensaver, //Auto-Alias Service Page - NSPanel_ScreensaverDimmode, //Auto-Alias Service Page - NSPanel_ScreensaverBrightness, //Auto-Alias Service Page - NSPanel_ScreensaverLayout, //Auto-Alias Service Page - NSPanel_ScreensaverWeather, //Auto-Alias Service Page - NSPanel_ScreensaverDateformat, //Auto-Alias Service Page - NSPanel_ScreensaverIndicators, //Auto-Alias Service Page - NSPanel_Relays, //Auto-Alias Service Page - NSPanel_Script, //Auto-Alias Service Page - NSPanel_Firmware, //Auto-Alias Service Page - NSPanel_FirmwareTasmota, //Auto-Alias Service Page - NSPanel_FirmwareBerry, //Auto-Alias Service Page - NSPanel_FirmwareNextion, //Auto-Alias Service Page + NSPanel_Service_SubPage, //Auto-Alias Service Page (only used with cardUnlock) + NSPanel_Infos, //Auto-Alias Service Page + NSPanel_Wifi_Info_1, //Auto-Alias Service Page + NSPanel_Wifi_Info_2, //Auto-Alias Service Page + NSPanel_Sensoren, //Auto-Alias Service Page + NSPanel_Hardware, //Auto-Alias Service Page + NSPanel_IoBroker, //Auot-Alias Service Page + NSPanel_Einstellungen, //Auto-Alias Service Page + NSPanel_Screensaver, //Auto-Alias Service Page + NSPanel_ScreensaverDimmode, //Auto-Alias Service Page + NSPanel_ScreensaverBrightness, //Auto-Alias Service Page + NSPanel_ScreensaverLayout, //Auto-Alias Service Page + NSPanel_ScreensaverWeather, //Auto-Alias Service Page + NSPanel_ScreensaverDateformat, //Auto-Alias Service Page + NSPanel_ScreensaverIndicators, //Auto-Alias Service Page + NSPanel_Relays, //Auto-Alias Service Page + NSPanel_Script, //Auto-Alias Service Page + NSPanel_Firmware, //Auto-Alias Service Page + NSPanel_FirmwareTasmota, //Auto-Alias Service Page + NSPanel_FirmwareBerry, //Auto-Alias Service Page + NSPanel_FirmwareNextion, //Auto-Alias Service Page ], -/*********************************************************************** - ** ** - ** Screensaver Configuration ** - ** ** - ***********************************************************************/ - leftScreensaverEntity: - [ - // Examples for Advanced-Screensaver: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Config-Screensaver#entity-status-icons-ab-v400 + /*********************************************************************** + ** ** + ** Screensaver Configuration ** + ** ** + ***********************************************************************/ + leftScreensaverEntity: [ + // Examples for Advanced-Screensaver: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Config-Screensaver#entity-status-icons-ab-v400 + ], - ], - - bottomScreensaverEntity : - [ - // bottomScreensaverEntity 1 - { - ScreensaverEntity: 'accuweather.0.Daily.Day1.Sunrise', - ScreensaverEntityFactor: 1, - ScreensaverEntityDecimalPlaces: 0, - ScreensaverEntityDateFormat: { hour: '2-digit', minute: '2-digit' }, // Description at Wiki-Pages - ScreensaverEntityIconOn: 'weather-sunset-up', - ScreensaverEntityIconOff: null, - ScreensaverEntityText: 'Sonne', - ScreensaverEntityUnitText: '%', - ScreensaverEntityIconColor: MSYellow //{'val_min': 0, 'val_max': 100} - }, - // bottomScreensaverEntity 2 - { - ScreensaverEntity: 'accuweather.0.Current.WindSpeed', - ScreensaverEntityFactor: (1000/3600), - ScreensaverEntityDecimalPlaces: 1, - ScreensaverEntityIconOn: 'weather-windy', - ScreensaverEntityIconOff: null, - ScreensaverEntityText: "Wind", - ScreensaverEntityUnitText: 'm/s', - ScreensaverEntityIconColor: { 'val_min': 0, 'val_max': 120 } - }, - // bottomScreensaverEntity 3 - { - ScreensaverEntity: 'accuweather.0.Current.WindGust', - ScreensaverEntityFactor: (1000/3600), - ScreensaverEntityDecimalPlaces: 1, - ScreensaverEntityIconOn: 'weather-tornado', - ScreensaverEntityIconOff: null, - ScreensaverEntityText: 'Böen', - ScreensaverEntityUnitText: 'm/s', - ScreensaverEntityIconColor: { 'val_min': 0, 'val_max': 120 } - }, - // bottomScreensaverEntity 4 - { - ScreensaverEntity: 'accuweather.0.Current.WindDirectionText', - ScreensaverEntityFactor: 1, - ScreensaverEntityDecimalPlaces: 0, - ScreensaverEntityIconOn: 'windsock', - ScreensaverEntityIconOff: null, - ScreensaverEntityText: 'Windr.', - ScreensaverEntityUnitText: '°', - ScreensaverEntityIconColor: White - }, - // bottomScreensaverEntity 5 (for Alternative and Advanced Screensaver) - { - ScreensaverEntity: 'accuweather.0.Current.RelativeHumidity', - ScreensaverEntityFactor: 1, - ScreensaverEntityDecimalPlaces: 1, - ScreensaverEntityIconOn: 'water-percent', - ScreensaverEntityIconOff: null, - ScreensaverEntityText: 'Feuchte', - ScreensaverEntityUnitText: '%', - ScreensaverEntityIconColor: {'val_min': 0, 'val_max': 100, 'val_best': 65} - }, - // bottomScreensaverEntity 6 (for Advanced Screensaver) - { - ScreensaverEntity: NSPanel_Path + 'Relay.1', - ScreensaverEntityIconOn: 'coach-lamp-variant', - ScreensaverEntityText: 'Street', - ScreensaverEntityOnColor: Yellow, - ScreensaverEntityOffColor: White, - ScreensaverEntityOnText: 'Is ON', - ScreensaverEntityOffText: 'Not ON' - }, - // Examples for Advanced-Screensaver: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Config-Screensaver#entity-status-icons-ab-v400 - ], - - indicatorScreensaverEntity: - [ - // Examples for Advanced-Screensaver: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Config-Screensaver#entity-status-icons-ab-v400 - ], - - // Status Icon - mrIcon1ScreensaverEntity: - { - ScreensaverEntity: NSPanel_Path + 'Relay.1', - ScreensaverEntityIconOn: 'lightbulb', - ScreensaverEntityIconOff: null, - ScreensaverEntityValue: null, - ScreensaverEntityValueDecimalPlace : 0, - ScreensaverEntityValueUnit: null, - ScreensaverEntityOnColor: On, - ScreensaverEntityOffColor: HMIOff + bottomScreensaverEntity: [ + // bottomScreensaverEntity 1 + { + ScreensaverEntity: 'accuweather.0.Daily.Day1.Sunrise', + ScreensaverEntityFactor: 1, + ScreensaverEntityDecimalPlaces: 0, + ScreensaverEntityDateFormat: {hour: '2-digit', minute: '2-digit'}, // Description at Wiki-Pages + ScreensaverEntityIconOn: 'weather-sunset-up', + ScreensaverEntityIconOff: null, + ScreensaverEntityText: 'Sonne', + ScreensaverEntityUnitText: '%', + ScreensaverEntityIconColor: MSYellow //{'val_min': 0, 'val_max': 100} }, - mrIcon2ScreensaverEntity: - { - ScreensaverEntity: NSPanel_Path + 'Relay.2', - ScreensaverEntityIconOn: 'lightbulb', - ScreensaverEntityIconOff: null, - ScreensaverEntityValue: null, - ScreensaverEntityValueDecimalPlace : 0, - ScreensaverEntityValueUnit: null, - ScreensaverEntityOnColor: On, - ScreensaverEntityOffColor: HMIOff + // bottomScreensaverEntity 2 + { + ScreensaverEntity: 'accuweather.0.Current.WindSpeed', + ScreensaverEntityFactor: (1000 / 3600), + ScreensaverEntityDecimalPlaces: 1, + ScreensaverEntityIconOn: 'weather-windy', + ScreensaverEntityIconOff: null, + ScreensaverEntityText: "Wind", + ScreensaverEntityUnitText: 'm/s', + ScreensaverEntityIconColor: {'val_min': 0, 'val_max': 120} }, -// ------ DE: Ende der Screensaver Einstellungen -------------------- -// ------ EN: End of screensaver settings --------------------------- + // bottomScreensaverEntity 3 + { + ScreensaverEntity: 'accuweather.0.Current.WindGust', + ScreensaverEntityFactor: (1000 / 3600), + ScreensaverEntityDecimalPlaces: 1, + ScreensaverEntityIconOn: 'weather-tornado', + ScreensaverEntityIconOff: null, + ScreensaverEntityText: 'Böen', + ScreensaverEntityUnitText: 'm/s', + ScreensaverEntityIconColor: {'val_min': 0, 'val_max': 120} + }, + // bottomScreensaverEntity 4 + { + ScreensaverEntity: 'accuweather.0.Current.WindDirectionText', + ScreensaverEntityFactor: 1, + ScreensaverEntityDecimalPlaces: 0, + ScreensaverEntityIconOn: 'windsock', + ScreensaverEntityIconOff: null, + ScreensaverEntityText: 'Windr.', + ScreensaverEntityUnitText: '°', + ScreensaverEntityIconColor: White + }, + // bottomScreensaverEntity 5 (for Alternative and Advanced Screensaver) + { + ScreensaverEntity: 'accuweather.0.Current.RelativeHumidity', + ScreensaverEntityFactor: 1, + ScreensaverEntityDecimalPlaces: 1, + ScreensaverEntityIconOn: 'water-percent', + ScreensaverEntityIconOff: null, + ScreensaverEntityText: 'Feuchte', + ScreensaverEntityUnitText: '%', + ScreensaverEntityIconColor: {'val_min': 0, 'val_max': 100, 'val_best': 65} + }, + // bottomScreensaverEntity 6 (for Advanced Screensaver) + { + ScreensaverEntity: NSPanel_Path + 'Relay.1', + ScreensaverEntityIconOn: 'coach-lamp-variant', + ScreensaverEntityText: 'Street', + ScreensaverEntityOnColor: Yellow, + ScreensaverEntityOffColor: White, + ScreensaverEntityOnText: 'Is ON', + ScreensaverEntityOffText: 'Not ON' + }, + // Examples for Advanced-Screensaver: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Config-Screensaver#entity-status-icons-ab-v400 + ], + indicatorScreensaverEntity: [ + // Examples for Advanced-Screensaver: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Config-Screensaver#entity-status-icons-ab-v400 + ], -//-------DE: Anfang Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- -//-------EN: Start Settings for Hardware Button, if used in software (Rule2) -------------------------------------- + // Status Icon + mrIcon1ScreensaverEntity: { + ScreensaverEntity: NSPanel_Path + 'Relay.1', + ScreensaverEntityIconOn: 'lightbulb', + ScreensaverEntityIconOff: null, + ScreensaverEntityValue: null, + ScreensaverEntityValueDecimalPlace: 0, + ScreensaverEntityValueUnit: null, + ScreensaverEntityOnColor: On, + ScreensaverEntityOffColor: HMIOff + }, + mrIcon2ScreensaverEntity: { + ScreensaverEntity: NSPanel_Path + 'Relay.2', + ScreensaverEntityIconOn: 'lightbulb', + ScreensaverEntityIconOff: null, + ScreensaverEntityValue: null, + ScreensaverEntityValueDecimalPlace: 0, + ScreensaverEntityValueUnit: null, + ScreensaverEntityOnColor: On, + ScreensaverEntityOffColor: HMIOff + }, + // ------ DE: Ende der Screensaver Einstellungen -------------------- + // ------ EN: End of screensaver settings --------------------------- + //-------DE: Anfang Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- + //-------EN: Start Settings for Hardware Button, if used in software (Rule2) -------------------------------------- // DE: Konfiguration des linken Schalters des NSPanels // EN: Configuration of the left switch of the NSPanel button1: { @@ -946,10 +934,8 @@ export const config = { entity: null, setValue: null }, -//--------- DE: Ende - Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- -//--------- EN: End - settings for hardware button if they are used in software (Rule2) ------------------------------ - - + //--------- DE: Ende - Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- + //--------- EN: End - settings for hardware button if they are used in software (Rule2) ------------------------------ // DE: WICHTIG !! Parameter nicht ändern WICHTIG!! // EN: IMPORTANT !! Do not change parameters IMPORTANT!! panelRecvTopic: NSPanelReceiveTopic, @@ -973,7 +959,7 @@ const tasmotaOtaUrl: string = 'http://ota.tasmota.com/tasmota32/release/'; const Icons = new IconsSelector(); let timeoutSlider: any; -let vwIconColor = []; +let vwIconColor: number[] = []; let weatherForecast: boolean; let pageCounter: number = 0; let alwaysOn: boolean = false; @@ -1000,7 +986,7 @@ async function Init_dayjs() { require('dayjs/locale/'+ dayjsLanguages[i]); } dayjs.locale(getDayjsLocale()); - } catch (err) { + } catch (err: any) { log('error at function init_dayjs: ' + err.message,'warn'); } } @@ -1082,19 +1068,19 @@ async function CheckConfigParameters() { log('nodeJS does not have an even version number. An odd version number is a developer version. Please correct nodeJS version','info'); } }); - if (existsObject(config.mrIcon1ScreensaverEntity.ScreensaverEntity) == false && config.mrIcon1ScreensaverEntity.ScreensaverEntity != null) { + if (config.mrIcon1ScreensaverEntity.ScreensaverEntity != null && existsObject(config.mrIcon1ScreensaverEntity.ScreensaverEntity) == false ) { log('mrIcon1ScreensaverEntity data point in the config not available - please adjust','warn'); } - if (existsObject(config.mrIcon2ScreensaverEntity.ScreensaverEntity) == false && config.mrIcon2ScreensaverEntity.ScreensaverEntity != null) { + if (config.mrIcon2ScreensaverEntity.ScreensaverEntity != null && existsObject(config.mrIcon2ScreensaverEntity.ScreensaverEntity) == false) { log('mrIcon2ScreensaverEntity data point in the config not available - please adjust','warn'); } - if (CheckEnableSetObject) { + if (CheckEnableSetObject()) { log('setObjects enabled - create Alias Channels possible','info'); isSetOptionActive = true; } else { log('setObjects disabled - Please enable setObjects in JS-Adapter Instance - create Alias Channels not possible', 'warn'); } - } catch (err) { + } catch (err: any) { log('error at function CheckConfigParameters: ' + err.message, 'warn'); } } @@ -1117,7 +1103,7 @@ async function InitIoBrokerInfo() { await createAliasAsync(AliasPath + 'IoBroker.JavaScriptVersion.ACTUAL', NSPanel_Path + 'IoBroker.JavaScriptVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); } setIfExists(NSPanel_Path + 'IoBroker.ScriptVersion', scriptVersion); - } catch (err) { + } catch (err: any) { log('error at funktion InitIoBrokerInfo ' + err.message, 'warn'); } } @@ -1140,7 +1126,7 @@ async function CheckDebugMode() { log('Debug mode disabled','info'); } - } catch (err) { + } catch (err: any) { log('error at function CheckDebugModus: ' + err.message,'warn'); } } @@ -1197,7 +1183,7 @@ async function CheckMQTTPorts() { } }); } - } catch (err) { + } catch (err: any) { log('error at function CheckMQTTPorts: ' + err.message, 'warn'); } } @@ -1244,7 +1230,7 @@ async function Init_Release() { await setStateAsync(NSPanel_Path + 'Display_Firmware.TFT.currentVersion', currentFW + ' / v' + FWRelease[findFWIndex]); await setStateAsync(NSPanel_Path + 'Display_Firmware.TFT.desiredVersion', desired_display_firmware_version + ' / ' + tft_version); } - } catch (err) { + } catch (err: any) { log('error at function Init_Release: ' + err.message, 'warn'); } } @@ -1306,23 +1292,23 @@ async function InitConfigParameters() { await createAliasAsync(AliasPath + 'Config.temperatureUnitNumber.VALUE', NSPanel_Path + 'Config.temperatureUnitNumber', true, { type: 'number', role: 'state', name: 'VALUE' }); } } - } catch (err) { + } catch (err: any) { log('error at function InitConfigParameters: ' + err.message, 'warn'); } } InitConfigParameters(); -on({id: [].concat(NSPanel_Path + 'Config.ScripgtDebugStatus'), change: "ne"}, async function (obj) { +on({id: [NSPanel_Path + 'Config.ScripgtDebugStatus'], change: "ne"}, async function (obj) { try { obj.state.val ? log('Debug mode activated', 'info') : log('Debug mode disabled', 'info'); Debug = obj.state.val - } catch (err) { + } catch (err: any) { log('error at Trigger ScripgtDebugStatus: ' + err.message, 'warn'); } }); -on({id: [].concat(NSPanel_Path + 'Config.localeNumber') - .concat(NSPanel_Path + 'Config.temperatureUnitNumber'), change: "ne"}, async function (obj) { +on({id: [NSPanel_Path + 'Config.localeNumber', + NSPanel_Path + 'Config.temperatureUnitNumber'], change: "ne"}, async function (obj) { try { if (obj.id == NSPanel_Path + 'Config.localeNumber') { let localesList = [ 'en-US', 'de-DE', 'nl-NL', 'da-DK', 'es-ES', 'fr-FR', 'it-IT', 'ru-RU', 'nb-NO', 'nn-NO', 'pl-PL', 'pt-PT', 'af-ZA', 'ar-SY', @@ -1335,7 +1321,7 @@ on({id: [].concat(NSPanel_Path + 'Config.localeNumber') let tempunitList = ['°C', '°F', 'K']; setStateAsync(NSPanel_Path + 'Config.temperatureUnit', tempunitList[obj.state.val]); } - } catch (err) { + } catch (err: any) { log('error at Trigger temperatureUnitNumber + localeNumber: ' + err.message, 'warn'); } }); @@ -1346,7 +1332,7 @@ async function Init_ScreensaverAdvanced() { if (existsState(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced') == false ) { await createStateAsync(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false, true, { type: 'boolean' }); } - } catch (err) { + } catch (err: any) { log('error at function Init_ScreensaverAdvanced: ' + err.message, 'warn'); } } @@ -1361,16 +1347,16 @@ function CheckEnableSetObject() { //switch BackgroundColors for Screensaver Indicators async function Init_ActivePageData() { try { - if (existsState(NSPanel_Path + 'ActivePage.heading') == false ) { - await createStateAsync(NSPanel_Path + 'ActivePage.heading', '', true, { type: 'string' }); + if (existsState(NSPanel_Path + 'activePage!.heading') == false ) { + await createStateAsync(NSPanel_Path + 'activePage!.heading', '', true, { type: 'string' }); } - if (existsState(NSPanel_Path + 'ActivePage.type') == false ) { - await createStateAsync(NSPanel_Path + 'ActivePage.type', '', true, { type: 'string' }); + if (existsState(NSPanel_Path + 'activePage!.type') == false ) { + await createStateAsync(NSPanel_Path + 'activePage!.type', '', true, { type: 'string' }); } - if (existsState(NSPanel_Path + 'ActivePage.id0') == false ) { - await createStateAsync(NSPanel_Path + 'ActivePage.id0', '', true, { type: 'string' }); + if (existsState(NSPanel_Path + 'activePage!.id0') == false ) { + await createStateAsync(NSPanel_Path + 'activePage!.id0', '', true, { type: 'string' }); } - } catch (err) { + } catch (err: any) { log('error at function Init_ActivePageData: ' + err.message, 'warn'); } } @@ -1382,7 +1368,7 @@ async function Init_Screensaver_Backckground_Color_Switch() { if (existsState(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator') == false ) { await createStateAsync(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator', 0, true, { type: 'number' }); } - } catch (err) { + } catch (err: any) { log('error at function Init_Screensaver_Backckground_Color_Switch: ' + err.message, 'warn'); } } @@ -1394,7 +1380,7 @@ on({id: NSPanel_Path + 'ScreensaverInfo.bgColorIndicator', change: "ne"}, async if (bgColorScrSaver < 4) { HandleScreensaverUpdate(); } - } catch (err) { + } catch (err: any) { log('error at trigger bgColorIndicator: ' + err.message, 'warn'); } }); @@ -1404,7 +1390,7 @@ on({id: NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', change: "ne"}, try { if (obj.state.val) setState( NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', false ); //setState(config.panelSendTopic, 'pageType~pageStartup'); - } catch (err) { + } catch (err: any) { log('error at trigger Screensaver Advanced: ' + err.message, 'warn'); } }); @@ -1413,7 +1399,7 @@ on({id: NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', change try { if (obj.state.val) setState( NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false ); //setState(config.panelSendTopic, 'pageType~pageStartup'); - } catch (err) { + } catch (err: any) { log('error at trigger Screensaver Alternativ: ' + err.message, 'warn'); } }); @@ -1426,7 +1412,7 @@ async function Init_bExit_Page_Change() { if (existsState(NSPanel_Path + 'ScreensaverInfo.bExitPage') == false ) { await createStateAsync(NSPanel_Path + 'ScreensaverInfo.bExitPage', -1, true, { type: 'number' }); } - } catch (err) { + } catch (err: any) { log('error at function Init_bExit_Page_Change: ' + err.message, 'warn'); } } @@ -1438,7 +1424,7 @@ async function Init_Dimmode_Trigger() { if (existsState(NSPanel_Path + 'ScreensaverInfo.Trigger_Dimmode') == false ) { await createStateAsync(NSPanel_Path + 'ScreensaverInfo.Trigger_Dimmode', false, true, { type: 'boolean' }); } - } catch (err) { + } catch (err: any) { log('error at function Init_Dimmode_Trigger: ' + err.message, 'warn'); } } @@ -1457,13 +1443,13 @@ async function InitActiveBrightness() { await createAliasAsync(AliasPath + 'ScreensaverInfo.activeBrightness.ACTUAL', NSPanel_Path + 'ScreensaverInfo.activeBrightness', true, { type: 'number', role: 'value', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'ScreensaverInfo.activeBrightness.SET', NSPanel_Path + 'ScreensaverInfo.activeBrightness', true, { type: 'number', role: 'level', name: 'SET' }); } - } catch (err) { + } catch (err: any) { log('error at function InitActiveBrightness: ' + err.message, 'warn'); } } InitActiveBrightness(); -on({id: [].concat(String(NSPanel_Path) + 'ScreensaverInfo.activeDimmodeBrightness'), change: "ne"}, async function (obj) { +on({id: [NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness'], change: "ne"}, async function (obj) { try { let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val; if (obj.state.val != null && obj.state.val != -1) { @@ -1488,7 +1474,7 @@ on({id: [].concat(String(NSPanel_Path) + 'ScreensaverInfo.activeDimmodeBrightnes InitDimmode(); HandleMessage('event', 'startup',undefined, undefined); } - } catch (err) { + } catch (err: any) { log('error at trigger activeDimmodeBrightness: ' + err.message, 'warn'); } }); @@ -1501,7 +1487,7 @@ on({id: String(NSPanel_Path) + 'ScreensaverInfo.Trigger_Dimmode', change: "ne"}, } else { InitDimmode(); } - } catch (err) { + } catch (err: any) { log('error at trigger Trigger_Dimmode: ' + err.message, 'warn'); } }); @@ -1513,7 +1499,7 @@ async function InitRebootPanel() { setObject(AliasPath + 'Config.rebootNSPanel', {type: 'channel', common: {role: 'button', name:'Reboot NSPanel'}, native: {}}); await createAliasAsync(AliasPath + 'Config.rebootNSPanel.SET', NSPanel_Path + 'Config.rebootNSPanel', true, { type: 'boolean', role: 'state', name: 'SET' }); } - } catch (err) { + } catch (err: any) { log('error at function InitRebootPanel: ' + err.message, 'warn'); } } @@ -1546,7 +1532,7 @@ on({id: AliasPath + 'Config.rebootNSPanel.SET', change: "any"}, async function ( log('Reboot NSPanel... done', 'info'); } }); - } catch (err) { + } catch (err: any) { log('error at Trigger Restart NSPanel: ' + err.message, 'warn'); } } @@ -1567,15 +1553,15 @@ async function InitUpdateDatapoints() { await createAliasAsync(AliasPath + 'Config.Update.UpdateNextion.SET', NSPanel_Path + 'Config.Update.UpdateNextion', true, { type: 'boolean', role: 'state', name: 'SET' }); } } - } catch (err) { + } catch (err: any) { log('function InitUpdateDatapoints: ' + err.message, 'warn'); } } InitUpdateDatapoints(); -on({id: [].concat(NSPanel_Path + 'Config.Update.UpdateTasmota') - .concat(NSPanel_Path + 'Config.Update.UpdateBerry') - .concat(NSPanel_Path + 'Config.Update.UpdateNextion'), change: "any"}, async function (obj) { +on({id: [NSPanel_Path + 'Config.Update.UpdateTasmota', + NSPanel_Path + 'Config.Update.UpdateBerry', + NSPanel_Path + 'Config.Update.UpdateNextion'], change: "any"}, async function (obj) { try { switch (obj.id) { case NSPanel_Path + 'Config.Update.UpdateTasmota': @@ -1591,7 +1577,7 @@ on({id: [].concat(NSPanel_Path + 'Config.Update.UpdateTasmota') update_tft_firmware(); break; } - } catch (err) { + } catch (err: any) { log('error at Trigger Update Firmware: ' + err.message, 'warn'); } }); @@ -1613,7 +1599,7 @@ async function Init_Relays() { await createAliasAsync(AliasPath + 'Relay.2.ACTUAL', NSPanel_Path + 'Relay.2', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Relay.2.SET', NSPanel_Path + 'Relay.2', true, { type: 'boolean', role: 'switch', name: 'SET' }); } - } catch (err) { + } catch (err: any) { log('error at function Init_Relays: ' + err.message, 'warn'); } } @@ -1637,7 +1623,7 @@ async function InitAlternateMRIconsSize() { await createAliasAsync(AliasPath + 'Config.MRIcons.alternateMRIconSize.2.ACTUAL', NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.MRIcons.alternateMRIconSize.2.SET', NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2', true, { type: 'boolean', role: 'switch', name: 'SET' }); } - } catch (err) { + } catch (err: any) { log('error at function InitAlternateMRIconsSize: ' + err.message, 'warn'); } } @@ -1666,14 +1652,14 @@ async function InitDateformat() { await createAliasAsync(AliasPath + 'Config.Dateformat.Switch.month.SET', NSPanel_Path + 'Config.Dateformat.Switch.month', true, { type: 'boolean', role: 'switch', name: 'SET' }); } } - } catch (err) { + } catch (err: any) { log('error at function InitDateformat: ' + err.message, 'warn'); } } InitDateformat(); //Control Dateformat short/long from DP's -on({id: [].concat(String(NSPanel_Path) + 'Config.Dateformat.Switch.weekday') - .concat(String(NSPanel_Path) + 'Config.Dateformat.Switch.month'), change: "ne"}, async function (obj) { +on({id: [String(NSPanel_Path) + 'Config.Dateformat.Switch.weekday', + String(NSPanel_Path) + 'Config.Dateformat.Switch.month'], change: "ne"}, async function (obj) { try { if (obj.id == NSPanel_Path + 'Config.Dateformat.Switch.weekday') { if (getState(NSPanel_Path + 'Config.Dateformat.Switch.weekday').val) { @@ -1689,15 +1675,15 @@ on({id: [].concat(String(NSPanel_Path) + 'Config.Dateformat.Switch.weekday') } } SendDate(); - } catch (err) { + } catch (err: any) { log('error at Trigger Config.Dateformat: ' + err.message, 'warn'); } }); //Control Relays from DP's -on({id: [].concat(String(NSPanel_Path) + 'Relay.1').concat(String(NSPanel_Path) + 'Relay.2'), change: "ne"}, async function (obj) { +on({id: [String(NSPanel_Path) + 'Relay.1',String(NSPanel_Path) + 'Relay.2'], change: "ne"}, async function (obj) { try { - let Button = obj.id.split('.'); + let Button = obj.id!.split('.'); let urlString: string = ['http://',get_current_tasmota_ip_address(),'/cm?cmnd=Power',Button[Button.length - 1],' ',(obj.state ? obj.state.val : "")].join(''); axios.get(urlString) @@ -1712,7 +1698,7 @@ on({id: [].concat(String(NSPanel_Path) + 'Relay.1').concat(String(NSPanel_Path) log(error, 'warn'); }) - } catch (err) { + } catch (err: any) { log('error at Trigger Relay1/2: ' + err.message, 'warn'); } }); @@ -1721,8 +1707,8 @@ async function SubscribeMRIcons () { try { if (config.mrIcon1ScreensaverEntity.ScreensaverEntity != null) { on({id: config.mrIcon1ScreensaverEntity.ScreensaverEntity, change: "ne"}, async function (obj) { - if (obj.id.substring(0,4) == 'mqtt') { - let Button = obj.id.split('.'); + if (obj.id!.substring(0,4) == 'mqtt') { + let Button = obj.id!.split('.'); if (getState(NSPanel_Path + 'Relay.' + Button[Button.length - 1].substring(5,6)).val != obj.state.val) { await setStateAsync(NSPanel_Path + 'Relay.' + Button[Button.length - 1].substring(5,6), obj.state.val == 'ON' ? true : false); } @@ -1733,8 +1719,8 @@ async function SubscribeMRIcons () { } if (config.mrIcon2ScreensaverEntity.ScreensaverEntity != null) { on({id: config.mrIcon2ScreensaverEntity.ScreensaverEntity, change: "ne"}, async function (obj) { - if (obj.id.substring(0,4) == 'mqtt') { - let Button = obj.id.split('.'); + if (obj.id!.substring(0,4) == 'mqtt') { + let Button = obj.id!.split('.'); if (getState(NSPanel_Path + 'Relay.' + Button[Button.length - 1].substring(5,6)).val != obj.state.val) { await setStateAsync(NSPanel_Path + 'Relay.' + Button[Button.length - 1].substring(5,6), obj.state.val == 'ON' ? true : false); } @@ -1743,7 +1729,7 @@ async function SubscribeMRIcons () { } }); } - } catch (err) { + } catch (err: any) { log('error at function SubscribeMRIcons: ' + err.message, 'warn'); } } @@ -1767,7 +1753,7 @@ async function CreateWeatherAlias () { log('weather alias for daswetter.' + weatherAdapterInstanceNumber + '. already exists', 'info'); } } - } catch (err) { + } catch (err: any) { log('error at function CreateWeatherAlias daswetter.' + weatherAdapterInstanceNumber + '. : ' + err.message, 'warn'); } } else if (weatherAdapterInstance == 'accuweather.' + weatherAdapterInstanceNumber + '.') { @@ -1784,12 +1770,12 @@ async function CreateWeatherAlias () { log('weather alias for accuweather.' + weatherAdapterInstanceNumber + '. already exists', 'info'); } } - } catch (err) { + } catch (err: any) { log('error at function CreateWeatherAlias accuweather.' + weatherAdapterInstanceNumber + '.: ' + err.message, 'warn'); } } } - } catch (err) { + } catch (err: any) { log('error at function CreateWeatherAlias: ' + err.message, 'warn'); } } @@ -1802,14 +1788,14 @@ async function InitPageNavi() { await createStateAsync(NSPanel_Path + 'PageNavi', { type: 'string' }); await setStateAsync(NSPanel_Path + 'PageNavi', { val: {"pagetype": "page","pageId": 0}, ack: true }); } - } catch (err) { + } catch (err: any) { log('error at function InitPageNavi: ' + err.message, 'warn'); } } InitPageNavi(); //PageNavi -on({id: [].concat([NSPanel_Path + 'PageNavi']), change: "any"}, async function (obj) { +on({id: [NSPanel_Path + 'PageNavi'], change: "any"}, async function (obj) { try { if (existsState(NSPanel_Path + 'PageNavi')) { let vObj = JSON.parse(obj.state.val); @@ -1819,7 +1805,7 @@ on({id: [].concat([NSPanel_Path + 'PageNavi']), change: "any"}, async function ( GeneratePage(config.subPages[vObj.pageId]); } } - } catch (err) { + } catch (err: any) { log('error at Trigger PageNavi: ' + err.message, 'warn'); } }); @@ -1850,7 +1836,7 @@ function ScreensaverDimmode(timeDimMode: DimMode) { } else { SendToPanel({ payload: 'dimmode~' + dimmode + '~' + active + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); } - } catch (err) { + } catch (err: any) { log('error at function ScreensaverDimmode: ' + err.message, 'warn'); } } @@ -1879,7 +1865,7 @@ async function InitWeatherForecast() { await createAliasAsync(AliasPath + 'ScreensaverInfo.entityChangeTime.ACTUAL', NSPanel_Path + 'ScreensaverInfo.entityChangeTime', true, { type: 'number', role: 'value', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'ScreensaverInfo.entityChangeTime.SET', NSPanel_Path + 'ScreensaverInfo.entityChangeTime', true, { type: 'number', role: 'level', name: 'SET' }); } - } catch (err) { + } catch (err: any) { log('error at function InitWeatherForecast: ' + err.message, 'warn'); } } @@ -1945,7 +1931,7 @@ async function InitDimmode() { ScreensaverDimmode(timeDimMode); } } - } catch (err) { + } catch (err: any) { log('error at function InitDimmode: ' + err.message, 'warn'); } } @@ -2047,7 +2033,7 @@ async function InitPopupNotify() { // popupNotify - Notification to a separate page //on({ id: [popupNotifyInternalName], change: 'ne' }, async () => { - on({ id: [].concat([popupNotifyText]), change: 'any' }, async() => { + on({ id: [popupNotifyText], change: 'any' }, async() => { let notification: string; @@ -2082,7 +2068,7 @@ async function InitPopupNotify() { setIfExists(config.panelSendTopic, notification); }); - } catch (err) { + } catch (err: any) { log('error at function InitPopupNotify: ' + err.message, 'warn'); } } @@ -2091,14 +2077,14 @@ InitPopupNotify(); let subscriptions: any = {}; let screensaverEnabled: boolean = false; let pageId = 0; -let activePage = undefined; +let activePage: Page | undefined = undefined; //Send time to NSPanel let scheduleSendTime = schedule('* * * * *', () => { try { SendTime(); HandleScreensaverUpdate(); - } catch (err) { + } catch (err: any) { log('error at schedule SendTime: ' + err.message, 'warn'); } }); @@ -2112,7 +2098,7 @@ let scheduleSwichScreensaver = schedule('*/' + getState(NSPanel_Path + 'Screensa } else if (getState(NSPanel_Path + "ScreensaverInfo.popupNotifyHeading").val == '' && getState(NSPanel_Path + "ScreensaverInfo.popupNotifyText").val == '' && getState(NSPanel_Path + "ScreensaverInfo.weatherForecast").val == false && getState(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer").val == true) { setStateDelayed(NSPanel_Path + "ScreensaverInfo.weatherForecast", true, (getState(NSPanel_Path + 'ScreensaverInfo.entityChangeTime').val / 2 * 1000), false); } - } catch (err) { + } catch (err: any) { log('error at schedule entityChangeTime: ' + err.message, 'warn'); } }); @@ -2124,7 +2110,7 @@ function InitHWButton1Color() { HandleScreensaverUpdate(); }); } - } catch (err) { + } catch (err: any) { log('error at function InitHWButton1Color: ' + err.message, 'warn'); } } @@ -2137,28 +2123,28 @@ function InitHWButton2Color() { HandleScreensaverUpdate(); }); } - } catch (err) { + } catch (err: any) { log('error at function InitHWButton2Color: ' + err.message, 'warn'); } } InitHWButton2Color(); //Switch between data points and weather forecast in the screensaver -on({id: [].concat([NSPanel_Path + "ScreensaverInfo.weatherForecast"]), change: "ne"}, async function (obj) { +on({id: [NSPanel_Path + "ScreensaverInfo.weatherForecast"], change: "ne"}, async function (obj) { try { weatherForecast = obj.state.val; HandleScreensaverUpdate(); - } catch (err) { + } catch (err: any) { log('error at trigger weatherForecast: ' + err.message, 'warn'); } }); //Update if Changing Values on Wheather Alias -on({id: [].concat(config.weatherEntity + '.TEMP') - .concat(config.weatherEntity + '.ICON'), change: "ne"}, async function (obj) { +on({id: [config.weatherEntity + '.TEMP', + config.weatherEntity + '.ICON'], change: "ne"}, async function (obj) { try { HandleScreensaverUpdate(); - } catch (err) { + } catch (err: any) { log('error at trigger weatherForecast .TEMP + .ICON: ' + err.message, 'warn'); } }); @@ -2202,8 +2188,10 @@ function getDayjsLocale(): String { } else { return locale.substring(0, 2); } - } catch (err) { + } catch (err: any) { log('error in function getDayjsLocale: ' + err.message, 'warn'); + // hier muß eine Return oder ein neuer throw err hin + return ''; } } @@ -2230,7 +2218,7 @@ async function get_locales() { log(error, 'warn'); }); - } catch (err) { + } catch (err: any) { log('error requesting locales in function get_locales: ' + err.message, 'warn'); } } @@ -2258,7 +2246,7 @@ async function get_locales_servicemenu() { log(error, 'warn'); }); - } catch (err) { + } catch (err: any) { log('error requesting locales in function get_locales_servicemenu: ' + err.message, 'warn'); } } @@ -2388,7 +2376,7 @@ async function check_updates() { log('No Updates for NSPanel available', 'info'); } - } catch (err) { + } catch (err: any) { log('error at function check_updates: ' + err.message, 'warn'); } } @@ -2416,7 +2404,7 @@ on({ id: NSPanel_Path + 'popupNotify.popupNotifyAction', change: 'any' }, async log('Button2 was pressed', 'info'); } } - } catch (err) { + } catch (err: any) { log('error at Trigger popupNotifyAction: ' + err.message, 'warn'); } }); @@ -2448,7 +2436,7 @@ async function get_panel_update_data() { check_version_tft_firmware(); check_online_display_firmware(); } - } catch (err) { + } catch (err: any) { log('error at function get_panel_update_data: ' + err.message, 'warn'); } } @@ -2463,7 +2451,7 @@ function get_current_tasmota_ip_address() { } return infoObj.Info2.IPAddress; - } catch (err) { + } catch (err: any) { log('error at function get_current_tasmota_ip_address: ' + err.message, 'warn'); } } @@ -2500,7 +2488,7 @@ function get_online_tasmota_firmware_version() { log(error, 'warn'); }); - } catch (err) { + } catch (err: any) { log('error requesting firmware in function get_online_tasmota_firmware_version: ' + err.message, 'warn'); } } @@ -2540,7 +2528,7 @@ function get_current_berry_driver_version() { log(error, 'warn'); }); - } catch (err) { + } catch (err: any) { log('error requesting firmware in function get_current_berry_driver_version: ' + err.message, 'warn'); } } @@ -2594,7 +2582,7 @@ function get_tasmota_status0() { await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.Signal', { val: Tasmota_JSON.StatusSTS.Wifi.Signal, ack: true }); await setStateAsync(NSPanel_Path + 'Tasmota.Product', { val: 'SONOFF NSPanel', ack: true }); if (Debug) log('current tasmota firmware version => ' + tasmoVersion, 'info'); - } catch (err) { + } catch (err: any) { log('error setState in function get_tasmota_status0' + err.message, 'warn'); } if (autoCreateAlias) { @@ -2630,7 +2618,7 @@ function get_tasmota_status0() { log(error, 'warn'); }); - } catch (err) { + } catch (err: any) { log('error requesting firmware in function get_tasmota_status0: ' + err.message, 'warn'); } } @@ -2667,7 +2655,7 @@ function get_online_berry_driver_version() { }); } - } catch (err) { + } catch (err: any) { log('error requesting firmware in function get_online_berry_driver_version: ' + err.message, 'warn'); } } @@ -2701,7 +2689,7 @@ function check_version_tft_firmware() { log(error, 'warn'); }); - } catch (err) { + } catch (err: any) { log('error requesting firmware in function check_version_tft_firmware: ' + err.message, 'warn'); } } @@ -2733,7 +2721,7 @@ function check_online_display_firmware() { log(error, 'warn'); }); - } catch (err) { + } catch (err: any) { log('error requesting firmware in function check_online_display_firmware: ' + err.message, 'warn'); } } @@ -2759,7 +2747,7 @@ on({ id: config.panelRecvTopic }, async (obj) => { } } } - } catch (err) { + } catch (err: any) { log('error at trigger rceiving CustomRecv: ' + err.message, 'warn'); } } @@ -2787,7 +2775,7 @@ function update_berry_driver_version() { log(error, 'warn'); }); - } catch (err) { + } catch (err: any) { log('error at function update_berry_driver_version: ' + err.message, 'warn'); } } @@ -2832,7 +2820,7 @@ function update_tft_firmware() { log(error, 'warn'); }); - } catch (err) { + } catch (err: any) { log('error request in function update_tft_firmware: ' + err.message, 'warn'); } } @@ -2880,7 +2868,7 @@ function update_tasmota_firmware() { }); } - } catch (err) { + } catch (err: any) { log('error request in function update_tasmota_firmware: ' + err.message, 'warn'); } } @@ -2898,7 +2886,7 @@ on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESU //check_updates(); } } - } catch (err) { + } catch (err: any) { log('error at trigger with reading senor-data: '+ err.message, 'warn'); } }); @@ -2913,11 +2901,11 @@ on({ id: config.panelRecvTopic, change: 'any' }, async function (obj) { let split = json.CustomRecv.split(','); HandleMessage(split[0], split[1], parseInt(split[2]), split); - } catch (err) { + } catch (err: any) { log('error json.split in Trigger panelRecTopic: ' + err.message, 'warn'); } } - } catch (err) { + } catch (err: any) { log('error at Trigger panelRecTopic: ' + err.message, 'warn'); } }); @@ -2935,7 +2923,7 @@ async function SendToPanel(val: Payload | Payload[]) { setState(config.panelSendTopic, val.payload); } - } catch (err) { + } catch (err: any) { log('error at function SendToPanel: ' + err.message, 'warn'); } } @@ -2947,15 +2935,15 @@ on({ id: NSPanel_Alarm_Path + 'Alarm.AlarmState', change: 'ne' }, async (obj) => log('Trigger AlarmState aktivePage: ' + activePage, 'info'); } if (NSPanel_Path == getState(NSPanel_Alarm_Path + 'Alarm.PANEL').val) { - GeneratePage(activePage); + if (activePage != undefined) GeneratePage(activePage!); } } - } catch (err) { + } catch (err: any) { log('error at Trigger AlarmState: ' + err.message, 'warn'); } }); -function HandleMessage(typ: string, method: string, page: number, words: Array): void { +function HandleMessage(typ: string, method: string, page: number | undefined, words: Array | undefined): void { try { if (typ == 'event') { switch (method) { @@ -2977,30 +2965,32 @@ function HandleMessage(typ: string, method: string, page: number, words: Array sleepReached', 'info'); break; case 'pageOpenDetail': - screensaverEnabled = false; - UnsubscribeWatcher(); - if (Debug) { - log('HandleMessage -> pageOpenDetail ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4], 'info'); - } - let tempId: PageItem['id']; - let tempPageItem = words[3].split('?'); - let placeId = undefined; - if (!isNaN(parseInt(tempPageItem[0]))){ - tempId = activePage.items[tempPageItem[0]].id; - placeId = tempPageItem[0] - } else { - tempId = tempPageItem[0]; - } - let pageItem: PageItem = findPageItem(tempId); - if (pageItem !== undefined) { - SendToPanel(GenerateDetailPage(words[2], tempPageItem[1], pageItem, placeId)); + if (words != undefined) { + screensaverEnabled = false; + UnsubscribeWatcher(); + if (Debug) { + log('HandleMessage -> pageOpenDetail ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4], 'info'); + } + let tempId: PageItem['id']; + let tempPageItem = words[3].split('?'); + let placeId: string | undefined = undefined; + if (!isNaN(parseInt(tempPageItem[0]))){ + tempId = activePage!.items[tempPageItem[0]].id; + placeId = tempPageItem[0] + } else { + tempId = tempPageItem[0]; + } + let pageItem: PageItem = findPageItem(tempId); + if (pageItem !== undefined) { + SendToPanel(GenerateDetailPage(words[2], tempPageItem[1], pageItem, Number(placeId))); + } } break; case 'buttonPress2': screensaverEnabled = false; HandleButtonEvent(words); if (Debug) { - log('HandleMessage -> buttonPress2 ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4], 'info'); + if (words != undefined) log('HandleMessage -> buttonPress2 ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4], 'info'); } break; case 'renderCurrentPage': @@ -3017,15 +3007,15 @@ function HandleMessage(typ: string, method: string, page: number, words: Array e.id === searching); + let pageItem = activePage!.items.find(e => e.id === searching); if (pageItem !== undefined) { if (Debug) log('findPageItem -> pageItem ' + JSON.stringify(pageItem), 'info'); @@ -3039,9 +3029,9 @@ function findPageItem(searching: String): PageItem { }); if (Debug) log('findPageItem -> pageItem SubPage ' + JSON.stringify(pageItem), 'info'); - + //@ts-ignore ticaki bitte lösen, pageItem kann undefined sein. return pageItem; - } catch (err) { + } catch (err: any) { log('error at function findPageItem: ' + err.message, 'warn'); } } @@ -3049,9 +3039,9 @@ function findPageItem(searching: String): PageItem { function GeneratePage(page: Page): void { try { activePage = page; - setIfExists(NSPanel_Path + 'ActivePage.type', activePage.type); - setIfExists(NSPanel_Path + 'ActivePage.heading', activePage.heading); - setIfExists(NSPanel_Path + 'ActivePage.id0', activePage.items[0].id); + setIfExists(NSPanel_Path + 'activePage!.type', activePage!.type); + setIfExists(NSPanel_Path + 'activePage!.heading', activePage!.heading); + setIfExists(NSPanel_Path + 'activePage!.id0', activePage!.items[0].id); switch (page.type) { case 'cardEntities': SendToPanel(GenerateEntitiesPage(page)); @@ -3088,7 +3078,7 @@ function GeneratePage(page: Page): void { SendToPanel(GenerateUnlockPage(page)); break; } - } catch (err) { + } catch (err: any) { if (err.message == "Cannot read properties of undefined (reading 'type')") { log('Please wait a few seconds longer when launching the NSPanel. Not all parameters are loaded yet.', 'warn'); } else { @@ -3131,7 +3121,7 @@ function HandleHardwareButton(method: string): void { screensaverEnabled = true; break; } - } catch (err) { + } catch (err: any) { log('error at function HandleHardwareButton: ' + err.message, 'warn'); } } @@ -3155,7 +3145,7 @@ function SendDate(): void { SendToPanel({ payload: 'date~' + _SendDate }); } - } catch (err) { + } catch (err: any) { if (err.message = 'Cannot convert undefined or null to object') { log('Datumsformat noch nicht initialisiert', 'info'); } else { @@ -3171,7 +3161,7 @@ function SendTime(): void { const min = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); SendToPanel({ payload: 'time~' + hr + ':' + min }); - } catch (err) { + } catch (err: any) { log('error at function SendTime: ' + err.message, 'warn'); } } @@ -3182,8 +3172,9 @@ function GenerateEntitiesPage(page: PageEntities): Payload[] { out_msgs = [{ payload: 'pageType~cardEntities' }] out_msgs.push({ payload: GeneratePageElements(page) }); return out_msgs - } catch (err) { + } catch (err: any) { log('error at function GenerateEntitiesPage: ' + err.message, 'warn'); + return []; } } @@ -3192,8 +3183,9 @@ function GenerateGridPage(page: PageGrid): Payload[] { let out_msgs: Array = [{ payload: 'pageType~cardGrid' }]; out_msgs.push({ payload: GeneratePageElements(page) }); return out_msgs; - } catch (err) { + } catch (err: any) { log('error at function GenerateGridPage: ' + err.message, 'warn'); + return []; } } @@ -3202,8 +3194,9 @@ function GenerateGridPage2(page: PageGrid2): Payload[] { let out_msgs: Array = [{ payload: 'pageType~cardGrid2' }]; out_msgs.push({ payload: GeneratePageElements(page) }); return out_msgs; - } catch (err) { + } catch (err: any) { log('error at function GenerateGridPage2: ' + err.message, 'warn'); + return []; } } @@ -3257,8 +3250,9 @@ function GeneratePageElements(page: Page): string { } if (Debug) log('GeneratePageElements pageData ' + pageData, 'info'); return pageData; - } catch (err) { + } catch (err: any) { log('error at function GeneratePageElements: ' + err.message, 'warn'); + return ''; } } @@ -3290,7 +3284,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let iconColor = rgb_dec565(config.defaultColor); let optVal = '0'; - let val = null; + let val: any = null; let o:any if (pageItem.id != null && existsObject(pageItem.id)) { @@ -3733,7 +3727,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = case 'gate': type = 'text'; - let gateState: string; + let gateState: string | undefined = undefined; if (existsState(pageItem.id + '.ACTUAL')) { if (getState(pageItem.id + '.ACTUAL').val == 0 || getState(pageItem.id + '.ACTUAL').val === false) { @@ -3748,6 +3742,9 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } } + if (gateState == undefined) { + throw new Error(`Missing ${pageItem.id}.ACTUAL for type ${type}`) + } if (Debug) log('CreateEntity Icon role gate ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState, 'info'); return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState; @@ -4035,11 +4032,13 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } if (Debug) log('CreateEntity return ~delete~~~~~', 'info'); return '~delete~~~~~'; - } catch (err) { + } catch (err: any) { if (err.message == "Cannot read properties of undefined (reading 'common')") { log('Found Alias without channel: ' + pageItem.id + '! Please correct the Alias', 'warn'); + return ''; } else { log('error at function CreateEntity: ' + err.message, 'warn'); + return ''; } } } @@ -4062,7 +4061,7 @@ function findLocale(controlsObject: string, controlsState: string): string { return controlsState; } - } catch (err) { + } catch (err: any) { if (err.message.substring(0, 35) == 'Cannot read properties of undefined') { if (Debug) { log('function findLocale: missing translation: ' + controlsObject + ' - ' + controlsState, 'info'); @@ -4096,7 +4095,7 @@ function findLocaleServMenu(controlsState: string): string { } } - } catch (err) { + } catch (err: any) { if (err.message.substring(0, 35) == 'Cannot read properties of undefined') { if (Debug) { log('function findLocale: missing translation: ' + controlsState, 'info'); @@ -4133,8 +4132,9 @@ function GetIconColor(pageItem: PageItem, value: (boolean | number), useColors: } return rgb_dec565(pageItem.offColor !== undefined ? pageItem.offColor : config.defaultOffColor); - } catch (err) { + } catch (err: any) { log('error at function GetIconColor: ' + err.message, 'warn'); + return -1; } } @@ -4152,10 +4152,10 @@ function RegisterEntityWatcher(id: string): void { SendToPanel({ payload: GeneratePageElements(config.button2.page) }); } if (activePage !== undefined) { - SendToPanel({ payload: GeneratePageElements(activePage) }); + SendToPanel({ payload: GeneratePageElements(activePage!) }); } })); - } catch (err) { + } catch (err: any) { log('error at function RegisterEntityWatcher: ' + err.message, 'warn'); } } @@ -4171,7 +4171,7 @@ function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: strin subscriptions[id] = (on({ id: id, change: 'any' }, () => { SendToPanel(GenerateDetailPage(type, undefined, pageItem, placeId)); })) - } catch (err) { + } catch (err: any) { log('error at function RegisterDetailEntityWatcher: ' + err.message, 'warn'); } } @@ -4191,8 +4191,9 @@ function GetUnitOfMeasurement(id: string): string { } return ''; - } catch (err) { + } catch (err: any) { log('error at function GetUnitOfMeasurement: ' + err.message, 'warn'); + return '' } } @@ -4570,8 +4571,9 @@ function GenerateThermoPage(page: PageThermo): Payload[] { log('GenerateThermoPage payload: ' + out_msgs, 'info'); } return out_msgs; - } catch (err) { + } catch (err: any) { log('error at function GenerateThermoPage: ' + err.message, 'warn'); + return []; } } @@ -4610,19 +4612,19 @@ function unsubscribeMediaSubscriptions(): void { } function subscribeMediaSubscriptions(id: string): void { - on({id: [].concat([id + '.STATE']) - .concat([id + '.VOLUME']) - .concat([id + '.ARTIST']) - .concat([id + '.ALBUM']) - .concat([id + '.TITLE']) - .concat([id + '.REPEAT']) - .concat([id + '.SHUFFLE']), change: "any"}, async function () { + on({id: [id + '.STATE', + id + '.VOLUME', + id + '.ARTIST', + id + '.ALBUM', + id + '.TITLE', + id + '.REPEAT', + id + '.SHUFFLE'], change: "any"}, async function () { (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); timeoutMedia = setTimeout(async function () { if (useMediaEvents) { - GeneratePage(activePage); + GeneratePage(activePage!); setTimeout(async function () { - GeneratePage(activePage); + GeneratePage(activePage!); }, 3000); } },50) @@ -4630,15 +4632,15 @@ function subscribeMediaSubscriptions(id: string): void { } function subscribeMediaSubscriptionsSonosAdd(id: string): void { - on({id: [].concat([id + '.QUEUE']) - .concat([id + '.DURATION']) - .concat([id + '.ELAPSED']), change: "any"}, async function () { + on({id: [id + '.QUEUE', + id + '.DURATION', + id + '.ELAPSED'], change: "any"}, async function () { (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); timeoutMedia = setTimeout(async function () { if (useMediaEvents) { - GeneratePage(activePage); + GeneratePage(activePage!); setTimeout(async function () { - GeneratePage(activePage); + GeneratePage(activePage!); }, 50); } },50) @@ -4646,14 +4648,14 @@ function subscribeMediaSubscriptionsSonosAdd(id: string): void { } function subscribeMediaSubscriptionsAlexaAdd(id: string): void { - on({id: [].concat([id + '.DURATION']) - .concat([id + '.ELAPSED']), change: "any"}, async function () { + on({id: [id + '.DURATION', + id + '.ELAPSED'], change: "any"}, async function () { (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); timeoutMedia = setTimeout(async function () { if (useMediaEvents) { - GeneratePage(activePage); + GeneratePage(activePage!); setTimeout(async function () { - GeneratePage(activePage); + GeneratePage(activePage!); }, 50); } },50) @@ -4683,7 +4685,7 @@ async function createAutoMediaAlias(id: string, mediaDevice: string, adapterPlay await createAliasAsync(id + '.VOLUME', dpPath + '.Player.volume', true, { type: 'number', role: 'level.volume', name: 'VOLUME' }); await createAliasAsync(id + '.REPEAT', dpPath + '.Player.controlRepeat', true, { type: 'boolean', role: 'media.mode.repeat', name: 'REPEAT' }); await createAliasAsync(id + '.SHUFFLE', dpPath + '.Player.controlShuffle', true, { type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE' }); - } catch (err) { + } catch (err: any) { log('error at function createAutoMediaAlias Adapter Alexa2: ' + err.message, 'warn'); } } @@ -4717,7 +4719,7 @@ async function createAutoMediaAlias(id: string, mediaDevice: string, adapterPlay await createAliasAsync(id + '.REPEAT', dpPath + 'player.repeat', true, { type: 'string', role: 'value', name: 'REPEAT' }); await createAliasAsync(id + '.SHUFFLE', dpPath + 'player.shuffle', true, { type: 'string', role: 'value', name: 'SHUFFLE' }); - } catch (err) { + } catch (err: any) { log('error at function createAutoMediaAlias Adapter spotify-premium: ' + err.message, 'warn'); } } @@ -4744,7 +4746,7 @@ async function createAutoMediaAlias(id: string, mediaDevice: string, adapterPlay await createAliasAsync(id + '.VOLUME', dpPath + '.volume', true, { type: 'number', role: 'level.volume', name: 'VOLUME' }); await createAliasAsync(id + '.REPEAT', dpPath + '.repeat', true, { type: 'number', role: 'media.mode.repeat', name: 'REPEAT' }); await createAliasAsync(id + '.SHUFFLE', dpPath + '.shuffle', true, { type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE' }); - } catch (err) { + } catch (err: any) { log('error at function createAutoMediaAlias Adapter sonos: ' + err.message, 'warn'); } } @@ -4778,7 +4780,7 @@ async function createAutoMediaAlias(id: string, mediaDevice: string, adapterPlay await createAliasAsync(id + '.REPEAT', dpPath + 'playbackInfo.repeat', true, { type: 'number', role: 'media.mode.repeat', name: 'REPEAT' }); await createAliasAsync(id + '.SHUFFLE', dpPath + 'queue.shuffle', true, { type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE' }); await createAliasAsync(id + '.status', dpPath + 'playbackInfo.status', true, { type: 'string', role: 'media.state', name: 'status' }); - } catch (err) { + } catch (err: any) { log('error function createAutoMediaAlias Adapter volumio: ' + err.message, 'warn'); } } @@ -4804,7 +4806,7 @@ async function createAutoMediaAlias(id: string, mediaDevice: string, adapterPlay await createAliasAsync(id + '.VOLUME_ACTUAL', dpPath + '.Volume', true, { type: 'number', role: 'value.volume', name: 'VOLUME_ACTUAL'}); await createAliasAsync(id + '.SHUFFLE', dpPath + '.PlaylistShuffle', true, { type: 'string', role: 'media.mode.shuffle', name: 'SHUFFLE', alias: { id: dpPath + '.PlaylistShuffle', read: 'val !== 0 ? \'on\' : \'off\'', write: 'val === \'off\' ? 0 : 1' }}); await createAliasAsync(id + '.REPEAT', dpPath + '.PlaylistRepeat', true, {type: 'number', role: 'media.mode.repeat', name: 'REPEAT'}); - } catch (err) { + } catch (err: any) { log('error at function createAutoMediaAlias Adapter Squeezebox: ' + err.message, 'warn'); } } @@ -4820,7 +4822,8 @@ function GenerateMediaPage(page: PageMedia): Payload[] { let id = page.items[0].id; let out_msgs: Array = []; - let vInstance = page.items[0].adapterPlayerInstance; + if (!page.items[0].adapterPlayerInstance!) throw new Error('page.items[0].adapterPlayerInstance is undefined!') + let vInstance = page.items[0].adapterPlayerInstance!; let v1Adapter = vInstance.split('.'); let v2Adapter = v1Adapter[0]; @@ -4843,7 +4846,7 @@ function GenerateMediaPage(page: PageMedia): Payload[] { if (page.items[0].autoCreateALias) { let vMediaDevice = (page.items[0].mediaDevice != undefined) ? page.items[0].mediaDevice : ''; - createAutoMediaAlias(id, vMediaDevice, page.items[0].adapterPlayerInstance); + createAutoMediaAlias(id, vMediaDevice, page.items[0].adapterPlayerInstance!); } // Leave the display on if the alwaysOnDisplay parameter is specified (true) @@ -5345,8 +5348,9 @@ function GenerateMediaPage(page: PageMedia): Payload[] { log('GenerateMediaPage payload: ' + JSON.stringify(out_msgs), 'info'); } return out_msgs - } catch (err) { + } catch (err: any) { log('error at function GenerateMediaPage: ' + err.message, 'warn'); + return []; } } @@ -5373,7 +5377,7 @@ async function createAutoAlarmAlias (id: string, nsPath: string){ } } } - } catch (err) { + } catch (err: any) { log('error at function createAutoAlarmAlias: ' + err.message, 'warn'); } } @@ -5391,10 +5395,16 @@ function GenerateAlarmPage(page: PageAlarm): Payload[] { if (page.items[0].autoCreateALias) { createAutoAlarmAlias(id, nsPath); } - + + type AlarmEntityType = 'triggered' | 'armed' | 'disarmed' | 'pending' | 'arming'; + const AlarmEntityElements: AlarmEntityType[] = ['triggered', 'armed', 'disarmed', 'pending', 'arming'] + if (existsState(nsPath + '.AlarmPin') && existsState(nsPath + '.AlarmState') && existsState(nsPath + '.AlarmType')) { //let entityPin = getState(nsPath + 'AlarmPin').val; - let entityState = getState(nsPath + '.AlarmState').val; + let entityState: AlarmEntityType = getState(nsPath + '.AlarmState').val as AlarmEntityType; + if ( AlarmEntityElements.indexOf(entityState) == -1 ) { + throw new Error(`Invalid value in state ${nsPath}.AlarmPin!`) + } //let entityType = getState(nsPath + 'AlarmType').val; let arm1: string, arm2: string, arm3: string, arm4: string; let arm1ActionName: string, arm2ActionName: string, arm3ActionName: string, arm4ActionName: string; @@ -5420,9 +5430,7 @@ function GenerateAlarmPage(page: PageAlarm): Payload[] { arm3ActionName = ''; //arm3ActionName*~* arm4 = ''; //arm4*~* arm4ActionName = ''; //arm4ActionName*~* - } - - if (entityState == 'disarmed' || entityState == 'arming' || entityState == 'pending') { + } else/* if (entityState == 'disarmed' || entityState == 'arming' || entityState == 'pending')*/ { if (page.items[0].actionStringArray !== undefined && page.items[0].actionStringArray[0] !== '') { arm1 = page.items[0].actionStringArray[0]; } else { @@ -5447,11 +5455,10 @@ function GenerateAlarmPage(page: PageAlarm): Payload[] { arm4 = formatInSelText(findLocale('alarm_control_panel', 'arm_vacation')); //'Besuch'; //arm4*~* } arm4ActionName = 'A4'; //arm4ActionName*~* - } - - if (Debug) { - log('GenerateAlarmPage String for arm1: ' + arm1 + ', arm2: ' + arm2 + ', arm3: ' + arm3 + ', arm4: ' + arm4, 'info'); - } + if (Debug) { + log('GenerateAlarmPage String for arm1: ' + arm1 + ', arm2: ' + arm2 + ', arm3: ' + arm3 + ', arm4: ' + arm4, 'info'); + } + } if (entityState == 'armed') { icon = Icons.GetIcon('shield-home'); //icon*~* @@ -5477,7 +5484,7 @@ function GenerateAlarmPage(page: PageAlarm): Payload[] { numpadStatus = 'enable'; //numpadStatus*~* flashing = 'enable' //flashing* } - + out_msgs.push({ payload: 'entityUpd~' + //entityUpd~* name + '~' + //heading @@ -5502,8 +5509,10 @@ function GenerateAlarmPage(page: PageAlarm): Payload[] { } return out_msgs; } - } catch (err) { + return []; + } catch (err: any) { log('error at function GenerateAlarmPage: ' + err.message, 'warn'); + return []; } } @@ -5524,7 +5533,7 @@ async function createAutoUnlockAlias(id: string, dpPath: string) { } } } - } catch (err) { + } catch (err: any) { log('error at function createAutoUnlockAlias: ' + err.message, 'warn'); } @@ -5582,8 +5591,9 @@ function GenerateUnlockPage(page: PageUnlock): Payload[] { } return out_msgs; - } catch (err) { + } catch (err: any) { log('error at function GenerateUnlockPage: ' + err.message, 'warn'); + return []; } } @@ -5605,7 +5615,7 @@ async function createAutoQRAlias(id:string, dpPath:string) { } } } - } catch (err) { + } catch (err: any) { log('error at function createAutoQRkAlias: ' + err.message, 'warn'); } } @@ -5697,8 +5707,9 @@ function GenerateQRPage(page: PageQR): Payload[] { } return out_msgs; - } catch (err) { + } catch (err: any) { log('error at function GenerateQRPage: ' + err.message, 'warn'); + return []; } } @@ -5722,7 +5733,7 @@ function subscribePowerSubscriptions(id: string): void { on({id: id + '.ACTUAL', change: "ne"}, async function () { (function () { if (timeoutPower) { clearTimeout(timeoutPower); timeoutPower = null; } })(); timeoutPower = setTimeout(async function () { - GeneratePage(activePage); + GeneratePage(activePage!); },25) }); } @@ -5730,7 +5741,7 @@ function subscribePowerSubscriptions(id: string): void { function GeneratePowerPage(page: PagePower): Payload[] { try { - let obj:object; + let obj:object = {}; let demoMode = false; if (page.items[0].id == undefined){ log('No PageItem defined - cardPower demo mode active', 'info'); @@ -5841,8 +5852,9 @@ function GeneratePowerPage(page: PagePower): Payload[] { if (Debug) log('GeneratePowerPage payload: ' + JSON.stringify(out_msgs), 'info'); return out_msgs; - } catch (err) { + } catch (err: any) { log('error at function GeneratePowerPage: ' + err.message, 'warn'); + return []; } } @@ -5857,6 +5869,12 @@ function GenerateChartPage(page: PageChart): Payload[] { let heading = page.heading !== undefined ? page.heading : "Chart..."; let txt = getState(id + '.ACTUAL').val; + if (!page.items[0].yAxisTicks) { + throw new Error (`Page item ${id} yAxisTicks is undefined!`) + } + if (!page.items[0].onColor) { + throw new Error (`Page item ${id} onColor is undefined!`) + } let yAxisTicks = (typeof page.items[0].yAxisTicks == 'object') ? page.items[0].yAxisTicks : JSON.parse(getState(page.items[0].yAxisTicks).val); @@ -5873,8 +5891,9 @@ function GenerateChartPage(page: PageChart): Payload[] { if (Debug) log('GenerateChartPage payload: ' + JSON.stringify(out_msgs), 'info'); return out_msgs; - } catch (err) { + } catch (err: any) { log('error at function GenerateChartPage: ' + err.message, 'warn'); + return []; } } @@ -5892,11 +5911,10 @@ function setIfExists(id: string, value: any, type: string | null = null): boolea return true; } } - - return false; - } catch (err) { + } catch (err: any) { log('error at function setIfExists: ' + err.message, 'warn'); } + return false; } function toggleState(id: string): boolean { @@ -5906,10 +5924,10 @@ function toggleState(id: string): boolean { setIfExists(id, !getState(id).val); return true; } - return false; - } catch (err) { + } catch (err: any) { log('error at function toggleState: ' + err.message, 'warn'); } + return false; } // Begin Monobutton @@ -5921,10 +5939,11 @@ function triggerButton(id: string): boolean{ setTimeout(function() { setState(id, false) }, 250); return true; } - return false; - } catch (err) { + + } catch (err: any) { log('error at function triggerButton: ' + err.message, 'warn'); - } + } + return false; } // End Monobutton @@ -5943,9 +5962,9 @@ function HandleButtonEvent(words: any): void { let pageItemID: string = ''; if (!isNaN(id)) { - pageItemID = activePage.items[id].id; + pageItemID = activePage!.items[id].id; if (Debug) { - log('HandleButtonEvent activePage: ' + activePage.items.length + ' id: ' + id + ' tempid: ' + tempid + ' pageItemId: ' + pageItemID); + log('HandleButtonEvent activePage: ' + activePage!.items.length + ' id: ' + id + ' tempid: ' + tempid + ' pageItemId: ' + pageItemID); } id = pageItemID }; @@ -5989,15 +6008,15 @@ function HandleButtonEvent(words: any): void { pageNum = (((pageId - 1) % config.pages.length) + config.pages.length) % config.pages.length; pageId = pageNum; UnsubscribeWatcher(); - if (activePage != undefined && activePage.parent != undefined) { + if (activePage != undefined && activePage!.parent != undefined) { //update pageID for (let i = 0; i < config.pages.length; i++) { - if (config.pages[i] == activePage.parent) { + if (config.pages[i] == activePage!.parent) { pageId = i; break; } } - GeneratePage(activePage.parent); + GeneratePage(activePage!.parent); } else { GeneratePage(config.pages[pageId]); @@ -6013,21 +6032,22 @@ function HandleButtonEvent(words: any): void { break; case 'bSubNext': UnsubscribeWatcher(); - GeneratePage(eval(activePage.next)); + // check this please + GeneratePage(eval(activePage!.next!)); break; case 'bPrev': pageNum = (((pageId - 1) % config.pages.length) + config.pages.length) % config.pages.length; pageId = pageNum; UnsubscribeWatcher(); - if (activePage != undefined && activePage.parent != undefined) { + if (activePage != undefined && activePage!.parent != undefined) { //update pageID for (let i = 0; i < config.pages.length; i++) { - if (config.pages[i] == activePage.parent) { + if (config.pages[i] == activePage!.parent) { pageId = i; break; } } - GeneratePage(activePage.parent); + GeneratePage(activePage!.parent); } else { GeneratePage(config.pages[pageId]); @@ -6035,7 +6055,8 @@ function HandleButtonEvent(words: any): void { break; case 'bSubPrev': UnsubscribeWatcher(); - GeneratePage(eval(activePage.prev)); + // check this please + GeneratePage(eval(activePage!.prev!)); break; case 'bExit': if (Debug) { @@ -6070,17 +6091,17 @@ function HandleButtonEvent(words: any): void { } activePage = config.pages[pageId]; } - if (words[2] == 'popupInSel' && activePage.type == 'cardMedia') { + if (words[2] == 'popupInSel' && activePage!.type == 'cardMedia') { if (Debug) log('Leave popupInsel without any action', 'info') pageCounter = 0; - GeneratePage(activePage); + GeneratePage(activePage!); setTimeout(async function () { pageCounter = 1; - GeneratePage(activePage); + GeneratePage(activePage!); }, 3000); } else { pageCounter = 0; - GeneratePage(activePage); + GeneratePage(activePage!); } break; case 'bHome': @@ -6088,8 +6109,8 @@ function HandleButtonEvent(words: any): void { log('HandleButtonEvent -> bHome: ' + words[4] + ' - ' + pageId, 'info'); } UnsubscribeWatcher(); - if (activePage.home != undefined) { - GeneratePage(eval(activePage.home)); + if (activePage!.home != undefined) { + GeneratePage(eval(activePage!.home)); } else { GeneratePage(config.pages[0]); } @@ -6140,7 +6161,7 @@ function HandleButtonEvent(words: any): void { break; case 'switch.mode.wlan': setIfExists(id + '.SWITCH', action); - GeneratePage(activePage); + GeneratePage(activePage!); break; } } @@ -6185,10 +6206,10 @@ function HandleButtonEvent(words: any): void { case 'media': if (tempid[1] == undefined) { if (Debug) log('Logo click', 'info'); - GeneratePage(activePage); + GeneratePage(activePage!); } else if (tempid[1] == 'repeat') { let pageItemRepeat = findPageItem(id); - let adapterInstanceRepeat = pageItemRepeat.adapterPlayerInstance; + let adapterInstanceRepeat = pageItemRepeat.adapterPlayerInstance!; let adapterRepeat = adapterInstanceRepeat.split('.'); let deviceAdapterRP = adapterRepeat[0]; @@ -6202,7 +6223,7 @@ function HandleButtonEvent(words: any): void { } else if (stateSpotifyRepeat == 'one') { setIfExists(id + '.REPEAT', 'none'); } - GeneratePage(activePage); + GeneratePage(activePage!); break; case 'sonos': let stateSonosRepeat = getState(id + '.REPEAT').val @@ -6213,15 +6234,15 @@ function HandleButtonEvent(words: any): void { } else if (stateSonosRepeat == 2) { setIfExists(id + '.REPEAT', 0); } - GeneratePage(activePage); + GeneratePage(activePage!); break; case 'alexa2': try { setIfExists(id + '.REPEAT', !getState(id + '.REPEAT').val); - } catch (err) { + } catch (err: any) { log('ALEXA2: Repeat kann nicht verändert werden', 'warn'); } - GeneratePage(activePage); + GeneratePage(activePage!); break; case 'volumio': let urlString: string = `${getState(adapterInstanceRepeat+'info.host').val}/api/commands/?cmd=repeat`; @@ -6231,7 +6252,7 @@ function HandleButtonEvent(words: any): void { if (Debug) { log(response.data, 'info'); } - GeneratePage(activePage); + GeneratePage(activePage!); } else { log('Axios Status - adapterInstanceRepeat: ' + response.state, 'warn'); } @@ -6245,18 +6266,18 @@ function HandleButtonEvent(words: any): void { switch(getState(id + '.REPEAT').val) { case 0: setIfExists(id + '.REPEAT', 1); - GeneratePage(activePage); + GeneratePage(activePage!); break; case 1: setIfExists(id + '.REPEAT', 2) - GeneratePage(activePage); + GeneratePage(activePage!); break; case 2: setIfExists(id + '.REPEAT', 0); - GeneratePage(activePage); + GeneratePage(activePage!); break; } - } catch (err) { + } catch (err: any) { log('Squeezebox: Repeat kann nicht verändert werden', 'warn'); } break; @@ -6404,11 +6425,11 @@ function HandleButtonEvent(words: any): void { break; case 'media-back': setIfExists(id + '.PREV', true); - GeneratePage(activePage); + GeneratePage(activePage!); break; case 'media-pause': let pageItemTemp = findPageItem(id); - let adaInstanceSplit = pageItemTemp.adapterPlayerInstance.split('.'); + let adaInstanceSplit = pageItemTemp.adapterPlayerInstance!.split('.'); if (adaInstanceSplit[0] == 'squeezeboxrpc') { let adapterPlayerInstanceStateSeceltor: string = [pageItemTemp.adapterPlayerInstance, 'Players', pageItemTemp.mediaDevice, 'state'].join('.'); if (Debug) log('HandleButtonEvent media-pause Squeezebox-> adapterPlayerInstanceStateSeceltor: ' + adapterPlayerInstanceStateSeceltor, 'info'); @@ -6428,38 +6449,38 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.PLAY', true); } } - GeneratePage(activePage); + GeneratePage(activePage!); break; case 'media-next': setIfExists(id + '.NEXT', true); - GeneratePage(activePage); + GeneratePage(activePage!); break; case 'media-shuffle': - if ((findPageItem(id).adapterPlayerInstance).startsWith("volumio")) { + if ((findPageItem(id).adapterPlayerInstance!).startsWith("volumio")) { findPageItem(id).playList = []; break; } //Volumio: empty playlist $uha-20230103 - if ((findPageItem(id).adapterPlayerInstance).startsWith("spotify")) { + if ((findPageItem(id).adapterPlayerInstance!).startsWith("spotify")) { if (getState(id + '.SHUFFLE').val == 'off') { setIfExists(id + '.SHUFFLE', 'on'); } else { setIfExists(id + '.SHUFFLE', 'off'); } } - if ((findPageItem(id).adapterPlayerInstance).startsWith("alexa")) { + if ((findPageItem(id).adapterPlayerInstance!).startsWith("alexa")) { if (getState(id + '.SHUFFLE').val == false) { setIfExists(id + '.SHUFFLE', true); } else { setIfExists(id + '.SHUFFLE', false); } } - if ((findPageItem(id).adapterPlayerInstance).startsWith("sonos")) { + if ((findPageItem(id).adapterPlayerInstance!).startsWith("sonos")) { if (getState(id + '.SHUFFLE').val == false) { setIfExists(id + '.SHUFFLE', true); } else { setIfExists(id + '.SHUFFLE', false); } } - GeneratePage(activePage); + GeneratePage(activePage!); break; case 'volumeSlider': pageCounter = -1; @@ -6468,19 +6489,19 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.VOLUME', parseInt(words[4])); setTimeout(async function () { pageCounter = 1; - GeneratePage(activePage); + GeneratePage(activePage!); }, 3000); }, 20); break; case 'mode-speakerlist': let pageItem = findPageItem(id); - let adapterInstance = pageItem.adapterPlayerInstance; - let adapter = adapterInstance.split('.'); + let adapterInstance = pageItem.adapterPlayerInstance!; + let adapter = adapterInstance!.split('.'); let deviceAdapter = adapter[0]; switch (deviceAdapter) { case 'spotify-premium': - let strDevicePI = pageItem.speakerList[words[4]]; + let strDevicePI = pageItem.speakerList![words[4]]; let strDeviceID = spotifyGetDeviceID(strDevicePI); setState(adapterInstance + 'devices.' + strDeviceID + ".useForPlayback", true); break; @@ -6488,11 +6509,11 @@ function HandleButtonEvent(words: any): void { let i_list = Array.prototype.slice.apply($('[state.id="' + adapterInstance + 'Echo-Devices.*.Info.name"]')); for (let i_index in i_list) { let i = i_list[i_index]; - if ((getState(i).val) === pageItem.speakerList[words[4]]) { - if (Debug) log('HandleButtonEvent mode-Speakerlist Alexa2: ' + getState(i).val + ' - ' + pageItem.speakerList[words[4]], 'info'); + if ((getState(i).val) === pageItem.speakerList![words[4]]) { + if (Debug) log('HandleButtonEvent mode-Speakerlist Alexa2: ' + getState(i).val + ' - ' + pageItem.speakerList![words[4]], 'info'); let deviceId = i; deviceId = deviceId.split('.'); - setIfExists(adapterInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Commands.textCommand', 'Schiebe meine Musik auf ' + pageItem.speakerList[words[4]]); + setIfExists(adapterInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Commands.textCommand', 'Schiebe meine Musik auf ' + pageItem.speakerList![words[4]]); pageItem.mediaDevice = deviceId[3]; } } @@ -6502,25 +6523,25 @@ function HandleButtonEvent(words: any): void { case 'chromecast': break; case 'squeezeboxrpc': - pageItem.mediaDevice = pageItem.speakerList[words[4]]; + pageItem.mediaDevice = pageItem.speakerList![words[4]]; break; } pageCounter = 0; - GeneratePage(activePage); + GeneratePage(activePage!); setTimeout(async function () { pageCounter = 1; - GeneratePage(activePage); + GeneratePage(activePage!); }, 3000); break; case 'mode-playlist': let pageItemPL = findPageItem(id); - let adapterInstancePL = pageItemPL.adapterPlayerInstance; + let adapterInstancePL = pageItemPL.adapterPlayerInstance!; let adapterPL = adapterInstancePL.split('.'); let deviceAdapterPL = adapterPL[0]; switch (deviceAdapterPL) { case 'spotify-premium': - let strDevicePI = pageItemPL.playList[words[4]]; + let strDevicePI = pageItemPL.playList![words[4]]; if (Debug) log('HandleButtonEvent mode-playlist Spotify -> strDevicePI: ' + strDevicePI, 'info'); let playlistListString = (getState(adapterInstancePL + 'playlists.playlistListString').val).split(';'); let playlistListIds = (getState(adapterInstancePL + 'playlists.playlistListIds').val).split(';'); @@ -6531,16 +6552,16 @@ function HandleButtonEvent(words: any): void { }, 2000); break; case 'alexa2': - let tempListItem = pageItemPL.playList[words[4]].split('.'); + let tempListItem = pageItemPL.playList![words[4]].split('.'); setState(adapterInstancePL + 'Echo-Devices.' + pageItemPL.mediaDevice + '.Music-Provider.' + tempListItem[0], tempListItem[1]); break; case 'sonos': - let strDevicePLSonos = pageItemPL.playList[words[4]].split('.'); + let strDevicePLSonos = pageItemPL.playList![words[4]].split('.'); if (Debug) log(adapterInstancePL + 'root.' + pageItemPL.mediaDevice + '.playlist_set', 'info') setState(adapterInstancePL + 'root.' + pageItemPL.mediaDevice + '.playlist_set', strDevicePLSonos[0]); break; case 'volumio': - let strDevicePL = pageItemPL.playList[words[4]]; + let strDevicePL = pageItemPL.playList![words[4]]; let urlString: string = `${getState(adapterInstancePL+'info.host').val}/api/commands/?cmd=playplaylist&name=${strDevicePL}`; axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) .then(async function (response) { @@ -6561,15 +6582,15 @@ function HandleButtonEvent(words: any): void { break; } pageCounter = 0; - GeneratePage(activePage); + GeneratePage(activePage!); setTimeout(async function () { pageCounter = 1; - GeneratePage(activePage); + GeneratePage(activePage!); }, 3000); break; case 'mode-tracklist': let pageItemTL = findPageItem(id); - let adapterInstanceTL = pageItemTL.adapterPlayerInstance; + let adapterInstanceTL = pageItemTL.adapterPlayerInstance!; let adapterTL = adapterInstanceTL.split('.'); let deviceAdapterTL = adapterTL[0]; @@ -6600,30 +6621,31 @@ function HandleButtonEvent(words: any): void { }); break; case 'squeezeboxrpc': + //@@ts-ignore Fehler kommt von findPageItem in vscode setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'PlaylistCurrentIndex'].join('.'), words[4]); break; } pageCounter = 0; - GeneratePage(activePage); + GeneratePage(activePage!); setTimeout(async function () { pageCounter = 1; - GeneratePage(activePage); + GeneratePage(activePage!); }, 3000); break; case 'mode-repeat': let pageItemRP = findPageItem(id); - let adapterInstanceRP = pageItemRP.adapterPlayerInstance; + let adapterInstanceRP = pageItemRP.adapterPlayerInstance!; let adapterRP = adapterInstanceRP.split('.'); let deviceAdapterRP = adapterRP[0]; - if (Debug) log(pageItemRP.repeatList[words[4]], 'warn'); + if (Debug) log(pageItemRP.repeatList![words[4]], 'warn'); switch (deviceAdapterRP) { case 'spotify-premium': - setIfExists(id + '.REPEAT', pageItemRP.repeatList[words[4]]); - GeneratePage(activePage); + setIfExists(id + '.REPEAT', pageItemRP.repeatList![words[4]]); + GeneratePage(activePage!); break; case 'alexa2': - GeneratePage(activePage); + GeneratePage(activePage!); break; } break; @@ -6631,17 +6653,17 @@ function HandleButtonEvent(words: any): void { let pageItemEQ = findPageItem(id); if (Debug) log('HandleButtonEvent mode-equalizer -> id: ' + id, 'info'); let lastIndex = (id.split('.')).pop(); - setState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode', pageItemEQ.equalizerList[words[4]]); + setState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode', pageItemEQ.equalizerList![words[4]]); pageCounter = 0; - GeneratePage(activePage); + GeneratePage(activePage!); setTimeout(async function () { pageCounter = 1; - GeneratePage(activePage); + GeneratePage(activePage!); }, 3000); break; case 'mode-seek': let pageItemSeek = findPageItem(id); - let adapterInstanceSK = pageItemSeek.adapterPlayerInstance; + let adapterInstanceSK = pageItemSeek.adapterPlayerInstance!; let adapterSK = adapterInstanceSK.split('.'); let deviceAdapterSK = adapterSK[0]; switch (deviceAdapterSK) { @@ -6653,15 +6675,15 @@ function HandleButtonEvent(words: any): void { break; } pageCounter = 0; - GeneratePage(activePage); + GeneratePage(activePage!); setTimeout(async function () { pageCounter = 1; - GeneratePage(activePage); + GeneratePage(activePage!); }, 3000); break; case 'mode-crossfade': let pageItemCrossfade = findPageItem(id); - let adapterInstanceCF = pageItemCrossfade.adapterPlayerInstance; + let adapterInstanceCF = pageItemCrossfade.adapterPlayerInstance!; let adapterCF = adapterInstanceCF.split('.'); let deviceAdapterCF = adapterCF[0]; switch (deviceAdapterCF) { @@ -6677,10 +6699,10 @@ function HandleButtonEvent(words: any): void { break; } pageCounter = 0; - GeneratePage(activePage); + GeneratePage(activePage!); setTimeout(async function () { pageCounter = 1; - GeneratePage(activePage); + GeneratePage(activePage!); }, 3000); break; case 'mode-favorites': @@ -6689,10 +6711,10 @@ function HandleButtonEvent(words: any): void { let favListArray = getState(pageItemFav.adapterPlayerInstance + 'root.' + pageItemFav.mediaDevice + '.favorites_list_array').val; setState(pageItemFav.adapterPlayerInstance + 'root.' + pageItemFav.mediaDevice + '.favorites_set', favListArray[words[4]]); pageCounter = 0; - GeneratePage(activePage); + GeneratePage(activePage!); setTimeout(async function () { pageCounter = 1; - GeneratePage(activePage); + GeneratePage(activePage!); }, 3000); break; case 'mode-insel': @@ -6700,7 +6722,7 @@ function HandleButtonEvent(words: any): void { break; case 'media-OnOff': let pageItemTem = findPageItem(id); - let adaInstanceSpli = pageItemTem.adapterPlayerInstance.split('.'); + let adaInstanceSpli = pageItemTem.adapterPlayerInstance!.split('.'); if (adaInstanceSpli[0] == 'squeezeboxrpc') { let adapterPlayerInstancePowerSelector: string = [pageItemTem.adapterPlayerInstance, 'Players', pageItemTem.mediaDevice, 'Power'].join('.'); let stateVal = getState(adapterPlayerInstancePowerSelector).val; @@ -6716,7 +6738,7 @@ function HandleButtonEvent(words: any): void { } else { setIfExists(id + '.STOP', true); } - GeneratePage(activePage); + GeneratePage(activePage!); break; case 'timer-start': if (words[4] != undefined) { @@ -6763,7 +6785,7 @@ function HandleButtonEvent(words: any): void { setIfExists(words[2] + '.' + modesDP[mode], false); } } - GeneratePage(activePage); + GeneratePage(activePage!); } else { let HVACMode = getState(words[2] + '.MODE').val; @@ -6793,20 +6815,20 @@ function HandleButtonEvent(words: any): void { } setIfExists(words[2] + '.' + 'MODE', HVACMode); - GeneratePage(activePage); + GeneratePage(activePage!); } break; case 'mode-modus1': let pageItemT1 = findPageItem(id); - setIfExists(id + '.' + pageItemT1.setThermoAlias[0], pageItemT1.popupThermoMode1[parseInt(words[4])]); + setIfExists(id + '.' + pageItemT1.setThermoAlias![0], pageItemT1.popupThermoMode1![parseInt(words[4])]); break; case 'mode-modus2': let pageItemT2 = findPageItem(id); - setIfExists(id + '.' + pageItemT2.setThermoAlias[1], pageItemT2.popupThermoMode2[parseInt(words[4])]); + setIfExists(id + '.' + pageItemT2.setThermoAlias![1], pageItemT2.popupThermoMode2![parseInt(words[4])]); break; case 'mode-modus3': let pageItemT3 = findPageItem(id); - setIfExists(id + '.' + pageItemT3.setThermoAlias[2], pageItemT3.popupThermoMode3[parseInt(words[4])]); + setIfExists(id + '.' + pageItemT3.setThermoAlias![2], pageItemT3.popupThermoMode3![parseInt(words[4])]); break; case 'number-set': let nobj = getObject(id); @@ -6836,7 +6858,7 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.PANEL', NSPanel_Path); } setTimeout(function(){ - GeneratePage(activePage); + GeneratePage(activePage!); },250); break; case 'A2': // Alarm page - activate alarm 2 @@ -6847,7 +6869,7 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.PANEL', NSPanel_Path); } setTimeout(function(){ - GeneratePage(activePage); + GeneratePage(activePage!); },250); break; case 'A3': // Alarm page - activate alarm 3 @@ -6858,7 +6880,7 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.PANEL', NSPanel_Path); } setTimeout(function(){ - GeneratePage(activePage); + GeneratePage(activePage!); },250); break; case 'A4': // Alarm page - activate alarm 4 @@ -6869,7 +6891,7 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.PANEL', NSPanel_Path); } setTimeout(function(){ - GeneratePage(activePage); + GeneratePage(activePage!); },250); break; case 'D1': // Alarm page - deactivate alarm 4 @@ -6891,7 +6913,7 @@ function HandleButtonEvent(words: any): void { } setIfExists(id + '.PANEL', NSPanel_Path); setTimeout(function(){ - GeneratePage(activePage); + GeneratePage(activePage!); },500); } break; @@ -6899,7 +6921,7 @@ function HandleButtonEvent(words: any): void { let pageItemUnlock = findPageItem(id); if (words[4] == getState(id + '.PIN').val) { UnsubscribeWatcher(); - GeneratePage(eval(pageItemUnlock.targetPage)); + GeneratePage(eval(pageItemUnlock.targetPage!)); setIfExists(id + '.ACTUAL', true) } else { setIfExists(id + '.ACTUAL', false) @@ -6908,7 +6930,7 @@ function HandleButtonEvent(words: any): void { default: break; } - } catch (err) { + } catch (err: any) { log('error at function HandleButtonEvent: ' + err.message, 'warn'); } } @@ -6923,13 +6945,13 @@ function GetNavigationString(pageId: number): string { var navigationString:string = ""; - if (activePage.subPage){ + if (activePage!.subPage){ //Left icon - if (activePage.prev == undefined){ - if (activePage.parentIcon != undefined){ - navigationString = 'button~bUp~' + Icons.GetIcon(activePage.parentIcon); - if (activePage.parentIconColor != undefined){ - navigationString += '~' + rgb_dec565(activePage.parentIconColor); + if (activePage!.prev == undefined){ + if (activePage!.parentIcon != undefined){ + navigationString = 'button~bUp~' + Icons.GetIcon(activePage!.parentIcon); + if (activePage!.parentIconColor != undefined){ + navigationString += '~' + rgb_dec565(activePage!.parentIconColor); } else { navigationString += '~' + rgb_dec565(White); } @@ -6937,10 +6959,10 @@ function GetNavigationString(pageId: number): string { navigationString = 'button~bUp~' + Icons.GetIcon('arrow-up-bold') + '~' + rgb_dec565(White); } } else { - if (activePage.prevIcon != undefined){ - navigationString = 'button~bSubPrev~' + Icons.GetIcon(activePage.prevIcon); - if (activePage.prevIconColor != undefined){ - navigationString += '~' + rgb_dec565(activePage.prevIconColor); + if (activePage!.prevIcon != undefined){ + navigationString = 'button~bSubPrev~' + Icons.GetIcon(activePage!.prevIcon); + if (activePage!.prevIconColor != undefined){ + navigationString += '~' + rgb_dec565(activePage!.prevIconColor); } else { navigationString += '~' + rgb_dec565(White); } @@ -6950,11 +6972,11 @@ function GetNavigationString(pageId: number): string { } //Right icon - if (activePage.next == undefined){ - if (activePage.homeIcon != undefined){ - navigationString += '~~~button~bHome~' + Icons.GetIcon(activePage.homeIcon); - if (activePage.homeIconColor != undefined){ - navigationString += '~' + rgb_dec565(activePage.homeIconColor) + '~~';; + if (activePage!.next == undefined){ + if (activePage!.homeIcon != undefined){ + navigationString += '~~~button~bHome~' + Icons.GetIcon(activePage!.homeIcon); + if (activePage!.homeIconColor != undefined){ + navigationString += '~' + rgb_dec565(activePage!.homeIconColor) + '~~';; } else { navigationString += '~' + rgb_dec565(White) + '~~'; } @@ -6962,10 +6984,10 @@ function GetNavigationString(pageId: number): string { navigationString += '~~~button~bHome~' + Icons.GetIcon('home') + '~' + rgb_dec565(White) + '~~'; } } else { - if (activePage.nextIcon != undefined){ - navigationString += '~~~button~bSubNext~' + Icons.GetIcon(activePage.nextIcon); - if (activePage.nextIconColor != undefined){ - navigationString += '~' + rgb_dec565(activePage.nextIconColor) + '~~'; + if (activePage!.nextIcon != undefined){ + navigationString += '~~~button~bSubNext~' + Icons.GetIcon(activePage!.nextIcon); + if (activePage!.nextIconColor != undefined){ + navigationString += '~' + rgb_dec565(activePage!.nextIconColor) + '~~'; } else { navigationString += '~' + rgb_dec565(White) + '~~'; } @@ -6975,7 +6997,7 @@ function GetNavigationString(pageId: number): string { } } - if (activePage.subPage && (navigationString != "")){ + if (activePage!.subPage && (navigationString != "")){ return navigationString } @@ -6986,25 +7008,25 @@ function GetNavigationString(pageId: number): string { return 'button~bUp~' + Icons.GetIcon('arrow-up-bold') + '~' + rgb_dec565(White) + '~~~delete~~~~~'; default: { - if (activePage.prevIcon != undefined){ - navigationString = 'button~bPrev~' + Icons.GetIcon(activePage.prevIcon); + if (activePage!.prevIcon != undefined){ + navigationString = 'button~bPrev~' + Icons.GetIcon(activePage!.prevIcon); } else { navigationString = 'button~bPrev~' + Icons.GetIcon('arrow-left-bold'); } - if (activePage.prevIconColor != undefined){ - navigationString += '~' + rgb_dec565(activePage.prevIconColor); + if (activePage!.prevIconColor != undefined){ + navigationString += '~' + rgb_dec565(activePage!.prevIconColor); } else { navigationString += '~' + rgb_dec565(White); } - if (activePage.nextIcon != undefined){ - navigationString += '~~~button~bNext~' + Icons.GetIcon(activePage.nextIcon); + if (activePage!.nextIcon != undefined){ + navigationString += '~~~button~bNext~' + Icons.GetIcon(activePage!.nextIcon); } else { navigationString += '~~~button~bNext~' + Icons.GetIcon('arrow-right-bold'); } - if (activePage.nextIconColor != undefined){ - navigationString += '~' + rgb_dec565(activePage.nextIconColor) + '~~'; + if (activePage!.nextIconColor != undefined){ + navigationString += '~' + rgb_dec565(activePage!.nextIconColor) + '~~'; } else { navigationString += '~' + rgb_dec565(White) + '~~'; } @@ -7012,12 +7034,13 @@ function GetNavigationString(pageId: number): string { } } - } catch (err) { + } catch (err: any) { log('error at function GetNavigationString: ' + err.message, 'warn'); } + return ''; } -function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, placeId: number): Payload[] { +function GenerateDetailPage(type: string, optional: string | undefined, pageItem: PageItem, placeId: number): Payload[] { if (Debug) log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); try { let out_msgs: Array = []; @@ -7249,7 +7272,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, colorTemp = 0; if (getState(id + '.TEMPERATURE').val != null) { if (pageItem.minValueColorTemp !== undefined && pageItem.minValueColorTemp !== undefined) { - colorTemp = Math.trunc(scale(getState(id + '.TEMPERATURE').val, pageItem.minValueColorTemp, pageItem.maxValueColorTemp, 100, 0)); + colorTemp = Math.trunc(scale(getState(id + '.TEMPERATURE').val, pageItem.minValueColorTemp, pageItem.maxValueColorTemp!, 100, 0)); } else { colorTemp = getState(id + '.TEMPERATURE').val; } @@ -7529,28 +7552,28 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, let payloadParameters1 = '~~~~' if (pageItem.popupThermoMode1 != undefined) { - RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias[0], pageItem, type, placeId); - payloadParameters1 = pageItem.popUpThermoName[0] + '~' //{heading}~ Mode 1 + RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias![0], pageItem, type, placeId); + payloadParameters1 = pageItem.popUpThermoName![0] + '~' //{heading}~ Mode 1 + 'modus1' + '~' //{id}~ Mode 1 - + getState(pageItem.id + "." + pageItem.setThermoAlias[0]).val + '~' //{ACTUAL}~ Mode 1 + + getState(pageItem.id + "." + pageItem.setThermoAlias![0]).val + '~' //{ACTUAL}~ Mode 1 + mode1 + '~'; //{possible values} Mode 1 (1-n) } let payloadParameters2 = '~~~~' if (pageItem.popupThermoMode2 != undefined) { - RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias[1], pageItem, type, placeId); - payloadParameters2 = pageItem.popUpThermoName[1] + '~' //{heading}~ Mode 2 + RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias![1], pageItem, type, placeId); + payloadParameters2 = pageItem.popUpThermoName![1] + '~' //{heading}~ Mode 2 + 'modus2' + '~' //{id}~ Mode 2 - + getState(pageItem.id + "." + pageItem.setThermoAlias[1]).val + '~' //{ACTUAL}~ Mode 2 + + getState(pageItem.id + "." + pageItem.setThermoAlias![1]).val + '~' //{ACTUAL}~ Mode 2 + mode2 + '~'; //{possible values} } let payloadParameters3 = '~~~~' if (pageItem.popupThermoMode3 != undefined) { - RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias[2], pageItem, type, placeId); - payloadParameters3 = pageItem.popUpThermoName[2] + '~' //{heading}~ Mode 3 + RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias![2], pageItem, type, placeId); + payloadParameters3 = pageItem.popUpThermoName![2] + '~' //{heading}~ Mode 3 + 'modus3' + '~' //{id}~ Mode 3 - + getState(pageItem.id + "." + pageItem.setThermoAlias[2]).val + '~' //{ACTUAL}~ Mode 3 + + getState(pageItem.id + "." + pageItem.setThermoAlias![2]).val + '~' //{ACTUAL}~ Mode 3 + mode3; //{possible values} Mode 3 (1-n) } @@ -7677,8 +7700,8 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, let actualSpeed = getState(id + '.SPEED').val; let maxSpeed = (pageItem.maxValue != undefined) ? pageItem.maxValue : 100; - let modeList = pageItem.modeList.join('?'); - let actualMode = pageItem.modeList[getState(id + '.MODE').val]; + let modeList = pageItem.modeList!.join('?'); + let actualMode = pageItem.modeList![getState(id + '.MODE').val]; let tempId = placeId != undefined ? placeId : id; @@ -7703,7 +7726,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, let optionalString: string = 'Kein Eintrag'; let mode: string = ''; - let vTempAdapter = (pageItem.adapterPlayerInstance).split('.'); + let vTempAdapter = (pageItem.adapterPlayerInstance!).split('.'); let vAdapter = vTempAdapter[0]; if (optional == 'seek') { let actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; @@ -7760,9 +7783,9 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, } else if (vAdapter == 'squeezeboxrpc') { actualState = pageItem.mediaDevice; } - let tempSpeakerList = []; - for (let i = 0; i < pageItem.speakerList.length; i++) { - tempSpeakerList[i] = formatInSelText(pageItem.speakerList[i]).trim(); + let tempSpeakerList: string[] = []; + for (let i = 0; i < pageItem.speakerList!.length; i++) { + tempSpeakerList[i] = formatInSelText(pageItem.speakerList![i]).trim(); } optionalString = pageItem.speakerList != undefined ? tempSpeakerList.join('?') : ''; mode = 'speakerlist'; @@ -7771,9 +7794,9 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, if (existsObject(pageItem.adapterPlayerInstance + 'player.playlist.name')) { actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'player.playlist.name').val); } - let tempPlayList = []; - for (let i = 0; i < pageItem.playList.length; i++) { - tempPlayList[i] = formatInSelText(pageItem.playList[i]); + let tempPlayList: string[] = []; + for (let i = 0; i < pageItem.playList!.length; i++) { + tempPlayList[i] = formatInSelText(pageItem.playList![i]); } optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' } else if (vAdapter == 'alexa2') { @@ -7781,13 +7804,13 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Player.currentAlbum').val); let tPlayList: any = [] - for (let i = 0; i < pageItem.playList.length; i++) { - if (Debug) log('function GenerateDetailPage role:media -> Playlist ' + pageItem.playList[i], 'info'); - let tempItem = pageItem.playList[i].split('.'); + for (let i = 0; i < pageItem.playList!.length; i++) { + if (Debug) log('function GenerateDetailPage role:media -> Playlist ' + pageItem.playList![i], 'info'); + let tempItem = pageItem.playList![i].split('.'); tPlayList[i] = tempItem[1]; } - let tempPlayList = []; + let tempPlayList: string[] = []; for (let i = 0; i < tPlayList.length; i++) { tempPlayList[i] = formatInSelText(tPlayList[i]); } @@ -7797,30 +7820,30 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, if (existsObject(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set')) { actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set').val); } - let tempPlayList = []; - for (let i = 0; i < pageItem.playList.length; i++) { - tempPlayList[i] = formatInSelText(pageItem.playList[i]); + let tempPlayList: string[] = []; + for (let i = 0; i < pageItem.playList!.length; i++) { + tempPlayList[i] = formatInSelText(pageItem.playList![i]); } optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' } else if (vAdapter == 'volumio') { /* Volumio: limit 900 chars */ actualState = ''; //todo: no actual playlistname saving - let tempPlayList = []; let tempPll = 0; - for (let i = 0; i < pageItem.playList.length; i++) { - tempPll += pageItem.playList[i].length; if (tempPll > 900) break; - tempPlayList[i] = formatInSelText(pageItem.playList[i]); + let tempPlayList: string[] = []; let tempPll = 0; + for (let i = 0; i < pageItem.playList!.length; i++) { + tempPll += pageItem.playList![i].length; if (tempPll > 900) break; + tempPlayList[i] = formatInSelText(pageItem.playList![i]); } optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' } else if(vAdapter == 'squeezeboxrpc') { // Playlist browsing not supported by squeezeboxrpc adapter. But Favorites can be used actualState = ''; // Not supported by squeezeboxrpc adapter - let tempPlayList = []; - let pathParts: Array = pageItem.adapterPlayerInstance.split('.'); + let tempPlayList: string[] = []; + let pathParts: Array = pageItem.adapterPlayerInstance!.split('.'); for (let favorite_index=0; favorite_index < 45; favorite_index++) { let favorite_name_selector: string = [pathParts[0], pathParts[1], 'Favorites', favorite_index, 'Name'].join('.'); if(!existsObject(favorite_name_selector)) { break; } - let favoritename = getState(favorite_name_selector).val; + let favoritename: string = getState(favorite_name_selector).val; tempPlayList.push(formatInSelText(favoritename)); } optionalString = tempPlayList.length > 0 ? tempPlayList.join('?') : ''; @@ -7845,7 +7868,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, if (Debug) log(actualState, 'info'); if (Debug) log(globalTracklist, 'info'); //Limit 900 characters, then memory overflow --> Shorten as much as possible - let temp_array = []; + let temp_array: any[] = []; //let trackArray = (function () { try {return JSON.parse(getState(pageItem.adapterPlayerInstance + 'player.playlist.trackListArray').val);} catch(e) {return {};}})(); for (let track_index=0; track_index < 45; track_index++) { let temp_cut_array = getAttr(globalTracklist, track_index + '.title'); @@ -7868,7 +7891,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, break; } } - let tempTrackList = []; + let tempTrackList: string[] = []; for (let i = 0; i < temp_array.length; i++) { tempTrackList[i] = formatInSelText(temp_array[i]); } @@ -7889,22 +7912,22 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, actualState = formatInSelText(getState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode').val); } - let tempEQList = []; - for (let i = 0; i < pageItem.equalizerList.length; i++) { - tempEQList[i] = formatInSelText(pageItem.equalizerList[i]); + let tempEQList: string[] = []; + for (let i = 0; i < pageItem.equalizerList!.length; i++) { + tempEQList[i] = formatInSelText(pageItem!.equalizerList![i]); } optionalString = pageItem.equalizerList != undefined ? tempEQList.join('?') : ''; mode = 'equalizer'; } else if (optional == 'repeat') { actualState = getState(pageItem.adapterPlayerInstance + 'player.repeat').val; - optionalString = pageItem.repeatList.join('?'); + optionalString = pageItem.repeatList!.join('?'); mode = 'repeat'; } else if (optional == 'favorites') { if (Debug) log(getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.favorites_set').val, 'info') actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.favorites_set').val); - let tempFavList = []; + let tempFavList:string [] = []; let favList = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.favorites_list_array').val; for (let i = 0; i < favList.length; i++) { tempFavList[i] = formatInSelText(favList[i]); @@ -7923,21 +7946,21 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, + actualState + '~' + optionalString }); - GeneratePage(activePage); + GeneratePage(activePage!); } else if (o.common.role == 'buttonSensor') { let actualValue: string = ''; if (pageItem.inSel_ChoiceState || pageItem.inSel_ChoiceState == undefined) { if (existsObject(pageItem.id + '.VALUE')) { - actualValue = formatInSelText(pageItem.modeList[getState(pageItem.id + '.VALUE').val]); + actualValue = formatInSelText(pageItem.modeList![getState(pageItem.id + '.VALUE').val]); RegisterDetailEntityWatcher(id + '.VALUE', pageItem, type, placeId); } } - let tempModeList = []; - for (let i = 0; i < pageItem.modeList.length; i++) { - tempModeList[i] = formatInSelText(pageItem.modeList[i]); + let tempModeList: string[] = []; + for (let i = 0; i < pageItem.modeList!.length; i++) { + tempModeList[i] = formatInSelText(pageItem.modeList![i]); } let valueList = pageItem.modeList != undefined ? tempModeList.join('?') : ''; @@ -7970,7 +7993,7 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, } } - let tempModeList = []; + let tempModeList: string[] = []; for (let i = 0; i < pageItem.modeList.length; i++) { tempModeList[i] = formatInSelText(pageItem.modeList[i]); } @@ -7994,17 +8017,19 @@ function GenerateDetailPage(type: string, optional: string, pageItem: PageItem, if (Debug) log('GenerateDetailPage -> payload: ' + JSON.stringify(out_msgs), 'info'); return out_msgs; - } catch (err) { + } catch (err: any) { log('error at function GenerateDetailPage: ' + err.message, 'warn'); } + return []; } function scale(number: number, inMin: number, inMax: number, outMin: number, outMax: number): number { try { return (outMax + outMin) - ((number - inMin) * (outMax - outMin) / (inMax - inMin) + outMin); - } catch (err) { + } catch (err: any) { log('error at function scale: ' + err.message, 'warn'); } + return 0 } function UnsubscribeWatcher(): void { @@ -8013,15 +8038,15 @@ function UnsubscribeWatcher(): void { unsubscribe(value); delete subscriptions[key]; } - } catch (err) { + } catch (err: any) { log('error at function UnsubscribeWatcher: ' + err.message, 'warn'); } } function HandleScreensaver(): void { - setIfExists(NSPanel_Path + 'ActivePage.type', 'screensaver'); - setIfExists(NSPanel_Path + 'ActivePage.id0', 'screensaver'); - setIfExists(NSPanel_Path + 'ActivePage.heading', 'Screensaver'); + setIfExists(NSPanel_Path + 'activePage!.type', 'screensaver'); + setIfExists(NSPanel_Path + 'activePage!.id0', 'screensaver'); + setIfExists(NSPanel_Path + 'activePage!.heading', 'Screensaver'); if (existsObject(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced')) { if (getState(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced').val) { SendToPanel({ payload: 'pageType~screensaver2' }); @@ -8088,7 +8113,7 @@ function HandleScreensaverUpdate(): void { let i = 0; for (i = 0; i < 3; i++) { - if (config.leftScreensaverEntity[i] == null) { + if (config.leftScreensaverEntity[i] == null || config.leftScreensaverEntity[i] == undefined) { checkpoint = false; break; } @@ -8097,8 +8122,8 @@ function HandleScreensaverUpdate(): void { let val = getState(config.leftScreensaverEntity[i].ScreensaverEntity).val; let iconColor = rgb_dec565(White); let icon; - if (existsObject(config.leftScreensaverEntity[i].ScreensaverEntityIconOn)) { - let iconName = getState(config.leftScreensaverEntity[i].ScreensaverEntityIconOn).val; + if (typeof config.leftScreensaverEntity[i].ScreensaverEntityIconOn == 'string' && existsObject(config.leftScreensaverEntity[i].ScreensaverEntityIconOn as string)) { + let iconName = getState(config.leftScreensaverEntity[i].ScreensaverEntityIconOn!).val; icon = Icons.GetIcon(iconName); } else { icon = Icons.GetIcon(config.leftScreensaverEntity[i].ScreensaverEntityIconOn); @@ -8109,7 +8134,7 @@ function HandleScreensaverUpdate(): void { } if (typeof(val) == 'number') { - val = (val * config.leftScreensaverEntity[i].ScreensaverEntityFactor).toFixed(config.leftScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.leftScreensaverEntity[i].ScreensaverEntityUnitText; + val = (val * (config.leftScreensaverEntity[i].ScreensaverEntityFactor ? config.leftScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.leftScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.leftScreensaverEntity[i].ScreensaverEntityUnitText; iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); } else if (typeof(val) == 'boolean') { @@ -8211,8 +8236,8 @@ function HandleScreensaverUpdate(): void { if (weatherAdapterInstance == 'accuweather.' + weatherAdapterInstanceNumber + '.' && i == 6) { let nextSunEvent = 0 - let valDateNow = new Date; - let arraySunEvent = []; + let valDateNow = new Date().getTime(); + let arraySunEvent: number[] = []; arraySunEvent[0] = getDateObject(getState('accuweather.' + weatherAdapterInstanceNumber + '.Daily.Day1.Sunrise').val).getTime(); arraySunEvent[1] = getDateObject(getState('accuweather.' + weatherAdapterInstanceNumber + '.Daily.Day1.Sunset').val).getTime(); @@ -8256,7 +8281,7 @@ function HandleScreensaverUpdate(): void { } let iconColor = rgb_dec565(White); if (typeof(val) == 'number') { - val = (val * config.bottomScreensaverEntity[4].ScreensaverEntityFactor).toFixed(config.bottomScreensaverEntity[4].ScreensaverEntityDecimalPlaces) + config.bottomScreensaverEntity[4].ScreensaverEntityUnitText; + val = (val * (config.bottomScreensaverEntity[4].ScreensaverEntityFactor ? config.bottomScreensaverEntity[4].ScreensaverEntityFactor : 0)).toFixed(config.bottomScreensaverEntity[4].ScreensaverEntityDecimalPlaces) + config.bottomScreensaverEntity[4].ScreensaverEntityUnitText; iconColor = GetScreenSaverEntityColor(config.bottomScreensaverEntity[4]); } else if (typeof(val) == 'boolean') { @@ -8304,15 +8329,15 @@ function HandleScreensaverUpdate(): void { } let iconColor = rgb_dec565(White); let icon; - if (existsObject(config.bottomScreensaverEntity[i].ScreensaverEntityIconOn)) { - let iconName = getState(config.bottomScreensaverEntity[i].ScreensaverEntityIconOn).val; + if (config.bottomScreensaverEntity[i].ScreensaverEntityIconOn && existsObject(config.bottomScreensaverEntity[i].ScreensaverEntityIconOn!)) { + let iconName = getState(config.bottomScreensaverEntity[i].ScreensaverEntityIconOn!).val; icon = Icons.GetIcon(iconName); } else { icon = Icons.GetIcon(config.bottomScreensaverEntity[i].ScreensaverEntityIconOn); } if (typeof(val) == 'number') { - val = (val * config.bottomScreensaverEntity[i].ScreensaverEntityFactor).toFixed(config.bottomScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.bottomScreensaverEntity[i].ScreensaverEntityUnitText; + val = (val * (config.bottomScreensaverEntity[i].ScreensaverEntityFactor ? config.bottomScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.bottomScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.bottomScreensaverEntity[i].ScreensaverEntityUnitText; iconColor = GetScreenSaverEntityColor(config.bottomScreensaverEntity[i]); } else if (typeof(val) == 'boolean') { @@ -8379,15 +8404,15 @@ function HandleScreensaverUpdate(): void { let iconColor = rgb_dec565(White); let icon; - if (existsObject(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn)) { - let iconName = getState(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn).val; + if (config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn && existsObject(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn!)) { + let iconName = getState(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn!).val; icon = Icons.GetIcon(iconName); } else { icon = Icons.GetIcon(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn); } if (typeof(val) == 'number') { - val = (val * config.indicatorScreensaverEntity[i].ScreensaverEntityFactor).toFixed(config.indicatorScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.indicatorScreensaverEntity[i].ScreensaverEntityUnitText; + val = (val * (config.indicatorScreensaverEntity[i].ScreensaverEntityFactor ? config.indicatorScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.indicatorScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.indicatorScreensaverEntity[i].ScreensaverEntityUnitText; iconColor = GetScreenSaverEntityColor(config.indicatorScreensaverEntity[i]); } else if (typeof(val) == 'boolean') { @@ -8415,7 +8440,7 @@ function HandleScreensaverUpdate(): void { } - } catch (err) { + } catch (err: any) { log('error at function HandleScreensaverUpdate: ' + err.message, 'warn'); } } @@ -8429,7 +8454,7 @@ function RegisterScreensaverEntityWatcher(id: string): void { subscriptions[id] = (on({ id: id, change: 'any' }, () => { HandleScreensaverUpdate(); })); - } catch (err) { + } catch (err: any) { log('function RegisterEntityWatcher: ' + err.message, 'warn'); } } @@ -8609,7 +8634,7 @@ function HandleScreensaverStatusIcons() : void { SendToPanel({ payload: 'statusUpdate~' + payloadString }); - } catch (err) { + } catch (err: any) { log('error at function HandleScreensaverStatusIcons: ' + err.message, 'warn'); } } @@ -8638,12 +8663,14 @@ function HandleColorScale(valueScaletemp: string): number { return rgb_dec565(colorScale9); case '10': return rgb_dec565(colorScale10); + default: + return rgb_dec565(colorScale10); } } function HandleScreensaverColors(): void { try { - let vwIcon = []; + let vwIcon: number[] = []; if (getState(NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout').val) { vwIcon[0] = vwIconColor[0]; vwIcon[1] = vwIconColor[1]; @@ -8697,15 +8724,15 @@ function HandleScreensaverColors(): void { rgb_dec565(sctTimeAdd); //tTimeAdd SendToPanel({ payload: payloadString }); - } catch (err) { + } catch (err: any) { log('error at function HandleScreensaverColors: '+ err.message, 'warn'); } } function GetScreenSaverEntityColor(configElement: ScreenSaverElement | null): number { try { - let colorReturn: any; - if (configElement.ScreensaverEntityIconColor != undefined) { + let colorReturn: number; + if (configElement && configElement.ScreensaverEntityIconColor != undefined) { if (typeof getState(configElement.ScreensaverEntity).val == 'boolean') { let iconvalbest = (configElement.ScreensaverEntityIconColor.val_best != undefined) ? configElement.ScreensaverEntityIconColor.val_best : false ; colorReturn = (getState(configElement.ScreensaverEntity).val == iconvalbest) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); @@ -8713,7 +8740,7 @@ function GetScreenSaverEntityColor(configElement: ScreenSaverElement | null): nu let iconvalmin = (configElement.ScreensaverEntityIconColor.val_min != undefined) ? configElement.ScreensaverEntityIconColor.val_min : 0 ; let iconvalmax = (configElement.ScreensaverEntityIconColor.val_max != undefined) ? configElement.ScreensaverEntityIconColor.val_max : 100 ; let iconvalbest = (configElement.ScreensaverEntityIconColor.val_best != undefined) ? configElement.ScreensaverEntityIconColor.val_best : iconvalmin ; - let valueScale = getState(configElement.ScreensaverEntity).val * configElement.ScreensaverEntityFactor; + let valueScale = getState(configElement.ScreensaverEntity).val * configElement.ScreensaverEntityFactor!; if (iconvalmin == 0 && iconvalmax == 1) { colorReturn = (getState(configElement.ScreensaverEntity).val == 1) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); @@ -8744,8 +8771,9 @@ function GetScreenSaverEntityColor(configElement: ScreenSaverElement | null): nu colorReturn = rgb_dec565(White); } } else { - if (typeof getState(configElement.ScreensaverEntity).val == 'boolean') { - if (getState(configElement.ScreensaverEntity).val) { + const value: number | boolean = configElement ? getState(configElement.ScreensaverEntity).val : 0; + if (configElement && typeof value == 'boolean') { + if (value) { if (configElement.ScreensaverEntityOnColor != undefined) { colorReturn = rgb_dec565(configElement.ScreensaverEntityOnColor); } else { @@ -8763,9 +8791,10 @@ function GetScreenSaverEntityColor(configElement: ScreenSaverElement | null): nu } } return colorReturn; - } catch (err) { + } catch (err: any) { log('error at function GetScreenSaverEntityColor: '+ err.message, 'warn'); } + return rgb_dec565(White); } function GetAccuWeatherIcon(icon: number): string { @@ -8844,9 +8873,10 @@ function GetAccuWeatherIcon(icon: number): string { default: return 'alert-circle-outline'; } - } catch (err) { + } catch (err: any) { log('error at function GetAccuWeatherIcon: '+ err.message, 'warn'); } + return ''; } function GetAccuWeatherIconColor(icon: number): number { @@ -8923,9 +8953,10 @@ function GetAccuWeatherIconColor(icon: number): number { default: return rgb_dec565(White); } - } catch (err) { + } catch (err: any) { log('error at function GetAccuWeatherIconColor: '+ err.message, 'warn'); } + return 0; } function GetDasWetterIcon(icon: number): string { @@ -8982,9 +9013,10 @@ function GetDasWetterIcon(icon: number): string { default: return 'alert-circle-outline'; } - } catch (err) { + } catch (err: any) { log('error at function GetDasWetterIcon: '+ err.message, 'warn'); } + return ''; } function GetDasWetterIconColor(icon: number): number { @@ -9041,9 +9073,10 @@ function GetDasWetterIconColor(icon: number): number { default: return rgb_dec565(White); } - } catch (err) { + } catch (err: any) { log('error at function GetDasWetterIconColor: '+ err.message, 'warn'); } + return 0; } //------------------Begin Read Internal Sensor Data @@ -9077,7 +9110,7 @@ on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESU await createAliasAsync(AliasPath + 'Sensor.Time.ACTUAL', NSPanel_Path + 'Sensor.Time', true, { type: 'string' }); await createAliasAsync(AliasPath + 'Sensor.TempUnit.ACTUAL', NSPanel_Path + 'Sensor.TempUnit', true, { type: 'string' }); } - } catch (err) { + } catch (err: any) { log('error Trigger reading senor-data: '+ err.message, 'warn'); } }); @@ -9086,7 +9119,7 @@ on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESU function formatInSelText(Text: string ) : string { let splitText = Text.split(' '); let lengthLineOne = 0; - let arrayLineOne = []; + let arrayLineOne: string[] = []; for (let i = 0; i < splitText.length; i++) { lengthLineOne = lengthLineOne + splitText[i].length + 1; if (lengthLineOne > 12) { @@ -9096,7 +9129,7 @@ function formatInSelText(Text: string ) : string { } } let textLineOne = arrayLineOne.join(' '); - let arrayLineTwo = []; + let arrayLineTwo: string[] = []; for (let i = arrayLineOne.length; i < splitText.length; i++) { arrayLineTwo[i] = splitText[i]; } @@ -9404,21 +9437,21 @@ type DimMode = { } type ConfigButtonFunction = { - mode: string | null, + mode: 'page' | 'toggle' | 'set' | null, page: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PageGrid2 | PagePower | PageChart | PageUnlock | null), entity: string | null, - setValue: string | number | null + setValue: string | number | boolean | null } type Config = { panelRecvTopic: string, panelSendTopic: string, - weatherEntity: string | null, - leftScreensaverEntity: ScreenSaverElement[] | null, - bottomScreensaverEntity: ScreenSaverElement[] | null, - indicatorScreensaverEntity: ScreenSaverElement[] | null, - mrIcon1ScreensaverEntity: ScreenSaverMRElement | null, - mrIcon2ScreensaverEntity: ScreenSaverMRElement | null, + weatherEntity: string, + leftScreensaverEntity: ScreenSaverElement[], + bottomScreensaverEntity: ScreenSaverElement[], + indicatorScreensaverEntity: ScreenSaverElement[], + mrIcon1ScreensaverEntity: ScreenSaverMRElement, + mrIcon2ScreensaverEntity: ScreenSaverMRElement, defaultColor: RGB, defaultOnColor: RGB, defaultOffColor: RGB, @@ -9430,19 +9463,19 @@ type Config = { } type ScreenSaverElement = { - ScreensaverEntity: string | null, - ScreensaverEntityFactor: number | 1, - ScreensaverEntityDecimalPlaces: number | 0, - ScreensaverEntityDateFormat: any | null, - ScreensaverEntityIconOn: string | null, - ScreensaverEntityIconOff: string | null, + ScreensaverEntity: string, + ScreensaverEntityFactor?: number | 1, + ScreensaverEntityDecimalPlaces?: number | 0, + ScreensaverEntityDateFormat?: any | null, + ScreensaverEntityIconOn?: string | null, + ScreensaverEntityIconOff?: string | null, ScreensaverEntityText: string | null, - ScreensaverEntityUnitText: string | null, - ScreensaverEntityIconColor: any | null - ScreensaverEntityOnColor: any | null - ScreensaverEntityOffColor: any | null - ScreensaverEntityOnText: string | null, - ScreensaverEntityOffText: string | null, + ScreensaverEntityUnitText?: string | null, + ScreensaverEntityIconColor?: any | null + ScreensaverEntityOnColor?: any | null + ScreensaverEntityOffColor?: any | null + ScreensaverEntityOnText?: string | null, + ScreensaverEntityOffText?: string | null, } type ScreenSaverMRElement = { From dbc5ff7ccdca6735b7efc72afaa9ab7ee20ba87b Mon Sep 17 00:00:00 2001 From: ticaki Date: Mon, 1 Jan 2024 21:55:22 +0100 Subject: [PATCH 13/99] fix typo --- ioBroker/NsPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 8c70cdfd..625e4d04 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -6621,7 +6621,7 @@ function HandleButtonEvent(words: any): void { }); break; case 'squeezeboxrpc': - //@@ts-ignore Fehler kommt von findPageItem in vscode + //@ts-ignore Fehler kommt von findPageItem in vscode setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'PlaylistCurrentIndex'].join('.'), words[4]); break; } From 131aa491b9669a56ec1d942b6860236d9d458469 Mon Sep 17 00:00:00 2001 From: ticaki Date: Mon, 1 Jan 2024 22:09:19 +0100 Subject: [PATCH 14/99] update config: Config --- ioBroker/NsPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 625e4d04..3d237130 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -769,7 +769,7 @@ let NSPanel_Service_SubPage = ** ** ***********************************************************************/ -export const config = { +export const config: Config = { // Seiteneinteilung / Page division // Hauptseiten / Mainpages pages: [ From 7748c222923f4e4f1b2ad05b0fc4494be20f36ed Mon Sep 17 00:00:00 2001 From: ticaki Date: Mon, 1 Jan 2024 23:30:31 +0100 Subject: [PATCH 15/99] fix ActivePage --- ioBroker/NsPanelTs.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 3d237130..fca76549 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1347,14 +1347,14 @@ function CheckEnableSetObject() { //switch BackgroundColors for Screensaver Indicators async function Init_ActivePageData() { try { - if (existsState(NSPanel_Path + 'activePage!.heading') == false ) { - await createStateAsync(NSPanel_Path + 'activePage!.heading', '', true, { type: 'string' }); + if (existsState(NSPanel_Path + 'ActivePage.heading') == false ) { + await createStateAsync(NSPanel_Path + 'ActivePage.heading', '', true, { type: 'string' }); } - if (existsState(NSPanel_Path + 'activePage!.type') == false ) { - await createStateAsync(NSPanel_Path + 'activePage!.type', '', true, { type: 'string' }); + if (existsState(NSPanel_Path + 'ActivePage.type') == false ) { + await createStateAsync(NSPanel_Path + 'ActivePage.type', '', true, { type: 'string' }); } - if (existsState(NSPanel_Path + 'activePage!.id0') == false ) { - await createStateAsync(NSPanel_Path + 'activePage!.id0', '', true, { type: 'string' }); + if (existsState(NSPanel_Path + 'ActivePage.id0') == false ) { + await createStateAsync(NSPanel_Path + 'ActivePage.id0', '', true, { type: 'string' }); } } catch (err: any) { log('error at function Init_ActivePageData: ' + err.message, 'warn'); @@ -3039,9 +3039,9 @@ function findPageItem(searching: String): PageItem { function GeneratePage(page: Page): void { try { activePage = page; - setIfExists(NSPanel_Path + 'activePage!.type', activePage!.type); - setIfExists(NSPanel_Path + 'activePage!.heading', activePage!.heading); - setIfExists(NSPanel_Path + 'activePage!.id0', activePage!.items[0].id); + setIfExists(NSPanel_Path + 'ActivePage.type', activePage!.type); + setIfExists(NSPanel_Path + 'ActivePage.heading', activePage!.heading); + setIfExists(NSPanel_Path + 'ActivePage.id0', activePage!.items[0].id); switch (page.type) { case 'cardEntities': SendToPanel(GenerateEntitiesPage(page)); @@ -8014,7 +8014,7 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem } } } - if (Debug) log('GenerateDetailPage -> payload: ' + JSON.stringify(out_msgs), 'info'); + if (Debug) log('GenerateDetailPage -> payload: ' + JSON.stringify(out_msgs), 'info'); return out_msgs; } catch (err: any) { @@ -8044,9 +8044,9 @@ function UnsubscribeWatcher(): void { } function HandleScreensaver(): void { - setIfExists(NSPanel_Path + 'activePage!.type', 'screensaver'); - setIfExists(NSPanel_Path + 'activePage!.id0', 'screensaver'); - setIfExists(NSPanel_Path + 'activePage!.heading', 'Screensaver'); + setIfExists(NSPanel_Path + 'ActivePage.type', 'screensaver'); + setIfExists(NSPanel_Path + 'ActivePage.id0', 'screensaver'); + setIfExists(NSPanel_Path + 'ActivePage.heading', 'Screensaver'); if (existsObject(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced')) { if (getState(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced').val) { SendToPanel({ payload: 'pageType~screensaver2' }); From f1ce806dedaf17506953ef39d57fda57c840083a Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 2 Jan 2024 02:02:28 +0100 Subject: [PATCH 16/99] fix cardMedia --- ioBroker/NsPanelTs.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index fca76549..37bdc960 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -2973,16 +2973,16 @@ function HandleMessage(typ: string, method: string, page: number | undefined, wo } let tempId: PageItem['id']; let tempPageItem = words[3].split('?'); - let placeId: string | undefined = undefined; + let placeId: number | undefined = undefined; if (!isNaN(parseInt(tempPageItem[0]))){ tempId = activePage!.items[tempPageItem[0]].id; - placeId = tempPageItem[0] + placeId = parseInt(tempPageItem[0]) } else { tempId = tempPageItem[0]; } let pageItem: PageItem = findPageItem(tempId); if (pageItem !== undefined) { - SendToPanel(GenerateDetailPage(words[2], tempPageItem[1], pageItem, Number(placeId))); + SendToPanel(GenerateDetailPage(words[2], tempPageItem[1], pageItem, placeId)); } } break; @@ -4160,7 +4160,7 @@ function RegisterEntityWatcher(id: string): void { } } -function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: string, placeId: number): void { +function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: string, placeId: number | undefined): void { try { if (subscriptions.hasOwnProperty(id)) { return; @@ -7040,7 +7040,7 @@ function GetNavigationString(pageId: number): string { return ''; } -function GenerateDetailPage(type: string, optional: string | undefined, pageItem: PageItem, placeId: number): Payload[] { +function GenerateDetailPage(type: string, optional: string | undefined, pageItem: PageItem, placeId: number | undefined): Payload[] { if (Debug) log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); try { let out_msgs: Array = []; From 956bd23a56f5115753f339c1a93cb6ca0f9468ab Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 2 Jan 2024 11:59:19 +0100 Subject: [PATCH 17/99] add types for ScreensaverEntityIconColor --- ioBroker/NsPanelTs.ts | 45 ++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 37bdc960..e592ea28 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -8156,9 +8156,9 @@ function HandleScreensaverUpdate(): void { } } } - - if (existsObject(config.leftScreensaverEntity[i].ScreensaverEntityIconColor)) { - iconColor = getState(config.leftScreensaverEntity[i].ScreensaverEntityIconColor).val; + const temp = config.leftScreensaverEntity[i].ScreensaverEntityIconColor; + if (temp && typeof temp == 'string' && existsObject(temp)) { + iconColor = getState(temp).val; } payloadString += '~' + @@ -8302,8 +8302,9 @@ function HandleScreensaverUpdate(): void { } } - if (existsObject(config.bottomScreensaverEntity[4].ScreensaverEntityIconColor)) { - iconColor = getState(config.bottomScreensaverEntity[4].ScreensaverEntityIconColor).val; + const temp = config.bottomScreensaverEntity[4].ScreensaverEntityIconColor + if (temp && typeof temp == 'string' && existsObject(temp)) { + iconColor = getState(temp).val; } payloadString += '~' + '~' + @@ -8367,8 +8368,9 @@ function HandleScreensaverUpdate(): void { } } - if (existsObject(config.bottomScreensaverEntity[i].ScreensaverEntityIconColor)) { - iconColor = getState(config.bottomScreensaverEntity[i].ScreensaverEntityIconColor).val; + const temp = config.bottomScreensaverEntity[4].ScreensaverEntityIconColor + if (temp && typeof temp == 'string' && existsObject(temp)) { + iconColor = getState(temp).val; } if (i < maxEntities - 1) { val = val + '~'; @@ -8421,8 +8423,9 @@ function HandleScreensaverUpdate(): void { icon = Icons.GetIcon(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOff) } } - if (existsObject(config.indicatorScreensaverEntity[i].ScreensaverEntityIconColor)) { - iconColor = getState(config.indicatorScreensaverEntity[i].ScreensaverEntityIconColor).val; + const temp = config.indicatorScreensaverEntity[4].ScreensaverEntityIconColor + if (temp && typeof temp == 'string' && existsObject(temp)) { + iconColor = getState(temp).val; } payloadString += '~' + '~' + @@ -8733,13 +8736,14 @@ function GetScreenSaverEntityColor(configElement: ScreenSaverElement | null): nu try { let colorReturn: number; if (configElement && configElement.ScreensaverEntityIconColor != undefined) { + const ScreensaverEntityIconColor = configElement.ScreensaverEntityIconColor as IconScaleElement; if (typeof getState(configElement.ScreensaverEntity).val == 'boolean') { - let iconvalbest = (configElement.ScreensaverEntityIconColor.val_best != undefined) ? configElement.ScreensaverEntityIconColor.val_best : false ; + let iconvalbest = (typeof ScreensaverEntityIconColor == 'object' && ScreensaverEntityIconColor.val_best !== undefined ) ? ScreensaverEntityIconColor.val_best : false ; colorReturn = (getState(configElement.ScreensaverEntity).val == iconvalbest) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); - } else if (typeof configElement.ScreensaverEntityIconColor == 'object') { - let iconvalmin = (configElement.ScreensaverEntityIconColor.val_min != undefined) ? configElement.ScreensaverEntityIconColor.val_min : 0 ; - let iconvalmax = (configElement.ScreensaverEntityIconColor.val_max != undefined) ? configElement.ScreensaverEntityIconColor.val_max : 100 ; - let iconvalbest = (configElement.ScreensaverEntityIconColor.val_best != undefined) ? configElement.ScreensaverEntityIconColor.val_best : iconvalmin ; + } else if (typeof ScreensaverEntityIconColor == 'object') { + const iconvalmin: number = ScreensaverEntityIconColor.val_min != undefined ? ScreensaverEntityIconColor.val_min : 0 ; + const iconvalmax: number = ScreensaverEntityIconColor.val_max != undefined ? ScreensaverEntityIconColor.val_max : 100 ; + const iconvalbest: number = ScreensaverEntityIconColor.val_best != undefined ? ScreensaverEntityIconColor.val_best : iconvalmin ; let valueScale = getState(configElement.ScreensaverEntity).val * configElement.ScreensaverEntityFactor!; if (iconvalmin == 0 && iconvalmax == 1) { @@ -8763,11 +8767,10 @@ function GetScreenSaverEntityColor(configElement: ScreenSaverElement | null): nu let valueScaletemp = (Math.round(valueScale)).toFixed(); colorReturn = HandleColorScale(valueScaletemp); } - if (configElement.ScreensaverEntityIconColor.val_min == undefined) { - colorReturn = rgb_dec565(configElement.ScreensaverEntityIconColor); + if (ScreensaverEntityIconColor.val_min == undefined) { + colorReturn = rgb_dec565(configElement.ScreensaverEntityIconColor as RGB); } } else { - colorReturn = rgb_dec565(White); } } else { @@ -9471,7 +9474,7 @@ type ScreenSaverElement = { ScreensaverEntityIconOff?: string | null, ScreensaverEntityText: string | null, ScreensaverEntityUnitText?: string | null, - ScreensaverEntityIconColor?: any | null + ScreensaverEntityIconColor?: RGB | IconScaleElement | string ScreensaverEntityOnColor?: any | null ScreensaverEntityOffColor?: any | null ScreensaverEntityOnText?: string | null, @@ -9488,3 +9491,9 @@ type ScreenSaverMRElement = { ScreensaverEntityOnColor: RGB, ScreensaverEntityOffColor: RGB } + +type IconScaleElement = { + val_min:number, + val_max:number, + val_best?: number +} From 6cc41bf5109fa0d522bcca441d05fe6295cf1efc Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 2 Jan 2024 14:05:03 +0100 Subject: [PATCH 18/99] some types work --- ioBroker/NsPanelTs.ts | 495 ++++++++++++++++++++++-------------------- 1 file changed, 254 insertions(+), 241 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index e592ea28..75faa033 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -392,33 +392,33 @@ let Debug: boolean = false; */ //Level 0 (if service pages are used with cardUnlock) -let Unlock_Service = +let Unlock_Service: PageUnlock = { 'type': 'cardUnlock', 'heading': findLocaleServMenu('service_pages'), 'useColor': true, - 'items': [{ id: 'alias.0.NSPanel.Unlock', + 'items': [/*PageItem*/{ id: 'alias.0.NSPanel.Unlock', targetPage: 'NSPanel_Service_SubPage', autoCreateALias: true } ] }; //Level_0 (if service pages are used without cardUnlock) -let NSPanel_Service = +let NSPanel_Service: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('service_menu'), 'useColor': true, 'items': [ - { navigate: true, id: 'NSPanel_Infos', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('infos'), buttonText: findLocaleServMenu('more')}, - { navigate: true, id: 'NSPanel_Einstellungen', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('settings'), buttonText: findLocaleServMenu('more')}, - { navigate: true, id: 'NSPanel_Firmware', icon: 'update', offColor: Menu, onColor: Menu, name: findLocaleServMenu('firmware'), buttonText: findLocaleServMenu('more')}, - { id: AliasPath + 'Config.rebootNSPanel', name: findLocaleServMenu('reboot') ,icon: 'refresh', offColor: MSRed, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Infos', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('infos'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Einstellungen', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('settings'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Firmware', icon: 'update', offColor: Menu, onColor: Menu, name: findLocaleServMenu('firmware'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ id: AliasPath + 'Config.rebootNSPanel', name: findLocaleServMenu('reboot') ,icon: 'refresh', offColor: MSRed, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, ] }; //Level_0 (if service pages are used with cardUnlock) -let NSPanel_Service_SubPage = +let NSPanel_Service_SubPage: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('service_menu'), @@ -427,15 +427,15 @@ let NSPanel_Service_SubPage = 'parent': Unlock_Service, 'home': 'Unlock_Service', 'items': [ - { navigate: true, id: 'NSPanel_Infos', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('infos'), buttonText: findLocaleServMenu('more')}, - { navigate: true, id: 'NSPanel_Einstellungen', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('settings'), buttonText: findLocaleServMenu('more')}, - { navigate: true, id: 'NSPanel_Firmware', icon: 'update', offColor: Menu, onColor: Menu, name: findLocaleServMenu('firmware'), buttonText: findLocaleServMenu('more')}, - { id: AliasPath + 'Config.rebootNSPanel', name: findLocaleServMenu('reboot') ,icon: 'refresh', offColor: MSRed, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Infos', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('infos'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Einstellungen', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('settings'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Firmware', icon: 'update', offColor: Menu, onColor: Menu, name: findLocaleServMenu('firmware'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ id: AliasPath + 'Config.rebootNSPanel', name: findLocaleServMenu('reboot') ,icon: 'refresh', offColor: MSRed, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, ] }; //Level_1 - let NSPanel_Infos = + let NSPanel_Infos: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('nspanel_infos'), @@ -444,14 +444,14 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Service, 'home': 'NSPanel_Service', 'items': [ - { navigate: true, id: 'NSPanel_Wifi_Info_1', icon: 'wifi', offColor: Menu, onColor: Menu, name: findLocaleServMenu('wifi'), buttonText: findLocaleServMenu('more')}, - { navigate: true, id: 'NSPanel_Sensoren', icon: 'memory', offColor: Menu, onColor: Menu, name: findLocaleServMenu('sensors_hardware'), buttonText: findLocaleServMenu('more')}, - { navigate: true, id: 'NSPanel_IoBroker', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('info_iobroker'), buttonText: findLocaleServMenu('more')}, - { id: AliasPath + 'Config.Update.UpdateMessage', name: findLocaleServMenu('update_message') ,icon: 'message-alert-outline', offColor: HMIOff, onColor: MSGreen}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Wifi_Info_1', icon: 'wifi', offColor: Menu, onColor: Menu, name: findLocaleServMenu('wifi'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Sensoren', icon: 'memory', offColor: Menu, onColor: Menu, name: findLocaleServMenu('sensors_hardware'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_IoBroker', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('info_iobroker'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ id: AliasPath + 'Config.Update.UpdateMessage', name: findLocaleServMenu('update_message') ,icon: 'message-alert-outline', offColor: HMIOff, onColor: MSGreen}, ] }; //Level_2 - let NSPanel_Wifi_Info_1 = + let NSPanel_Wifi_Info_1: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('nspanel_wifi1'), @@ -460,14 +460,14 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Infos, 'next': 'NSPanel_Wifi_Info_2', 'items': [ - { id: AliasPath + 'ipAddress', name: findLocaleServMenu('ip_address'), icon: 'ip-network-outline', offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Tasmota.Wifi.BSSId', name: findLocaleServMenu('mac_address'), icon: 'check-network', offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Tasmota.Wifi.RSSI', name: findLocaleServMenu('rssi'), icon: 'signal', unit: '%', colorScale: {'val_min': 100, 'val_max': 0} }, - { id: AliasPath + 'Tasmota.Wifi.Signal', name: findLocaleServMenu('wifi_signal'), icon: 'signal-distance-variant', unit: 'dBm', colorScale: {'val_min': 0, 'val_max': -100} }, + /*PageItem*/{ id: AliasPath + 'ipAddress', name: findLocaleServMenu('ip_address'), icon: 'ip-network-outline', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.BSSId', name: findLocaleServMenu('mac_address'), icon: 'check-network', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.RSSI', name: findLocaleServMenu('rssi'), icon: 'signal', unit: '%', colorScale: {'val_min': 100, 'val_max': 0} }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.Signal', name: findLocaleServMenu('wifi_signal'), icon: 'signal-distance-variant', unit: 'dBm', colorScale: {'val_min': 0, 'val_max': -100} }, ] }; - let NSPanel_Wifi_Info_2 = + let NSPanel_Wifi_Info_2: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('nspanel_wifi2'), @@ -476,14 +476,14 @@ let NSPanel_Service_SubPage = 'prev': 'NSPanel_Wifi_Info_1', 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'Tasmota.Wifi.SSId', name: findLocaleServMenu('ssid'), icon: 'signal-distance-variant', offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Tasmota.Wifi.Mode', name: findLocaleServMenu('mode'), icon: 'signal-distance-variant', offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Tasmota.Wifi.Channel', name: findLocaleServMenu('channel'), icon: 'timeline-clock-outline', offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Tasmota.Wifi.AP', name: findLocaleServMenu('accesspoint'), icon: 'router-wireless-settings', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.SSId', name: findLocaleServMenu('ssid'), icon: 'signal-distance-variant', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.Mode', name: findLocaleServMenu('mode'), icon: 'signal-distance-variant', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.Channel', name: findLocaleServMenu('channel'), icon: 'timeline-clock-outline', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.AP', name: findLocaleServMenu('accesspoint'), icon: 'router-wireless-settings', offColor: Menu, onColor: Menu }, ] }; - let NSPanel_Sensoren = + let NSPanel_Sensoren: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('sensors1'), @@ -492,14 +492,14 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Infos, 'next': 'NSPanel_Hardware', 'items': [ - { id: AliasPath + 'Sensor.ANALOG.Temperature', name: findLocaleServMenu('room_temperature'), icon: 'home-thermometer-outline', unit: '°C', colorScale: {'val_min': 0, 'val_max': 40, 'val_best': 22 } }, - { id: AliasPath + 'Sensor.ESP32.Temperature', name: findLocaleServMenu('esp_temperature'), icon: 'thermometer', unit: '°C', colorScale: {'val_min': 0, 'val_max': 100, 'val_best': 50 } }, - { id: AliasPath + 'Sensor.TempUnit', name: findLocaleServMenu('temperature_unit'), icon: 'temperature-celsius', offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Sensor.Time', name: findLocaleServMenu('refresh'), icon: 'clock-check-outline', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Sensor.ANALOG.Temperature', name: findLocaleServMenu('room_temperature'), icon: 'home-thermometer-outline', unit: '°C', colorScale: {'val_min': 0, 'val_max': 40, 'val_best': 22 } }, + /*PageItem*/{ id: AliasPath + 'Sensor.ESP32.Temperature', name: findLocaleServMenu('esp_temperature'), icon: 'thermometer', unit: '°C', colorScale: {'val_min': 0, 'val_max': 100, 'val_best': 50 } }, + /*PageItem*/{ id: AliasPath + 'Sensor.TempUnit', name: findLocaleServMenu('temperature_unit'), icon: 'temperature-celsius', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Sensor.Time', name: findLocaleServMenu('refresh'), icon: 'clock-check-outline', offColor: Menu, onColor: Menu }, ] }; - let NSPanel_Hardware = + let NSPanel_Hardware: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('hardware2'), @@ -508,14 +508,14 @@ let NSPanel_Service_SubPage = 'prev': 'NSPanel_Sensoren', 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'Tasmota.Product', name: findLocaleServMenu('product'), icon: 'devices', offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Tasmota.Hardware', name: findLocaleServMenu('esp32_hardware'), icon: 'memory', offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Display.Model', name: findLocaleServMenu('nspanel_version'), offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Tasmota.Uptime', name: findLocaleServMenu('operating_time'), icon: 'timeline-clock-outline', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Product', name: findLocaleServMenu('product'), icon: 'devices', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Hardware', name: findLocaleServMenu('esp32_hardware'), icon: 'memory', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Display.Model', name: findLocaleServMenu('nspanel_version'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Uptime', name: findLocaleServMenu('operating_time'), icon: 'timeline-clock-outline', offColor: Menu, onColor: Menu }, ] }; - let NSPanel_IoBroker = + let NSPanel_IoBroker: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('info_iobroker'), @@ -524,14 +524,14 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Infos, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'IoBroker.ScriptVersion', name: findLocaleServMenu('script_version_nspanelts'), offColor: Menu, onColor: Menu }, - { id: AliasPath + 'IoBroker.NodeJSVersion', name: findLocaleServMenu('nodejs_version'), offColor: Menu, onColor: Menu }, - { id: AliasPath + 'IoBroker.JavaScriptVersion', name: findLocaleServMenu('instance_javascript'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'IoBroker.ScriptVersion', name: findLocaleServMenu('script_version_nspanelts'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'IoBroker.NodeJSVersion', name: findLocaleServMenu('nodejs_version'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'IoBroker.JavaScriptVersion', name: findLocaleServMenu('instance_javascript'), offColor: Menu, onColor: Menu }, ] }; //Level_1 - let NSPanel_Einstellungen = + let NSPanel_Einstellungen: PageGrid = { 'type': 'cardGrid', 'heading': findLocaleServMenu('settings'), @@ -540,20 +540,20 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Service, 'home': 'NSPanel_Service', 'items': [ - { navigate: true, id: 'NSPanel_Screensaver', icon: 'monitor-dashboard',offColor: Menu, onColor: Menu, name: findLocaleServMenu('screensaver'), buttonText: findLocaleServMenu('more')}, - { navigate: true, id: 'NSPanel_Relays', icon: 'electric-switch', offColor: Menu, onColor: Menu, name: findLocaleServMenu('relays'), buttonText: findLocaleServMenu('more')}, - { id:AliasPath + 'Config.temperatureUnitNumber', icon: 'gesture-double-tap', name: findLocaleServMenu('temp_unit'), offColor: Menu, onColor: Menu, + /*PageItem*/{ navigate: true, id: 'NSPanel_Screensaver', icon: 'monitor-dashboard',offColor: Menu, onColor: Menu, name: findLocaleServMenu('screensaver'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Relays', icon: 'electric-switch', offColor: Menu, onColor: Menu, name: findLocaleServMenu('relays'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ id:AliasPath + 'Config.temperatureUnitNumber', icon: 'gesture-double-tap', name: findLocaleServMenu('temp_unit'), offColor: Menu, onColor: Menu, modeList: ['°C', '°F', 'K']}, - { id: AliasPath + 'Config.localeNumber', icon: 'select-place', name: findLocaleServMenu('language'), offColor: Menu, onColor: Menu, + /*PageItem*/{ id: AliasPath + 'Config.localeNumber', icon: 'select-place', name: findLocaleServMenu('language'), offColor: Menu, onColor: Menu, modeList: ['en-US', 'de-DE', 'nl-NL', 'da-DK', 'es-ES', 'fr-FR', 'it-IT', 'ru-RU', 'nb-NO', 'nn-NO', 'pl-PL', 'pt-PT', 'af-ZA', 'ar-SY', 'bg-BG', 'ca-ES', 'cs-CZ', 'el-GR', 'et-EE', 'fa-IR', 'fi-FI', 'he-IL', 'hr-xx', 'hu-HU', 'hy-AM', 'id-ID', 'is-IS', 'lb-xx', 'lt-LT', 'ro-RO', 'sk-SK', 'sl-SI', 'sv-SE', 'th-TH', 'tr-TR', 'uk-UA', 'vi-VN', 'zh-CN', 'zh-TW']}, - { navigate: true, id: 'NSPanel_Script', icon: 'code-json',offColor: Menu, onColor: Menu, name: findLocaleServMenu('script'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Script', icon: 'code-json',offColor: Menu, onColor: Menu, name: findLocaleServMenu('script'), buttonText: findLocaleServMenu('more')}, ] }; //Level_2 - let NSPanel_Screensaver = + let NSPanel_Screensaver: PageGrid = { 'type': 'cardGrid', 'heading': findLocaleServMenu('screensaver'), @@ -562,17 +562,17 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Einstellungen, 'home': 'NSPanel_Service', 'items': [ - { navigate: true, id: 'NSPanel_ScreensaverDimmode', icon: 'sun-clock', offColor: Menu, onColor: Menu, name: findLocaleServMenu('dimmode')}, - { navigate: true, id: 'NSPanel_ScreensaverBrightness', icon: 'brightness-5', offColor: Menu, onColor: Menu, name: findLocaleServMenu('brightness')}, - { navigate: true, id: 'NSPanel_ScreensaverLayout', icon: 'page-next-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('layout')}, - { navigate: true, id: 'NSPanel_ScreensaverWeather', icon: 'weather-partly-rainy', offColor: Menu, onColor: Menu, name: findLocaleServMenu('weather')}, - { navigate: true, id: 'NSPanel_ScreensaverDateformat', icon: 'calendar-expand-horizontal', offColor: Menu, onColor: Menu, name: findLocaleServMenu('date_format')}, - { navigate: true, id: 'NSPanel_ScreensaverIndicators', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('indicators')} + /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverDimmode', icon: 'sun-clock', offColor: Menu, onColor: Menu, name: findLocaleServMenu('dimmode')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverBrightness', icon: 'brightness-5', offColor: Menu, onColor: Menu, name: findLocaleServMenu('brightness')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverLayout', icon: 'page-next-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('layout')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverWeather', icon: 'weather-partly-rainy', offColor: Menu, onColor: Menu, name: findLocaleServMenu('weather')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverDateformat', icon: 'calendar-expand-horizontal', offColor: Menu, onColor: Menu, name: findLocaleServMenu('date_format')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverIndicators', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('indicators')} ] }; //Level_3 - let NSPanel_ScreensaverDimmode = + let NSPanel_ScreensaverDimmode: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('dimmode'), @@ -581,15 +581,15 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Screensaver, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'Dimmode.brightnessDay', name: findLocaleServMenu('brightness_day'), icon: 'brightness-5', offColor: Menu, onColor: Menu, minValue: 5, maxValue: 10}, - { id: AliasPath + 'Dimmode.brightnessNight', name: findLocaleServMenu('brightness_night'), icon: 'brightness-4', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 4}, - { id: AliasPath + 'Dimmode.hourDay', name: findLocaleServMenu('hour_day'), icon: 'sun-clock', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 23}, - { id: AliasPath + 'Dimmode.hourNight', name: findLocaleServMenu('hour_night'), icon: 'sun-clock-outline', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 23} + /*PageItem*/{ id: AliasPath + 'Dimmode.brightnessDay', name: findLocaleServMenu('brightness_day'), icon: 'brightness-5', offColor: Menu, onColor: Menu, minValue: 5, maxValue: 10}, + /*PageItem*/{ id: AliasPath + 'Dimmode.brightnessNight', name: findLocaleServMenu('brightness_night'), icon: 'brightness-4', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 4}, + /*PageItem*/{ id: AliasPath + 'Dimmode.hourDay', name: findLocaleServMenu('hour_day'), icon: 'sun-clock', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 23}, + /*PageItem*/{ id: AliasPath + 'Dimmode.hourNight', name: findLocaleServMenu('hour_night'), icon: 'sun-clock-outline', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 23} ] }; //Level_3 - let NSPanel_ScreensaverBrightness = + let NSPanel_ScreensaverBrightness: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('brightness'), @@ -598,14 +598,14 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Screensaver, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'ScreensaverInfo.activeBrightness', name: findLocaleServMenu('brightness_activ'), icon: 'brightness-5', offColor: Menu, onColor: Menu, minValue: 20, maxValue: 100}, - { id: AliasPath + 'Config.Screensaver.timeoutScreensaver', name: findLocaleServMenu('screensaver_timeout'), icon: 'clock-end', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 60}, - { id: AliasPath + 'Config.Screensaver.screenSaverDoubleClick', name: findLocaleServMenu('wakeup_doublecklick') ,icon: 'gesture-two-double-tap', offColor: HMIOff, onColor: HMIOn} + /*PageItem*/{ id: AliasPath + 'ScreensaverInfo.activeBrightness', name: findLocaleServMenu('brightness_activ'), icon: 'brightness-5', offColor: Menu, onColor: Menu, minValue: 20, maxValue: 100}, + /*PageItem*/{ id: AliasPath + 'Config.Screensaver.timeoutScreensaver', name: findLocaleServMenu('screensaver_timeout'), icon: 'clock-end', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 60}, + /*PageItem*/{ id: AliasPath + 'Config.Screensaver.screenSaverDoubleClick', name: findLocaleServMenu('wakeup_doublecklick') ,icon: 'gesture-two-double-tap', offColor: HMIOff, onColor: HMIOn} ] }; //Level_3 - let NSPanel_ScreensaverLayout = + let NSPanel_ScreensaverLayout: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('layout'), @@ -614,13 +614,13 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Screensaver, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'Config.Screensaver.alternativeScreensaverLayout', name: findLocaleServMenu('alternative_layout') ,icon: 'page-previous-outline', offColor: HMIOff, onColor: HMIOn}, - { id: AliasPath + 'Config.Screensaver.ScreensaverAdvanced', name: findLocaleServMenu('advanced_layout') ,icon: 'page-next-outline', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Config.Screensaver.alternativeScreensaverLayout', name: findLocaleServMenu('alternative_layout') ,icon: 'page-previous-outline', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Config.Screensaver.ScreensaverAdvanced', name: findLocaleServMenu('advanced_layout') ,icon: 'page-next-outline', offColor: HMIOff, onColor: HMIOn}, ] }; //Level_3 - let NSPanel_ScreensaverWeather = + let NSPanel_ScreensaverWeather: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('weather_parameters'), @@ -629,15 +629,15 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Screensaver, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'ScreensaverInfo.weatherForecast', name: findLocaleServMenu('weather_forecast_offon') ,icon: 'weather-sunny-off', offColor: HMIOff, onColor: HMIOn}, - { id: AliasPath + 'ScreensaverInfo.weatherForecastTimer', name: findLocaleServMenu('weather_forecast_change_switch') ,icon: 'devices', offColor: HMIOff, onColor: HMIOn}, - { id: AliasPath + 'ScreensaverInfo.entityChangeTime', name: findLocaleServMenu('weather_forecast_change_time'), icon: 'cog-sync', offColor: Menu, onColor: Menu, minValue: 15, maxValue: 60}, - { id: AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout', name: findLocaleServMenu('weather_forecast_icon_colors') ,icon: 'format-color-fill', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'ScreensaverInfo.weatherForecast', name: findLocaleServMenu('weather_forecast_offon') ,icon: 'weather-sunny-off', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'ScreensaverInfo.weatherForecastTimer', name: findLocaleServMenu('weather_forecast_change_switch') ,icon: 'devices', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'ScreensaverInfo.entityChangeTime', name: findLocaleServMenu('weather_forecast_change_time'), icon: 'cog-sync', offColor: Menu, onColor: Menu, minValue: 15, maxValue: 60}, + /*PageItem*/{ id: AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout', name: findLocaleServMenu('weather_forecast_icon_colors') ,icon: 'format-color-fill', offColor: HMIOff, onColor: HMIOn}, ] }; //Level_3 - let NSPanel_ScreensaverDateformat = + let NSPanel_ScreensaverDateformat: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('date_format'), @@ -646,13 +646,13 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Screensaver, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'Config.Dateformat.Switch.weekday', name: findLocaleServMenu('weekday_large') ,icon: 'calendar-expand-horizontal', offColor: HMIOff, onColor: HMIOn}, - { id: AliasPath + 'Config.Dateformat.Switch.month', name: findLocaleServMenu('month_large') ,icon: 'calendar-expand-horizontal', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Config.Dateformat.Switch.weekday', name: findLocaleServMenu('weekday_large') ,icon: 'calendar-expand-horizontal', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Config.Dateformat.Switch.month', name: findLocaleServMenu('month_large') ,icon: 'calendar-expand-horizontal', offColor: HMIOff, onColor: HMIOn}, ] }; //Level_3 - let NSPanel_ScreensaverIndicators = + let NSPanel_ScreensaverIndicators: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('indicators'), @@ -661,13 +661,13 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Screensaver, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'Config.MRIcons.alternateMRIconSize.1', name: findLocaleServMenu('mr_icon1_size') ,icon: 'format-size', offColor: HMIOff, onColor: HMIOn}, - { id: AliasPath + 'Config.MRIcons.alternateMRIconSize.2', name: findLocaleServMenu('mr_icon2_size') ,icon: 'format-size', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Config.MRIcons.alternateMRIconSize.1', name: findLocaleServMenu('mr_icon1_size') ,icon: 'format-size', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Config.MRIcons.alternateMRIconSize.2', name: findLocaleServMenu('mr_icon2_size') ,icon: 'format-size', offColor: HMIOff, onColor: HMIOn}, ] }; //Level_2 - let NSPanel_Relays = + let NSPanel_Relays: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('relays'), @@ -676,13 +676,13 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Einstellungen, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'Relay.1', name: findLocaleServMenu('relay1_onoff'), icon: 'power', offColor: HMIOff, onColor: HMIOn}, - { id: AliasPath + 'Relay.2', name: findLocaleServMenu('relay2_onoff'), icon: 'power', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Relay.1', name: findLocaleServMenu('relay1_onoff'), icon: 'power', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Relay.2', name: findLocaleServMenu('relay2_onoff'), icon: 'power', offColor: HMIOff, onColor: HMIOn}, ] }; //Level_2 - let NSPanel_Script = + let NSPanel_Script: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('script'), @@ -691,13 +691,13 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Einstellungen, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'Config.ScripgtDebugStatus', name: findLocaleServMenu('debugmode_offon') ,icon: 'code-tags-check', offColor: HMIOff, onColor: HMIOn}, - { id: AliasPath + 'Config.MQTT.portCheck', name: findLocaleServMenu('port_check_offon') ,icon: 'check-network', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Config.ScripgtDebugStatus', name: findLocaleServMenu('debugmode_offon') ,icon: 'code-tags-check', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Config.MQTT.portCheck', name: findLocaleServMenu('port_check_offon') ,icon: 'check-network', offColor: HMIOff, onColor: HMIOn}, ] }; //Level_1 - let NSPanel_Firmware = + let NSPanel_Firmware: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('firmware'), @@ -706,14 +706,14 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Service, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'autoUpdate', name: findLocaleServMenu('automatically_updates') ,icon: 'power', offColor: HMIOff, onColor: HMIOn}, - { navigate: true, id: 'NSPanel_FirmwareTasmota', icon: 'usb-flash-drive', offColor: Menu, onColor: Menu, name: findLocaleServMenu('tasmota_firmware'), buttonText: findLocaleServMenu('more')}, - { navigate: true, id: 'NSPanel_FirmwareBerry', icon: 'usb-flash-drive', offColor: Menu, onColor: Menu, name: findLocaleServMenu('berry_driver'), buttonText: findLocaleServMenu('more')}, - { navigate: true, id: 'NSPanel_FirmwareNextion', icon: 'cellphone-cog', offColor: Menu, onColor: Menu, name: findLocaleServMenu('nextion_tft_firmware'), buttonText: findLocaleServMenu('more')} + /*PageItem*/{ id: AliasPath + 'autoUpdate', name: findLocaleServMenu('automatically_updates') ,icon: 'power', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ navigate: true, id: 'NSPanel_FirmwareTasmota', icon: 'usb-flash-drive', offColor: Menu, onColor: Menu, name: findLocaleServMenu('tasmota_firmware'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_FirmwareBerry', icon: 'usb-flash-drive', offColor: Menu, onColor: Menu, name: findLocaleServMenu('berry_driver'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_FirmwareNextion', icon: 'cellphone-cog', offColor: Menu, onColor: Menu, name: findLocaleServMenu('nextion_tft_firmware'), buttonText: findLocaleServMenu('more')} ] }; - let NSPanel_FirmwareTasmota = + let NSPanel_FirmwareTasmota: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('tasmota'), @@ -722,14 +722,14 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Firmware, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'Tasmota.Version', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Tasmota_Firmware.onlineVersion', name: findLocaleServMenu('available_release'), offColor: Menu, onColor: Menu }, - { id: 'Divider' }, - { id: AliasPath + 'Config.Update.UpdateTasmota', name: findLocaleServMenu('update_tasmota') ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + /*PageItem*/{ id: AliasPath + 'Tasmota.Version', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota_Firmware.onlineVersion', name: findLocaleServMenu('available_release'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: 'Divider' }, + /*PageItem*/{ id: AliasPath + 'Config.Update.UpdateTasmota', name: findLocaleServMenu('update_tasmota') ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, ] }; - let NSPanel_FirmwareBerry = + let NSPanel_FirmwareBerry: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('berry_driver'), @@ -738,14 +738,14 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Firmware, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'Display.BerryDriver', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Berry_Driver.onlineVersion', name: findLocaleServMenu('available_release'), offColor: Menu, onColor: Menu}, - { id: 'Divider' }, - { id: AliasPath + 'Config.Update.UpdateBerry', name: findLocaleServMenu('update_berry_driver') ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + /*PageItem*/{ id: AliasPath + 'Display.BerryDriver', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Berry_Driver.onlineVersion', name: findLocaleServMenu('available_release'), offColor: Menu, onColor: Menu}, + /*PageItem*/{ id: 'Divider' }, + /*PageItem*/{ id: AliasPath + 'Config.Update.UpdateBerry', name: findLocaleServMenu('update_berry_driver') ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, ] }; - let NSPanel_FirmwareNextion = + let NSPanel_FirmwareNextion: PageEntities = { 'type': 'cardEntities', 'heading': findLocaleServMenu('nextion_tft'), @@ -754,10 +754,10 @@ let NSPanel_Service_SubPage = 'parent': NSPanel_Firmware, 'home': 'NSPanel_Service', 'items': [ - { id: AliasPath + 'Display_Firmware.TFT.currentVersion', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Display_Firmware.TFT.desiredVersion', name: findLocaleServMenu('desired_release'), offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Display.Model', name: findLocaleServMenu('nspanel_model'), offColor: Menu, onColor: Menu }, - { id: AliasPath + 'Config.Update.UpdateNextion', name: 'Nextion TFT Update' ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + /*PageItem*/{ id: AliasPath + 'Display_Firmware.TFT.currentVersion', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Display_Firmware.TFT.desiredVersion', name: findLocaleServMenu('desired_release'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Display.Model', name: findLocaleServMenu('nspanel_model'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Config.Update.UpdateNextion', name: 'Nextion TFT Update' ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, ] }; @@ -809,7 +809,7 @@ export const config: Config = { leftScreensaverEntity: [ // Examples for Advanced-Screensaver: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Config-Screensaver#entity-status-icons-ab-v400 ], - + bottomScreensaverEntity: [ // bottomScreensaverEntity 1 { @@ -1905,7 +1905,7 @@ async function InitDimmode() { } const vTimeDay = getState(NSPanel_Path + 'NSPanel_Dimmode_hourDay').val; const vTimeNight = getState(NSPanel_Path + 'NSPanel_Dimmode_hourNight').val; - const timeDimMode = { + const timeDimMode: DimMode = { dimmodeOn: true, brightnessDay: getState(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay').val, brightnessNight: getState(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight').val, @@ -3580,7 +3580,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = if (existsState(pageItem.id + '.HUE')) { if (getState(pageItem.id + '.HUE').val != null) { let huecolor = hsv2rgb(getState(pageItem.id + '.HUE').val, 1, 1); - let rgb = { red: Math.round(huecolor[0]), green: Math.round(huecolor[1]), blue: Math.round(huecolor[2]) }; + let rgb: 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); } } @@ -3631,7 +3631,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let rgbRed = getState(pageItem.id + '.RED').val; let rgbGreen = getState(pageItem.id + '.GREEN').val; let rgbBlue = getState(pageItem.id + '.BLUE').val; - let rgb = { red: Math.round(rgbRed), green: Math.round(rgbGreen), blue: Math.round(rgbBlue) }; + let rgb: RGB = { red: Math.round(rgbRed), green: Math.round(rgbGreen), blue: Math.round(rgbBlue) }; iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); } } @@ -3663,7 +3663,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let hexRed = parseInt(hex[1] + hex[2], 16); let hexGreen = parseInt(hex[3] + hex[4], 16); let hexBlue = parseInt(hex[5] + hex[6], 16); - let rgb = { red: Math.round(hexRed), green: Math.round(hexGreen), blue: Math.round(hexBlue) }; + let rgb: RGB = { red: Math.round(hexRed), green: Math.round(hexGreen), blue: Math.round(hexBlue) }; iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); } } @@ -7192,7 +7192,7 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem if (getState(id + '.HUE').val != null) { colorMode = 'enable'; let huecolor = hsv2rgb(getState(id + '.HUE').val, 1, 1); - let rgb = { red: Math.round(huecolor[0]), green: Math.round(huecolor[1]), blue: Math.round(huecolor[2]) } + let rgb: 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); } } @@ -7263,7 +7263,7 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem if (existsState(id + '.RED') && existsState(id + '.GREEN') && existsState(id + '.BLUE')) { if (getState(id + '.RED').val != null && getState(id + '.GREEN').val != null && getState(id + '.BLUE').val != null) { colorMode = 'enable'; - let rgb = { red: Math.round(getState(id + '.RED').val), green: Math.round(getState(id + '.GREEN').val), blue: Math.round(getState(id + '.BLUE').val) } + let rgb: RGB = { red: Math.round(getState(id + '.RED').val), green: Math.round(getState(id + '.GREEN').val), blue: Math.round(getState(id + '.BLUE').val) } iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); } } @@ -7338,7 +7338,7 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem let hexRed = parseInt(hex[1] + hex[2], 16); let hexGreen = parseInt(hex[3] + hex[4], 16); let hexBlue = parseInt(hex[5] + hex[6], 16); - let rgb = { red: Math.round(hexRed), green: Math.round(hexGreen), blue: Math.round(hexBlue) } + let rgb: RGB = { red: Math.round(hexRed), green: Math.round(hexGreen), blue: Math.round(hexBlue) } iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); } } @@ -9119,7 +9119,7 @@ on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESU }); //------------------End Read Internal Sensor Data -function formatInSelText(Text: string ) : string { +function formatInSelText(Text: string ): string { let splitText = Text.split(' '); let lengthLineOne = 0; let arrayLineOne: string[] = []; @@ -9171,44 +9171,46 @@ function rgb_dec565(rgb: RGB): number { return ((rgb.red >> 3) << 11) | ((rgb.green >> 2)) << 5 | ((rgb.blue) >> 3); } -/* Convert radians to degrees -rad - radians to convert, expects rad in range +/- PI per Math.atan2 -returns {number} degrees equivalent of rad -*/ -function rad2deg(rad) { +/** + * Convert radians to degrees + * @param rad radians to convert, expects rad in range +/- PI per Math.atan2 + * @returns {number} degrees equivalent of rad + */ +function rad2deg(rad): number { return (360 + 180 * rad / Math.PI) % 360; } -function ColorToHex(color) { - let hexadecimal = color.toString(16); +function ColorToHex(color): string { + let hexadecimal: string = color.toString(16); return hexadecimal.length == 1 ? '0' + hexadecimal : hexadecimal; } -function ConvertRGBtoHex(red: number, green: number, blue: Number) { +function ConvertRGBtoHex(red: number, green: number, blue: Number): string { 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 +/** + * Convert h,s,v values to r,g,b + * @param hue in range [0, 360] + * @param saturation in range 0 to 1 + * @param value in range 0 to 1 + * @returns {[number, number, number]} [r, g,b] in range 0 to 255 */ -function hsv2rgb(hue: number, saturation: number, value: number) { +function hsv2rgb(hue: number, saturation: number, value: number): [number, number, number] { hue /= 60; let chroma = value * saturation; let x = chroma * (1 - Math.abs((hue % 2) - 1)); - let rgb = hue <= 1 ? [chroma, x, 0] : + let rgb: [number, number, number] = hue <= 1 ? [chroma, x, 0] : hue <= 2 ? [x, chroma, 0] : hue <= 3 ? [0, chroma, x] : hue <= 4 ? [0, x, chroma] : hue <= 5 ? [x, 0, chroma] : [chroma, 0, x]; - return rgb.map(v => (v + value - chroma) * 255); + return rgb.map(v => (v + value - chroma) * 255) as [number, number, number]; } -function getHue(red: number, green: number, blue: number) { +function getHue(red: number, green: number, blue: number): number { let min = Math.min(Math.min(red, green), blue); let max = Math.max(Math.max(red, green), blue); @@ -9250,10 +9252,17 @@ function pos_to_color(x: number, y: number): RGB { let hsv = rad2deg(Math.atan2(y, x)); let rgb = hsv2rgb(hsv, sat, 1); - return { red: Math.round(rgb[0]), green: Math.round(rgb[1]), blue: Math.round(rgb[2]) }; + return { red: Math.round(rgb[0]), green: Math.round(rgb[1]), blue: Math.round(rgb[2]) }; } -function rgb_to_cie(red, green, blue) +/** + * + * @param red + * @param green + * @param blue + * @returns + */ +function rgb_to_cie(red: number, green: number, blue: number): string { //Apply a gamma correction to the RGB values, which makes the color more vivid and more the like the color displayed on the screen of your device let vred = (red > 0.04045) ? Math.pow((red + 0.055) / (1.0 + 0.055), 2.4) : (red / 12.92); @@ -9272,13 +9281,17 @@ function rgb_to_cie(red, green, blue) return cie; } - -function spotifyGetDeviceID(vDeviceString) { - const availableDeviceIDs = getState("spotify-premium.0.devices.availableDeviceListIds").val; - const availableDeviceNames = getState("spotify-premium.0.devices.availableDeviceListString").val; - let arrayDeviceListIds = availableDeviceIDs.split(";"); - let arrayDeviceListSting = availableDeviceNames.split(";"); - let indexPos = arrayDeviceListSting.indexOf(vDeviceString); +/** + * + * @param vDeviceString + * @returns + */ +function spotifyGetDeviceID(vDeviceString: string): string { + const availableDeviceIDs: string = getState("spotify-premium.0.devices.availableDeviceListIds").val; + const availableDeviceNames: string = getState("spotify-premium.0.devices.availableDeviceListString").val; + let arrayDeviceListIds: string[] = availableDeviceIDs.split(";"); + let arrayDeviceListSting: string[] = availableDeviceNames.split(";"); + let indexPos: number = arrayDeviceListSting.indexOf(vDeviceString); let strDevID = arrayDeviceListIds[indexPos]; return strDevID; } @@ -9297,138 +9310,138 @@ type Page = { type: string, heading: string, items: PageItem[], - useColor: (boolean | false), - subPage: (boolean | false), - parent: (Page | undefined), - parentIcon: (string | undefined), - parentIconColor: (RGB | undefined), - prev: (string | undefined), - prevIcon: (string | undefined), - prevIconColor: (RGB | undefined), - next: (string | undefined), - nextIcon: (string | undefined), - nextIconColor: (RGB | undefined), - home: (string | undefined), - homeIcon: (string | undefined), - homeIconColor: (RGB | undefined) + useColor: boolean, + subPage?: boolean, + parent?: Page, + parentIcon?: string, + parentIconColor?: RGB, + prev?: string, + prevIcon?: string, + prevIconColor?: RGB, + next?: string, + nextIcon?: string, + nextIconColor?: RGB, + home?: string, + homeIcon?: string, + homeIconColor?: RGB }; -interface PageEntities extends Page { +type PageEntities = { type: 'cardEntities', items: PageItem[], -} +} & Page -interface PageGrid extends Page { +type PageGrid = { type: 'cardGrid', items: PageItem[], -} +} & Page -interface PageGrid2 extends Page { +type PageGrid2 = { type: 'cardGrid2', items: PageItem[], -} +} & Page -interface PageThermo extends Page { +type PageThermo = { type: 'cardThermo', items: PageItem[], -} +} & Page -interface PageMedia extends Page { +type PageMedia = { type: 'cardMedia', items: PageItem[], -} +} & Page -interface PageAlarm extends Page { +type PageAlarm = { type: 'cardAlarm', items: PageItem[], -} +} & Page -interface PageUnlock extends Page { +type PageUnlock = { type: 'cardUnlock', items: PageItem[], -} +} & Page -interface PageQR extends Page { +type PageQR = { type: 'cardQR', items: PageItem[], -} +} & Page -interface PagePower extends Page { +type PagePower = { type: 'cardPower', items: PageItem[], -} +} & Page -interface PageChart extends Page { +type PageChart = { type: 'cardChart' | 'cardLChart', items: PageItem[], -} +} & Page type PageItem = { id: string, - icon: (string | undefined), - icon2: (string | undefined), - onColor: (RGB | undefined), - offColor: (RGB | undefined), - useColor: (boolean | undefined), - interpolateColor: (boolean | undefined), - minValueBrightness: (number | undefined), - maxValueBrightness: (number | undefined), - minValueColorTemp: (number | undefined), - maxValueColorTemp: (number | undefined), - minValueLevel: (number | undefined), - maxValueLevel: (number | undefined), - minValueTilt: (number | undefined), - maxValueTilt: (number | undefined), - minValue: (number | undefined), - maxValue: (number | undefined), - stepValue: (number | undefined), - prefixName: (string | undefined), - suffixName: (string | undefined), - name: (string | undefined), - secondRow: (string | undefined), - buttonText: (string | undefined), - unit: (string | undefined), - navigate: (boolean | undefined), - colormode: (string | undefined), - colorScale: (any | undefined), - adapterPlayerInstance: (string | undefined), - mediaDevice: (string | undefined), - targetPage: (string | undefined), - speakerList: (string[] | undefined), - playList: (string[] | undefined), - equalizerList: (string[] | undefined), - repeatList: (string[] | undefined), - globalTracklist: (string[] | undefined), - modeList: (string[] | undefined), - hidePassword: (boolean | undefined), - autoCreateALias: (boolean | undefined) - colorMediaIcon: (RGB | undefined), - colorMediaArtist: (RGB | undefined), - colorMediaTitle: (RGB | undefined), - popupThermoMode1: (string[] | undefined), - popupThermoMode2: (string[] | undefined), - popupThermoMode3: (string[] | undefined), - popUpThermoName: (string[] | undefined), - popupMediaMode1: (string[] | undefined), - popupMediaMode2: (string[] | undefined), - popupMediaMode3: (string[] | undefined), - popUpMediaName: (string[] | undefined), - setThermoAlias: (string[] | undefined), - setThermoDestTemp2: (string | undefined), - yAxis: (string | undefined), - yAxisTicks: (number[] | string | undefined), - xAxisDecorationId: (string | undefined), - popupType: (string | undefined), - popupOptions: (string[] | undefined), - useValue: (boolean | undefined), - monobutton: (boolean | undefined), - inSel_ChoiceState: (boolean | undefined), - iconArray: (string[] | undefined), - fontSize: (number | undefined), - actionStringArray: (string[] | undefined), - popupTimerType: (string | undefined), - alwaysOnDisplay: (boolean | undefined), - crossfade: (boolean | undefined), + icon?: string, + icon2?: string, + onColor?: RGB, + offColor?: RGB, + useColor?: boolean, + interpolateColor?: boolean, + minValueBrightness?: number, + maxValueBrightness?: number, + minValueColorTemp?: number, + maxValueColorTemp?: number, + minValueLevel?: number, + maxValueLevel?: number, + minValueTilt?: number, + maxValueTilt?: number, + minValue?: number, + maxValue?: number, + stepValue?: number, + prefixName?: string, + suffixName?: string, + name?: string, + secondRow?: string, + buttonText?: string, + unit?: string, + navigate?: boolean, + colormode?: string, + colorScale?: any, + adapterPlayerInstance?: string, + mediaDevice?: string, + targetPage?: string, + speakerList?: string[], + playList?: string[], + equalizerList?: string[], + repeatList?: string[], + globalTracklist?: string[], + modeList?: string[], + hidePassword?: boolean, + autoCreateALias?: boolean + colorMediaIcon?: RGB, + colorMediaArtist?: RGB, + colorMediaTitle?: RGB, + popupThermoMode1?: string[], + popupThermoMode2?: string[], + popupThermoMode3?: string[], + popUpThermoName?: string[], + popupMediaMode1?: string[], + popupMediaMode2?: string[], + popupMediaMode3?: string[], + popUpMediaName?: string[], + setThermoAlias?: string[], + setThermoDestTemp2?: string, + yAxis?: string, + yAxisTicks?: number[] | string, + xAxisDecorationId?: string, + popupType?: string, + popupOptions?: string[], + useValue?: boolean, + monobutton?: boolean, + inSel_ChoiceState?: boolean, + iconArray?: string[], + fontSize?: number, + actionStringArray?: string[], + popupTimerType?: string, + alwaysOnDisplay?: boolean, + crossfade?: boolean, } type DimMode = { @@ -9467,16 +9480,16 @@ type Config = { type ScreenSaverElement = { ScreensaverEntity: string, - ScreensaverEntityFactor?: number | 1, - ScreensaverEntityDecimalPlaces?: number | 0, + ScreensaverEntityFactor?: number, + ScreensaverEntityDecimalPlaces?: number, ScreensaverEntityDateFormat?: any | null, ScreensaverEntityIconOn?: string | null, ScreensaverEntityIconOff?: string | null, - ScreensaverEntityText: string | null, + ScreensaverEntityText: string, ScreensaverEntityUnitText?: string | null, ScreensaverEntityIconColor?: RGB | IconScaleElement | string - ScreensaverEntityOnColor?: any | null - ScreensaverEntityOffColor?: any | null + ScreensaverEntityOnColor?: RGB + ScreensaverEntityOffColor?: RGB ScreensaverEntityOnText?: string | null, ScreensaverEntityOffText?: string | null, } From 330e5fecdf3aedede61455d03145f89503231ddb Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Tue, 2 Jan 2024 15:51:48 +0100 Subject: [PATCH 19/99] v4.3.3.29 Update NSPanel.ts - Add Tasmota Buzzer for NotifyPage - Fix ThermoPage -> UnSubScribsWatcher --- ioBroker/NsPanelTs.ts | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 381add65..42a6e332 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -88,6 +88,8 @@ ReleaseNotes: - 30.12.2023 - v4.3.3.28 Fix short ID's in v4.3.3.27 - 30.12.2023 - v4.3.3.28 Fix window Icons in CreateEntity - 30.12.2023 - v4.3.3.28 Add MQTT-Client Check + - 02.01.2024 - v4.3.3.29 Add Tasmota Buzzer for NotifyPage + - 02.02.2024 - v4.3.3.29 Fix ThermoPage -> UnSubScribsWatcher Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -964,7 +966,7 @@ export const config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.28'; +const scriptVersion: string = 'v4.3.3.29'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -2002,9 +2004,11 @@ const popupNotifyLayout = NSPanel_Path + 'popupNotify.popupNotifyLayout'; const popupNotifyFontIdText = NSPanel_Path + 'popupNotify.popupNotifyFontIdText'; // 1 - 5 const popupNotifyIcon = NSPanel_Path + 'popupNotify.popupNotifyIcon'; // 1 - 5 const popupNotifyIconColor = NSPanel_Path + 'popupNotify.popupNotifyIconColor'; // 1 - 5 +const popupNotifyBuzzer = NSPanel_Path + 'popupNotify.popupNotifyBuzzer'; // 1,1,1 -> off 0 async function InitPopupNotify() { try { + if (!existsState(screensaverNotifyHeading)) { await createStateAsync(screensaverNotifyHeading, { type: 'string' }); await setStateAsync(screensaverNotifyHeading, { val: '', ack: true }); @@ -2030,6 +2034,7 @@ async function InitPopupNotify() { await createStateAsync(popupNotifyFontIdText, { type: 'number' }); await createStateAsync(popupNotifyIcon, { type: 'string' }); await createStateAsync(popupNotifyIconColor, { type: 'string' }); + await createStateAsync(popupNotifyBuzzer,{type: 'string', def: '0'}); // Notification to screensaver on({ id: [screensaverNotifyHeading, screensaverNotifyText], change: 'ne', ack: false }, async (obj) => { @@ -2049,6 +2054,7 @@ async function InitPopupNotify() { //on({ id: [popupNotifyInternalName], change: 'ne' }, async () => { on({ id: [].concat([popupNotifyText]), change: 'any' }, async() => { + let notification: string; let v_popupNotifyHeadingColor = (getState(popupNotifyHeadingColor).val != null) ? getState(popupNotifyHeadingColor).val : '65504'// Farbe Headline - gelb 65504 @@ -2058,7 +2064,8 @@ async function InitPopupNotify() { let v_popupNotifyIconColor = (getState(popupNotifyIconColor).val != null) ? getState(popupNotifyIconColor).val : '65535'// Farbe Icon - weiss 65535 let v_popupNotifyFontIdText = (getState(popupNotifyFontIdText).val != null) ? getState(popupNotifyFontIdText).val : '1' let v_popupNotifyIcon = (getState(popupNotifyIcon).val != null) ? getState(popupNotifyIcon).val : 'alert' - + let v_popupNotifyBuzzer = (getState(popupNotifyBuzzer).val != null) ? getState(popupNotifyBuzzer).val : '0'; + notification = 'entityUpdateDetail' + '~' + getState(popupNotifyInternalName).val + '~' + getState(popupNotifyHeading).val + '~' @@ -2081,6 +2088,35 @@ async function InitPopupNotify() { setIfExists(config.panelSendTopic, 'pageType~popupNotify'); setIfExists(config.panelSendTopic, notification); + //------ Tasmota Buzzer ------ + + if (v_popupNotifyBuzzer != '0') { + if (Debug){ + log('Tasmota Buzzer enabled. Value: ' + v_popupNotifyBuzzer, 'info'); + } + let urlString = `http://${get_current_tasmota_ip_address()}/cm?cmnd=Buzzer ${v_popupNotifyBuzzer}`; + if (tasmota_web_admin_password != '') { + urlString = `http://${get_current_tasmota_ip_address()}/cm?user=${tasmota_web_admin_user}&password=${tasmota_web_admin_password}&cmnd=Buzzer ${v_popupNotifyBuzzer}`; + } + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + log('Axios Data: ' + JSON.stringify(response.data), 'info'); + } else { + log('Axios Status - Tasmota Buzzer: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + } else { + if (Debug){ + log('Tasmota Buzzer disabled', 'info'); + } + } + //---- Tasmota Buzzer ----- + }); } catch (err) { log('error at function InitPopupNotify: ' + err.message, 'warn'); @@ -4198,6 +4234,7 @@ function GetUnitOfMeasurement(id: string): string { function GenerateThermoPage(page: PageThermo): Payload[] { try { + UnsubscribeWatcher(); let id = page.items[0].id let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~cardThermo' }); @@ -8446,7 +8483,7 @@ function HandleScreensaverStatusIcons() : void { if (hwBtn1 == 'ON') { hwBtn1Col = config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor; } - if (Debug) log(hwBtn1 + ' ' + hwBtn1Col, 'info') + if (Debug) log('Value: ' + hwBtn1 + ' Color: ' + JSON.stringify(hwBtn1Col), 'info') // Icon ermitteln if (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val) { From 9ddb6c783463c326aea0e8cc765a8c71fe2d4da7 Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Tue, 2 Jan 2024 15:53:38 +0100 Subject: [PATCH 20/99] Update NsPanelTs.ts --- ioBroker/NsPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 42a6e332..bde220a3 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.28 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne +TypeScript v4.3.3.29 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 From e2acb70a1c59113495698cf8f52cc98ad6071877 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 2 Jan 2024 17:36:30 +0100 Subject: [PATCH 21/99] some types --- ioBroker/NsPanelTs.ts | 108 +++++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 44 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 75faa033..d74cf3e8 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -451,7 +451,7 @@ let NSPanel_Service_SubPage: PageEntities = ] }; //Level_2 - let NSPanel_Wifi_Info_1: PageEntities = + let NSPanel_Wifi_Info_1: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('nspanel_wifi1'), @@ -467,7 +467,7 @@ let NSPanel_Service_SubPage: PageEntities = ] }; - let NSPanel_Wifi_Info_2: PageEntities = + let NSPanel_Wifi_Info_2: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('nspanel_wifi2'), @@ -2077,7 +2077,7 @@ InitPopupNotify(); let subscriptions: any = {}; let screensaverEnabled: boolean = false; let pageId = 0; -let activePage: Page | undefined = undefined; +let activePage: PageType | undefined = undefined; //Send time to NSPanel let scheduleSendTime = schedule('* * * * *', () => { @@ -2977,6 +2977,9 @@ function HandleMessage(typ: string, method: string, page: number | undefined, wo if (!isNaN(parseInt(tempPageItem[0]))){ tempId = activePage!.items[tempPageItem[0]].id; placeId = parseInt(tempPageItem[0]) + if (tempId == undefined) { + throw new Error(`Missing id in HandleMessage!`) + } } else { tempId = tempPageItem[0]; } @@ -3036,7 +3039,7 @@ function findPageItem(searching: String): PageItem { } } -function GeneratePage(page: Page): void { +function GeneratePage(page: PageType): void { try { activePage = page; setIfExists(NSPanel_Path + 'ActivePage.type', activePage!.type); @@ -3044,38 +3047,38 @@ function GeneratePage(page: Page): void { setIfExists(NSPanel_Path + 'ActivePage.id0', activePage!.items[0].id); switch (page.type) { case 'cardEntities': - SendToPanel(GenerateEntitiesPage(page)); + SendToPanel(GenerateEntitiesPage(page)); break; case 'cardThermo': - SendToPanel(GenerateThermoPage(page)); + SendToPanel(GenerateThermoPage(page)); break; case 'cardGrid': - SendToPanel(GenerateGridPage(page)); + SendToPanel(GenerateGridPage(page)); break; case 'cardGrid2': - SendToPanel(GenerateGridPage2(page)); + SendToPanel(GenerateGridPage2(page)); break; case 'cardMedia': useMediaEvents = true; - SendToPanel(GenerateMediaPage(page)); + SendToPanel(GenerateMediaPage(page)); break; case 'cardAlarm': - SendToPanel(GenerateAlarmPage(page)); + SendToPanel(GenerateAlarmPage(page)); break; case 'cardQR': - SendToPanel(GenerateQRPage(page)); + SendToPanel(GenerateQRPage(page)); break; case 'cardPower': - SendToPanel(GeneratePowerPage(page)); + SendToPanel(GeneratePowerPage(page)); break; case 'cardChart': - SendToPanel(GenerateChartPage(page)); + SendToPanel(GenerateChartPage(page)); break; case 'cardLChart': - SendToPanel(GenerateChartPage(page)); + SendToPanel(GenerateChartPage(page)); break; case 'cardUnlock': - SendToPanel(GenerateUnlockPage(page)); + SendToPanel(GenerateUnlockPage(page)); break; } } catch (err: any) { @@ -3200,7 +3203,7 @@ function GenerateGridPage2(page: PageGrid2): Payload[] { } } -function GeneratePageElements(page: Page): string { +function GeneratePageElements(page: PageType): string { try { activePage = page; let maxItems = 0; @@ -3245,7 +3248,7 @@ function GeneratePageElements(page: Page): string { for (let index = 0; index < maxItems; index++) { if (page.items[index] !== undefined) { - pageData += CreateEntity(page.items[index], index, page.useColor); + pageData += CreateEntity(page.items[index], index, 'useColor' in page ? page.useColor : false ); } } if (Debug) log('GeneratePageElements pageData ' + pageData, 'info'); @@ -3268,7 +3271,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let buttonText: string = 'PRESS'; let type: string; - if (existsState(pageItem.id + '.ACTUAL') == false) { + if (pageItem.id && existsState(pageItem.id + '.ACTUAL') == false) { if (pageItem.popupTimerType == 'TimeCard' && pageItem.autoCreateALias == true) { log(NSPanel_Path + 'Userdata.' + pageItem.id + '.Time') createStateAsync(NSPanel_Path + 'Userdata.' + pageItem.id + '.Time', '0', { type: 'number' }); @@ -3280,7 +3283,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } // ioBroker - if (existsObject(pageItem.id) || pageItem.navigate === true) { + if (pageItem.id && existsObject(pageItem.id) || pageItem.navigate === true) { let iconColor = rgb_dec565(config.defaultColor); let optVal = '0'; @@ -3824,7 +3827,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let valueScale = val; if (iconvalmin == 0 && iconvalmax == 1) { - iconColor = (getState(pageItem.id).val == 1) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); + iconColor = (!pageItem.id || getState(pageItem.id).val == 1) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); } else { if (iconvalbest == iconvalmin) { valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0); @@ -4204,7 +4207,7 @@ function GenerateThermoPage(page: PageThermo): Payload[] { out_msgs.push({ payload: 'pageType~cardThermo' }); // ioBroker - if (existsObject(id)) { + if (id && existsObject(id)) { let o = getObject(id); let name = page.heading !== undefined ? page.heading : o.common.name.de; let currentTemp = 0; @@ -4819,9 +4822,11 @@ function GenerateMediaPage(page: PageMedia): Payload[] { try { unsubscribeMediaSubscriptions(); + if (!page.items[0].id) throw new Error ('Missing page id for cardMedia!'); + let id = page.items[0].id; let out_msgs: Array = []; - + if (!page.items[0].adapterPlayerInstance!) throw new Error('page.items[0].adapterPlayerInstance is undefined!') let vInstance = page.items[0].adapterPlayerInstance!; let v1Adapter = vInstance.split('.'); @@ -4829,7 +4834,7 @@ function GenerateMediaPage(page: PageMedia): Payload[] { // Some magic to change the ID of the alias, since speakers are not a property but separate objects if(v2Adapter == 'squeezeboxrpc') { - if(getObject(id).type != 'channel') { + if(id && getObject(id).type != 'channel') { id = id + '.' + page.items[0].mediaDevice; page.items[0].id = id; page.heading = page.items[0].mediaDevice ?? ''; @@ -5385,6 +5390,7 @@ async function createAutoAlarmAlias (id: string, nsPath: string){ function GenerateAlarmPage(page: PageAlarm): Payload[] { try { activePage = page; + let id = page.items[0].id let name = page.heading; @@ -5393,6 +5399,7 @@ function GenerateAlarmPage(page: PageAlarm): Payload[] { let nsPath = NSPanel_Alarm_Path + 'Alarm'; if (page.items[0].autoCreateALias) { + if (!id) throw new Error ('Missing pageItem.id for cardAlarm! Property autoCreateAlias is true!'); createAutoAlarmAlias(id, nsPath); } @@ -5556,6 +5563,7 @@ function GenerateUnlockPage(page: PageUnlock): Payload[] { dpPath = (dpPath + 'Unlock.'); if (page.items[0].autoCreateALias) { + if (!id) throw new Error ('Missing pageItem.id for cardUnlock! Property autoCreateAlias is true!'); createAutoUnlockAlias(id, dpPath) } @@ -5623,7 +5631,7 @@ async function createAutoQRAlias(id:string, dpPath:string) { function GenerateQRPage(page: PageQR): Payload[] { try { activePage = page; - + if (!page.items[0].id) throw new Error ('Missing pageItem.id for cardQRPage!'); let id = page.items[0].id; let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~cardQR' }); @@ -5741,6 +5749,8 @@ function subscribePowerSubscriptions(id: string): void { function GeneratePowerPage(page: PagePower): Payload[] { try { + if (!page.items[0].id) throw new Error ('Missing pageItem.id for PowerPage!'); + let obj:object = {}; let demoMode = false; if (page.items[0].id == undefined){ @@ -5962,7 +5972,8 @@ function HandleButtonEvent(words: any): void { let pageItemID: string = ''; if (!isNaN(id)) { - pageItemID = activePage!.items[id].id; + if (activePage!.items[id].id == undefined) throw new Error ('Missing pageItem.id in HandleButtonEvent!'); + pageItemID = activePage!.items[id].id!; if (Debug) { log('HandleButtonEvent activePage: ' + activePage!.items.length + ' id: ' + id + ' tempid: ' + tempid + ' pageItemId: ' + pageItemID); } @@ -7046,7 +7057,7 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem let out_msgs: Array = []; let id = pageItem.id; - if (existsObject(id)) { + if (id && existsObject(id)) { let o = getObject(id); let val: (boolean | number) = 0; @@ -7898,7 +7909,7 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem optionalString = pageItem.playList != undefined ? tempTrackList.join('?') : '' mode = 'tracklist'; } else if (optional == 'equalizer') { - + if (pageItem.id == undefined) throw new Error ('Missing pageItem.id in equalizer!'); let lastIndex = (pageItem.id.split('.')).pop(); if (existsObject(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode') == false || @@ -9306,13 +9317,13 @@ type Payload = { payload: string; }; -type Page = { - type: string, +type PageBaseType = { + type: PagetypeType, heading: string, items: PageItem[], useColor: boolean, subPage?: boolean, - parent?: Page, + parent?: PageType, parentIcon?: string, parentIconColor?: RGB, prev?: string, @@ -9326,58 +9337,67 @@ type Page = { homeIconColor?: RGB }; +type PagetypeType = 'cardChart' | 'cardLChart' | 'cardEntities' |'cardGrid'|'cardGrid2'|'cardThermo'|'cardMedia'|'cardUnlock'|'cardQR'|'cardAlarm'|'cardPower' + +type PageType = PageChart | PageEntities | PageGrid | PageGrid2 | PageThermo | PageMedia | PageUnlock | PageQR | PageAlarm | PagePower + +// If u get a error here u forgot something in PagetypeType or PageType +function checkPageType(F: PagetypeType, A: PageType) { + A.type = F; +} + type PageEntities = { type: 'cardEntities', items: PageItem[], -} & Page +} & PageBaseType type PageGrid = { type: 'cardGrid', items: PageItem[], -} & Page +} & PageBaseType type PageGrid2 = { type: 'cardGrid2', items: PageItem[], -} & Page +} & PageBaseType type PageThermo = { type: 'cardThermo', items: PageItem[], -} & Page +} & PageBaseType type PageMedia = { type: 'cardMedia', items: PageItem[], -} & Page +} & PageBaseType type PageAlarm = { type: 'cardAlarm', items: PageItem[], -} & Page +} & PageBaseType type PageUnlock = { type: 'cardUnlock', items: PageItem[], -} & Page +} & PageBaseType type PageQR = { type: 'cardQR', items: PageItem[], -} & Page +} & PageBaseType type PagePower = { type: 'cardPower', items: PageItem[], -} & Page +} & PageBaseType type PageChart = { type: 'cardChart' | 'cardLChart', items: PageItem[], -} & Page +} & Omit type PageItem = { - id: string, + id?: string | null, icon?: string, icon2?: string, onColor?: RGB, @@ -9472,8 +9492,8 @@ type Config = { defaultOnColor: RGB, defaultOffColor: RGB, defaultBackgroundColor: RGB, - pages: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PageGrid2 | PagePower | PageChart | PageUnlock )[], - subPages: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PageGrid2 | PagePower | PageChart | PageUnlock)[], + pages: PageType[], + subPages: PageType[], button1: ConfigButtonFunction, button2: ConfigButtonFunction } @@ -9509,4 +9529,4 @@ type IconScaleElement = { val_min:number, val_max:number, val_best?: number -} +} \ No newline at end of file From e87febc54afe4b68253a5ba94e1776bfc1f33fa2 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 2 Jan 2024 17:44:44 +0100 Subject: [PATCH 22/99] cardUnlock partial usecolor --- ioBroker/NsPanelTs.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 644e59dd..1ea472bd 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -9401,32 +9401,32 @@ type PageGrid2 = { type PageThermo = { type: 'cardThermo', items: PageItem[], -} & PageBaseType +} & Omit type PageMedia = { type: 'cardMedia', items: PageItem[], -} & PageBaseType +} & Omit type PageAlarm = { type: 'cardAlarm', items: PageItem[], -} & PageBaseType +} & Omit type PageUnlock = { type: 'cardUnlock', items: PageItem[], -} & PageBaseType +} & Omit & Partial> type PageQR = { type: 'cardQR', items: PageItem[], -} & PageBaseType +} & Omit type PagePower = { type: 'cardPower', items: PageItem[], -} & PageBaseType +} & Omit type PageChart = { type: 'cardChart' | 'cardLChart', From 8bfa6deb76d37bb21c484affc3b98141f2672d14 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 2 Jan 2024 17:52:31 +0100 Subject: [PATCH 23/99] Add version --- ioBroker/NsPanelTs.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 1ea472bd..9c098da4 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.29 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne +TypeScript v4.3.3.30 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -90,6 +90,7 @@ ReleaseNotes: - 30.12.2023 - v4.3.3.28 Add MQTT-Client Check - 02.01.2024 - v4.3.3.29 Add Tasmota Buzzer for NotifyPage - 02.02.2024 - v4.3.3.29 Fix ThermoPage -> UnSubScribsWatcher + - 02.02.2024 - v4.3.3.30 Add stronger config type checks Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -952,7 +953,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.29'; +const scriptVersion: string = 'v4.3.3.30'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; From 4e7119768bc13b5748b4ccf0bd7c7851c7099422 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 2 Jan 2024 18:32:39 +0100 Subject: [PATCH 24/99] PageType in config --- ioBroker/NsPanelTs.ts | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 9c098da4..6c719b67 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -395,7 +395,7 @@ let Debug: boolean = false; */ //Level 0 (if service pages are used with cardUnlock) -let Unlock_Service: PageUnlock = +let Unlock_Service: PageType = { 'type': 'cardUnlock', 'heading': findLocaleServMenu('service_pages'), @@ -407,7 +407,7 @@ let Unlock_Service: PageUnlock = }; //Level_0 (if service pages are used without cardUnlock) -let NSPanel_Service: PageEntities = +let NSPanel_Service: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('service_menu'), @@ -421,7 +421,7 @@ let NSPanel_Service: PageEntities = }; //Level_0 (if service pages are used with cardUnlock) -let NSPanel_Service_SubPage: PageEntities = +let NSPanel_Service_SubPage: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('service_menu'), @@ -438,7 +438,7 @@ let NSPanel_Service_SubPage: PageEntities = }; //Level_1 - let NSPanel_Infos: PageEntities = + let NSPanel_Infos: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('nspanel_infos'), @@ -486,7 +486,7 @@ let NSPanel_Service_SubPage: PageEntities = ] }; - let NSPanel_Sensoren: PageEntities = + let NSPanel_Sensoren: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('sensors1'), @@ -518,7 +518,7 @@ let NSPanel_Service_SubPage: PageEntities = ] }; - let NSPanel_IoBroker: PageEntities = + let NSPanel_IoBroker: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('info_iobroker'), @@ -534,7 +534,7 @@ let NSPanel_Service_SubPage: PageEntities = }; //Level_1 - let NSPanel_Einstellungen: PageGrid = + let NSPanel_Einstellungen: PageType = { 'type': 'cardGrid', 'heading': findLocaleServMenu('settings'), @@ -556,7 +556,7 @@ let NSPanel_Service_SubPage: PageEntities = }; //Level_2 - let NSPanel_Screensaver: PageGrid = + let NSPanel_Screensaver: PageType = { 'type': 'cardGrid', 'heading': findLocaleServMenu('screensaver'), @@ -575,7 +575,7 @@ let NSPanel_Service_SubPage: PageEntities = }; //Level_3 - let NSPanel_ScreensaverDimmode: PageEntities = + let NSPanel_ScreensaverDimmode: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('dimmode'), @@ -592,7 +592,7 @@ let NSPanel_Service_SubPage: PageEntities = }; //Level_3 - let NSPanel_ScreensaverBrightness: PageEntities = + let NSPanel_ScreensaverBrightness: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('brightness'), @@ -608,7 +608,7 @@ let NSPanel_Service_SubPage: PageEntities = }; //Level_3 - let NSPanel_ScreensaverLayout: PageEntities = + let NSPanel_ScreensaverLayout: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('layout'), @@ -623,7 +623,7 @@ let NSPanel_Service_SubPage: PageEntities = }; //Level_3 - let NSPanel_ScreensaverWeather: PageEntities = + let NSPanel_ScreensaverWeather: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('weather_parameters'), @@ -640,7 +640,7 @@ let NSPanel_Service_SubPage: PageEntities = }; //Level_3 - let NSPanel_ScreensaverDateformat: PageEntities = + let NSPanel_ScreensaverDateformat: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('date_format'), @@ -655,7 +655,7 @@ let NSPanel_Service_SubPage: PageEntities = }; //Level_3 - let NSPanel_ScreensaverIndicators: PageEntities = + let NSPanel_ScreensaverIndicators: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('indicators'), @@ -670,7 +670,7 @@ let NSPanel_Service_SubPage: PageEntities = }; //Level_2 - let NSPanel_Relays: PageEntities = + let NSPanel_Relays: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('relays'), @@ -685,7 +685,7 @@ let NSPanel_Service_SubPage: PageEntities = }; //Level_2 - let NSPanel_Script: PageEntities = + let NSPanel_Script: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('script'), @@ -700,7 +700,7 @@ let NSPanel_Service_SubPage: PageEntities = }; //Level_1 - let NSPanel_Firmware: PageEntities = + let NSPanel_Firmware: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('firmware'), @@ -716,7 +716,7 @@ let NSPanel_Service_SubPage: PageEntities = ] }; - let NSPanel_FirmwareTasmota: PageEntities = + let NSPanel_FirmwareTasmota: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('tasmota'), @@ -732,7 +732,7 @@ let NSPanel_Service_SubPage: PageEntities = ] }; - let NSPanel_FirmwareBerry: PageEntities = + let NSPanel_FirmwareBerry: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('berry_driver'), @@ -748,7 +748,7 @@ let NSPanel_Service_SubPage: PageEntities = ] }; - let NSPanel_FirmwareNextion: PageEntities = + let NSPanel_FirmwareNextion: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('nextion_tft'), From 73a0ba468edbe6509ad2f928780845559636c8be Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 2 Jan 2024 19:58:44 +0100 Subject: [PATCH 25/99] ticaki for ever --- ioBroker/NsPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 6c719b67..45f0d09d 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.30 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne +TypeScript v4.3.3.30 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne /@ticaki - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 From 360fb881f14bdd4eb7c1bd9a2bd199df9f653f49 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Tue, 2 Jan 2024 22:52:47 +0100 Subject: [PATCH 26/99] v4.3.3.30 - Update NsPanelTs.ts by Ticaki MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Überarbeitung der Types - Verbesserung der Variablenprüfung - Bessere Fehleranzeige in der Konfiguration --- ioBroker/NsPanelTs.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 45f0d09d..c65e43e1 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.30 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @Sternmiere / @Britzelpuf / @ravenS0ne /@ticaki +TypeScript v4.3.3.30 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Sternmiere / @Britzelpuf / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -9567,4 +9567,4 @@ type IconScaleElement = { val_min:number, val_max:number, val_best?: number -} \ No newline at end of file +} From b14687cb301938dd60e9b720e851da818fe25ffc Mon Sep 17 00:00:00 2001 From: ticaki Date: Wed, 3 Jan 2024 17:02:32 +0100 Subject: [PATCH 27/99] some more types --- ioBroker/NsPanelTs.ts | 1363 ++++++++++++++++++++++------------------- 1 file changed, 719 insertions(+), 644 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index c65e43e1..16cae287 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.30 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Sternmiere / @Britzelpuf / @ravenS0ne +TypeScript v4.3.3.31 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Sternmiere / @Britzelpuf / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -91,6 +91,9 @@ ReleaseNotes: - 02.01.2024 - v4.3.3.29 Add Tasmota Buzzer for NotifyPage - 02.02.2024 - v4.3.3.29 Fix ThermoPage -> UnSubScribsWatcher - 02.02.2024 - v4.3.3.30 Add stronger config type checks + - 03.02.2024 - v4.3.3.31 Remove: autoCreateAlias from cardMedia + - 03.02.2024 - v4.3.3.31 Remove: adapterPlayerInstance from every card except cardMedia + - 03.02.2024 - v4.3.3.31 [dev]: optional with type - cardMedia has adapterPlayerInstance all other not Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -953,7 +956,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.30'; +const scriptVersion: string = 'v4.3.3.31'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -3022,7 +3025,9 @@ function HandleMessage(typ: string, method: string, page: number | undefined, wo } let pageItem: PageItem = findPageItem(tempId); if (pageItem !== undefined) { - SendToPanel(GenerateDetailPage(words[2], tempPageItem[1], pageItem, placeId)); + let temp: string | mediaOptional | undefined = tempPageItem[1] + if (isMediaOptional(temp)) SendToPanel(GenerateDetailPage(words[2], temp, pageItem, placeId)); + else SendToPanel(GenerateDetailPage(words[2], undefined, pageItem, placeId)); } } break; @@ -4286,288 +4291,290 @@ function GenerateThermoPage(page: PageThermo): Payload[] { if ((i_list.length - 3) != 0) { let i = 0; + switch (o.common.role) { + case 'thermostat': { - if (o.common.role == 'thermostat') { - - if (existsState(id + '.AUTOMATIC') && getState(id + '.AUTOMATIC').val != null) { - if (getState(id + '.AUTOMATIC').val) { - bt[i++] = Icons.GetIcon('alpha-a-circle') + '~' + rgb_dec565(On) + '~1~' + 'AUTT' + '~'; - statusStr = 'AUTO'; - } else { - bt[i++] = Icons.GetIcon('alpha-a-circle') + '~33840~1~' + 'AUTT' + '~'; - } - } - if (existsState(id + '.MANUAL') && getState(id + '.MANUAL').val != null) { - if (getState(id + '.MANUAL').val) { - bt[i++] = Icons.GetIcon('alpha-m-circle') + '~' + rgb_dec565(On) + '~1~' + 'MANT' + '~'; - statusStr = 'MANU'; - } else { - bt[i++] = Icons.GetIcon('alpha-m-circle') + '~33840~1~' + 'MANT' + '~'; - } - } - if (existsState(id + '.PARTY') && getState(id + '.PARTY').val != null) { - if (getState(id + '.PARTY').val) { - bt[i++] = Icons.GetIcon('party-popper') + '~' + rgb_dec565(On) + '~1~' + 'PART' + '~'; - statusStr = 'PARTY'; - } else { - bt[i++] = Icons.GetIcon('party-popper') + '~33840~1~' + 'PART' + '~'; - } - } - if (existsState(id + '.VACATION') && getState(id + '.VACATION').val != null) { - if (getState(id + '.VACATION').val) { - bt[i++] = Icons.GetIcon('palm-tree') + '~' + rgb_dec565(On) + '~1~' + 'VACT' + '~'; - statusStr = 'VAC'; - } else { - bt[i++] = Icons.GetIcon('palm-tree') + '~33840~1~' + 'VACT' + '~'; - } - } - if (existsState(id + '.BOOST') && getState(id + '.BOOST').val != null) { - if (getState(id + '.BOOST').val) { - bt[i++] = Icons.GetIcon('fast-forward-60') + '~' + rgb_dec565(On) + '~1~' + 'BOOT' + '~'; - statusStr = 'BOOST'; - } else { - bt[i++] = Icons.GetIcon('fast-forward-60') + '~33840~1~' + 'BOOT' + '~'; - } - } - - for (let i_index in i_list) { - let thermostatState = i_list[i_index].split('.'); - if ( - thermostatState[thermostatState.length - 1] != 'SET' && - thermostatState[thermostatState.length - 1] != 'ACTUAL' && - thermostatState[thermostatState.length - 1] != 'MODE' - ) { - i++; - - switch (thermostatState[thermostatState.length - 1]) { - case 'HUMIDITY': - if (existsState(id + '.HUMIDITY') && getState(id + '.HUMIDITY').val != null) { - if (parseInt(getState(id + '.HUMIDITY').val) < 40) { - bt[i - 1] = Icons.GetIcon('water-percent') + '~65504~1~' + 'HUM' + '~'; - } else if (parseInt(getState(id + '.HUMIDITY').val) < 30) { - bt[i - 1] = Icons.GetIcon('water-percent') + '~63488~1~' + 'HUM' + '~'; - } else if (parseInt(getState(id + '.HUMIDITY').val) >= 40) { - bt[i - 1] = Icons.GetIcon('water-percent') + '~2016~1~' + 'HUM' + '~'; - } else if (parseInt(getState(id + '.HUMIDITY').val) > 65) { - bt[i - 1] = Icons.GetIcon('water-percent') + '~65504~1~' + 'HUM' + '~'; - } else if (parseInt(getState(id + '.HUMIDITY').val) > 75) { - bt[i - 1] = Icons.GetIcon('water-percent') + '~63488~1~' + 'HUM' + '~'; - } - } else i--; - break; - case 'LOWBAT': - if (existsState(id + '.LOWBAT') && getState(id + '.LOWBAT').val != null) { - if (getState(id + '.LOWBAT').val) { - bt[i - 1] = Icons.GetIcon('battery-low') + '~63488~1~' + 'LBAT' + '~'; - } else { - bt[i - 1] = Icons.GetIcon('battery-high') + '~2016~1~' + 'LBAT' + '~'; - } - } else i--; - break; - case 'MAINTAIN': - if (existsState(id + '.MAINTAIN') && getState(id + '.MAINTAIN').val != null) { - if (getState(id + '.MAINTAIN').val >> .1) { - bt[i - 1] = Icons.GetIcon('account-wrench') + '~60897~1~' + 'MAIN' + '~'; - } else { - bt[i - 1] = Icons.GetIcon('account-wrench') + '~33840~1~' + 'MAIN' + '~'; - } - } else i--; - break; - case 'UNREACH': - if (existsState(id + '.UNREACH') && getState(id + '.UNREACH').val != null) { - if (getState(id + '.UNREACH').val) { - bt[i - 1] = Icons.GetIcon('wifi-off') + '~63488~1~' + 'WLAN' + '~'; - } else { - bt[i - 1] = Icons.GetIcon('wifi') + '~2016~1~' + 'WLAN' + '~'; - } - } else i--; - break; - case 'POWER': - if (existsState(id + '.POWER') && getState(id + '.POWER').val != null) { - if (getState(id + '.POWER').val) { - bt[i - 1] = Icons.GetIcon('power-standby') + '~2016~1~' + '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~' + 'ERR' + '~'; - } else { - bt[i - 1] = Icons.GetIcon('alert-circle') + '~33840~1~' + 'ERR' + '~'; - } - } else i--; - break; - case 'WORKING': - if (existsState(id + '.WORKING') && getState(id + '.WORKING').val != null) { - if (getState(id + '.WORKING').val) { - bt[i - 1] = Icons.GetIcon('briefcase-check') + '~2016~1~' + 'WORK' + '~'; - } else { - bt[i - 1] = Icons.GetIcon('briefcase-check') + '~33840~1~' + 'WORK' + '~'; - } - } else i--; - break; - case 'WINDOWOPEN': - if (existsState(id + '.WINDOWOPEN') && getState(id + '.WINDOWOPEN').val != null) { - if (getState(id + '.WINDOWOPEN').val) { - bt[i - 1] = Icons.GetIcon('window-open-variant') + '~63488~1~' + 'WIN' + '~'; - } else { - bt[i - 1] = Icons.GetIcon('window-closed-variant') + '~2016~1~' + 'WIN' + '~'; - } - } else i--; - break; - default: - i--; - break; - } - } - } - - for (let j = i; j < 9; j++) { - bt[j] = '~~~~'; - } - } - - if (o.common.role == 'airCondition') { - if (existsState(id + '.MODE') && getState(id + '.MODE').val != null) { - let Mode = getState(id + '.MODE').val - let States = getObject(id + '.MODE').common.states; - - let iconIndex: number = 1; - for(const statekey in States) { - let stateName: string = States[statekey]; - let stateKeyNumber: number = parseInt(statekey); - if(stateName == 'OFF' || stateKeyNumber > 6) { - continue; - } - if(stateKeyNumber == Mode) { - statusStr = stateName.replace('_', ' '); - } - - switch(stateName) { - case 'AUTO': - if (page.items[0].iconArray !== undefined && page.items[0].iconArray[1] !== '') { - tempIcon = page.items[0].iconArray[1]; - } else { - tempIcon = 'air-conditioner'; - } - if(stateKeyNumber == Mode) { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~1024~1~' + 'AUTO' + '~'; - } else { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'AUTO' + '~'; - } - break; - case 'COOL': - if (page.items[0].iconArray !== undefined && page.items[0].iconArray[2] !== '') { - tempIcon = page.items[0].iconArray[2]; - } else { - tempIcon = 'snowflake'; - } - if(stateKeyNumber == Mode) { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~11487~1~' + 'COOL' + '~'; - } else { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'COOL' + '~'; - } - break; - case 'HEAT': - if (page.items[0].iconArray !== undefined && page.items[0].iconArray[3] !== '') { - tempIcon = page.items[0].iconArray[3]; - } else { - tempIcon = 'fire'; - } - if(stateKeyNumber == Mode) { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~64512~1~' + 'HEAT' + '~'; - } else { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'HEAT' + '~'; - } - break; - case 'ECO': - if (page.items[0].iconArray !== undefined && page.items[0].iconArray[4] !== '') { - tempIcon = page.items[0].iconArray[4]; - } else { - tempIcon = 'alpha-e-circle-outline'; - } - if(stateKeyNumber == Mode) { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~2016~1~' + 'ECO' + '~'; - } else { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'ECO' + '~'; - } - break; - case 'FAN_ONLY': - if (page.items[0].iconArray !== undefined && page.items[0].iconArray[5] !== '') { - tempIcon = page.items[0].iconArray[5]; - } else { - tempIcon = 'fan'; - } - if(stateKeyNumber == Mode) { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~11487~1~' + 'FAN_ONLY' + '~'; - } else { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'FAN_ONLY' + '~'; - } - break; - case 'DRY': - if (page.items[0].iconArray !== undefined && page.items[0].iconArray[6] !== '') { - tempIcon = page.items[0].iconArray[6]; - } else { - tempIcon = 'water-percent'; - } - if(stateKeyNumber == Mode) { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~60897~1~' + 'DRY' + '~'; - } else { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'DRY' + '~'; - } - break; - } - iconIndex++; - } - - if (iconIndex <= 7 && existsState(id + '.ECO') && getState(id + '.ECO').val != null) { - if (page.items[0].iconArray !== undefined && page.items[0].iconArray[4] !== '') { - tempIcon = page.items[0].iconArray[4]; + if (existsState(id + '.AUTOMATIC') && getState(id + '.AUTOMATIC').val != null) { + if (getState(id + '.AUTOMATIC').val) { + bt[i++] = Icons.GetIcon('alpha-a-circle') + '~' + rgb_dec565(On) + '~1~' + 'AUTT' + '~'; + statusStr = 'AUTO'; } else { - tempIcon = 'alpha-e-circle-outline'; + bt[i++] = Icons.GetIcon('alpha-a-circle') + '~33840~1~' + 'AUTT' + '~'; } - if (getState(id + '.ECO').val && getState(id + '.ECO').val == 1) { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~2016~1~' + 'ECO' + '~'; - statusStr = 'ECO'; + } + if (existsState(id + '.MANUAL') && getState(id + '.MANUAL').val != null) { + if (getState(id + '.MANUAL').val) { + bt[i++] = Icons.GetIcon('alpha-m-circle') + '~' + rgb_dec565(On) + '~1~' + 'MANT' + '~'; + statusStr = 'MANU'; } else { - bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'ECO' + '~'; + bt[i++] = Icons.GetIcon('alpha-m-circle') + '~33840~1~' + 'MANT' + '~'; + } + } + if (existsState(id + '.PARTY') && getState(id + '.PARTY').val != null) { + if (getState(id + '.PARTY').val) { + bt[i++] = Icons.GetIcon('party-popper') + '~' + rgb_dec565(On) + '~1~' + 'PART' + '~'; + statusStr = 'PARTY'; + } else { + bt[i++] = Icons.GetIcon('party-popper') + '~33840~1~' + 'PART' + '~'; + } + } + if (existsState(id + '.VACATION') && getState(id + '.VACATION').val != null) { + if (getState(id + '.VACATION').val) { + bt[i++] = Icons.GetIcon('palm-tree') + '~' + rgb_dec565(On) + '~1~' + 'VACT' + '~'; + statusStr = 'VAC'; + } else { + bt[i++] = Icons.GetIcon('palm-tree') + '~33840~1~' + 'VACT' + '~'; + } + } + if (existsState(id + '.BOOST') && getState(id + '.BOOST').val != null) { + if (getState(id + '.BOOST').val) { + bt[i++] = Icons.GetIcon('fast-forward-60') + '~' + rgb_dec565(On) + '~1~' + 'BOOT' + '~'; + statusStr = 'BOOST'; + } else { + bt[i++] = Icons.GetIcon('fast-forward-60') + '~33840~1~' + 'BOOT' + '~'; } - iconIndex++; } - if (iconIndex <= 7 && existsState(id + '.SWING') && getState(id + '.SWING').val != null) { - if (page.items[0].iconArray !== undefined && page.items[0].iconArray[7] !== '') { - tempIcon = page.items[0].iconArray[7]; - } else { - tempIcon = 'swap-vertical-bold'; + for (let i_index in i_list) { + let thermostatState = i_list[i_index].split('.'); + if ( + thermostatState[thermostatState.length - 1] != 'SET' && + thermostatState[thermostatState.length - 1] != 'ACTUAL' && + thermostatState[thermostatState.length - 1] != 'MODE' + ) { + i++; + + switch (thermostatState[thermostatState.length - 1]) { + case 'HUMIDITY': + if (existsState(id + '.HUMIDITY') && getState(id + '.HUMIDITY').val != null) { + if (parseInt(getState(id + '.HUMIDITY').val) < 40) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~65504~1~' + 'HUM' + '~'; + } else if (parseInt(getState(id + '.HUMIDITY').val) < 30) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~63488~1~' + 'HUM' + '~'; + } else if (parseInt(getState(id + '.HUMIDITY').val) >= 40) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~2016~1~' + 'HUM' + '~'; + } else if (parseInt(getState(id + '.HUMIDITY').val) > 65) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~65504~1~' + 'HUM' + '~'; + } else if (parseInt(getState(id + '.HUMIDITY').val) > 75) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~63488~1~' + 'HUM' + '~'; + } + } else i--; + break; + case 'LOWBAT': + if (existsState(id + '.LOWBAT') && getState(id + '.LOWBAT').val != null) { + if (getState(id + '.LOWBAT').val) { + bt[i - 1] = Icons.GetIcon('battery-low') + '~63488~1~' + 'LBAT' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('battery-high') + '~2016~1~' + 'LBAT' + '~'; + } + } else i--; + break; + case 'MAINTAIN': + if (existsState(id + '.MAINTAIN') && getState(id + '.MAINTAIN').val != null) { + if (getState(id + '.MAINTAIN').val >> .1) { + bt[i - 1] = Icons.GetIcon('account-wrench') + '~60897~1~' + 'MAIN' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('account-wrench') + '~33840~1~' + 'MAIN' + '~'; + } + } else i--; + break; + case 'UNREACH': + if (existsState(id + '.UNREACH') && getState(id + '.UNREACH').val != null) { + if (getState(id + '.UNREACH').val) { + bt[i - 1] = Icons.GetIcon('wifi-off') + '~63488~1~' + 'WLAN' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('wifi') + '~2016~1~' + 'WLAN' + '~'; + } + } else i--; + break; + case 'POWER': + if (existsState(id + '.POWER') && getState(id + '.POWER').val != null) { + if (getState(id + '.POWER').val) { + bt[i - 1] = Icons.GetIcon('power-standby') + '~2016~1~' + '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~' + 'ERR' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('alert-circle') + '~33840~1~' + 'ERR' + '~'; + } + } else i--; + break; + case 'WORKING': + if (existsState(id + '.WORKING') && getState(id + '.WORKING').val != null) { + if (getState(id + '.WORKING').val) { + bt[i - 1] = Icons.GetIcon('briefcase-check') + '~2016~1~' + 'WORK' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('briefcase-check') + '~33840~1~' + 'WORK' + '~'; + } + } else i--; + break; + case 'WINDOWOPEN': + if (existsState(id + '.WINDOWOPEN') && getState(id + '.WINDOWOPEN').val != null) { + if (getState(id + '.WINDOWOPEN').val) { + bt[i - 1] = Icons.GetIcon('window-open-variant') + '~63488~1~' + 'WIN' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('window-closed-variant') + '~2016~1~' + 'WIN' + '~'; + } + } else i--; + break; + default: + i--; + break; + } } - if (getState(id + '.POWER').val && getState(id + '.SWING').val == 1) { //0=ON oder .SWING = true - bt[7] = Icons.GetIcon(tempIcon) + '~2016~1~' + 'SWING' + '~'; - } else { - bt[7] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'SWING' + '~'; - } - iconIndex++; } - // Power Icon zuletzt pruefen, damit der Mode ggf. mit OFF ueberschrieben werden kann - if (existsState(id + '.POWER') && getState(id + '.POWER').val != null) { - if (page.items[0].iconArray !== undefined && page.items[0].iconArray[0] !== '') { - tempIcon = page.items[0].iconArray[0]; - } else { - tempIcon = 'power-standby'; + for (let j = i; j < 9; j++) { + bt[j] = '~~~~'; + } + } + break; + case 'airCondition': { + if (existsState(id + '.MODE') && getState(id + '.MODE').val != null) { + let Mode = getState(id + '.MODE').val + let States = getObject(id + '.MODE').common.states; + + let iconIndex: number = 1; + for (const statekey in States) { + let stateName: string = States[statekey]; + let stateKeyNumber: number = parseInt(statekey); + if (stateName == 'OFF' || stateKeyNumber > 6) { + continue; + } + if (stateKeyNumber == Mode) { + statusStr = stateName.replace('_', ' '); + } + + switch (stateName) { + case 'AUTO': + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[1] !== '') { + tempIcon = page.items[0].iconArray[1]; + } else { + tempIcon = 'air-conditioner'; + } + if (stateKeyNumber == Mode) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~1024~1~' + 'AUTO' + '~'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'AUTO' + '~'; + } + break; + case 'COOL': + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[2] !== '') { + tempIcon = page.items[0].iconArray[2]; + } else { + tempIcon = 'snowflake'; + } + if (stateKeyNumber == Mode) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~11487~1~' + 'COOL' + '~'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'COOL' + '~'; + } + break; + case 'HEAT': + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[3] !== '') { + tempIcon = page.items[0].iconArray[3]; + } else { + tempIcon = 'fire'; + } + if (stateKeyNumber == Mode) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~64512~1~' + 'HEAT' + '~'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'HEAT' + '~'; + } + break; + case 'ECO': + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[4] !== '') { + tempIcon = page.items[0].iconArray[4]; + } else { + tempIcon = 'alpha-e-circle-outline'; + } + if (stateKeyNumber == Mode) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~2016~1~' + 'ECO' + '~'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'ECO' + '~'; + } + break; + case 'FAN_ONLY': + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[5] !== '') { + tempIcon = page.items[0].iconArray[5]; + } else { + tempIcon = 'fan'; + } + if (stateKeyNumber == Mode) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~11487~1~' + 'FAN_ONLY' + '~'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'FAN_ONLY' + '~'; + } + break; + case 'DRY': + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[6] !== '') { + tempIcon = page.items[0].iconArray[6]; + } else { + tempIcon = 'water-percent'; + } + if (stateKeyNumber == Mode) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~60897~1~' + 'DRY' + '~'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'DRY' + '~'; + } + break; + } + iconIndex++; } - if (States[Mode] == 'OFF' || !getState(id + '.POWER').val) { - bt[0] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'POWER' + '~'; - statusStr = 'OFF'; + + if (iconIndex <= 7 && existsState(id + '.ECO') && getState(id + '.ECO').val != null) { + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[4] !== '') { + tempIcon = page.items[0].iconArray[4]; + } else { + tempIcon = 'alpha-e-circle-outline'; + } + if (getState(id + '.ECO').val && getState(id + '.ECO').val == 1) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~2016~1~' + 'ECO' + '~'; + statusStr = 'ECO'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'ECO' + '~'; + } + iconIndex++; } - else { - bt[0] = Icons.GetIcon(tempIcon) + '~2016~1~' + 'POWER' + '~'; + + if (iconIndex <= 7 && existsState(id + '.SWING') && getState(id + '.SWING').val != null) { + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[7] !== '') { + tempIcon = page.items[0].iconArray[7]; + } else { + tempIcon = 'swap-vertical-bold'; + } + if (getState(id + '.POWER').val && getState(id + '.SWING').val == 1) { //0=ON oder .SWING = true + bt[7] = Icons.GetIcon(tempIcon) + '~2016~1~' + 'SWING' + '~'; + } else { + bt[7] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'SWING' + '~'; + } + iconIndex++; + } + + // Power Icon zuletzt pruefen, damit der Mode ggf. mit OFF ueberschrieben werden kann + if (existsState(id + '.POWER') && getState(id + '.POWER').val != null) { + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[0] !== '') { + tempIcon = page.items[0].iconArray[0]; + } else { + tempIcon = 'power-standby'; + } + if (States[Mode] == 'OFF' || !getState(id + '.POWER').val) { + bt[0] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'POWER' + '~'; + statusStr = 'OFF'; + } + else { + bt[0] = Icons.GetIcon(tempIcon) + '~2016~1~' + 'POWER' + '~'; + } } } } + break; } } @@ -4887,11 +4894,10 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } } - if (page.items[0].autoCreateALias) { - let vMediaDevice = (page.items[0].mediaDevice != undefined) ? page.items[0].mediaDevice : ''; - createAutoMediaAlias(id, vMediaDevice, page.items[0].adapterPlayerInstance!); - } - + let vMediaDevice = (page.items[0].mediaDevice != undefined) ? page.items[0].mediaDevice : ''; + if (!vMediaDevice) throw new Error(`Error in cardMedia! mediaDevice is empty! Page: ${JSON.stringify(page)}`); + createAutoMediaAlias(id, vMediaDevice, page.items[0].adapterPlayerInstance!); + // Leave the display on if the alwaysOnDisplay parameter is specified (true) if (page.type == 'cardMedia' && pageCounter == 0 && page.items[0].alwaysOnDisplay != undefined) { out_msgs.push({ payload: 'pageType~cardMedia' }); @@ -6253,83 +6259,90 @@ function HandleButtonEvent(words: any): void { case 'hue': toggleState(id + '.ON_ACTUAL'); case 'media': + if (!activePage || activePage.type != 'cardMedia') { + if (activePage) throw new Error(`Found channel role media for card: ${activePage.type} not allowed`) + else throw new Error(`Something went wrong! Active Page is empty!`); + } if (tempid[1] == undefined) { if (Debug) log('Logo click', 'info'); GeneratePage(activePage!); } else if (tempid[1] == 'repeat') { + let pageItemRepeat = findPageItem(id); - let adapterInstanceRepeat = pageItemRepeat.adapterPlayerInstance!; - let adapterRepeat = adapterInstanceRepeat.split('.'); - let deviceAdapterRP = adapterRepeat[0]; + if (isPageMediaItem(pageItemRepeat)) { + let adapterInstanceRepeat = pageItemRepeat.adapterPlayerInstance; + let adapterRepeat = adapterInstanceRepeat.split('.'); + let deviceAdapterRP = adapterRepeat[0]; - switch (deviceAdapterRP) { - case 'spotify-premium': - let stateSpotifyRepeat = getState(id + '.REPEAT').val - if (stateSpotifyRepeat == 'none') { - setIfExists(id + '.REPEAT', 'all'); - } else if (stateSpotifyRepeat == 'all') { - setIfExists(id + '.REPEAT', 'one'); - } else if (stateSpotifyRepeat == 'one') { - setIfExists(id + '.REPEAT', 'none'); - } - GeneratePage(activePage!); - break; - case 'sonos': - let stateSonosRepeat = getState(id + '.REPEAT').val - if (stateSonosRepeat == 0) { - setIfExists(id + '.REPEAT', 1); - } else if (stateSonosRepeat == 1) { - setIfExists(id + '.REPEAT', 2); - } else if (stateSonosRepeat == 2) { - setIfExists(id + '.REPEAT', 0); - } - GeneratePage(activePage!); - break; - case 'alexa2': - try { - setIfExists(id + '.REPEAT', !getState(id + '.REPEAT').val); - } catch (err: any) { - log('ALEXA2: Repeat kann nicht verändert werden', 'warn'); - } - GeneratePage(activePage!); - break; - case 'volumio': - let urlString: string = `${getState(adapterInstanceRepeat+'info.host').val}/api/commands/?cmd=repeat`; - axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) - .then(async function (response) { - if (response.status === 200) { - if (Debug) { - log(response.data, 'info'); - } - GeneratePage(activePage!); - } else { - log('Axios Status - adapterInstanceRepeat: ' + response.state, 'warn'); - } - }) - .catch(function (error) { - log(error, 'warn'); - }); - break; - case 'squeezeboxrpc': - try { - switch(getState(id + '.REPEAT').val) { - case 0: - setIfExists(id + '.REPEAT', 1); - GeneratePage(activePage!); - break; - case 1: - setIfExists(id + '.REPEAT', 2) - GeneratePage(activePage!); - break; - case 2: - setIfExists(id + '.REPEAT', 0); - GeneratePage(activePage!); - break; + switch (deviceAdapterRP) { + case 'spotify-premium': + let stateSpotifyRepeat = getState(id + '.REPEAT').val + if (stateSpotifyRepeat == 'none') { + setIfExists(id + '.REPEAT', 'all'); + } else if (stateSpotifyRepeat == 'all') { + setIfExists(id + '.REPEAT', 'one'); + } else if (stateSpotifyRepeat == 'one') { + setIfExists(id + '.REPEAT', 'none'); } - } catch (err: any) { - log('Squeezebox: Repeat kann nicht verändert werden', 'warn'); - } - break; + GeneratePage(activePage!); + break; + case 'sonos': + let stateSonosRepeat = getState(id + '.REPEAT').val + if (stateSonosRepeat == 0) { + setIfExists(id + '.REPEAT', 1); + } else if (stateSonosRepeat == 1) { + setIfExists(id + '.REPEAT', 2); + } else if (stateSonosRepeat == 2) { + setIfExists(id + '.REPEAT', 0); + } + GeneratePage(activePage!); + break; + case 'alexa2': + try { + setIfExists(id + '.REPEAT', !getState(id + '.REPEAT').val); + } catch (err: any) { + log('ALEXA2: Repeat kann nicht verändert werden', 'warn'); + } + GeneratePage(activePage!); + break; + case 'volumio': + let urlString: string = `${getState(adapterInstanceRepeat + 'info.host').val}/api/commands/?cmd=repeat`; + axios.get(urlString, {headers: {'User-Agent': 'ioBroker'}}) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(response.data, 'info'); + } + GeneratePage(activePage!); + } else { + log('Axios Status - adapterInstanceRepeat: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + break; + case 'squeezeboxrpc': + try { + switch (getState(id + '.REPEAT').val) { + case 0: + setIfExists(id + '.REPEAT', 1); + GeneratePage(activePage!); + break; + case 1: + setIfExists(id + '.REPEAT', 2) + GeneratePage(activePage!); + break; + case 2: + setIfExists(id + '.REPEAT', 0); + GeneratePage(activePage!); + break; + } + } catch (err: any) { + log('Squeezebox: Repeat kann nicht verändert werden', 'warn'); + } + break; + } } } } @@ -6478,58 +6491,63 @@ function HandleButtonEvent(words: any): void { break; case 'media-pause': let pageItemTemp = findPageItem(id); - let adaInstanceSplit = pageItemTemp.adapterPlayerInstance!.split('.'); - if (adaInstanceSplit[0] == 'squeezeboxrpc') { - let adapterPlayerInstanceStateSeceltor: string = [pageItemTemp.adapterPlayerInstance, 'Players', pageItemTemp.mediaDevice, 'state'].join('.'); - if (Debug) log('HandleButtonEvent media-pause Squeezebox-> adapterPlayerInstanceStateSeceltor: ' + adapterPlayerInstanceStateSeceltor, 'info'); - let stateVal = getState(adapterPlayerInstanceStateSeceltor).val; - if (stateVal == 0) { - setState(adapterPlayerInstanceStateSeceltor, 1); - } else if (stateVal == 1) { - setState(adapterPlayerInstanceStateSeceltor, 0); - } else if (stateVal == null) { - setState(adapterPlayerInstanceStateSeceltor, 1); - } - } else { - if (Debug) log('HandleButtonEvent media-pause -> .STATE Value: ' + getState(id + '.STATE').val, 'info'); - if (getState(id + '.STATE').val === true) { - setIfExists(id + '.PAUSE', true); + if (isPageMediaItem(pageItemTemp)) { + let adaInstanceSplit = pageItemTemp.adapterPlayerInstance!.split('.'); + if (adaInstanceSplit[0] == 'squeezeboxrpc') { + let adapterPlayerInstanceStateSeceltor: string = [pageItemTemp.adapterPlayerInstance, 'Players', pageItemTemp.mediaDevice, 'state'].join('.'); + if (Debug) log('HandleButtonEvent media-pause Squeezebox-> adapterPlayerInstanceStateSeceltor: ' + adapterPlayerInstanceStateSeceltor, 'info'); + let stateVal = getState(adapterPlayerInstanceStateSeceltor).val; + if (stateVal == 0) { + setState(adapterPlayerInstanceStateSeceltor, 1); + } else if (stateVal == 1) { + setState(adapterPlayerInstanceStateSeceltor, 0); + } else if (stateVal == null) { + setState(adapterPlayerInstanceStateSeceltor, 1); + } } else { - setIfExists(id + '.PLAY', true); + if (Debug) log('HandleButtonEvent media-pause -> .STATE Value: ' + getState(id + '.STATE').val, 'info'); + if (getState(id + '.STATE').val === true) { + setIfExists(id + '.PAUSE', true); + } else { + setIfExists(id + '.PLAY', true); + } } + GeneratePage(activePage!); } - GeneratePage(activePage!); break; case 'media-next': setIfExists(id + '.NEXT', true); GeneratePage(activePage!); break; case 'media-shuffle': - if ((findPageItem(id).adapterPlayerInstance!).startsWith("volumio")) { - findPageItem(id).playList = []; break; - } //Volumio: empty playlist $uha-20230103 - if ((findPageItem(id).adapterPlayerInstance!).startsWith("spotify")) { - if (getState(id + '.SHUFFLE').val == 'off') { - setIfExists(id + '.SHUFFLE', 'on'); - } else { - setIfExists(id + '.SHUFFLE', 'off'); + const tempPage = findPageItem(id); + if (isPageMediaItem(tempPage)) { + if (tempPage.adapterPlayerInstance.startsWith("volumio")) { + findPageItem(id).playList = []; break; + } //Volumio: empty playlist $uha-20230103 + if ((tempPage.adapterPlayerInstance).startsWith("spotify")) { + if (getState(id + '.SHUFFLE').val == 'off') { + setIfExists(id + '.SHUFFLE', 'on'); + } else { + setIfExists(id + '.SHUFFLE', 'off'); + } } - } - if ((findPageItem(id).adapterPlayerInstance!).startsWith("alexa")) { - if (getState(id + '.SHUFFLE').val == false) { - setIfExists(id + '.SHUFFLE', true); - } else { - setIfExists(id + '.SHUFFLE', false); + if ((tempPage.adapterPlayerInstance).startsWith("alexa")) { + if (getState(id + '.SHUFFLE').val == false) { + setIfExists(id + '.SHUFFLE', true); + } else { + setIfExists(id + '.SHUFFLE', false); + } } - } - if ((findPageItem(id).adapterPlayerInstance!).startsWith("sonos")) { - if (getState(id + '.SHUFFLE').val == false) { - setIfExists(id + '.SHUFFLE', true); - } else { - setIfExists(id + '.SHUFFLE', false); + if ((tempPage.adapterPlayerInstance).startsWith("sonos")) { + if (getState(id + '.SHUFFLE').val == false) { + setIfExists(id + '.SHUFFLE', true); + } else { + setIfExists(id + '.SHUFFLE', false); + } } + GeneratePage(activePage!); } - GeneratePage(activePage!); break; case 'volumeSlider': pageCounter = -1; @@ -6544,46 +6562,50 @@ function HandleButtonEvent(words: any): void { break; case 'mode-speakerlist': let pageItem = findPageItem(id); - let adapterInstance = pageItem.adapterPlayerInstance!; - let adapter = adapterInstance!.split('.'); - let deviceAdapter = adapter[0]; + if (isPageMediaItem(pageItem)) { + let adapterInstance = pageItem.adapterPlayerInstance!; + let adapter = adapterInstance!.split('.'); + let deviceAdapter = adapter[0]; - switch (deviceAdapter) { - case 'spotify-premium': - let strDevicePI = pageItem.speakerList![words[4]]; - let strDeviceID = spotifyGetDeviceID(strDevicePI); - setState(adapterInstance + 'devices.' + strDeviceID + ".useForPlayback", true); - break; - case 'alexa2': - let i_list = Array.prototype.slice.apply($('[state.id="' + adapterInstance + 'Echo-Devices.*.Info.name"]')); - for (let i_index in i_list) { - let i = i_list[i_index]; - if ((getState(i).val) === pageItem.speakerList![words[4]]) { - if (Debug) log('HandleButtonEvent mode-Speakerlist Alexa2: ' + getState(i).val + ' - ' + pageItem.speakerList![words[4]], 'info'); - let deviceId = i; - deviceId = deviceId.split('.'); - setIfExists(adapterInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Commands.textCommand', 'Schiebe meine Musik auf ' + pageItem.speakerList![words[4]]); - pageItem.mediaDevice = deviceId[3]; - } - } - break; - case 'sonos': - break; - case 'chromecast': - break; - case 'squeezeboxrpc': - pageItem.mediaDevice = pageItem.speakerList![words[4]]; - break; - } - pageCounter = 0; - GeneratePage(activePage!); - setTimeout(async function () { - pageCounter = 1; + switch (deviceAdapter) { + case 'spotify-premium': + let strDevicePI = pageItem.speakerList![words[4]]; + let strDeviceID = spotifyGetDeviceID(strDevicePI); + setState(adapterInstance + 'devices.' + strDeviceID + ".useForPlayback", true); + break; + case 'alexa2': + let i_list = Array.prototype.slice.apply($('[state.id="' + adapterInstance + 'Echo-Devices.*.Info.name"]')); + for (let i_index in i_list) { + let i = i_list[i_index]; + if ((getState(i).val) === pageItem.speakerList![words[4]]) { + if (Debug) log('HandleButtonEvent mode-Speakerlist Alexa2: ' + getState(i).val + ' - ' + pageItem.speakerList![words[4]], 'info'); + let deviceId = i; + deviceId = deviceId.split('.'); + setIfExists(adapterInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Commands.textCommand', 'Schiebe meine Musik auf ' + pageItem.speakerList![words[4]]); + pageItem.mediaDevice = deviceId[3]; + } + } + break; + case 'sonos': + break; + case 'chromecast': + break; + case 'squeezeboxrpc': + pageItem.mediaDevice = pageItem.speakerList![words[4]]; + break; + + } + pageCounter = 0; GeneratePage(activePage!); - }, 3000); + setTimeout(async function () { + pageCounter = 1; + GeneratePage(activePage!); + }, 3000); + } break; case 'mode-playlist': let pageItemPL = findPageItem(id); + if (!isPageMediaItem(pageItemPL)) break; let adapterInstancePL = pageItemPL.adapterPlayerInstance!; let adapterPL = adapterInstancePL.split('.'); let deviceAdapterPL = adapterPL[0]; @@ -6639,6 +6661,7 @@ function HandleButtonEvent(words: any): void { break; case 'mode-tracklist': let pageItemTL = findPageItem(id); + if (!isPageMediaItem(pageItemTL)) break; let adapterInstanceTL = pageItemTL.adapterPlayerInstance!; let adapterTL = adapterInstanceTL.split('.'); let deviceAdapterTL = adapterTL[0]; @@ -6683,6 +6706,7 @@ function HandleButtonEvent(words: any): void { break; case 'mode-repeat': let pageItemRP = findPageItem(id); + if (!isPageMediaItem(pageItemRP)) break; let adapterInstanceRP = pageItemRP.adapterPlayerInstance!; let adapterRP = adapterInstanceRP.split('.'); let deviceAdapterRP = adapterRP[0]; @@ -6712,6 +6736,7 @@ function HandleButtonEvent(words: any): void { break; case 'mode-seek': let pageItemSeek = findPageItem(id); + if (!isPageMediaItem(pageItemSeek)) break; let adapterInstanceSK = pageItemSeek.adapterPlayerInstance!; let adapterSK = adapterInstanceSK.split('.'); let deviceAdapterSK = adapterSK[0]; @@ -6732,6 +6757,7 @@ function HandleButtonEvent(words: any): void { break; case 'mode-crossfade': let pageItemCrossfade = findPageItem(id); + if (!isPageMediaItem(pageItemCrossfade)) break; let adapterInstanceCF = pageItemCrossfade.adapterPlayerInstance!; let adapterCF = adapterInstanceCF.split('.'); let deviceAdapterCF = adapterCF[0]; @@ -6756,6 +6782,7 @@ function HandleButtonEvent(words: any): void { break; case 'mode-favorites': let pageItemFav = findPageItem(id); + if (!isPageMediaItem(pageItemFav)) break; if (Debug) log(getState(pageItemFav.adapterPlayerInstance + 'root.' + pageItemFav.mediaDevice + '.favorites_set').val, 'info'); let favListArray = getState(pageItemFav.adapterPlayerInstance + 'root.' + pageItemFav.mediaDevice + '.favorites_list_array').val; setState(pageItemFav.adapterPlayerInstance + 'root.' + pageItemFav.mediaDevice + '.favorites_set', favListArray[words[4]]); @@ -6771,6 +6798,7 @@ function HandleButtonEvent(words: any): void { break; case 'media-OnOff': let pageItemTem = findPageItem(id); + if (!isPageMediaItem(pageItemTem)) break; let adaInstanceSpli = pageItemTem.adapterPlayerInstance!.split('.'); if (adaInstanceSpli[0] == 'squeezeboxrpc') { let adapterPlayerInstancePowerSelector: string = [pageItemTem.adapterPlayerInstance, 'Players', pageItemTem.mediaDevice, 'Power'].join('.'); @@ -7089,7 +7117,7 @@ function GetNavigationString(pageId: number): string { return ''; } -function GenerateDetailPage(type: string, optional: string | undefined, pageItem: PageItem, placeId: number | undefined): Payload[] { +function GenerateDetailPage(type: string, optional: mediaOptional | undefined, pageItem: PageItem, placeId: number | undefined): Payload[] { if (Debug) log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); try { let out_msgs: Array = []; @@ -7106,7 +7134,9 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem let switchVal = '0'; let brightness = 0; - if (o.common.role == 'light' || o.common.role == 'socket') { + switch (o.common.role) { + case 'light': + case 'socket': { if (existsState(id + '.GET')) { val = getState(id + '.GET').val; RegisterDetailEntityWatcher(id + '.GET', pageItem, type, placeId); @@ -7152,9 +7182,9 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem + effect_supported }); } - + break; // Dimmer - if (o.common.role == 'dimmer') { + case 'dimmer': { if (existsState(id + '.ON_ACTUAL')) { val = getState(id + '.ON_ACTUAL').val; RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type, placeId); @@ -7209,9 +7239,9 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem + effect_supported }); } - + break; // HUE-Licht - if (o.common.role == 'hue') { + case 'hue': { if (existsState(id + '.ON_ACTUAL')) { val = getState(id + '.ON_ACTUAL').val; @@ -7281,9 +7311,9 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem + effect_supported }); } - + break; // RGB-Licht - if (o.common.role == 'rgb') { + case 'rgb': { if (existsState(id + '.ON_ACTUAL')) { val = getState(id + '.ON_ACTUAL').val; @@ -7352,9 +7382,9 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem + effect_supported }); } - + break; // RGB-Licht-einzeln (HEX) - if (o.common.role == 'rgbSingle') { + case 'rgbSingle': { if (existsState(id + '.ON_ACTUAL')) { val = getState(id + '.ON_ACTUAL').val; @@ -7428,9 +7458,9 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem + effect_supported }); } - + break; // Farbtemperatur (CT) - if (o.common.role == 'ct') { + case 'ct': { if (existsState(id + '.ON')) { val = getState(id + '.ON').val; @@ -7492,6 +7522,8 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem + effect_supported }); } + break; + } } if (type == 'popupShutter') { @@ -7774,228 +7806,229 @@ function GenerateDetailPage(type: string, optional: string | undefined, pageItem let actualState: any = ''; let optionalString: string = 'Kein Eintrag'; let mode: string = ''; - - let vTempAdapter = (pageItem.adapterPlayerInstance!).split('.'); - let vAdapter = vTempAdapter[0]; - if (optional == 'seek') { - let actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; - if (actualStateTemp >= 95) { - actualState = '100%'; - } else if (actualStateTemp >= 85) { - actualState = '90%'; - } else if (actualStateTemp >= 75) { - actualState = '80%'; - } else if (actualStateTemp >= 65) { - actualState = '70%'; - } else if (actualStateTemp >= 55) { - actualState = '60%'; - } else if (actualStateTemp >= 45) { - actualState = '50%'; - } else if (actualStateTemp >= 35) { - actualState = '40%'; - } else if (actualStateTemp >= 25) { - actualState = '30%'; - } else if (actualStateTemp >= 15) { - actualState = '20%'; - } else if (actualStateTemp >= 5) { - actualState = '10%'; - } else if (actualStateTemp >= 0) { - actualState = '0%'; - } - if (vAdapter == 'sonos') { - optionalString = '0%?10%?20%?30%?40%?50%?60%?70%?80%?90%?100%'; - } - mode = 'seek'; - } else if (optional == 'crossfade') { - if (existsObject(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.crossfade')) { - let actualStateTemp: boolean = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.crossfade').val; - if (actualStateTemp) { - actualState = findLocale('media', 'on'); - } else { - actualState = findLocale('media', 'off'); + if (isPageMediaItem(pageItem)) { + let vTempAdapter = (pageItem.adapterPlayerInstance!).split('.'); + let vAdapter = vTempAdapter[0]; + if (optional == 'seek') { + let actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; + if (actualStateTemp >= 95) { + actualState = '100%'; + } else if (actualStateTemp >= 85) { + actualState = '90%'; + } else if (actualStateTemp >= 75) { + actualState = '80%'; + } else if (actualStateTemp >= 65) { + actualState = '70%'; + } else if (actualStateTemp >= 55) { + actualState = '60%'; + } else if (actualStateTemp >= 45) { + actualState = '50%'; + } else if (actualStateTemp >= 35) { + actualState = '40%'; + } else if (actualStateTemp >= 25) { + actualState = '30%'; + } else if (actualStateTemp >= 15) { + actualState = '20%'; + } else if (actualStateTemp >= 5) { + actualState = '10%'; + } else if (actualStateTemp >= 0) { + actualState = '0%'; } - } - if (vAdapter == 'sonos') { - optionalString = findLocale('media', 'on') + '?' + findLocale('media', 'off'); - } - mode = 'crossfade'; - } else if (optional == 'speakerlist') { - if (vAdapter == 'spotify-premium') { - if (existsObject(pageItem.adapterPlayerInstance + 'player.device.name')) { - actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'player.device.name').val); + if (vAdapter == 'sonos') { + optionalString = '0%?10%?20%?30%?40%?50%?60%?70%?80%?90%?100%'; } - } else if (vAdapter == 'alexa2') { - if (existsObject(pageItem.adapterPlayerInstance + 'player.device.name')) { + mode = 'seek'; + } else if (optional == 'crossfade') { + if (existsObject(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.crossfade')) { + let actualStateTemp: boolean = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.crossfade').val; + if (actualStateTemp) { + actualState = findLocale('media', 'on'); + } else { + actualState = findLocale('media', 'off'); + } + } + if (vAdapter == 'sonos') { + optionalString = findLocale('media', 'on') + '?' + findLocale('media', 'off'); + } + mode = 'crossfade'; + } else if (optional == 'speakerlist') { + if (vAdapter == 'spotify-premium') { + if (existsObject(pageItem.adapterPlayerInstance + 'player.device.name')) { + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'player.device.name').val); + } + } else if (vAdapter == 'alexa2') { + if (existsObject(pageItem.adapterPlayerInstance + 'player.device.name')) { + //Todo Richtiges Device finden + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Info.name').val); + } + } else if (vAdapter == 'squeezeboxrpc') { + actualState = pageItem.mediaDevice; + } + let tempSpeakerList: string[] = []; + for (let i = 0; i < pageItem.speakerList!.length; i++) { + tempSpeakerList[i] = formatInSelText(pageItem.speakerList![i]).trim(); + } + optionalString = pageItem.speakerList != undefined ? tempSpeakerList.join('?') : ''; + mode = 'speakerlist'; + } else if (optional == 'playlist') { + if (vAdapter == 'spotify-premium') { + if (existsObject(pageItem.adapterPlayerInstance + 'player.playlist.name')) { + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'player.playlist.name').val); + } + let tempPlayList: string[] = []; + for (let i = 0; i < pageItem.playList!.length; i++) { + tempPlayList[i] = formatInSelText(pageItem.playList![i]); + } + optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' + } else if (vAdapter == 'alexa2') { //Todo Richtiges Device finden - actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Info.name').val); + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Player.currentAlbum').val); + + let tPlayList: any = [] + for (let i = 0; i < pageItem.playList!.length; i++) { + if (Debug) log('function GenerateDetailPage role:media -> Playlist ' + pageItem.playList![i], 'info'); + let tempItem = pageItem.playList![i].split('.'); + tPlayList[i] = tempItem[1]; + } + + let tempPlayList: string[] = []; + for (let i = 0; i < tPlayList.length; i++) { + tempPlayList[i] = formatInSelText(tPlayList[i]); + } + optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' + } else if (vAdapter == 'sonos') { + if (Debug) log(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set', 'info'); + if (existsObject(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set')) { + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set').val); + } + let tempPlayList: string[] = []; + for (let i = 0; i < pageItem.playList!.length; i++) { + tempPlayList[i] = formatInSelText(pageItem.playList![i]); + } + optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' + } else if (vAdapter == 'volumio') { /* Volumio: limit 900 chars */ + actualState = ''; //todo: no actual playlistname saving + let tempPlayList: string[] = []; let tempPll = 0; + for (let i = 0; i < pageItem.playList!.length; i++) { + tempPll += pageItem.playList![i].length; if (tempPll > 900) break; + tempPlayList[i] = formatInSelText(pageItem.playList![i]); + } + optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' + } else if (vAdapter == 'squeezeboxrpc') { + // Playlist browsing not supported by squeezeboxrpc adapter. But Favorites can be used + actualState = ''; // Not supported by squeezeboxrpc adapter + let tempPlayList: string[] = []; + let pathParts: Array = pageItem.adapterPlayerInstance!.split('.'); + for (let favorite_index = 0; favorite_index < 45; favorite_index++) { + let favorite_name_selector: string = [pathParts[0], pathParts[1], 'Favorites', favorite_index, 'Name'].join('.'); + if (!existsObject(favorite_name_selector)) { + break; + } + let favoritename: string = getState(favorite_name_selector).val; + tempPlayList.push(formatInSelText(favoritename)); + } + optionalString = tempPlayList.length > 0 ? tempPlayList.join('?') : ''; } - } else if (vAdapter == 'squeezeboxrpc') { - actualState = pageItem.mediaDevice; - } - let tempSpeakerList: string[] = []; - for (let i = 0; i < pageItem.speakerList!.length; i++) { - tempSpeakerList[i] = formatInSelText(pageItem.speakerList![i]).trim(); - } - optionalString = pageItem.speakerList != undefined ? tempSpeakerList.join('?') : ''; - mode = 'speakerlist'; - } else if (optional == 'playlist') { - if (vAdapter == 'spotify-premium') { - if (existsObject(pageItem.adapterPlayerInstance + 'player.playlist.name')) { - actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'player.playlist.name').val); + mode = 'playlist'; + } else if (optional == 'tracklist') { + actualState = ''; + /* Volumio: works for files */ + if (vAdapter == 'volumio') { + actualState = getState(pageItem.id + '.TITLE').val; + globalTracklist = pageItem.globalTracklist; + } else if (vAdapter == 'squeezeboxrpc') { + actualState = getState(pageItem.id + '.TITLE').val; + } else if (vAdapter == 'sonos') { + actualState = getState(pageItem.id + '.TITLE').val; + } else { + actualState = getState(pageItem.adapterPlayerInstance + 'player.trackName').val; } - let tempPlayList: string[] = []; - for (let i = 0; i < pageItem.playList!.length; i++) { - tempPlayList[i] = formatInSelText(pageItem.playList![i]); - } - optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' - } else if (vAdapter == 'alexa2') { - //Todo Richtiges Device finden - actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Player.currentAlbum').val); - - let tPlayList: any = [] - for (let i = 0; i < pageItem.playList!.length; i++) { - if (Debug) log('function GenerateDetailPage role:media -> Playlist ' + pageItem.playList![i], 'info'); - let tempItem = pageItem.playList![i].split('.'); - tPlayList[i] = tempItem[1]; - } - - let tempPlayList: string[] = []; - for (let i = 0; i < tPlayList.length; i++) { - tempPlayList[i] = formatInSelText(tPlayList[i]); - } - optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' - } else if (vAdapter == 'sonos') { - if (Debug) log(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set', 'info'); - if (existsObject(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set')) { - actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set').val); - } - let tempPlayList: string[] = []; - for (let i = 0; i < pageItem.playList!.length; i++) { - tempPlayList[i] = formatInSelText(pageItem.playList![i]); - } - optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' - } else if (vAdapter == 'volumio') { /* Volumio: limit 900 chars */ - actualState = ''; //todo: no actual playlistname saving - let tempPlayList: string[] = []; let tempPll = 0; - for (let i = 0; i < pageItem.playList!.length; i++) { - tempPll += pageItem.playList![i].length; if (tempPll > 900) break; - tempPlayList[i] = formatInSelText(pageItem.playList![i]); - } - optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' - } else if(vAdapter == 'squeezeboxrpc') { - // Playlist browsing not supported by squeezeboxrpc adapter. But Favorites can be used - actualState = ''; // Not supported by squeezeboxrpc adapter - let tempPlayList: string[] = []; - let pathParts: Array = pageItem.adapterPlayerInstance!.split('.'); - for (let favorite_index=0; favorite_index < 45; favorite_index++) { - let favorite_name_selector: string = [pathParts[0], pathParts[1], 'Favorites', favorite_index, 'Name'].join('.'); - if(!existsObject(favorite_name_selector)) { + actualState = (actualState.replace('?', '')).split(' -'); + actualState = actualState[0].split(" ("); + actualState = formatInSelText(actualState[0]); + if (Debug) log(actualState, 'info'); + if (Debug) log(globalTracklist, 'info'); + //Limit 900 characters, then memory overflow --> Shorten as much as possible + let temp_array: any[] = []; + //let trackArray = (function () { try {return JSON.parse(getState(pageItem.adapterPlayerInstance + 'player.playlist.trackListArray').val);} catch(e) {return {};}})(); + for (let track_index = 0; track_index < 45; track_index++) { + let temp_cut_array = getAttr(globalTracklist, track_index + '.title'); + /* Volumio: @local/NAS no title -> name */ + if (temp_cut_array == undefined) { + temp_cut_array = getAttr(globalTracklist, track_index + '.name'); + } + if (Debug) log('function GenerateDetailPage role:media tracklist -> ' + temp_cut_array, 'info'); + if (temp_cut_array != undefined) { + temp_cut_array = (temp_cut_array.replace('?', '')).split(' -'); + temp_cut_array = temp_cut_array[0].split(" ("); + temp_cut_array = temp_cut_array[0]; + if (String(temp_cut_array[0]).length >= 22) { + temp_array[track_index] = temp_cut_array.substring(0, 20) + '..'; + } else { + temp_array[track_index] = temp_cut_array.substring(0, 23); + } + } + else { break; } - let favoritename: string = getState(favorite_name_selector).val; - tempPlayList.push(formatInSelText(favoritename)); } - optionalString = tempPlayList.length > 0 ? tempPlayList.join('?') : ''; - } - mode = 'playlist'; - } else if (optional == 'tracklist') { - actualState = ''; - /* Volumio: works for files */ - if (vAdapter == 'volumio') { - actualState = getState(pageItem.id + '.TITLE').val; - globalTracklist = pageItem.globalTracklist; - }else if(vAdapter == 'squeezeboxrpc') { - actualState = getState(pageItem.id + '.TITLE').val; - }else if(vAdapter == 'sonos') { - actualState = getState(pageItem.id + '.TITLE').val; - } else { - actualState = getState(pageItem.adapterPlayerInstance + 'player.trackName').val; - } - actualState = (actualState.replace('?','')).split(' -'); - actualState = actualState[0].split(" ("); - actualState = formatInSelText(actualState[0]); - if (Debug) log(actualState, 'info'); - if (Debug) log(globalTracklist, 'info'); - //Limit 900 characters, then memory overflow --> Shorten as much as possible - let temp_array: any[] = []; - //let trackArray = (function () { try {return JSON.parse(getState(pageItem.adapterPlayerInstance + 'player.playlist.trackListArray').val);} catch(e) {return {};}})(); - for (let track_index=0; track_index < 45; track_index++) { - let temp_cut_array = getAttr(globalTracklist, track_index + '.title'); - /* Volumio: @local/NAS no title -> name */ - if (temp_cut_array == undefined) { - temp_cut_array = getAttr(globalTracklist, track_index + '.name'); - } - if (Debug) log('function GenerateDetailPage role:media tracklist -> ' + temp_cut_array, 'info'); - if (temp_cut_array != undefined) { - temp_cut_array = (temp_cut_array.replace('?','')).split(' -'); - temp_cut_array = temp_cut_array[0].split(" ("); - temp_cut_array = temp_cut_array[0]; - if (String(temp_cut_array[0]).length >= 22) { - temp_array[track_index] = temp_cut_array.substring(0,20) + '..'; - } else { - temp_array[track_index] = temp_cut_array.substring(0,23); - } + let tempTrackList: string[] = []; + for (let i = 0; i < temp_array.length; i++) { + tempTrackList[i] = formatInSelText(temp_array[i]); } - else { - break; - } - } - let tempTrackList: string[] = []; - for (let i = 0; i < temp_array.length; i++) { - tempTrackList[i] = formatInSelText(temp_array[i]); - } - optionalString = pageItem.playList != undefined ? tempTrackList.join('?') : '' - mode = 'tracklist'; - } else if (optional == 'equalizer') { - if (pageItem.id == undefined) throw new Error ('Missing pageItem.id in equalizer!'); - let lastIndex = (pageItem.id.split('.')).pop(); + optionalString = pageItem.playList != undefined ? tempTrackList.join('?') : '' + mode = 'tracklist'; + } else if (optional == 'equalizer') { + if (pageItem.id == undefined) throw new Error('Missing pageItem.id in equalizer!'); + let lastIndex = (pageItem.id.split('.')).pop(); - if (existsObject(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode') == false || - existsObject(NSPanel_Path + 'Media.Player.' + lastIndex + '.Speaker') == false) { - createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode', { type: 'string' }); - createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.Speaker', { type: 'string' }); - } - - actualState = '' - if (getState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode').val != null) { - actualState = formatInSelText(getState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode').val); - } - - let tempEQList: string[] = []; - for (let i = 0; i < pageItem.equalizerList!.length; i++) { - tempEQList[i] = formatInSelText(pageItem!.equalizerList![i]); + if (existsObject(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode') == false || + existsObject(NSPanel_Path + 'Media.Player.' + lastIndex + '.Speaker') == false) { + createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode', {type: 'string'}); + createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.Speaker', {type: 'string'}); + } + + actualState = '' + if (getState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode').val != null) { + actualState = formatInSelText(getState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode').val); + } + + let tempEQList: string[] = []; + for (let i = 0; i < pageItem.equalizerList!.length; i++) { + tempEQList[i] = formatInSelText(pageItem!.equalizerList![i]); + } + + optionalString = pageItem.equalizerList != undefined ? tempEQList.join('?') : ''; + mode = 'equalizer'; + } else if (optional == 'repeat') { + actualState = getState(pageItem.adapterPlayerInstance + 'player.repeat').val; + optionalString = pageItem.repeatList!.join('?'); + mode = 'repeat'; + } else if (optional == 'favorites') { + if (Debug) log(getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.favorites_set').val, 'info') + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.favorites_set').val); + + let tempFavList: string[] = []; + let favList = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.favorites_list_array').val; + for (let i = 0; i < favList.length; i++) { + tempFavList[i] = formatInSelText(favList[i]); + } + optionalString = tempFavList != undefined ? tempFavList.join('?') : ''; + mode = 'favorites'; } - optionalString = pageItem.equalizerList != undefined ? tempEQList.join('?') : ''; - mode = 'equalizer'; - } else if (optional == 'repeat') { - actualState = getState(pageItem.adapterPlayerInstance + 'player.repeat').val; - optionalString = pageItem.repeatList!.join('?'); - mode = 'repeat'; - } else if (optional == 'favorites') { - if (Debug) log(getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.favorites_set').val, 'info') - actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.favorites_set').val); - - let tempFavList:string [] = []; - let favList = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.favorites_list_array').val; - for (let i = 0; i < favList.length; i++) { - tempFavList[i] = formatInSelText(favList[i]); - } - optionalString = tempFavList != undefined ? tempFavList.join('?') : ''; - mode = 'favorites'; + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail + + tempId + '?' + optional + '~~' //{entity_id} + + rgb_dec565(HMIOn) + '~' //{icon_color}~ + + mode + '~' + + actualState + '~' + + optionalString + }); + GeneratePage(activePage!); } - - let tempId = placeId != undefined ? placeId : id; - - out_msgs.push({ - payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail - + tempId + '?' + optional + '~~' //{entity_id} - + rgb_dec565(HMIOn) + '~' //{icon_color}~ - + mode + '~' - + actualState + '~' - + optionalString - }); - GeneratePage(activePage!); } else if (o.common.role == 'buttonSensor') { let actualValue: string = ''; @@ -9406,8 +9439,8 @@ type PageThermo = { type PageMedia = { type: 'cardMedia', - items: PageItem[], -} & Omit + items: PageMediaItem[], +} & Omit type PageAlarm = { type: 'cardAlarm', @@ -9434,7 +9467,16 @@ type PageChart = { items: PageItem[], } & Omit -type PageItem = { +type PageItem = PageBaseItem | PageMediaItem + +function isPageMediaItem(F: PageItem | PageMediaItem):F is PageMediaItem { + return (F as PageMediaItem).adapterPlayerInstance !== undefined +} +type PageMediaItem = { + adapterPlayerInstance: adapterPlayerInstanceType, +} & PageBaseItem + +type PageBaseItem = { id?: string | null, icon?: string, icon2?: string, @@ -9462,7 +9504,7 @@ type PageItem = { navigate?: boolean, colormode?: string, colorScale?: any, - adapterPlayerInstance?: string, + //adapterPlayerInstance?: adapterPlayerInstanceType, mediaDevice?: string, targetPage?: string, speakerList?: string[], @@ -9568,3 +9610,36 @@ type IconScaleElement = { val_max:number, val_best?: number } + +type adapterPlayerInstanceType = + 'alexa2.1.' | 'sonos.1.' | 'spotify-premium.1.' | 'volumio.1.' | 'squeezebox-rpc.1.' +| 'alexa2.2.' | 'sonos.2.' | 'spotify-premium.2.' | 'volumio.2.' | 'squeezebox-rpc.2.' +| 'alexa2.0.' | 'sonos.0.' | 'spotify-premium.0.' | 'volumio.0.' | 'squeezebox-rpc.0.' +| 'alexa2.3.' | 'sonos.3.' | 'spotify-premium.3.' | 'volumio.3.' | 'squeezebox-rpc.3.' +| 'alexa2.4.' | 'sonos.4.' | 'spotify-premium.4.' | 'volumio.4.' | 'squeezebox-rpc.4.' +| 'alexa2.5.' | 'sonos.5.' | 'spotify-premium.5.' | 'volumio.5.' | 'squeezebox-rpc.5.' +| 'alexa2.6.' | 'sonos.6.' | 'spotify-premium.6.' | 'volumio.6.' | 'squeezebox-rpc.6.' +| 'alexa2.7.' | 'sonos.7.' | 'spotify-premium.7.' | 'volumio.7.' | 'squeezebox-rpc.7.' +| 'alexa2.8.' | 'sonos.8.' | 'spotify-premium.8.' | 'volumio.8.' | 'squeezebox-rpc.8.' +| 'alexa2.9.' | 'sonos.9.' | 'spotify-premium.9.' | 'volumio.9.' | 'squeezebox-rpc.9.' +| 'alexa2.10.' | 'sonos.10.' | 'spotify-premium.10.' | 'volumio.10.' | 'squeezebox-rpc.10' + + + +type mediaOptional = 'seek' | 'crossfade' | 'speakerlist' | 'playlist' | 'tracklist' | 'equalizer' | 'repeat' | 'favorites' + +function isMediaOptional(F: string | mediaOptional): F is mediaOptional { + switch(F as mediaOptional) { + case "seek": + case "crossfade": + case "speakerlist": + case "playlist": + case "tracklist": + case "equalizer": + case "repeat": + case "favorites": + return true; + default: + return false + } +} \ No newline at end of file From e2530cdf62ae001932b3ca13cfe3115711a82eda Mon Sep 17 00:00:00 2001 From: ticaki Date: Wed, 3 Jan 2024 17:38:53 +0100 Subject: [PATCH 28/99] typo in types --- ioBroker/NsPanelTs.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 16cae287..1870afcc 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -9612,17 +9612,17 @@ type IconScaleElement = { } type adapterPlayerInstanceType = - 'alexa2.1.' | 'sonos.1.' | 'spotify-premium.1.' | 'volumio.1.' | 'squeezebox-rpc.1.' -| 'alexa2.2.' | 'sonos.2.' | 'spotify-premium.2.' | 'volumio.2.' | 'squeezebox-rpc.2.' -| 'alexa2.0.' | 'sonos.0.' | 'spotify-premium.0.' | 'volumio.0.' | 'squeezebox-rpc.0.' -| 'alexa2.3.' | 'sonos.3.' | 'spotify-premium.3.' | 'volumio.3.' | 'squeezebox-rpc.3.' -| 'alexa2.4.' | 'sonos.4.' | 'spotify-premium.4.' | 'volumio.4.' | 'squeezebox-rpc.4.' -| 'alexa2.5.' | 'sonos.5.' | 'spotify-premium.5.' | 'volumio.5.' | 'squeezebox-rpc.5.' -| 'alexa2.6.' | 'sonos.6.' | 'spotify-premium.6.' | 'volumio.6.' | 'squeezebox-rpc.6.' -| 'alexa2.7.' | 'sonos.7.' | 'spotify-premium.7.' | 'volumio.7.' | 'squeezebox-rpc.7.' -| 'alexa2.8.' | 'sonos.8.' | 'spotify-premium.8.' | 'volumio.8.' | 'squeezebox-rpc.8.' -| 'alexa2.9.' | 'sonos.9.' | 'spotify-premium.9.' | 'volumio.9.' | 'squeezebox-rpc.9.' -| 'alexa2.10.' | 'sonos.10.' | 'spotify-premium.10.' | 'volumio.10.' | 'squeezebox-rpc.10' + 'alexa2.1.' | 'sonos.1.' | 'spotify-premium.1.' | 'volumio.1.' | 'squeezeboxrpc.1.' +| 'alexa2.2.' | 'sonos.2.' | 'spotify-premium.2.' | 'volumio.2.' | 'squeezeboxrpc.2.' +| 'alexa2.0.' | 'sonos.0.' | 'spotify-premium.0.' | 'volumio.0.' | 'squeezeboxrpc.0.' +| 'alexa2.3.' | 'sonos.3.' | 'spotify-premium.3.' | 'volumio.3.' | 'squeezeboxrpc.3.' +| 'alexa2.4.' | 'sonos.4.' | 'spotify-premium.4.' | 'volumio.4.' | 'squeezeboxrpc.4.' +| 'alexa2.5.' | 'sonos.5.' | 'spotify-premium.5.' | 'volumio.5.' | 'squeezeboxrpc.5.' +| 'alexa2.6.' | 'sonos.6.' | 'spotify-premium.6.' | 'volumio.6.' | 'squeezeboxrpc.6.' +| 'alexa2.7.' | 'sonos.7.' | 'spotify-premium.7.' | 'volumio.7.' | 'squeezeboxrpc.7.' +| 'alexa2.8.' | 'sonos.8.' | 'spotify-premium.8.' | 'volumio.8.' | 'squeezeboxrpc.8.' +| 'alexa2.9.' | 'sonos.9.' | 'spotify-premium.9.' | 'volumio.9.' | 'squeezeboxrpc.9.' +| 'alexa2.10.' | 'sonos.10.' | 'spotify-premium.10.' | 'volumio.10.' | 'squeezeboxrpc.10' From 5420abcfaad98bc61c9e953352721a965d2baa7a Mon Sep 17 00:00:00 2001 From: ticaki Date: Wed, 3 Jan 2024 18:38:45 +0100 Subject: [PATCH 29/99] adapterPlayerInstance more types --- ioBroker/.iobroker/types/javascript.d.ts | 1732 ++++++++++++++++++++++ ioBroker/NsPanelTs.ts | 366 +++-- ioBroker/tsconfig.json | 27 + 3 files changed, 1968 insertions(+), 157 deletions(-) create mode 100644 ioBroker/.iobroker/types/javascript.d.ts create mode 100644 ioBroker/tsconfig.json diff --git a/ioBroker/.iobroker/types/javascript.d.ts b/ioBroker/.iobroker/types/javascript.d.ts new file mode 100644 index 00000000..e51690f8 --- /dev/null +++ b/ioBroker/.iobroker/types/javascript.d.ts @@ -0,0 +1,1732 @@ +// import all modules that are available in the sandbox +// this has a nice side effect that we may augment the global scope +import * as child_process from "child_process"; +import * as os from "os"; + +type EmptyCallback = () => void | Promise; +type ErrorCallback = (err?: string) => void | Promise; +type GenericCallback = (err?: string | null, result?: T) => void | Promise; +type SimpleCallback = (result?: T) => void | Promise; +type LogCallback = (msg: any) => void | Promise; + +type SecondParameterOf any> = T extends ( + arg0: any, + arg1: infer R, + ...args: any[] +) => any + ? R + : never; +/** Infers the return type from a callback-style API and strips out null and undefined */ +type NonNullCallbackReturnTypeOf any> = Exclude< + SecondParameterOf, + null | undefined +>; +/** Infers the return type from a callback-style API and leaves null and undefined in */ +type CallbackReturnTypeOf any> = SecondParameterOf; + +/** Returns a type that requires at least one of the properties from the given type */ +type AtLeastOne = { [K in keyof U]: { [P in K]: U[P] } }[keyof U]; + +/** Returns all possible keys of a union of objects */ +type AllKeys = T extends any ? keyof T : never; +/** Simplifies mapped types to their basic forms */ +type Simplify = U extends infer O ? { [K in keyof O]: O[K] } : never; + +/** Takes an object type and adds all missing properties from the Keys union with the type `never` */ +type AddMissingNever = { + [K in Keys]: K extends keyof T ? T[K] : never; +}; + +/** + * Takes a union of objects and returns an object type + * which has all properties that exist on at least one of the objects. + * + * E.g. CombineObjectUnion<{a: 1} | {b: 2}> = {a: 1; b: 2}; + */ +type CombineObjectUnion< + T, + Keys extends string | number | symbol = AllKeys, + O = T extends any ? AddMissingNever : never + > = Simplify<{ [K in Keys]: K extends keyof O ? O[K] : never }> + +/** + * Takes a union of ioBroker Object types and returns a combined object type + * which has all properties that could exist on at least one of the objects. + * + * Note: This is not entirely sound to work with, but better for JS and working with read objects + */ +type AnyOf< + T, + Keys extends string | number | symbol = AllKeys, + O = T extends any ? AddMissingNever : never + > = Simplify<{ + [K in Keys]: K extends keyof O ? ( + O[K] extends any[] ? O[K] + : O[K] extends Record ? CombineObjectUnion + : O[K] + ) : never; + }>; + +// tslint:disable:no-namespace +declare global { + + namespace iobJS { + + enum StateQuality { + good = 0x00, // or undefined or null + bad = 0x01, + general_problem = 0x01, + general_device_problem = 0x41, + general_sensor_problem = 0x81, + device_not_connected = 0x42, + sensor_not_connected = 0x82, + device_reports_error = 0x44, + sensor_reports_error = 0x84, + } + + type PrimitiveTypeStateValue = string | number | boolean; + type StateValue = null | PrimitiveTypeStateValue | PrimitiveTypeStateValue[] | Record; + + interface State { + /** The value of the state. */ + val: T; + + /** Direction flag: false for desired value and true for actual value. Default: false. */ + ack: boolean; + + /** Unix timestamp. Default: current time */ + ts: number; + + /** Unix timestamp of the last time the value changed */ + lc: number; + + /** Name of the adapter instance which set the value, e.g. "system.adapter.web.0" */ + from: string; + + /** Optional time in seconds after which the state is reset to null */ + expire?: number; + + /** Optional quality of the state value */ + q?: StateQuality; + + /** Optional comment */ + c?: string; + + /** Discriminant property to switch between AbsentState and State */ + notExist: undefined; + } + + type SettableState = AtLeastOne; + + interface AbsentState { + val: null; + notExist: true; + + ack: undefined; + ts: undefined; + lc: undefined; + from: undefined; + expire: undefined; + q: undefined; + c: undefined; + } + + type Languages = 'en' | 'de' | 'ru' | 'pt' | 'nl' | 'fr' | 'it' | 'es' | 'pl' | 'zh-cn'; + type StringOrTranslated = string | { [lang in Languages]?: string; }; + type CommonType = "number" | "string" | "boolean" | "array" | "object" | "mixed" | "file"; + + /** Defines access rights for a single object type */ + interface ObjectOperationPermissions { + /** Whether a user may enumerate objects of this type */ + list: boolean; + /** Whether a user may read objects of this type */ + read: boolean; + /** Whether a user may write objects of this type */ + write: boolean; + /** Whether a user may create objects of this type */ + create: boolean; + /** Whether a user may delete objects of this type */ + delete: boolean; + } + + /** Defines the rights a user or group has to change objects */ + interface ObjectPermissions { + /** The access rights for files */ + file: ObjectOperationPermissions; + /** The access rights for objects */ + object: ObjectOperationPermissions; + /** The access rights for users/groups */ + users: ObjectOperationPermissions; + /** The access rights for states */ + state?: ObjectOperationPermissions; + } + /** Defined the complete set of access rights a user has */ + interface PermissionSet extends ObjectPermissions { + /** The name of the user this ACL is for */ + user: string; + /** The name of the groups this ACL was merged from */ + groups: string[]; + /** The access rights for certain commands */ + other: { + execute: boolean; + http: boolean; + sendto: boolean; + }; + } + + interface ObjectACL { + /** Full name of the user who owns this object, e.g. "system.user.admin" */ + owner: string; + /** Full name of the group who owns this object, e.g. "system.group.administrator" */ + ownerGroup: string; + /** Linux-type permissions defining access to this object */ + object: number; + } + /** Defines access rights for a single state object */ + interface StateACL extends ObjectACL { + /** Linux-type permissions defining access to this state */ + state: number; + } + + /** Defines the existing object types in ioBroker */ + type ObjectType = + | 'state' + | 'channel' + | 'device' + | 'folder' + | 'enum' + | 'adapter' + | 'config' + | 'group' + | 'host' + | 'instance' + | 'meta' + | 'script' + | 'user' + | 'chart'; + + // Define the naming schemes for objects, so we can provide more specific types for get/setObject + namespace ObjectIDs { + // Guaranteed meta objects + type Meta = + | `${string}.${number}` + | `${string}.${"meta" | "admin"}` + | `${string}.meta.${string}` + | `${string}.${number}.meta.${string}`; + + // Unsure, can be folder, device, channel or state + // --> We need this match to avoid matching the more specific types below + type Misc = + | `system.host.${string}.${string}` + | `0_userdata.0.${string}`; + + // Guaranteed channel objects + type Channel = + | `script.js.${"common" | "global"}` + | `${string}.${number}.info`; + // Either script or channel object + type ScriptOrChannel = `script.js.${string}`; + // Guaranteed state objects + type State = + | `system.adapter.${string}.${number}.${string}`; + // Guaranteed enum objects + type Enum = `enum.${string}`; + // Guaranteed instance objects + type Instance = `system.adapter.${string}.${number}`; + // Guaranteed adapter objects + type Adapter = `system.adapter.${string}`; + // Guaranteed group objects + type Group = `system.group.${string}`; + // Guaranteed user objects + type User = `system.user.${string}`; + // Guaranteed host objects + type Host = `system.host.${string}`; + // Guaranteed config objects + type Config = `system.${"certificates" | "config" | "repositories"}`; + + // Unsure, can be folder, device, channel or state (or whatever an adapter does) + type AdapterScoped = + | `${string}.${number}.${string}`; + + /** All possible typed object IDs */ + type Any = + | Meta + | Misc + | Channel + | ScriptOrChannel + | State + | Enum + | Instance + | Adapter + | Group + | User + | Host + | Config + | AdapterScoped; + } + + type ObjectIdToObjectType< + T extends string, + Read extends "read" | "write" = "read", + O = + // State must come before Adapter or system.adapter.admin.0.foobar will resolve to AdapterObject + T extends ObjectIDs.State ? StateObject : + // Instance and Adapter must come before meta or `system.adapter.admin` will resolve to MetaObject + T extends ObjectIDs.Instance ? InstanceObject : + T extends ObjectIDs.Adapter ? AdapterObject : + T extends ObjectIDs.Channel ? ChannelObject : + T extends ObjectIDs.Meta ? MetaObject : + T extends ObjectIDs.Misc ? AdapterScopedObject : + T extends ObjectIDs.ScriptOrChannel ? (ScriptObject | ChannelObject) : + T extends ObjectIDs.Enum ? EnumObject : + T extends ObjectIDs.Group ? GroupObject : + T extends ObjectIDs.User ? UserObject : + T extends ObjectIDs.Host ? HostObject : + T extends ObjectIDs.Config ? OtherObject & { type: "config" } : + T extends ObjectIDs.AdapterScoped ? AdapterScopedObject : + iobJS.AnyObject + // When reading objects, we should be less strict, so working with the return type is less of a pain to work with + > = Read extends "read" ? AnyOf : O; + + interface ObjectCommon { + /** The name of this object as a simple string or an object with translations */ + name: StringOrTranslated; + + /** When set to true, this object may not be deleted */ + dontDelete?: true; + + /** When set to true, this object is only visible when expert mode is turned on in admin */ + expert?: true; + + // Icon and role aren't defined in SCHEMA.md, + // but they are being used by some adapters + /** Icon for this object */ + icon?: string; + /** role of the object */ + role?: string; + } + + interface StateCommonAlias { + /** The target state id or two target states used for reading and writing values */ + id: string | { read: string; write: string }; + /** An optional conversion function when reading, e.g. `"(val − 32) * 5/9"` */ + read?: string; + /** An optional conversion function when reading, e.g. `"(val * 9/5) + 32"` */ + write?: string; + } + + interface StateCommon extends ObjectCommon { + /** Type of this state. See https://github.com/ioBroker/ioBroker/blob/master/doc/SCHEMA.md#state-commonrole for a detailed description */ + type?: CommonType; + /** minimum value */ + min?: number; + /** maximum value */ + max?: number; + /** the allowed interval for numeric values */ + step?: number; + /** unit of the value */ + unit?: string; + /** description of this state */ + desc?: StringOrTranslated; + + /** if this state is readable */ + read: boolean; + /** if this state is writable */ + write: boolean; + /** role of the state (used in user interfaces to indicate which widget to choose) */ + role: string; + + /** the default value */ + def?: any; + /** the default status of the ack flag */ + defAck?: boolean; + + /** Configures this state as an alias for another state */ + alias?: StateCommonAlias; + + /** + * Dictionary of possible values for this state in the form + *
+			 * {
+			 *     "internal value 1": "displayed value 1",
+			 *     "internal value 2": "displayed value 2",
+			 *     ...
+			 * }
+			 * 
+ * In old ioBroker versions, this could also be a string of the form + * "val1:text1;val2:text2" (now deprecated) + */ + states?: Record | string; + + /** ID of a helper state indicating if the handler of this state is working */ + workingID?: string; + + /** attached history information */ + history?: any; + + /** Custom settings for this state */ + custom?: Record; + + /** + * Settings for IOT adapters and how the state should be named in e.g., Alexa. + * The string "ignore" is a special case, causing the state to be ignored. + */ + smartName?: string | ({ [lang in Languages]?: string; } & { + /** Which kind of device this is */ + smartType?: string | null; + /** Which value to set when the ON command is issued */ + byOn?: string | null; + }); + } + interface ChannelCommon extends ObjectCommon { + /** description of this channel */ + desc?: string; + + // Make it possible to narrow the object type using the custom property + custom?: undefined; + } + interface DeviceCommon extends ObjectCommon { + // TODO: any other definition for device? + + // Make it possible to narrow the object type using the custom property + custom?: undefined; + } + interface EnumCommon extends ObjectCommon { + /** The IDs of the enum members */ + members?: string[]; + + // Make it possible to narrow the object type using the custom property + custom?: undefined; + } + + interface MetaCommon extends ObjectCommon { + // Meta-objects have to additional CommonTypes + type: CommonType | "meta.user" | "meta.folder"; + + // Make it possible to narrow the object type using the custom property + custom?: undefined; + } + + type InstanceMode = 'none' | 'daemon' | 'subscribe' | 'schedule' | 'once' | 'extension'; + interface InstanceCommon extends ObjectCommon { + /** The name of the host where this instance is running */ + host: string; + enabled: boolean; + /** How and when this instance should be started */ + mode: InstanceMode; + + // Make it possible to narrow the object type using the custom property + custom?: undefined; + } + + interface HostCommon extends ObjectCommon { + /** The display name of this host */ + name: string; + title: string; + installedVersion: string; // e.g. 1.2.3 (following semver) + /** The command line of the executable */ + cmd: string; + hostname: string; + /** An array of IP addresses this host exposes */ + address: string[]; // IPv4 or IPv6 + + type: 'js-controller'; + platform: 'Javascript/Node.js'; + + // Make it possible to narrow the object type using the custom property + custom?: undefined; + } + + interface HostNative { + process: { + title: string; + versions: NodeJS.ProcessVersions; + env: Record; + }; + os: { + hostname: string, + type: ReturnType; + platform: ReturnType; + arch: ReturnType; + release: ReturnType; + endianness: ReturnType; + tmpdir: ReturnType; + }; + hardware: { + cpus: ReturnType; + totalmem: ReturnType; + networkInterfaces: ReturnType; + }; + } + + interface UserCommon extends ObjectCommon { + /** The username */ + name: string; + /** The hashed password */ + password: string; + /** Whether this user is enabled */ + enabled: boolean; + + // Make it possible to narrow the object type using the custom property + custom?: undefined; + } + + interface GroupCommon extends ObjectCommon { + /** The name of this group */ + name: string; + /** The users of this group */ + members: string[]; // system.user.name, ... + /** The default permissions of this group */ + acl: Omit; + + // Make it possible to narrow the object type using the custom property + custom?: undefined; + } + + interface ScriptCommon extends ObjectCommon { + name: string; + /** Defines the type of the script, e.g. TypeScript/ts, JavaScript/js or Blockly */ + engineType: string; + /** The instance id of the instance which executes this script */ + engine: string; + /** The source code of this script */ + source: string; + debug: boolean; + verbose: boolean; + /** Whether this script should be executed */ + enabled: boolean; + /** Is used to determine whether a script has changed and needs to be recompiled */ + sourceHash?: string; + /** If the script uses a compiled language like TypeScript, this contains the compilation output */ + compiled?: string; + /** If the script uses a compiled language like TypeScript, this contains the generated declarations (global scripts only) */ + declarations?: string; + + // Make it possible to narrow the object type using the custom property + custom?: undefined; + } + + type WelcomeScreenEntry = string | { + link: string; + name: string; + img: string; + color: string; + }; + + interface AdapterCommon extends ObjectCommon { + /** Custom attributes to be shown in admin in the object browser */ + adminColumns?: any[]; + /** Settings for custom Admin Tabs */ + adminTab?: { + name?: string; + /** Icon name for FontAwesome */ + "fa-icon"?: string; + /** If true, the Tab is not reloaded when the configuration changes */ + ignoreConfigUpdate?: boolean; + /** Which URL should be loaded in the tab. Supports placeholders like http://%ip%:%port% */ + link?: string; + /** If true, only one instance of this tab will be created for all instances */ + singleton?: boolean; + }; + allowInit?: boolean; + /** Possible values for the instance mode (if more than one is possible) */ + availableModes?: InstanceMode[]; + /** Whether this adapter includes custom blocks for Blockly. If true, `admin/blockly.js` must exist. */ + blockly?: boolean; + /** Where the adapter will get its data from. Set this together with @see dataSource */ + connectionType?: "local" | "cloud"; + /** If true, this adapter can be started in compact mode (in the same process as other adpaters) */ + compact?: boolean; + /** The directory relative to iobroker-data where the adapter stores the data. Supports the placeholder `%INSTANCE%`. This folder will be backed up and restored automatically. */ + dataFolder?: string; + /** How the adapter will mainly receive its data. Set this together with @see connectionType */ + dataSource?: "poll" | "push" | "assumption"; + /** A record of ioBroker adapters (including "js-controller") and version ranges which are required for this adapter. */ + dependencies?: Array>; + /** Which files outside of the README.md have documentation for the adapter */ + docs?: Partial>; + /** Whether new instances should be enabled by default. *Should* be `false`! */ + enabled: boolean; + /** If true, all previous data in the target directory (web) should be deleted before uploading */ + eraseOnUpload?: boolean; + /** URL of an external icon that is shown for adapters that are not installed */ + extIcon?: string; + /** Whether this adapter responds to `getHistory` messages */ + getHistory?: boolean; + /** Filename of the local icon which is shown for installed adapters. Should be located in the `admin` directory */ + icon?: string; + /** Which version of this adapter is installed */ + installedVersion: string; + keywords?: string[]; + /** A dictionary of links to web services this adapter provides */ + localLinks?: Record; + /** @deprecated Use @see localLinks */ + localLink?: string; + logLevel?: LogLevel; + /** Whether this adapter receives logs from other hosts and adapters (e.g., to strore them somewhere) */ + logTransporter?: boolean; + /** Path to the start file of the adapter. Should be the same as in `package.json` */ + main?: string; + /** Whether the admin tab is written in materialize style. Required for Admin 3+ */ + materializeTab: boolean; + /** Whether the admin configuration dialog is written in materialize style. Required for Admin 3+ */ + materialize: boolean; + /** If `true`, the object `system.adapter...messagebox will be created to send messages to the adapter (used for email, pushover, etc...) */ + messagebox?: true; + mode: InstanceMode; + /** Name of the adapter (without leading `ioBroker.`) */ + name: string; + /** If `true`, no configuration dialog will be shown */ + noConfig?: true; + /** If `true`, this adapter's instances will not be shown in the admin overview screen. Useful for icon sets and widgets... */ + noIntro?: true; + /** Set to `true` if the adapter is not available in the official ioBroker repositories. */ + noRepository?: true; + /** If `true`, manual installation from GitHub is not possible */ + nogit?: true; + /** If `true`, this adapter cannot be deleted or updated manually. */ + nondeletable?: true; + /** If `true`, this "adapter" only contains HTML files and no main executable */ + onlyWWW?: boolean; + /** Used to configure native (OS) dependencies of this adapter that need to be installed with system package manager before installing the adapter */ + osDependencies?: { + /** For OSX */ + darwin: string[]; + /** For Linux */ + linux: string[]; + /** For Windows */ + win32: string[]; + }; + /** Which OSes this adapter supports */ + os?: "linux" | "darwin" | "win32" | Array<("linux" | "darwin" | "win32")>; + platform: "Javascript/Node.js"; + /** The keys of common attributes (e.g. `history`) which are not deleted in a `setObject` call even if they are not present. Deletion must be done explicitly by setting them to `null`. */ + preserveSettings?: string | string[]; + /** Which adapters must be restarted after installing or updating this adapter. */ + restartAdapters?: string[]; + /** If the adapter runs in `schedule` mode, this contains the CRON */ + schedule?: string; + serviceStates?: boolean | string; + /** Whether this adapter may only be installed once per host */ + singletonHost?: boolean; + /** Whether this adapter may only be installed once in the whole system */ + singleton?: boolean; + /** Whether the adapter must be stopped before an update */ + stopBeforeUpdate?: boolean; + /** Overrides the default timeout that ioBroker will wait before force-stopping the adapter */ + stopTimeout?: number; + subscribable?: boolean; + subscribe?: any; // ? + /** If `true`, this adapter provides custom per-state settings. Requires a `custom_m.html` file in the `admin` directory. */ + supportCustoms?: boolean; + /** Whether the adapter supports the signal stopInstance via messagebox */ + supportStopInstance?: boolean; + /** The translated names of this adapter to be shown in the admin UI */ + titleLang?: Record; + /** @deprecated The name of this adapter to be shown in the admin UI. Use @see titleLang instead. */ + title?: string; + /** The type of this adapter */ + type?: string; + /** If `true`, the `npm` package must be installed with the `--unsafe-perm` flag */ + unsafePerm?: true; + /** The available version in the ioBroker repo. */ + version: string; + /** If `true`, the adapter will be started if any value is written into `system.adapter...wakeup. Normally, the adapter should stop after processing the event. */ + wakeup?: boolean; + /** Include the adapter version in the URL of the web adapter, e.g. `http://ip:port/1.2.3/material` instead of `http://ip:port/material` */ + webByVersion?: boolean; + /** Whether the web server in this adapter can be extended with plugin/extensions */ + webExtendable?: boolean; + /** Relative path to a module that contains an extension for the web adapter. Use together with @see native.webInstance to configure which instances this affects */ + webExtension?: string; + webPreSettings?: any; // ? + webservers?: any; // ? + /** A list of pages that should be shown on the "web" index page */ + welcomeScreen?: WelcomeScreenEntry[]; + /** A list of pages that should be shown on the ioBroker cloud index page */ + welcomeScreenPro?: WelcomeScreenEntry[]; + wwwDontUpload?: boolean; + + // Make it possible to narrow the object type using the custom property + custom?: undefined; + } + + interface OtherCommon extends ObjectCommon { + [propName: string]: any; + + // Make it possible to narrow the object type using the custom property + custom?: undefined; + } + + /* Base type for Objects. Should not be used directly */ + interface BaseObject { + /** The ID of this object */ + _id: string; + type: ObjectType; // specified in the derived interfaces + // Ideally we would limit this to JSON-serializable objects, but TypeScript doesn't allow this + // without bugging users to change their code --> https://github.com/microsoft/TypeScript/issues/15300 + native: Record; + common: Record; + enums?: Record; + acl?: ObjectACL; + from?: string; + /** The user who created or updated this object */ + user?: string; + ts?: number; + } + + interface StateObject extends BaseObject { + type: 'state'; + common: StateCommon; + acl?: StateACL; + } + interface PartialStateObject extends Partial> { + common?: Partial; + acl?: Partial; + } + + interface ChannelObject extends BaseObject { + type: 'channel'; + common: ChannelCommon; + } + interface PartialChannelObject + extends Partial> { + common?: Partial; + } + + interface DeviceObject extends BaseObject { + type: 'device'; + common: DeviceCommon; + } + interface PartialDeviceObject extends Partial> { + common?: Partial; + } + + interface FolderObject extends BaseObject { + type: 'folder'; + // Nothing is set in stone here, so start with allowing every property + common: OtherCommon; + } + interface PartialFolderObject extends Partial> { + common?: Partial; + } + + interface EnumObject extends BaseObject { + type: 'enum'; + common: EnumCommon; + } + interface PartialEnumObject extends Partial> { + common?: Partial; + } + + interface MetaObject extends BaseObject { + type: 'meta'; + common: MetaCommon; + } + interface PartialMetaObject extends Partial> { + common?: Partial; + } + + interface InstanceObject extends BaseObject { + type: 'instance'; + common: InstanceCommon; + } + interface PartialInstanceObject extends Partial> { + common?: Partial; + } + + interface AdapterObject extends BaseObject { + type: 'adapter'; + common: AdapterCommon; + /** An array of `native` properties which cannot be accessed from outside the defining adapter */ + protectedNative?: string[]; + /** Like protectedNative, but the properties are also encrypted and decrypted automatically */ + encryptedNative?: string[]; + } + interface PartialAdapterObject extends Partial> { + common?: Partial; + } + + interface HostObject extends BaseObject { + type: 'host'; + common: HostCommon; + native: HostNative; + } + interface PartialHostObject extends Partial> { + common?: Partial; + native?: Partial; + } + + interface UserObject extends BaseObject { + type: 'user'; + common: UserCommon; + } + interface PartialUserObject extends Partial> { + common?: Partial; + } + + interface GroupObject extends BaseObject { + type: 'group'; + common: GroupCommon; + } + interface PartialGroupObject extends Partial> { + common?: Partial; + } + + interface ScriptObject extends BaseObject { + type: 'script'; + common: ScriptCommon; + } + interface PartialScriptObject extends Partial> { + common?: Partial; + } + + interface OtherObject extends BaseObject { + type: 'config' | 'chart'; + common: OtherCommon; + } + interface PartialOtherObject extends Partial> { + common?: Partial; + } + + type AnyObject = + | StateObject + | ChannelObject + | DeviceObject + | FolderObject + | EnumObject + | MetaObject + | HostObject + | AdapterObject + | InstanceObject + | UserObject + | GroupObject + | ScriptObject + | OtherObject; + + type AnyPartialObject = + | PartialStateObject + | PartialChannelObject + | PartialDeviceObject + | PartialFolderObject + | PartialEnumObject + | PartialMetaObject + | PartialHostObject + | PartialAdapterObject + | PartialInstanceObject + | PartialUserObject + | PartialGroupObject + | PartialScriptObject + | PartialOtherObject; + + /** All objects that usually appear in an adapter scope */ + type AdapterScopedObject = FolderObject | DeviceObject | ChannelObject | StateObject; + + // For all objects that are exposed to the user we need to tone the strictness down. + // Otherwise, every operation on objects becomes a pain to work with + type Object = AnyObject; + + // In set[Foreign]Object[NotExists] methods, the ID and acl of the object is optional + type SettableObjectWorker = T extends AnyObject ? Omit & { + _id?: T['_id']; + acl?: T['acl']; + } : never; + // in extend[Foreign]Object, most properties are optional + type PartialObjectWorker = T extends AnyObject ? AnyPartialObject & { type?: T["type"] } : never; + + type PartialObject = PartialObjectWorker; + + // Convenient definitions for manually specifying settable object types + type SettableObject = SettableObjectWorker; + type SettableStateObject = SettableObject; + type SettableChannelObject = SettableObject; + type SettableDeviceObject = SettableObject; + type SettableFolderObject = SettableObject; + type SettableEnumObject = SettableObject; + type SettableMetaObject = SettableObject; + type SettableHostObject = SettableObject; + type SettableAdapterObject = SettableObject; + type SettableInstanceObject = SettableObject; + type SettableUserObject = SettableObject; + type SettableGroupObject = SettableObject; + type SettableScriptObject = SettableObject; + type SettableOtherObject = SettableObject; + + /** Represents the change of a state */ + interface ChangedStateObject extends StateObject { + common: StateCommon; + native: Record; + id?: string; + name?: string; + channelId?: string; + channelName?: string; + deviceId?: string; + deviceName?: string; + /** The IDs of enums this state is assigned to. For example ["enum.functions.Licht","enum.rooms.Garten"] */ + enumIds?: string[]; + /** The names of enums this state is assigned to. For example ["Licht","Garten"] */ + enumNames?: string[]; + /** new state */ + state: State; + /** @deprecated Use state instead **/ + newState: State; + /** previous state */ + oldState: State; + /** Name of the adapter instance which set the value, e.g. "system.adapter.web.0" */ + from?: string; + /** Unix timestamp. Default: current time */ + ts?: number; + /** Unix timestamp of the last time the value changed */ + lc?: number; + /** Direction flag: false for desired value and true for actual value. Default: false. */ + ack?: boolean; + } + + type GetStateCallback = (err?: string | null, state?: State | AbsentState) => void | Promise; + type ExistsStateCallback = (err?: string | null, exists?: Boolean) => void | Promise; + + type GetBinaryStateCallback = (err?: string | null, state?: Buffer) => void | Promise; + type GetBinaryStatePromise = Promise>; + + type SetStateCallback = (err?: string | null, id?: string) => void | Promise; + type SetStatePromise = Promise>; + + type StateChangeHandler = (obj: ChangedStateObject) => void | Promise; + + type FileChangeHandler = + // Variant 1: WithFile is false, data/mimeType is definitely not there + [WithFile] extends [false] ? (id: string, fileName: string, size: number, data?: undefined, mimeType?: undefined) => void | Promise + // Variant 2: WithFile is true, data (and mimeType?) is definitely there + : [WithFile] extends [true] ? (id: string, fileName: string, size: number, data: Buffer | string, mimeType?: string) => void | Promise + // Variant 3: WithFile is not known, data/mimeType might be there + : (id: string, fileName: string, size: number, data?: Buffer | string, mimeType?: string) => void | Promise; + + type SetObjectCallback = (err?: string | null, obj?: { id: string }) => void | Promise; + type SetObjectPromise = Promise>; + + type GetObjectCallback = (err?: string | null, obj?: ObjectIdToObjectType | null) => void; + type GetObjectPromise = Promise>>; + + type LogLevel = "silly" | "debug" | "info" | "warn" | "error" | "force"; + + type ReadFileCallback = (err?: string | null, file?: Buffer | string, mimeType?: string) => void | Promise; + type ReadFilePromise = Promise>; + + /** Callback information for a passed message */ + interface MessageCallbackInfo { + /** The original message payload */ + message: string | object; + /** ID of this callback */ + id: number; + // ??? + ack: boolean; + /** Timestamp of this message */ + time: number; + } + type MessageCallback = (result?: any) => void | Promise; + + interface Subscription { + name: string; + pattern: string | RegExp | string[] | iobJS.SubscribeOptions | iobJS.SubscribeTime | iobJS.AstroSchedule; + } + + interface SubscribeOptions { + /** "and" or "or" logic to combine the conditions (default: "and") */ + logic?: "and" | "or"; + /** name is equal or matches to given one or name marches to any item in given list */ + id?: string | string[] | SubscribeOptions[] | RegExp | RegExp[]; + /** name is equal or matches to given one */ + name?: string | string[] | RegExp; + /** type of change */ + change?: "eq" | "ne" | "gt" | "ge" | "lt" | "le" | "any"; + val?: StateValue; + /** New value must not be equal to given one */ + valNe?: StateValue; + /** New value must be greater than given one */ + valGt?: number; + /** New value must be greater or equal to given one */ + valGe?: number; + /** New value must be smaller than given one */ + valLt?: number; + /** New value must be smaller or equal to given one */ + valLe?: number; + /** Acknowledged state of new value is equal to given one */ + ack?: boolean; + /** Previous value must be equal to given one */ + oldVal?: StateValue; + /** Previous value must be not equal to given one */ + oldValNe?: StateValue; + /** Previous value must be greater than given one */ + oldValGt?: number; + /** Previous value must be greater or equal given one */ + oldValGe?: number; + /** Previous value must be smaller than given one */ + oldValLt?: number; + /** Previous value must be smaller or equal to given one */ + oldValLe?: number; + /** Acknowledged state of previous value is equal to given one */ + oldAck?: boolean; + /** New value time stamp must be equal to given one (state.ts == ts) */ + ts?: number; + /** New value time stamp must be not equal to the given one (state.ts != ts) */ + tsGt?: number; + /** New value time stamp must be greater than given value (state.ts > ts) */ + tsGe?: number; + /** New value time stamp must be greater or equal to given one (state.ts >= ts) */ + tsLt?: number; + /** New value time stamp must be smaller than given one (state.ts < ts) */ + tsLe?: number; + /** Previous time stamp must be equal to given one (oldState.ts == ts) */ + oldTs?: number; + /** Previous time stamp must be not equal to the given one (oldState.ts != ts) */ + oldTsGt?: number; + /** Previous time stamp must be greater than the given value (oldState.ts > ts) */ + oldTsGe?: number; + /** Previous time stamp must be greater or equal to given one (oldState.ts >= ts) */ + oldTsLt?: number; + /** Previous time stamp must be smaller than given one (oldState.ts < ts) */ + oldTsLe?: number; + /** Last change time stamp must be equal to given one (state.lc == lc) */ + lc?: number; + /** Last change time stamp must be not equal to the given one (state.lc != lc) */ + lcGt?: number; + /** Last change time stamp must be greater than the given value (state.lc > lc) */ + lcGe?: number; + /** Last change time stamp must be greater or equal to given one (state.lc >= lc) */ + lcLt?: number; + /** Last change time stamp must be smaller than given one (state.lc < lc) */ + lcLe?: number; + /** Previous last change time stamp must be equal to given one (oldState.lc == lc) */ + oldLc?: number; + /** Previous last change time stamp must be not equal to the given one (oldState.lc != lc) */ + oldLcGt?: number; + /** Previous last change time stamp must be greater than the given value (oldState.lc > lc) */ + oldLcGe?: number; + /** Previous last change time stamp must be greater or equal to given one (oldState.lc >= lc) */ + oldLcLt?: number; + /** Previous last change time stamp must be smaller than given one (oldState.lc < lc) */ + oldLcLe?: number; + /** Channel ID must be equal or match to given one */ + channelId?: string | string[] | RegExp; + /** Channel name must be equal or match to given one */ + channelName?: string | string[] | RegExp; + /** Device ID must be equal or match to given one */ + deviceId?: string | string[] | RegExp; + /** Device name must be equal or match to given one */ + deviceName?: string | string[] | RegExp; + /** State belongs to given enum or one enum ID of state satisfy the given regular expression */ + enumId?: string | string[] | RegExp; + /** State belongs to given enum or one enum name of state satisfy the given regular expression */ + enumName?: string | string[] | RegExp; + /** New value is from defined adapter */ + from?: string | string[] | RegExp; + /** New value is not from defined adapter */ + fromNe?: string | string[] | RegExp; + /** Old value is from defined adapter */ + oldFrom?: string | string[] | RegExp; + /** Old value is not from defined adapter */ + oldFromNe?: string | string[] | RegExp; + } + + interface QueryResult extends Iterable { + /** State-ID */ + [index: number]: string; + /** Number of matched states */ + length: number; + /** Contains the error if one happened */ + error?: string; + + /** + * Executes a function for each state id in the result array + * The execution is canceled if a callback returns false + */ + each(callback?: (id: string, index: number) => boolean | void | Promise): this; + + /** + * Returns the first state found by this query. + * If the adapter is configured to subscribe to all states on start, + * this can be called synchronously and immediately returns the state. + * Otherwise, you need to provide a callback. + */ + getState(callback: GetStateCallback): void; + getState(): State | null | undefined; + getStateAsync(): Promise | null | undefined>; + + /** + * Returns the first state found by this query. + * If the adapter is configured to subscribe to all states on start, + * this can be called synchronously and immediately returns the state. + * Otherwise, you need to provide a callback. + */ + getBinaryState(callback: GetBinaryStateCallback): void; + getBinaryState(): Buffer | null | undefined; + getBinaryStateAsync(): Promise; + + /** + * Sets all queried states to the given value. + */ + setState(state: State | StateValue | SettableState, ack?: boolean, callback?: SetStateCallback): this; + setStateAsync(state: State | StateValue | SettableState, ack?: boolean): Promise; + setStateDelayed(state: any, isAck?: boolean, delay?: number, clearRunning?: boolean, callback?: SetStateCallback): this; + + /** + * Sets all queried binary states to the given value. + */ + setBinaryState(state: Buffer, ack?: boolean, callback?: SetStateCallback): this; + setBinaryStateAsync(state: Buffer, ack?: boolean): Promise; + + /** + * Subscribes the given callback to changes of the matched states. + */ + on(callback: StateChangeHandler): this; + } + + /** + * * "sunrise": sunrise (top edge of the sun appears on the horizon) + * * "sunriseEnd": sunrise ends (bottom edge of the sun touches the horizon) + * * "goldenHourEnd": morning golden hour (soft light, best time for photography) ends + * * "solarNoon": solar noon (sun is in the highest position) + * * "goldenHour": evening golden hour starts + * * "sunsetStart": sunset starts (bottom edge of the sun touches the horizon) + * * "sunset": sunset (sun disappears below the horizon, evening civil twilight starts) + * * "dusk": dusk (evening nautical twilight starts) + * * "nauticalDusk": nautical dusk (evening astronomical twilight starts) + * * "night": night starts (dark enough for astronomical observations) + * * "nightEnd": night ends (morning astronomical twilight starts) + * * "nauticalDawn": nautical dawn (morning nautical twilight starts) + * * "dawn": dawn (morning nautical twilight ends, morning civil twilight starts) + * * "nadir": nadir (darkest moment of the night, sun is in the lowest position) + */ + type AstroPattern = "sunrise" | "sunriseEnd" | "goldenHourEnd" | "solarNoon" | "goldenHour" | "sunsetStart" | "sunset" | "dusk" | "nauticalDusk" | "night" | "nightEnd" | "nauticalDawn" | "dawn" | "nadir"; + + interface AstroSchedule { + astro: AstroPattern; + /** + * Shift to the astro schedule. + */ + shift?: number; + } + + interface AstroDate { + astro: AstroPattern; + /** Offset to the astro event in minutes */ + offset?: number; + /** Date for which the astro time is wanted */ + date?: Date; + } + + /** + * from https://github.com/node-schedule/node-schedule + */ + interface ScheduleRule { + /** + * Day of the month. + */ + date?: number | number[] | string | string[]; + + /** + * Day of the week. + */ + dayOfWeek?: number | number[] | string | string[]; + + /** + * Hour. + */ + hour?: number | number[] | string | string[]; + + /** + * Minute. + */ + minute?: number | number[] | string | string[]; + + /** + * Month. + */ + month?: number | number[] | string | string[]; + + /** + * Second. + */ + second?: number | number[] | string | string[]; + + /** + * Year. + */ + year?: number | number[] | string | string[]; + /** + * timezone which should be used + * https://github.com/moment/moment-timezone + */ + tz?: string; + } + + /** + * from https://github.com/node-schedule/node-schedule + */ + interface ScheduleRuleConditional { + /** + * set a start time for schedule + * a Data object or a dateString resp a number in milliseconds which can create a Date object + */ + start?: Date | string | number; + /** + * set an end time for schedule + * a Data object or a dateString resp a number in milliseconds which can create a Date object + */ + end?: Date | string | number; + /** + * timezone which should be used + * https://github.com/moment/moment-timezone + */ + tz?: string; + /** + * scheduling rule + * schedule rule, a Data object or a dateString resp a number in milliseconds which can create a Date object + */ + rule: ScheduleRule | Date | string | number; + } + + interface LogMessage { + severity: LogLevel; // severity + ts: number; // timestamp as Date.now() + message: string; // message + from: string; // origin of the message + } + + type SchedulePattern = ScheduleRule | ScheduleRuleConditional | Date | string | number; + + interface SubscribeTime { + time: SchedulePattern; + } + + interface StateTimer { + id: number; + left: number; + delay: number; + val: any; + ack: boolean; + } + + type MessageSubscribeID = number; + interface MessageTarget { + /** Javascript Instance */ + instance?: string; + /** Script name */ + script?: string; + /** Message name */ + message: string; + } + } // end namespace iobJS + + // ======================================================= + // available functions in the sandbox + // ======================================================= + + // The already preloaded request module + const request: typeof import("request"); + + /** + * The instance number of the JavaScript adapter this script runs in + */ + const instance: number; + /** + * The name of the current script + */ + // @ts-ignore We need this variable, although it conflicts with lib.es6 + const name: string; + /** + * The name of the current script + */ + const scriptName: string; + + /** + * Queries all states with the given selector + * @param selector See @link{https://github.com/ioBroker/ioBroker.javascript#---selector} for a description + */ + // @ts-ignore We need this function, although it conflicts with vue + function $(selector: string): iobJS.QueryResult; + + /** + * Prints a message in the ioBroker log + * @param message The message to print + * @param severity (optional) severity of the message. default = "info" + */ + function log(message: string, severity?: iobJS.LogLevel): void; + + // console functions + // @ts-ignore We need this variable, although it conflicts with the node typings + namespace console { + /** log a message with debug level */ + function debug(message: string): void; + /** log a message with info level (default output level for all adapters) */ + function info(message: string): void; + /** log a message with warning severity */ + function warn(message: string): void; + /** log a message with error severity */ + function error(message: string): void; + } + + /** + * Executes a system command + */ + const exec: typeof import("child_process").exec; + + /** + * Sends an email using the email adapter. + * See the adapter documentation for a description of the msg parameter. + */ + function email(msg: any): void; + + /** + * Sends a pushover message using the pushover adapter. + * See the adapter documentation for a description of the msg parameter. + */ + function pushover(msg: any): void; + + /** + * Subscribe to the changes of the matched states. + */ + function on(pattern: string | RegExp | string[], handler: iobJS.StateChangeHandler): any; + function on( + astroOrScheduleOrOptions: iobJS.AstroSchedule | iobJS.SubscribeTime | iobJS.SubscribeOptions, + handler: iobJS.StateChangeHandler + ): any; + /** + * Subscribe to the changes of the matched states. + */ + function subscribe(pattern: string | RegExp | string[], handler: iobJS.StateChangeHandler): any; + function subscribe( + astroOrScheduleOrOptions: iobJS.AstroSchedule | iobJS.SubscribeTime | iobJS.SubscribeOptions, + handler: iobJS.StateChangeHandler + ): any; + + /** + * Subscribe to the changes of the matched files. + * The return value can be used for offFile later + * @param id ID of meta-object, like `vis.0` + * @param filePattern File name or file pattern, like `main/*` + * @param withFile If the content of the file must be returned in callback (high usage of memory) + * @param handler Callback: function (id, fileName, size, data, mimeType) {} + */ + function onFile(id: string, filePattern: string | string[], withFile: WithFile, handler: iobJS.FileChangeHandler): any; + function onFile(id: string, filePattern: string | string[], handler: iobJS.FileChangeHandler): any; + + /** + * Un-subscribe from the changes of the matched files. + * @param id ID of meta-object, like `vis.0`. You can provide here can be a returned object from onFile. In this case, no filePattern required. + * @param filePattern File name or file pattern, like `main/*` + */ + function offFile(id: string | any, filePattern?: string | string[]): boolean; + + /** + * Registers a one-time subscription which automatically unsubscribes after the first invocation + */ + function once( + pattern: string | RegExp | string[] | iobJS.AstroSchedule | iobJS.SubscribeTime | iobJS.SubscribeOptions, + handler: iobJS.StateChangeHandler + ): any; + function once( + pattern: string | RegExp | string[] | iobJS.AstroSchedule | iobJS.SubscribeTime | iobJS.SubscribeOptions + ): Promise; + + /** + * Causes all changes of the state with id1 to the state with id2. + * The return value can be used to unsubscribe later + */ + function on(id1: string, id2: string): any; + /** + * Watches the state with id1 for changes and overwrites the state with id2 with value2 when any occur. + * @param id1 The state to watch for changes + * @param id2 The state to update when changes occur + * @param value2 The value to write into state `id2` when `id1` gets changed + */ + function on(id1: string, id2: string, value2: any): any; + + /** + * Causes all changes of the state with id1 to the state with id2 + */ + function subscribe(id1: string, id2: string): any; + /** + * Watches the state with id1 for changes and overwrites the state with id2 with value2 when any occur. + * @param id1 The state to watch for changes + * @param id2 The state to update when changes occur + * @param value2 The value to write into state `id2` when `id1` gets changed + */ + function subscribe(id1: string, id2: string, value2: any): any; + + /** + * Returns the list of all currently active subscriptions + */ + function getSubscriptions(): { [id: string]: iobJS.Subscription[] }; + + /** + * Unsubscribe from changes of the given object ID(s) or handler(s) + */ + function unsubscribe(id: string | string[]): boolean; + function unsubscribe(handler: any | any[]): boolean; + + function adapterSubscribe(id: string): void; + function adapterUnsubscribe(id: string): void; + + /** + * Schedules a function to be executed on a defined schedule. + * The return value can be used to clear the schedule later. + */ + function schedule(pattern: string | iobJS.SchedulePattern, callback: EmptyCallback): any; + function schedule(date: Date, callback: EmptyCallback): any; + function schedule(astro: iobJS.AstroSchedule, callback: EmptyCallback): any; + /** + * Clears a schedule. Returns true if it was successful. + */ + function clearSchedule(schedule: any): boolean; + + /** + * Calculates the astro time which corresponds to the given pattern. + * For valid patterns, see @link{https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#astro-function} + * @param pattern One of predefined patterns, like: sunrise, sunriseEnd, ... + * @param date (optional) The date for which the astro time should be calculated. Default = today + * @param offsetMinutes (optional) The number of minutes to be added to the return value. + */ + function getAstroDate(pattern: string, date?: Date | number, offsetMinutes?: number): Date; + + /** + * Determines if now is between sunrise and sunset. + */ + function isAstroDay(): boolean; + + /** + * Sets a state to the given value + * @param id The ID of the state to be set + */ + function setState(id: string, state: iobJS.State | iobJS.StateValue | iobJS.SettableState, callback?: iobJS.SetStateCallback): void; + function setState(id: string, state: iobJS.State | iobJS.StateValue | iobJS.SettableState, ack: boolean, callback?: iobJS.SetStateCallback): void; + + function setStateAsync(id: string, state: iobJS.State | iobJS.StateValue | iobJS.SettableState, ack?: boolean): iobJS.SetStatePromise; + + /** + * Sets a state to the given value after a timeout has passed. + * Returns the timer, so it can be manually cleared with clearStateDelayed + * @param id The ID of the state to be set + * @param delay The delay in milliseconds + * @param clearRunning (optional) Whether an existing timeout for this state should be cleared + * @returns If a delayed setState was scheduled, this returns the timer id, otherwise null. + */ + function setStateDelayed(id: string, state: iobJS.State | iobJS.StateValue | iobJS.SettableState, delay: number, clearRunning: boolean, callback?: iobJS.SetStateCallback): number | null; + function setStateDelayed(id: string, state: iobJS.State | iobJS.StateValue | iobJS.SettableState, ack: boolean, clearRunning: boolean, callback?: iobJS.SetStateCallback): number | null; + function setStateDelayed(id: string, state: iobJS.State | iobJS.StateValue | iobJS.SettableState, ack: boolean, delay: number, callback?: iobJS.SetStateCallback): number | null; + function setStateDelayed(id: string, state: iobJS.State | iobJS.StateValue | iobJS.SettableState, delay: number, callback?: iobJS.SetStateCallback): number | null; + function setStateDelayed(id: string, state: iobJS.State | iobJS.StateValue | iobJS.SettableState, callback?: iobJS.SetStateCallback): number | null; + function setStateDelayed(id: string, state: iobJS.State | iobJS.StateValue | iobJS.SettableState, ack: boolean, delay: number, clearRunning: boolean, callback?: iobJS.SetStateCallback): number | null; + + /** + * Clears a timer created by setStateDelayed + * @param id The state id for which the timer should be cleared + * @param timerID (optional) ID of the specific timer to clear. If none is given, all timers are cleared. + */ + function clearStateDelayed(id: string, timerID?: number): boolean; + + /** + * Returns information about a specific timer created with `setStateDelayed`. + * @param timerId The timer id that was returned by `setStateDelayed`. + */ + function getStateDelayed(timerId: number): iobJS.StateTimer | null; + /** + * Returns a list of all timers created with `setStateDelayed`. Can be limited to a specific state id. + * @param id The state id for which the timers should be. + */ + function getStateDelayed(id?: string): iobJS.StateTimer[]; + + /** + * Sets a binary state to the given value + * @param id The ID of the state to be set + * @param state binary data as buffer + * @param callback called when the operation finished + */ + function setBinaryState(id: string, state: Buffer, callback?: iobJS.SetStateCallback): void; + function setBinaryStateAsync(id: string, state: Buffer): iobJS.SetStatePromise; + + /** + * Returns the state with the given ID. + * If the adapter is configured to subscribe to all states on start, + * this can be called synchronously and immediately returns the state. + * Otherwise, you need to provide a callback. + */ + function getState(id: string, callback: iobJS.GetStateCallback): void; + function getState(id: string): iobJS.State | iobJS.AbsentState; + function getStateAsync(id: string): Promise>; + + /** + * Returns the binary state with the given ID. + * If the adapter is configured to subscribe to all states on start, + * this can be called synchronously and immediately returns the state. + * Otherwise, you need to provide a callback. + */ + function getBinaryState(id: string, callback: iobJS.GetStateCallback): void; + function getBinaryState(id: string): Buffer; + function getBinaryStateAsync(id: string): iobJS.GetBinaryStatePromise; + + /** + * Checks if the state with the given ID exists + */ + function existsState(id: string, callback: iobJS.ExistsStateCallback): void; + function existsState(id: string): boolean; + function existsStateAsync(id: string): Promise; + /** + * Checks if the object with the given ID exists + */ + function existsObject(id: string): boolean; + function existsObjectAsync(id: string): Promise; + + /** + * Returns the IDs of the states with the given name + * @param name Name of the state + * @param forceArray (optional) Ensures that the return value is always an array, even if only one ID was found. + */ + function getIdByName(name: string, forceArray?: boolean): string | string[]; + + /** + * Reads an object from the object db. + * @param enumName Which enum should be included in the returned object. `true` to return all enums. + */ + function getObject(id: T, enumName?: string | true): iobJS.ObjectIdToObjectType; + function getObject(id: T, callback: iobJS.GetObjectCallback): void; + function getObject(id: T, enumName: string | true, callback: iobJS.GetObjectCallback): void; + function getObjectAsync(id: T, enumName?: string | true): iobJS.GetObjectPromise; + + /** Creates or overwrites an object in the object db */ + function setObject(id: string, obj: iobJS.SettableObject, callback?: iobJS.SetObjectCallback): void; + function setObjectAsync(id: string, obj: iobJS.SettableObject): iobJS.SetObjectPromise; + /** Extend an object and create it if it might not exist */ + function extendObject(id: string, objPart: iobJS.PartialObject, callback?: iobJS.SetObjectCallback): void; + function extendObjectAsync(id: string, objPart: iobJS.PartialObject): iobJS.SetObjectPromise; + + /** Deletes an object in the object db */ + function deleteObject(id: string, callback?: ErrorCallback): void; + function deleteObject(id: string, recursive: boolean, callback?: ErrorCallback): void; + function deleteObjectAsync(id: string, recursive?: boolean): Promise; + + function getEnums(enumName?: string): any; + + /** + * Creates a state and the corresponding object under the javascript namespace. + * @param name The name of the state without the namespace + * @param initValue (optional) Initial value of the state + * @param forceCreation (optional) Override the state if it already exists + * @param common (optional) Common part of the state object + * @param native (optional) Native part of the state object + * @param callback (optional) Called after the state was created + */ + function createState(name: string, callback?: iobJS.SetStateCallback): void; + function createState(name: string, initValue: iobJS.StateValue, callback?: iobJS.SetStateCallback): void; + function createState(name: string, initValue: iobJS.StateValue, forceCreation: boolean, callback?: iobJS.SetStateCallback): void; + function createState(name: string, initValue: iobJS.StateValue, forceCreation: boolean, common: Partial, callback?: iobJS.SetStateCallback): void; + function createState(name: string, initValue: iobJS.StateValue, forceCreation: boolean, common: Partial, native: any, callback?: iobJS.SetStateCallback): void; + function createState(name: string, common: Partial, callback?: iobJS.SetStateCallback): void; + function createState(name: string, initValue: iobJS.StateValue, common: Partial, callback?: iobJS.SetStateCallback): void; + function createState(name: string, common: Partial, native: any, callback?: iobJS.SetStateCallback): void; + function createState(name: string, initValue: iobJS.StateValue, common: Partial, native: any, callback?: iobJS.SetStateCallback): void; + + function createStateAsync(name: string, initValue?: iobJS.StateValue, forceCreation?: boolean, common?: Partial, native?: any): iobJS.SetStatePromise; + function createStateAsync(name: string, common: Partial): iobJS.SetStatePromise; + function createStateAsync(name: string, common: Partial, native?: any): iobJS.SetStatePromise; + function createStateAsync(name: string, initValue: iobJS.StateValue, common: Partial): iobJS.SetStatePromise; + function createStateAsync(name: string, initValue: iobJS.StateValue, common: Partial, native?: any): iobJS.SetStatePromise; + + function createAlias(name: string, alias: string | iobJS.StateCommonAlias, callback?: iobJS.SetStateCallback): void; + function createAlias(name: string, alias: string | iobJS.StateCommonAlias, forceCreation: boolean, callback?: iobJS.SetStateCallback): void; + function createAlias(name: string, alias: string | iobJS.StateCommonAlias, forceCreation: boolean, common: Partial, callback?: iobJS.SetStateCallback): void; + function createAlias(name: string, alias: string | iobJS.StateCommonAlias, forceCreation: boolean, common: Partial, native: any, callback?: iobJS.SetStateCallback): void; + function createAlias(name: string, alias: string | iobJS.StateCommonAlias, common: Partial, callback?: iobJS.SetStateCallback): void; + function createAlias(name: string, alias: string | iobJS.StateCommonAlias, common: Partial, native: any, callback?: iobJS.SetStateCallback): void; + + function createAliasAsync(name: string, alias: string | iobJS.StateCommonAlias, forceCreation?: boolean, common?: Partial, native?: any): iobJS.SetStatePromise; + function createAliasAsync(name: string, alias: string | iobJS.StateCommonAlias, common: Partial): iobJS.SetStatePromise; + function createAliasAsync(name: string, alias: string | iobJS.StateCommonAlias, common: Partial, native?: any): iobJS.SetStatePromise; + + + + /** + * Deletes the state with the given ID + * @param callback (optional) Is called after the state was deleted (or not). + */ + function deleteState(id: string, callback?: GenericCallback): void; + function deleteStateAsync(id: string): Promise; + + /** + * Sends a message to a specific instance or all instances of some specific adapter. + * @param instanceName The instance to send this message to. + * If the ID of an instance is given (e.g. "admin.0"), only this instance will receive the message. + * If the name of an adapter is given (e.g. "admin"), all instances of this adapter will receive it. + * @param command (optional) Command name of the target instance. Default: "send" + * @param message The message (e.g., params) to send. + */ + function sendTo(instanceName: string, command: string, message: string | object, callback?: iobJS.MessageCallback | iobJS.MessageCallbackInfo): void; + function sendTo(instanceName: string, message: string | object, callback?: iobJS.MessageCallback | iobJS.MessageCallbackInfo): void; + function sendToAsync(instanceName: string, message: string | object): Promise; + function sendToAsync(instanceName: string, command: string, message: string | object): Promise; + + /** + * Sends a message to a specific instance or all instances of some specific adapter. + * @param host Host name. + * @param command Command name for the target host. + * @param message The message (e.g., params) to send. + */ + function sendToHost(host: string, command: string, message: string | object, callback?: iobJS.MessageCallback | iobJS.MessageCallbackInfo): void; + function sendToHostAsync(host: string, command: string, message: string | object): Promise; + + type CompareTimeOperations = + "between" | "not between" | + ">" | ">=" | "<" | "<=" | "==" | "<>" + ; + + /** + * Compares two or more times + * @param timeToCompare - The time to compare with startTime and/or endTime. If none is given, the current time is used + */ + function compareTime( + startTime: string | number | Date | iobJS.AstroDate, + endTime: string | number | Date | iobJS.AstroDate, + operation: CompareTimeOperations, + timeToCompare?: string | number | Date | iobJS.AstroDate, + ): boolean; + + /** Sets up a callback which is called when the script stops */ + function onStop(callback: (cb?: EmptyCallback) => void, timeout?: number): void; + + function formatValue(value: number | string, format?: any): string; + function formatValue(value: number | string, decimals: number, format?: any): string; + function formatDate(dateObj: string | Date | number, format: string, language?: string): string; + function formatDate(dateObj: string | Date | number, isDuration: boolean | string, format: string, language?: string): string; + + function getDateObject(date: number | string | Date): Date; + + /** + * Writes a file. + * @param id Name of the root directory. This should be the adapter instance, e.g. "admin.0" + * @param name File name + * @param data Contents of the file + * @param callback Is called when the operation has finished (successfully or not) + */ + function writeFile(id: string, name: string, data: Buffer | string, callback: ErrorCallback): void; + function writeFileAsync(id: string, name: string, data: Buffer | string): Promise; + + /** + * Reads a file. + * @param id Name of the root directory. This should be the adapter instance, e.g. "admin.0" + * @param name File name + * @param callback Is called when the operation has finished (successfully or not) + */ + function readFile(id: string, name: string, callback: iobJS.ReadFileCallback): void; + function readFileAsync(id: string, name: string): iobJS.ReadFilePromise; + + /** + * Deletes a file. + * @param id Name of the root directory. This should be the adapter instance, e.g. "admin.0" + * @param name File name + * @param callback Is called when the operation has finished (successfully or not) + */ + function unlink(id: string, name: string, callback: ErrorCallback): void; + function unlinkAsync(id: string, name: string): Promise; + + /** + * Deletes a file. + * @param id Name of the root directory. This should be the adapter instance, e.g. "admin.0" + * @param name File name + * @param callback Is called when the operation has finished (successfully or not) + */ + function delFile(id: string, name: string, callback: ErrorCallback): void; + function delFileAsync(id: string, name: string): Promise; + + function getHistory(instance: any, options: any, callback: any): any; + function getHistoryAsync(instance: any, options: any): Promise; + + /** + * Starts or restarts a script by name + * @param scriptName (optional) Name of the script. If none is given, the current script is (re)started. + */ + function runScript(scriptName?: string, callback?: ErrorCallback): boolean; + function runScriptAsync(scriptName?: string): Promise; + + /** + * Starts or restarts a script by name + * @param scriptName (optional) Name of the script. If none is given, the current script is (re)started. + * @param ignoreIfStarted If set to true, running scripts will not be restarted. + * @param callback (optional) Is called when the script has finished (successfully or not) + */ + function startScript(scriptName: string | undefined, ignoreIfStarted: boolean, callback?: GenericCallback): boolean; + function startScriptAsync(scriptName?: string | undefined, ignoreIfStarted?: boolean): Promise; + + /** + * Starts or restarts a script by name + * @param scriptName (optional) Name of the script. If none is given, the current script is (re)started. + * @param callback (optional) Is called when the script has finished (successfully or not) + */ + function startScript(scriptName?: string, callback?: GenericCallback): boolean; + /** + * Stops a script by name + * @param scriptName (optional) Name of the script. If none is given, the current script is stopped. + */ + function stopScript(scriptName: string | undefined, callback?: GenericCallback): boolean; + function stopScriptAsync(scriptName?: string): Promise; + + function isScriptActive(scriptName: string): boolean; + + /** Converts a value to an integer */ + function toInt(val: any): number; + /** Converts a value to a floating point number */ + function toFloat(val: any): number; + /** Converts a value to a boolean */ + function toBoolean(val: any): boolean; + + /** + * Digs in an object for the property value at the given path. + * @param obj The object to dig in + * @param path The path of the property to dig for in the given object + */ + function getAttr(obj: string | Record, path: string | string[]): any; + + /** + * Sends a message to another script. + * @param target Message name or target object + * @param data Any data, that should be sent to message bus + * @param options Actually only {timeout: X} is supported as option + * @param callback Callback to get the result from other script + * @return ID of the subscription. It could be used for un-subscribe. + */ + function messageTo(target: iobJS.MessageTarget | string, data: any, options?: any, callback?: SimpleCallback): iobJS.MessageSubscribeID; + function messageToAsync(target: iobJS.MessageTarget | string, data: any, options?: any): Promise; + + /** + * Process message from another script. + * @param message Message name + * @param callback Callback to send the result to another script + */ + function onMessage(message: string, callback?: SimpleCallback); + + /** + * Unregister onmessage handler + * @param id Message subscription id from onMessage or by message name + * @return true if subscription exists and was deleted. + */ + function onMessageUnregister(id: iobJS.MessageSubscribeID | string): boolean; + + /** + * Receives logs of specified severity level in a script. + * @param severity Severity level + * @param callback Callback to send the result to another script + */ + function onLog(severity: iobJS.LogLevel | "*", callback: SimpleCallback); + + /** + * Unsubscribe log handler. + * @param idOrCallbackOrSeverity Message subscription id from onLog or by callback function + * @return true if subscription exists and was deleted. + */ + function onLogUnregister(idOrCallbackOrSeverity: iobJS.MessageSubscribeID | SimpleCallback | iobJS.LogLevel | "*"): boolean; + + /** `await` this method to pause for the given number of milliseconds */ + function wait(ms: number): Promise; + + /** `await` this method to pause for the given number of milliseconds */ + function sleep(ms: number): Promise; +} diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 1870afcc..afdf956c 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -94,6 +94,8 @@ ReleaseNotes: - 03.02.2024 - v4.3.3.31 Remove: autoCreateAlias from cardMedia - 03.02.2024 - v4.3.3.31 Remove: adapterPlayerInstance from every card except cardMedia - 03.02.2024 - v4.3.3.31 [dev]: optional with type - cardMedia has adapterPlayerInstance all other not + - 03.02.2024 - v4.3.3.31 [dev]: add PlayerType some more work to do + - 03.02.2024 - v4.3.3.31 changed: adapterPlayerInstance instance 0-9 allowed. Always require a '.' at the end. Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -4710,153 +4712,209 @@ function subscribeMediaSubscriptionsAlexaAdd(id: string): void { }); } -async function createAutoMediaAlias(id: string, mediaDevice: string, adapterPlayerInstance: string) { +async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPlayerInstance: adapterPlayerInstanceType) { if (autoCreateAlias) { if (isSetOptionActive) { - if (adapterPlayerInstance == 'alexa2.0.') { - if (existsObject(id) == false){ - log('Alexa Alias ' + id + ' does not exist - will be created now', 'info'); + switch (adapterPlayerInstance) { + case "alexa2.0.": + case "alexa2.1.": + case "alexa2.2.": + case "alexa2.3.": + case "alexa2.4.": + case "alexa2.5.": + case "alexa2.6.": + case "alexa2.7.": + case "alexa2.8.": + case "alexa2.9.": { + if (existsObject(id) == false) { + log('Alexa Alias ' + id + ' does not exist - will be created now', 'info'); - let dpPath: string = adapterPlayerInstance + 'Echo-Devices.' + mediaDevice; - try { - setObject(id, {_id: id, type: 'channel', common: {role: 'media', name:'media'}, native: {}}); - await createAliasAsync(id + '.ACTUAL', dpPath + '.Player.volume', true, { type: 'number', role: 'value.volume', name: 'ACTUAL' }); - await createAliasAsync(id + '.ALBUM', dpPath + '.Player.currentAlbum', true, { type: 'string', role: 'media.album', name: 'ALBUM' }); - await createAliasAsync(id + '.ARTIST', dpPath + '.Player.currentArtist', true, { type: 'string', role: 'media.artist', name: 'ARTIST' }); - await createAliasAsync(id + '.TITLE', dpPath + '.Player.currentTitle', true, { type: 'string', role: 'media.title', name: 'TITLE' }); - await createAliasAsync(id + '.NEXT', dpPath + '.Player.controlNext', true, { type: 'boolean', role: 'button.next', name: 'NEXT' }); - await createAliasAsync(id + '.PREV', dpPath + '.Player.controlPrevious', true, { type: 'boolean', role: 'button.prev', name: 'PREV' }); - await createAliasAsync(id + '.PLAY', dpPath + '.Player.controlPlay', true, { type: 'boolean', role: 'button.play', name: 'PLAY' }); - await createAliasAsync(id + '.PAUSE', dpPath + '.Player.controlPause', true, { type: 'boolean', role: 'button.pause', name: 'PAUSE' }); - await createAliasAsync(id + '.STOP', dpPath + '.Commands.deviceStop', true, { type: 'boolean', role: 'button.stop', name: 'STOP' }); - await createAliasAsync(id + '.STATE', dpPath + '.Player.currentState', true, { type: 'boolean', role: 'media.state', name: 'STATE' }); - await createAliasAsync(id + '.VOLUME', dpPath + '.Player.volume', true, { type: 'number', role: 'level.volume', name: 'VOLUME' }); - await createAliasAsync(id + '.REPEAT', dpPath + '.Player.controlRepeat', true, { type: 'boolean', role: 'media.mode.repeat', name: 'REPEAT' }); - await createAliasAsync(id + '.SHUFFLE', dpPath + '.Player.controlShuffle', true, { type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE' }); - } catch (err: any) { - log('error at function createAutoMediaAlias Adapter Alexa2: ' + err.message, 'warn'); + const dpPath: string = adapterPlayerInstance + 'Echo-Devices.' + mediaDevice; + try { + setObject(id, {_id: id, type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); + await createAliasAsync(id + '.ACTUAL', dpPath + '.Player.volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); + await createAliasAsync(id + '.ALBUM', dpPath + '.Player.currentAlbum', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); + await createAliasAsync(id + '.ARTIST', dpPath + '.Player.currentArtist', true, {type: 'string', role: 'media.artist', name: 'ARTIST'}); + await createAliasAsync(id + '.TITLE', dpPath + '.Player.currentTitle', true, {type: 'string', role: 'media.title', name: 'TITLE'}); + await createAliasAsync(id + '.NEXT', dpPath + '.Player.controlNext', true, {type: 'boolean', role: 'button.next', name: 'NEXT'}); + await createAliasAsync(id + '.PREV', dpPath + '.Player.controlPrevious', true, {type: 'boolean', role: 'button.prev', name: 'PREV'}); + await createAliasAsync(id + '.PLAY', dpPath + '.Player.controlPlay', true, {type: 'boolean', role: 'button.play', name: 'PLAY'}); + await createAliasAsync(id + '.PAUSE', dpPath + '.Player.controlPause', true, {type: 'boolean', role: 'button.pause', name: 'PAUSE'}); + await createAliasAsync(id + '.STOP', dpPath + '.Commands.deviceStop', true, {type: 'boolean', role: 'button.stop', name: 'STOP'}); + await createAliasAsync(id + '.STATE', dpPath + '.Player.currentState', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); + await createAliasAsync(id + '.VOLUME', dpPath + '.Player.volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.REPEAT', dpPath + '.Player.controlRepeat', true, {type: 'boolean', role: 'media.mode.repeat', name: 'REPEAT'}); + await createAliasAsync(id + '.SHUFFLE', dpPath + '.Player.controlShuffle', true, {type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE'}); + } catch (err: any) { + log('error at function createAutoMediaAlias Adapter Alexa2: ' + err.message, 'warn'); + } } - } - //Add Alexa Datapoints > v4.3.3.18 - if (existsObject(id + '.DURATION') == false) { - let dpPath: string = adapterPlayerInstance + 'Echo-Devices.' + mediaDevice; - await createAliasAsync(id + '.DURATION', dpPath + '.Player.mediaLength', true, { type: 'string', role: 'media.duration.text', name: 'DURATION' }); - await createAliasAsync(id + '.ELAPSED', dpPath + '.Player.mediaProgressStr', true, { type: 'string', role: 'media.elapsed.text', name: 'ELAPSED' }); - } - } - - if (adapterPlayerInstance == 'spotify-premium.0.') { - if (existsObject(id) == false){ - log('Spotify Alias ' + id + ' does not exist - will be created now', 'info'); - - let dpPath: string = adapterPlayerInstance; - try { - setObject(id, {_id: id + 'player', type: 'channel', common: {role: 'media', name:'media'}, native: {}}); - await createAliasAsync(id + '.ACTUAL', dpPath + 'player.volume', true, { type: 'number', role: 'value.volume', name: 'ACTUAL' }); - await createAliasAsync(id + '.ALBUM', dpPath + 'player.album', true, { type: 'string', role: 'media.album', name: 'ALBUM' }); - await createAliasAsync(id + '.ARTIST', dpPath + 'player.artistName', true, { type: 'string', role: 'media.artist', name: 'ARTIST' }); - await createAliasAsync(id + '.TITLE', dpPath + 'player.trackName', true, { type: 'string', role: 'media.title', name: 'TITLE' }); - await createAliasAsync(id + '.CONTEXT_DESCRIPTION', dpPath + 'player.contextDescription', true, { type: 'string', role: 'media.station', name: 'CONTEXT_DESCRIPTION' }); - await createAliasAsync(id + '.NEXT', dpPath + 'player.skipPlus', true, { type: 'boolean', role: 'button.next', name: 'NEXT' }); - await createAliasAsync(id + '.PREV', dpPath + 'player.skipMinus', true, { type: 'boolean', role: 'button.prev', name: 'PREV' }); - await createAliasAsync(id + '.PLAY', dpPath + 'player.play', true, { type: 'boolean', role: 'button.play', name: 'PLAY' }); - await createAliasAsync(id + '.PAUSE', dpPath + 'player.pause', true, { type: 'boolean', role: 'button.pause', name: 'PAUSE' }); - await createAliasAsync(id + '.STOP', dpPath + 'player.pause', true, { type: 'boolean', role: 'button.stop', name: 'STOP' }); - await createAliasAsync(id + '.STATE', dpPath + 'player.isPlaying', true, { type: 'boolean', role: 'media.state', name: 'STATE' }); - await createAliasAsync(id + '.VOLUME', dpPath + 'player.volume', true, { type: 'number', role: 'level.volume', name: 'VOLUME' }); - await createAliasAsync(id + '.REPEAT', dpPath + 'player.repeat', true, { type: 'string', role: 'value', name: 'REPEAT' }); - await createAliasAsync(id + '.SHUFFLE', dpPath + 'player.shuffle', true, { type: 'string', role: 'value', name: 'SHUFFLE' }); - - } catch (err: any) { - log('error at function createAutoMediaAlias Adapter spotify-premium: ' + err.message, 'warn'); + //Add Alexa Datapoints > v4.3.3.18 + if (existsObject(id + '.DURATION') == false) { + let dpPath: string = adapterPlayerInstance + 'Echo-Devices.' + mediaDevice; + await createAliasAsync(id + '.DURATION', dpPath + '.Player.mediaLength', true, {type: 'string', role: 'media.duration.text', name: 'DURATION'}); + await createAliasAsync(id + '.ELAPSED', dpPath + '.Player.mediaProgressStr', true, {type: 'string', role: 'media.elapsed.text', name: 'ELAPSED'}); } + } - } + break; + case "sonos.0.": + case "sonos.1.": + case "sonos.2.": + case "sonos.3.": + case "sonos.4.": + case "sonos.5.": + case "sonos.6.": + case "sonos.7.": + case "sonos.8.": + case "sonos.9.": { + if (existsObject(id) == false) { + log('Sonos Alias ' + id + ' does not exist - will be created now', 'info'); - if (adapterPlayerInstance == 'sonos.0.') { - if (existsObject(id) == false){ - log('Sonos Alias ' + id + ' does not exist - will be created now', 'info'); - - let dpPath: string = adapterPlayerInstance + 'root.' + mediaDevice; - try { - setObject(id, {_id: id, type: 'channel', common: {role: 'media', name:'media'}, native: {}}); - await createAliasAsync(id + '.ACTUAL', dpPath + '.volume', true, { type: 'number', role: 'value.volume', name: 'ACTUAL' }); - await createAliasAsync(id + '.ALBUM', dpPath + '.current_album', true, { type: 'string', role: 'media.album', name: 'ALBUM' }); - await createAliasAsync(id + '.ARTIST', dpPath + '.current_artist', true, { type: 'string', role: 'media.artist', name: 'ARTIST' }); - await createAliasAsync(id + '.TITLE', dpPath + '.current_title', true, { type: 'string', role: 'media.title', name: 'TITLE' }); - await createAliasAsync(id + '.CONTEXT_DESCRIPTION', dpPath + '.current_station', true, { type: 'string', role: 'media.station', name: 'CONTEXT_DESCRIPTION' }); - await createAliasAsync(id + '.NEXT', dpPath + '.next', true, { type: 'boolean', role: 'button.next', name: 'NEXT' }); - await createAliasAsync(id + '.PREV', dpPath + '.prev', true, { type: 'boolean', role: 'button.prev', name: 'PREV' }); - await createAliasAsync(id + '.PLAY', dpPath + '.play', true, { type: 'boolean', role: 'button.play', name: 'PLAY' }); - await createAliasAsync(id + '.PAUSE', dpPath + '.pause', true, { type: 'boolean', role: 'button.pause', name: 'PAUSE' }); - await createAliasAsync(id + '.STOP', dpPath + '.stop', true, { type: 'boolean', role: 'button.stop', name: 'STOP' }); - await createAliasAsync(id + '.STATE', dpPath + '.state_simple', true, { type: 'boolean', role: 'media.state', name: 'STATE' }); - await createAliasAsync(id + '.VOLUME', dpPath + '.volume', true, { type: 'number', role: 'level.volume', name: 'VOLUME' }); - await createAliasAsync(id + '.REPEAT', dpPath + '.repeat', true, { type: 'number', role: 'media.mode.repeat', name: 'REPEAT' }); - await createAliasAsync(id + '.SHUFFLE', dpPath + '.shuffle', true, { type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE' }); - } catch (err: any) { - log('error at function createAutoMediaAlias Adapter sonos: ' + err.message, 'warn'); + const dpPath: string = adapterPlayerInstance + 'root.' + mediaDevice; + try { + setObject(id, {_id: id, type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); + await createAliasAsync(id + '.ACTUAL', dpPath + '.volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); + await createAliasAsync(id + '.ALBUM', dpPath + '.current_album', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); + await createAliasAsync(id + '.ARTIST', dpPath + '.current_artist', true, {type: 'string', role: 'media.artist', name: 'ARTIST'}); + await createAliasAsync(id + '.TITLE', dpPath + '.current_title', true, {type: 'string', role: 'media.title', name: 'TITLE'}); + await createAliasAsync(id + '.CONTEXT_DESCRIPTION', dpPath + '.current_station', true, {type: 'string', role: 'media.station', name: 'CONTEXT_DESCRIPTION'}); + await createAliasAsync(id + '.NEXT', dpPath + '.next', true, {type: 'boolean', role: 'button.next', name: 'NEXT'}); + await createAliasAsync(id + '.PREV', dpPath + '.prev', true, {type: 'boolean', role: 'button.prev', name: 'PREV'}); + await createAliasAsync(id + '.PLAY', dpPath + '.play', true, {type: 'boolean', role: 'button.play', name: 'PLAY'}); + await createAliasAsync(id + '.PAUSE', dpPath + '.pause', true, {type: 'boolean', role: 'button.pause', name: 'PAUSE'}); + await createAliasAsync(id + '.STOP', dpPath + '.stop', true, {type: 'boolean', role: 'button.stop', name: 'STOP'}); + await createAliasAsync(id + '.STATE', dpPath + '.state_simple', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); + await createAliasAsync(id + '.VOLUME', dpPath + '.volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.REPEAT', dpPath + '.repeat', true, {type: 'number', role: 'media.mode.repeat', name: 'REPEAT'}); + await createAliasAsync(id + '.SHUFFLE', dpPath + '.shuffle', true, {type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE'}); + } catch (err: any) { + log('error at function createAutoMediaAlias Adapter sonos: ' + err.message, 'warn'); + } } - } - //Add Sonos Datapoints > v4.3.3.15 - if (existsObject(id + '.QUEUE') == false) { - let dpPath: string = adapterPlayerInstance + 'root.' + mediaDevice; - await createAliasAsync(id + '.QUEUE', dpPath + '.queue', true, { type: 'string', role: 'state', name: 'QUEUE' }); - await createAliasAsync(id + '.DURATION', dpPath + '.current_duration_s', true, { type: 'string', role: 'media.duration.text', name: 'DURATION' }); - await createAliasAsync(id + '.ELAPSED', dpPath + '.current_elapsed_s', true, { type: 'string', role: 'media.elapsed.text', name: 'ELAPSED' }); - } - } - - if (adapterPlayerInstance.startsWith('volumio')) { - if (existsObject(id) == false){ - log('Volumio Alias ' + id + ' does not exist - will be created now', 'info'); - - let dpPath: string = adapterPlayerInstance; - try { - setObject(id, {_id: id, type: 'channel', common: {role: 'media', name:'media'}, native: {}}); - await createAliasAsync(id + '.ACTUAL', dpPath + 'playbackInfo.volume', true, { type: 'number', role: 'value.volume', name: 'ACTUAL' }); - await createAliasAsync(id + '.ALBUM', dpPath + 'playbackInfo.album', true, { type: 'string', role: 'media.album', name: 'ALBUM' }); - await createAliasAsync(id + '.ARTIST', dpPath + 'playbackInfo.artist', true, { type: 'string', role: 'media.artist', name: 'ARTIST' }); - await createAliasAsync(id + '.TITLE', dpPath + 'playbackInfo.title', true, { type: 'string', role: 'media.title', name: 'TITLE' }); - await createAliasAsync(id + '.NEXT', dpPath + 'player.next', true, { type: 'boolean', role: 'button.next', name: 'NEXT' }); - await createAliasAsync(id + '.PREV', dpPath + 'player.prev', true, { type: 'boolean', role: 'button.prev', name: 'PREV' }); - await createAliasAsync(id + '.PLAY', dpPath + 'player.play', true, { type: 'boolean', role: 'button.play', name: 'PLAY' }); - await createAliasAsync(id + '.PAUSE', dpPath + 'player.toggle', true, { type: 'boolean', role: 'button.pause', name: 'PAUSE' }); - await createAliasAsync(id + '.STOP', dpPath + 'player.stop', true, { type: 'boolean', role: 'button.stop', name: 'STOP' }); - await createAliasAsync(id + '.STATE', dpPath + 'playbackInfo.status', true, { type: 'boolean', role: 'media.state', name: 'STATE' }); - await createAliasAsync(id + '.VOLUME', dpPath + 'playbackInfo.volume', true, { type: 'number', role: 'level.volume', name: 'VOLUME' }); - await createAliasAsync(id + '.REPEAT', dpPath + 'playbackInfo.repeat', true, { type: 'number', role: 'media.mode.repeat', name: 'REPEAT' }); - await createAliasAsync(id + '.SHUFFLE', dpPath + 'queue.shuffle', true, { type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE' }); - await createAliasAsync(id + '.status', dpPath + 'playbackInfo.status', true, { type: 'string', role: 'media.state', name: 'status' }); - } catch (err: any) { - log('error function createAutoMediaAlias Adapter volumio: ' + err.message, 'warn'); + //Add Sonos Datapoints > v4.3.3.15 + if (existsObject(id + '.QUEUE') == false) { + let dpPath: string = adapterPlayerInstance + 'root.' + mediaDevice; + await createAliasAsync(id + '.QUEUE', dpPath + '.queue', true, {type: 'string', role: 'state', name: 'QUEUE'}); + await createAliasAsync(id + '.DURATION', dpPath + '.current_duration_s', true, {type: 'string', role: 'media.duration.text', name: 'DURATION'}); + await createAliasAsync(id + '.ELAPSED', dpPath + '.current_elapsed_s', true, {type: 'string', role: 'media.elapsed.text', name: 'ELAPSED'}); } + } - } + break; + case "spotify-premium.0.": + case "spotify-premium.1.": + case "spotify-premium.2.": + case "spotify-premium.3.": + case "spotify-premium.4.": + case "spotify-premium.5.": + case "spotify-premium.6.": + case "spotify-premium.7.": + case "spotify-premium.8.": + case "spotify-premium.9.": { + if (existsObject(id) == false) { + log('Spotify Alias ' + id + ' does not exist - will be created now', 'info'); - if (adapterPlayerInstance.startsWith('squeezeboxrpc')) { - if (existsObject(id) == false){ - log('Squeezebox Alias ' + id + ' does not exist - will be created now', 'info'); + const dpPath: string = adapterPlayerInstance; + try { + setObject(id, {_id: id + 'player', type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); + await createAliasAsync(id + '.ACTUAL', dpPath + 'player.volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); + await createAliasAsync(id + '.ALBUM', dpPath + 'player.album', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); + await createAliasAsync(id + '.ARTIST', dpPath + 'player.artistName', true, {type: 'string', role: 'media.artist', name: 'ARTIST'}); + await createAliasAsync(id + '.TITLE', dpPath + 'player.trackName', true, {type: 'string', role: 'media.title', name: 'TITLE'}); + await createAliasAsync(id + '.CONTEXT_DESCRIPTION', dpPath + 'player.contextDescription', true, {type: 'string', role: 'media.station', name: 'CONTEXT_DESCRIPTION'}); + await createAliasAsync(id + '.NEXT', dpPath + 'player.skipPlus', true, {type: 'boolean', role: 'button.next', name: 'NEXT'}); + await createAliasAsync(id + '.PREV', dpPath + 'player.skipMinus', true, {type: 'boolean', role: 'button.prev', name: 'PREV'}); + await createAliasAsync(id + '.PLAY', dpPath + 'player.play', true, {type: 'boolean', role: 'button.play', name: 'PLAY'}); + await createAliasAsync(id + '.PAUSE', dpPath + 'player.pause', true, {type: 'boolean', role: 'button.pause', name: 'PAUSE'}); + await createAliasAsync(id + '.STOP', dpPath + 'player.pause', true, {type: 'boolean', role: 'button.stop', name: 'STOP'}); + await createAliasAsync(id + '.STATE', dpPath + 'player.isPlaying', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); + await createAliasAsync(id + '.VOLUME', dpPath + 'player.volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.REPEAT', dpPath + 'player.repeat', true, {type: 'string', role: 'value', name: 'REPEAT'}); + await createAliasAsync(id + '.SHUFFLE', dpPath + 'player.shuffle', true, {type: 'string', role: 'value', name: 'SHUFFLE'}); - let dpPath: string = adapterPlayerInstance + '.Players.' + mediaDevice; - try { - setObject(id, {_id: id, type: 'channel', common: {role: 'media', name:'media'}, native: {}}); - await createAliasAsync(id + '.ALBUM', dpPath + '.Album', true, { type: 'string', role: 'media.album', name: 'ALBUM'}); - await createAliasAsync(id + '.ARTIST', dpPath + '.Artist', true, { type: 'string', role: 'media.artist', name: 'ARTIST'}); - await createAliasAsync(id + '.TITLE', dpPath + '.Title', true, { type: 'string', role: 'media.title', name: 'TITLE'}); - await createAliasAsync(id + '.NEXT', dpPath + '.btnForward', true, { type: 'boolean', role: 'button.forward', name: 'NEXT'}); - await createAliasAsync(id + '.PREV', dpPath + '.btnRewind', true, { type: 'boolean', role: 'button.reverse', name: 'PREV'}); - await createAliasAsync(id + '.PLAY', dpPath + '.state', true, { type: 'boolean', role: 'media.state', name: 'PLAY', alias: { id: dpPath + '.state', read: 'val === 1 ? true : false' }}); - await createAliasAsync(id + '.PAUSE', dpPath + '.state', true, { type: 'boolean', role: 'media.state', name: 'PAUSE', alias: { id: dpPath + '.state', read: 'val === 0 ? true : false'}}); - await createAliasAsync(id + '.STOP', dpPath + '.state', true, { type: 'boolean', role: 'media.state', name: 'STOP', alias: { id: dpPath + '.state', read: 'val === 0 ? true : false'}}); - await createAliasAsync(id + '.STATE', dpPath + '.Power', true, { type: 'number', role: 'switch', name: 'STATE'}); - await createAliasAsync(id + '.VOLUME', dpPath + '.Volume', true, { type: 'number', role: 'level.volume', name: 'VOLUME'}); - await createAliasAsync(id + '.VOLUME_ACTUAL', dpPath + '.Volume', true, { type: 'number', role: 'value.volume', name: 'VOLUME_ACTUAL'}); - await createAliasAsync(id + '.SHUFFLE', dpPath + '.PlaylistShuffle', true, { type: 'string', role: 'media.mode.shuffle', name: 'SHUFFLE', alias: { id: dpPath + '.PlaylistShuffle', read: 'val !== 0 ? \'on\' : \'off\'', write: 'val === \'off\' ? 0 : 1' }}); - await createAliasAsync(id + '.REPEAT', dpPath + '.PlaylistRepeat', true, {type: 'number', role: 'media.mode.repeat', name: 'REPEAT'}); - } catch (err: any) { - log('error at function createAutoMediaAlias Adapter Squeezebox: ' + err.message, 'warn'); + } catch (err: any) { + log('error at function createAutoMediaAlias Adapter spotify-premium: ' + err.message, 'warn'); + } } + + } + break; + case "volumio.0.": + case "volumio.1.": + case "volumio.2.": + case "volumio.3.": + case "volumio.4.": + case "volumio.5.": + case "volumio.6.": + case "volumio.7.": + case "volumio.8.": + case "volumio.9.": { + if (existsObject(id) == false) { + log('Volumio Alias ' + id + ' does not exist - will be created now', 'info'); + + const dpPath: string = adapterPlayerInstance; + try { + setObject(id, {_id: id, type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); + await createAliasAsync(id + '.ACTUAL', dpPath + 'playbackInfo.volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); + await createAliasAsync(id + '.ALBUM', dpPath + 'playbackInfo.album', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); + await createAliasAsync(id + '.ARTIST', dpPath + 'playbackInfo.artist', true, {type: 'string', role: 'media.artist', name: 'ARTIST'}); + await createAliasAsync(id + '.TITLE', dpPath + 'playbackInfo.title', true, {type: 'string', role: 'media.title', name: 'TITLE'}); + await createAliasAsync(id + '.NEXT', dpPath + 'player.next', true, {type: 'boolean', role: 'button.next', name: 'NEXT'}); + await createAliasAsync(id + '.PREV', dpPath + 'player.prev', true, {type: 'boolean', role: 'button.prev', name: 'PREV'}); + await createAliasAsync(id + '.PLAY', dpPath + 'player.play', true, {type: 'boolean', role: 'button.play', name: 'PLAY'}); + await createAliasAsync(id + '.PAUSE', dpPath + 'player.toggle', true, {type: 'boolean', role: 'button.pause', name: 'PAUSE'}); + await createAliasAsync(id + '.STOP', dpPath + 'player.stop', true, {type: 'boolean', role: 'button.stop', name: 'STOP'}); + await createAliasAsync(id + '.STATE', dpPath + 'playbackInfo.status', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); + await createAliasAsync(id + '.VOLUME', dpPath + 'playbackInfo.volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.REPEAT', dpPath + 'playbackInfo.repeat', true, {type: 'number', role: 'media.mode.repeat', name: 'REPEAT'}); + await createAliasAsync(id + '.SHUFFLE', dpPath + 'queue.shuffle', true, {type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE'}); + await createAliasAsync(id + '.status', dpPath + 'playbackInfo.status', true, {type: 'string', role: 'media.state', name: 'status'}); + } catch (err: any) { + log('error function createAutoMediaAlias Adapter volumio: ' + err.message, 'warn'); + } + } + + } + break; + case "squeezeboxrpc.0.": + case "squeezeboxrpc.1.": + case "squeezeboxrpc.2.": + case "squeezeboxrpc.3.": + case "squeezeboxrpc.4.": + case "squeezeboxrpc.5.": + case "squeezeboxrpc.6.": + case "squeezeboxrpc.7.": + case "squeezeboxrpc.8.": + case "squeezeboxrpc.9.": { + if (existsObject(id) == false) { + log('Squeezebox Alias ' + id + ' does not exist - will be created now', 'info'); + + const dpPath: string = adapterPlayerInstance + 'Players.' + mediaDevice; + try { + setObject(id, {_id: id, type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); + await createAliasAsync(id + '.ALBUM', dpPath + '.Album', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); + await createAliasAsync(id + '.ARTIST', dpPath + '.Artist', true, {type: 'string', role: 'media.artist', name: 'ARTIST'}); + await createAliasAsync(id + '.TITLE', dpPath + '.Title', true, {type: 'string', role: 'media.title', name: 'TITLE'}); + await createAliasAsync(id + '.NEXT', dpPath + '.btnForward', true, {type: 'boolean', role: 'button.forward', name: 'NEXT'}); + await createAliasAsync(id + '.PREV', dpPath + '.btnRewind', true, {type: 'boolean', role: 'button.reverse', name: 'PREV'}); + await createAliasAsync(id + '.PLAY', dpPath + '.state', true, {type: 'boolean', role: 'media.state', name: 'PLAY', alias: {id: dpPath + '.state', read: 'val === 1 ? true : false'}}); + await createAliasAsync(id + '.PAUSE', dpPath + '.state', true, {type: 'boolean', role: 'media.state', name: 'PAUSE', alias: {id: dpPath + '.state', read: 'val === 0 ? true : false'}}); + await createAliasAsync(id + '.STOP', dpPath + '.state', true, {type: 'boolean', role: 'media.state', name: 'STOP', alias: {id: dpPath + '.state', read: 'val === 0 ? true : false'}}); + await createAliasAsync(id + '.STATE', dpPath + '.Power', true, {type: 'number', role: 'switch', name: 'STATE'}); + await createAliasAsync(id + '.VOLUME', dpPath + '.Volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.VOLUME_ACTUAL', dpPath + '.Volume', true, {type: 'number', role: 'value.volume', name: 'VOLUME_ACTUAL'}); + await createAliasAsync(id + '.SHUFFLE', dpPath + '.PlaylistShuffle', true, {type: 'string', role: 'media.mode.shuffle', name: 'SHUFFLE', alias: {id: dpPath + '.PlaylistShuffle', read: 'val !== 0 ? \'on\' : \'off\'', write: 'val === \'off\' ? 0 : 1'}}); + await createAliasAsync(id + '.REPEAT', dpPath + '.PlaylistRepeat', true, {type: 'number', role: 'media.mode.repeat', name: 'REPEAT'}); + } catch (err: any) { + log('error at function createAutoMediaAlias Adapter Squeezebox: ' + err.message, 'warn'); + } + } + + } + break; + default: { + log(`Dont find adapterPlayerInstance: ${adapterPlayerInstance}!`, 'warn') } } } @@ -4875,7 +4933,7 @@ function GenerateMediaPage(page: PageMedia): Payload[] { if (!page.items[0].adapterPlayerInstance!) throw new Error('page.items[0].adapterPlayerInstance is undefined!') let vInstance = page.items[0].adapterPlayerInstance!; let v1Adapter = vInstance.split('.'); - let v2Adapter = v1Adapter[0]; + let v2Adapter:PlayerType = v1Adapter[0] as PlayerType; // Some magic to change the ID of the alias, since speakers are not a property but separate objects if(v2Adapter == 'squeezeboxrpc') { @@ -6272,8 +6330,8 @@ function HandleButtonEvent(words: any): void { if (isPageMediaItem(pageItemRepeat)) { let adapterInstanceRepeat = pageItemRepeat.adapterPlayerInstance; let adapterRepeat = adapterInstanceRepeat.split('.'); - let deviceAdapterRP = adapterRepeat[0]; - + const deviceAdapterRP: PlayerType = adapterRepeat[0] as PlayerType; + switch (deviceAdapterRP) { case 'spotify-premium': let stateSpotifyRepeat = getState(id + '.REPEAT').val @@ -6565,7 +6623,7 @@ function HandleButtonEvent(words: any): void { if (isPageMediaItem(pageItem)) { let adapterInstance = pageItem.adapterPlayerInstance!; let adapter = adapterInstance!.split('.'); - let deviceAdapter = adapter[0]; + const deviceAdapter: PlayerType = adapter[0] as PlayerType; switch (deviceAdapter) { case 'spotify-premium': @@ -6588,8 +6646,8 @@ function HandleButtonEvent(words: any): void { break; case 'sonos': break; - case 'chromecast': - break; + /*case 'chromecast': + break;*/ case 'squeezeboxrpc': pageItem.mediaDevice = pageItem.speakerList![words[4]]; break; @@ -6608,7 +6666,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemPL)) break; let adapterInstancePL = pageItemPL.adapterPlayerInstance!; let adapterPL = adapterInstancePL.split('.'); - let deviceAdapterPL = adapterPL[0]; + const deviceAdapterPL: PlayerType = adapterPL[0] as PlayerType; switch (deviceAdapterPL) { case 'spotify-premium': @@ -6664,7 +6722,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemTL)) break; let adapterInstanceTL = pageItemTL.adapterPlayerInstance!; let adapterTL = adapterInstanceTL.split('.'); - let deviceAdapterTL = adapterTL[0]; + const deviceAdapterTL: PlayerType = adapterTL[0] as PlayerType; switch (deviceAdapterTL) { case 'spotify-premium': @@ -6799,7 +6857,7 @@ function HandleButtonEvent(words: any): void { case 'media-OnOff': let pageItemTem = findPageItem(id); if (!isPageMediaItem(pageItemTem)) break; - let adaInstanceSpli = pageItemTem.adapterPlayerInstance!.split('.'); + let adaInstanceSpli = pageItemTem.adapterPlayerInstance.split('.'); if (adaInstanceSpli[0] == 'squeezeboxrpc') { let adapterPlayerInstancePowerSelector: string = [pageItemTem.adapterPlayerInstance, 'Players', pageItemTem.mediaDevice, 'Power'].join('.'); let stateVal = getState(adapterPlayerInstancePowerSelector).val; @@ -7807,8 +7865,8 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p let optionalString: string = 'Kein Eintrag'; let mode: string = ''; if (isPageMediaItem(pageItem)) { - let vTempAdapter = (pageItem.adapterPlayerInstance!).split('.'); - let vAdapter = vTempAdapter[0]; + const vTempAdapter = (pageItem.adapterPlayerInstance!).split('.'); + const vAdapter: PlayerType = vTempAdapter[0] as PlayerType; if (optional == 'seek') { let actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; if (actualStateTemp >= 95) { @@ -9612,19 +9670,13 @@ type IconScaleElement = { } type adapterPlayerInstanceType = - 'alexa2.1.' | 'sonos.1.' | 'spotify-premium.1.' | 'volumio.1.' | 'squeezeboxrpc.1.' -| 'alexa2.2.' | 'sonos.2.' | 'spotify-premium.2.' | 'volumio.2.' | 'squeezeboxrpc.2.' -| 'alexa2.0.' | 'sonos.0.' | 'spotify-premium.0.' | 'volumio.0.' | 'squeezeboxrpc.0.' -| 'alexa2.3.' | 'sonos.3.' | 'spotify-premium.3.' | 'volumio.3.' | 'squeezeboxrpc.3.' -| 'alexa2.4.' | 'sonos.4.' | 'spotify-premium.4.' | 'volumio.4.' | 'squeezeboxrpc.4.' -| 'alexa2.5.' | 'sonos.5.' | 'spotify-premium.5.' | 'volumio.5.' | 'squeezeboxrpc.5.' -| 'alexa2.6.' | 'sonos.6.' | 'spotify-premium.6.' | 'volumio.6.' | 'squeezeboxrpc.6.' -| 'alexa2.7.' | 'sonos.7.' | 'spotify-premium.7.' | 'volumio.7.' | 'squeezeboxrpc.7.' -| 'alexa2.8.' | 'sonos.8.' | 'spotify-premium.8.' | 'volumio.8.' | 'squeezeboxrpc.8.' -| 'alexa2.9.' | 'sonos.9.' | 'spotify-premium.9.' | 'volumio.9.' | 'squeezeboxrpc.9.' -| 'alexa2.10.' | 'sonos.10.' | 'spotify-premium.10.' | 'volumio.10.' | 'squeezeboxrpc.10' - + 'alexa2.0.' | 'alexa2.1.'| 'alexa2.2.' | 'alexa2.3.' | 'alexa2.4.' | 'alexa2.5.' | 'alexa2.6.' | 'alexa2.7.' | 'alexa2.8.' | 'alexa2.9.' +| 'sonos.0.' | 'sonos.1.' | 'sonos.2.' | 'sonos.3.' | 'sonos.4.' | 'sonos.5.' | 'sonos.6.' | 'sonos.7.' | 'sonos.8.' | 'sonos.9.' +| 'spotify-premium.0.' | 'spotify-premium.1.' | 'spotify-premium.2.' | 'spotify-premium.3.' | 'spotify-premium.4.' | 'spotify-premium.5.' | 'spotify-premium.6.' | 'spotify-premium.7.' | 'spotify-premium.8.' | 'spotify-premium.9.' +| 'volumio.0.' | 'volumio.1.' | 'volumio.2.' | 'volumio.3.' |'volumio.4.' | 'volumio.5.' | 'volumio.6.' | 'volumio.7.' | 'volumio.8.' | 'volumio.9.' +| 'squeezeboxrpc.0.' | 'squeezeboxrpc.1.' | 'squeezeboxrpc.2.' | 'squeezeboxrpc.3.' | 'squeezeboxrpc.4.' | 'squeezeboxrpc.5.' | 'squeezeboxrpc.6.' | 'squeezeboxrpc.7.' | 'squeezeboxrpc.8.' | 'squeezeboxrpc.9.' +type PlayerType = 'alexa2' | 'sonos'| 'sonos' | 'spotify-premium' | 'volumio' |'squeezeboxrpc' type mediaOptional = 'seek' | 'crossfade' | 'speakerlist' | 'playlist' | 'tracklist' | 'equalizer' | 'repeat' | 'favorites' diff --git a/ioBroker/tsconfig.json b/ioBroker/tsconfig.json new file mode 100644 index 00000000..6a5cb9b9 --- /dev/null +++ b/ioBroker/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compileOnSave": true, + "compilerOptions": { + "noEmit": true, + "allowJs": true, + "checkJs": true, + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, + "resolveJsonModule": true, + "strict": true, + "noImplicitAny": false, + "target": "es2020", + "typeRoots": [ + ".iobroker/types", + "node_modules/@types" + ] + }, + "include": [ + "**/*.js", + "**/*.ts", + "./.iobroker/types/javascript.d.ts" + ], + "exclude": [ + "node_modules/**" + ] +} \ No newline at end of file From 1ec463f6c77ad8d9821a65d58935aeba50692e2c Mon Sep 17 00:00:00 2001 From: ticaki Date: Wed, 3 Jan 2024 18:45:21 +0100 Subject: [PATCH 30/99] type --- ioBroker/NsPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index afdf956c..65032a52 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -9676,7 +9676,7 @@ type adapterPlayerInstanceType = | 'volumio.0.' | 'volumio.1.' | 'volumio.2.' | 'volumio.3.' |'volumio.4.' | 'volumio.5.' | 'volumio.6.' | 'volumio.7.' | 'volumio.8.' | 'volumio.9.' | 'squeezeboxrpc.0.' | 'squeezeboxrpc.1.' | 'squeezeboxrpc.2.' | 'squeezeboxrpc.3.' | 'squeezeboxrpc.4.' | 'squeezeboxrpc.5.' | 'squeezeboxrpc.6.' | 'squeezeboxrpc.7.' | 'squeezeboxrpc.8.' | 'squeezeboxrpc.9.' -type PlayerType = 'alexa2' | 'sonos'| 'sonos' | 'spotify-premium' | 'volumio' |'squeezeboxrpc' +type PlayerType = 'alexa2' | 'sonos' | 'spotify-premium' | 'volumio' | 'squeezeboxrpc' type mediaOptional = 'seek' | 'crossfade' | 'speakerlist' | 'playlist' | 'tracklist' | 'equalizer' | 'repeat' | 'favorites' From 03bae9e9bd5f93025cb18079f3b9cfdc9bf58c5e Mon Sep 17 00:00:00 2001 From: ticaki Date: Wed, 3 Jan 2024 19:10:42 +0100 Subject: [PATCH 31/99] add check for adapterPlayerInstanceType --- ioBroker/NsPanelTs.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 65032a52..848c1e6f 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -9668,7 +9668,7 @@ type IconScaleElement = { val_max:number, val_best?: number } - +/** we need this to have a nice order when using switch() */ type adapterPlayerInstanceType = 'alexa2.0.' | 'alexa2.1.'| 'alexa2.2.' | 'alexa2.3.' | 'alexa2.4.' | 'alexa2.5.' | 'alexa2.6.' | 'alexa2.7.' | 'alexa2.8.' | 'alexa2.9.' | 'sonos.0.' | 'sonos.1.' | 'sonos.2.' | 'sonos.3.' | 'sonos.4.' | 'sonos.5.' | 'sonos.6.' | 'sonos.7.' | 'sonos.8.' | 'sonos.9.' @@ -9678,6 +9678,13 @@ type adapterPlayerInstanceType = type PlayerType = 'alexa2' | 'sonos' | 'spotify-premium' | 'volumio' | 'squeezeboxrpc' +type notSortedPlayerType = `${PlayerType}.0.` | `${PlayerType}.1.` | `${PlayerType}.2.` | `${PlayerType}.3.` | `${PlayerType}.4.` | `${PlayerType}.5.` | `${PlayerType}.6.` | `${PlayerType}.7.` | `${PlayerType}.8.` | `${PlayerType}.9.` + +/** check if adapterPlayerInstanceType has all Playertypes */ +function checkSortedPlayerType(F: adapterPlayerInstanceType) { + const test: notSortedPlayerType = F; +} + type mediaOptional = 'seek' | 'crossfade' | 'speakerlist' | 'playlist' | 'tracklist' | 'equalizer' | 'repeat' | 'favorites' function isMediaOptional(F: string | mediaOptional): F is mediaOptional { From cb44fcc8c9b1f8b33abb432088c6e88d6f0462dc Mon Sep 17 00:00:00 2001 From: ticaki Date: Wed, 3 Jan 2024 20:16:13 +0100 Subject: [PATCH 32/99] add bose aliase --- ioBroker/NsPanelTs.ts | 58 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 848c1e6f..a71743f0 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -4913,6 +4913,47 @@ async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPla } break; + case "bosesoundtouch.0.": + case "bosesoundtouch.1.": + case "bosesoundtouch.2.": + case "bosesoundtouch.3.": + case "bosesoundtouch.4.": + case "bosesoundtouch.5.": + case "bosesoundtouch.6.": + case "bosesoundtouch.7.": + case "bosesoundtouch.8.": + case "bosesoundtouch.9.": { + if (existsObject(id) == false) { + log('bosesoundtouch Alias ' + id + ' does not exist - will be created now', 'info'); + + try { + let dpPath: string = adapterPlayerInstance + 'keys'; + await extendObjectAsync(id, {_id: id, type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); + await createAliasAsync(id + '.ACTUAL', dpPath + '.volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); + await createAliasAsync(id + '.VOLUME', dpPath + '.volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + + dpPath = adapterPlayerInstance + 'nowPlaying'; + await createAliasAsync(id + '.ALBUM', dpPath + '.album', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); + await createAliasAsync(id + '.ARTIST', dpPath + '.artist', true, {type: 'string', role: 'media.artist', name: 'ARTIST'}); + await createAliasAsync(id + '.TITLE', dpPath + '.track', true, {type: 'string', role: 'media.title', name: 'TITLE'}); + await createAliasAsync(id + '.DURATION', dpPath + '.total', true, {type: 'string', role: 'media.duration.text', name: 'DURATION'}); + await createAliasAsync(id + '.ELAPSED', dpPath + '.time', true, {type: 'string', role: 'media.elapsed.text', name: 'ELAPSED'}); + await createAliasAsync(id + '.REPEAT', dpPath + '.repeat', true, {type: 'boolean', role: 'media.mode.repeat', name: 'REPEAT'}); + await createAliasAsync(id + '.SHUFFLE', dpPath + '.shuffle', true, {type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE'}); + + dpPath = adapterPlayerInstance + 'keys'; + await createAliasAsync(id + '.STATE', dpPath + '.POWER', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); + await createAliasAsync(id + '.NEXT', dpPath + '.NEXT_TRACK', true, {type: 'boolean', role: 'button.next', name: 'NEXT'}); + await createAliasAsync(id + '.PREV', dpPath + '.PREV_TRACK', true, {type: 'boolean', role: 'button.prev', name: 'PREV'}); + await createAliasAsync(id + '.PLAY', dpPath + '.PLAY', true, {type: 'boolean', role: 'button.play', name: 'PLAY'}); + await createAliasAsync(id + '.PAUSE', dpPath + '.PAUSE', true, {type: 'boolean', role: 'button.pause', name: 'PAUSE'}); + await createAliasAsync(id + '.STOP', dpPath + '.STOP', true, {type: 'boolean', role: 'button.stop', name: 'STOP'}); + } catch (err: any) { + log('error at function createAutoMediaAlias Adapter bosesoundtouch: ' + err.message, 'warn'); + } + } + break; + } default: { log(`Dont find adapterPlayerInstance: ${adapterPlayerInstance}!`, 'warn') } @@ -6651,8 +6692,14 @@ function HandleButtonEvent(words: any): void { case 'squeezeboxrpc': pageItem.mediaDevice = pageItem.speakerList![words[4]]; break; + case "volumio": + break; + default: + log('Hello Mr. Developer u miss in speakerlist somthing!', 'warn') + } + function exhaustiveCheck(_v: never) {} pageCounter = 0; GeneratePage(activePage!); setTimeout(async function () { @@ -6709,6 +6756,8 @@ function HandleButtonEvent(words: any): void { case 'squeezeboxrpc': setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'cmdPlayFavorite'].join('.'), words[4]); break; + default: + log('Hello Mr. Developer u miss in mode-playlist somthing!', 'warn') } pageCounter = 0; GeneratePage(activePage!); @@ -6754,6 +6803,8 @@ function HandleButtonEvent(words: any): void { //@ts-ignore Fehler kommt von findPageItem in vscode setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'PlaylistCurrentIndex'].join('.'), words[4]); break; + default: + log('Hello Mr. Developer u miss in mode-tracklist somthing!', 'warn') } pageCounter = 0; GeneratePage(activePage!); @@ -9675,14 +9726,15 @@ type adapterPlayerInstanceType = | 'spotify-premium.0.' | 'spotify-premium.1.' | 'spotify-premium.2.' | 'spotify-premium.3.' | 'spotify-premium.4.' | 'spotify-premium.5.' | 'spotify-premium.6.' | 'spotify-premium.7.' | 'spotify-premium.8.' | 'spotify-premium.9.' | 'volumio.0.' | 'volumio.1.' | 'volumio.2.' | 'volumio.3.' |'volumio.4.' | 'volumio.5.' | 'volumio.6.' | 'volumio.7.' | 'volumio.8.' | 'volumio.9.' | 'squeezeboxrpc.0.' | 'squeezeboxrpc.1.' | 'squeezeboxrpc.2.' | 'squeezeboxrpc.3.' | 'squeezeboxrpc.4.' | 'squeezeboxrpc.5.' | 'squeezeboxrpc.6.' | 'squeezeboxrpc.7.' | 'squeezeboxrpc.8.' | 'squeezeboxrpc.9.' +| 'bosesoundtouch.0.' | 'bosesoundtouch.1.' | 'bosesoundtouch.2.' | 'bosesoundtouch.3.' |'bosesoundtouch.4.' | 'bosesoundtouch.5.' | 'bosesoundtouch.6.' | 'bosesoundtouch.7.' | 'bosesoundtouch.8.' | 'bosesoundtouch.9.' -type PlayerType = 'alexa2' | 'sonos' | 'spotify-premium' | 'volumio' | 'squeezeboxrpc' +type PlayerType = 'alexa2' | 'sonos' | 'spotify-premium' | 'volumio' | 'squeezeboxrpc' | 'bosesoundtouch' type notSortedPlayerType = `${PlayerType}.0.` | `${PlayerType}.1.` | `${PlayerType}.2.` | `${PlayerType}.3.` | `${PlayerType}.4.` | `${PlayerType}.5.` | `${PlayerType}.6.` | `${PlayerType}.7.` | `${PlayerType}.8.` | `${PlayerType}.9.` /** check if adapterPlayerInstanceType has all Playertypes */ -function checkSortedPlayerType(F: adapterPlayerInstanceType) { - const test: notSortedPlayerType = F; +function checkSortedPlayerType(F: notSortedPlayerType) { + const test: adapterPlayerInstanceType = F; } type mediaOptional = 'seek' | 'crossfade' | 'speakerlist' | 'playlist' | 'tracklist' | 'equalizer' | 'repeat' | 'favorites' From a4b90944e8a13a762f05b878a679118be8434894 Mon Sep 17 00:00:00 2001 From: ticaki Date: Wed, 3 Jan 2024 20:17:53 +0100 Subject: [PATCH 33/99] typo --- ioBroker/NsPanelTs.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index a71743f0..04ca8ca8 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -6695,7 +6695,7 @@ function HandleButtonEvent(words: any): void { case "volumio": break; default: - log('Hello Mr. Developer u miss in speakerlist somthing!', 'warn') + log('Hello Mr. Developer u miss in speakerlist something!', 'warn') } @@ -6757,7 +6757,7 @@ function HandleButtonEvent(words: any): void { setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'cmdPlayFavorite'].join('.'), words[4]); break; default: - log('Hello Mr. Developer u miss in mode-playlist somthing!', 'warn') + log('Hello Mr. Developer u miss in mode-playlist something!', 'warn') } pageCounter = 0; GeneratePage(activePage!); @@ -6804,7 +6804,7 @@ function HandleButtonEvent(words: any): void { setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'PlaylistCurrentIndex'].join('.'), words[4]); break; default: - log('Hello Mr. Developer u miss in mode-tracklist somthing!', 'warn') + log('Hello Mr. Developer u miss in mode-tracklist something!', 'warn') } pageCounter = 0; GeneratePage(activePage!); From de237171ef8d4175dc7a4fa4adf4a00d9e27c7b1 Mon Sep 17 00:00:00 2001 From: ticaki Date: Wed, 3 Jan 2024 20:53:15 +0100 Subject: [PATCH 34/99] add cases --- ioBroker/NsPanelTs.ts | 11 ++++++----- ioBroker/tsconfig.json | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 04ca8ca8..3a064ac4 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -6694,12 +6694,9 @@ function HandleButtonEvent(words: any): void { break; case "volumio": break; - default: - log('Hello Mr. Developer u miss in speakerlist something!', 'warn') - - + case "bosesoundtouch": + break; } - function exhaustiveCheck(_v: never) {} pageCounter = 0; GeneratePage(activePage!); setTimeout(async function () { @@ -6756,6 +6753,8 @@ function HandleButtonEvent(words: any): void { case 'squeezeboxrpc': setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'cmdPlayFavorite'].join('.'), words[4]); break; + case "bosesoundtouch": + break; default: log('Hello Mr. Developer u miss in mode-playlist something!', 'warn') } @@ -6803,6 +6802,8 @@ function HandleButtonEvent(words: any): void { //@ts-ignore Fehler kommt von findPageItem in vscode setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'PlaylistCurrentIndex'].join('.'), words[4]); break; + case "bosesoundtouch": + break; default: log('Hello Mr. Developer u miss in mode-tracklist something!', 'warn') } diff --git a/ioBroker/tsconfig.json b/ioBroker/tsconfig.json index 6a5cb9b9..ef388040 100644 --- a/ioBroker/tsconfig.json +++ b/ioBroker/tsconfig.json @@ -9,8 +9,9 @@ "esModuleInterop": true, "resolveJsonModule": true, "strict": true, + "noImplicitReturns": true, "noImplicitAny": false, - "target": "es2020", + "target": "ES2022", "typeRoots": [ ".iobroker/types", "node_modules/@types" From 9afdaa4cbc94f93380c81553952c27db49d6a42e Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Wed, 3 Jan 2024 21:11:51 +0100 Subject: [PATCH 35/99] v4.3.3.31 - Update NsPanelTs.ts * Remove: autoCreateAlias from cardMedia * Remove: adapterPlayerInstance from every card except cardMedia * [dev]: optional with type - cardMedia has adapterPlayerInstance all other not * [dev]: add PlayerType some more work to do * changed: adapterPlayerInstance instance 0-9 allowed. Always require a '.' at the end. --- ioBroker/NsPanelTs.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 3a064ac4..5a0b514e 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.31 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Sternmiere / @Britzelpuf / @ravenS0ne +TypeScript v4.3.3.31 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -9754,4 +9754,4 @@ function isMediaOptional(F: string | mediaOptional): F is mediaOptional { default: return false } -} \ No newline at end of file +} From c8a8feace2ae628ea933f1a44f6229116b9c7ad6 Mon Sep 17 00:00:00 2001 From: ticaki Date: Thu, 4 Jan 2024 21:49:02 +0100 Subject: [PATCH 36/99] some more types --- ioBroker/NsPanelTs.ts | 199 +++++++++++++++++++----------------------- 1 file changed, 89 insertions(+), 110 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 5a0b514e..3f157bf6 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -2768,12 +2768,14 @@ function check_online_display_firmware() { } } +//mqttCallback (topic: string, message: string): Promise { on({ id: config.panelRecvTopic }, async (obj) => { if (obj.state.val.startsWith('\{"CustomRecv":')) { try { + const json = JSON.parse(obj.state.val); + const split = json.CustomRecv.split(','); if (isSetOptionActive) { - let json = JSON.parse(obj.state.val); - let split = json.CustomRecv.split(','); + if (split[0] == 'event' && split[1] == 'startup') { await createStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { type: 'string' }); await createStateAsync(NSPanel_Path + 'NSPanel_Version', { type: 'string' }); @@ -2789,9 +2791,11 @@ on({ id: config.panelRecvTopic }, async (obj) => { } } } + HandleMessage(split[0], split[1], parseInt(split[2]), split); } catch (err: any) { log('error at trigger rceiving CustomRecv: ' + err.message, 'warn'); } + } }); @@ -2914,7 +2918,7 @@ function update_tasmota_firmware() { log('error request in function update_tasmota_firmware: ' + err.message, 'warn'); } } - +//mqttCallback (topic: string, message: string): Promise { on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'INFO1', change: 'ne'}, async (obj) => { try { if (getState(NSPanel_Path + 'Config.Update.activ').val == 0) { @@ -2935,23 +2939,6 @@ on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESU //------------------End Update Functions -on({ id: config.panelRecvTopic, change: 'any' }, async function (obj) { - try { - if (obj.state.val.startsWith('\{"CustomRecv":')) { - try { - let json = JSON.parse(obj.state.val); - - let split = json.CustomRecv.split(','); - HandleMessage(split[0], split[1], parseInt(split[2]), split); - } catch (err: any) { - log('error json.split in Trigger panelRecTopic: ' + err.message, 'warn'); - } - } - } catch (err: any) { - log('error at Trigger panelRecTopic: ' + err.message, 'warn'); - } -}); - async function SendToPanel(val: Payload | Payload[]) { try { if (Array.isArray(val)) { @@ -3315,17 +3302,6 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let buttonText: string = 'PRESS'; let type: string; - if (pageItem.id && existsState(pageItem.id + '.ACTUAL') == false) { - if (pageItem.popupTimerType == 'TimeCard' && pageItem.autoCreateALias == true) { - log(NSPanel_Path + 'Userdata.' + pageItem.id + '.Time') - createStateAsync(NSPanel_Path + 'Userdata.' + pageItem.id + '.Time', '0', { type: 'number' }); - createStateAsync(NSPanel_Path + 'Userdata.' + pageItem.id + '.State', 'idle', { type: 'string' }); - setObject(pageItem.id, { type: 'channel', common: { role: 'value.time', name: 'Time' }, native: {} }); - createAliasAsync(pageItem.id + '.ACTUAL', NSPanel_Path + 'Userdata.' + pageItem.id + '.Time', true, { type: 'number', role: 'state', name: 'ACTUAL' }); - createAliasAsync(pageItem.id + '.STATE', NSPanel_Path + 'Userdata.' + pageItem.id + '.State', true, { type: 'string', role: 'state', name: 'STATE' }); - } - } - // ioBroker if (pageItem.id && existsObject(pageItem.id) || pageItem.navigate === true) { @@ -8300,65 +8276,67 @@ function HandleScreensaverUpdate(): void { } // 3 leftScreensaverEntities - if (screensaverAdvanced) { + if (screensaverAdvanced) { let checkpoint = true; let i = 0; - for (i = 0; i < 3; i++) { - - if (config.leftScreensaverEntity[i] == null || config.leftScreensaverEntity[i] == undefined) { - checkpoint = false; - break; - } - RegisterScreensaverEntityWatcher(config.leftScreensaverEntity[i].ScreensaverEntity) - - let val = getState(config.leftScreensaverEntity[i].ScreensaverEntity).val; - let iconColor = rgb_dec565(White); - let icon; - if (typeof config.leftScreensaverEntity[i].ScreensaverEntityIconOn == 'string' && existsObject(config.leftScreensaverEntity[i].ScreensaverEntityIconOn as string)) { - let iconName = getState(config.leftScreensaverEntity[i].ScreensaverEntityIconOn!).val; - icon = Icons.GetIcon(iconName); - } else { - icon = Icons.GetIcon(config.leftScreensaverEntity[i].ScreensaverEntityIconOn); - } - - if (parseFloat(val+"") == val) { - val = parseFloat(val); - } - - if (typeof(val) == 'number') { - val = (val * (config.leftScreensaverEntity[i].ScreensaverEntityFactor ? config.leftScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.leftScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.leftScreensaverEntity[i].ScreensaverEntityUnitText; - iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); - } - else if (typeof(val) == 'boolean') { - iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); - if (!val && config.leftScreensaverEntity[i].ScreensaverEntityIconOff != null) { - icon = Icons.GetIcon(config.leftScreensaverEntity[i].ScreensaverEntityIconOff) + if (config.leftScreensaverEntity && Array.isArray(config.leftScreensaverEntity)) { + for (i = 0; i < 3; i++) { + const leftScreensaverEntity = config.leftScreensaverEntity[i] + if (leftScreensaverEntity === null || leftScreensaverEntity === undefined) { + checkpoint = false; + break;; } - } - else if (typeof(val) == 'string') { - iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); - let pformat = parseFormat(val); - if (Debug) log('moments.js --> Datum ' + val + ' valid?: ' + moment(val, pformat, true).isValid(), 'info'); - if (moment(val, pformat, true).isValid()) { - let DatumZeit = moment(val, pformat).unix(); // Umwandlung in Unix Time-Stamp - if (config.leftScreensaverEntity[i].ScreensaverEntityDateFormat !== undefined) { - val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val, config.leftScreensaverEntity[i].ScreensaverEntityDateFormat); - } else { - val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val); - } - } - } - const temp = config.leftScreensaverEntity[i].ScreensaverEntityIconColor; - if (temp && typeof temp == 'string' && existsObject(temp)) { - iconColor = getState(temp).val; - } + RegisterScreensaverEntityWatcher(leftScreensaverEntity.ScreensaverEntity) - payloadString += '~' + - '~' + - icon + '~' + - iconColor + '~' + - config.leftScreensaverEntity[i].ScreensaverEntityText + '~' + - val + '~'; + let val = getState(leftScreensaverEntity.ScreensaverEntity).val; + let iconColor = rgb_dec565(White); + let icon; + if (typeof leftScreensaverEntity.ScreensaverEntityIconOn == 'string' && existsObject(leftScreensaverEntity.ScreensaverEntityIconOn as string)) { + let iconName = getState(leftScreensaverEntity.ScreensaverEntityIconOn!).val; + icon = Icons.GetIcon(iconName); + } else { + icon = Icons.GetIcon(leftScreensaverEntity.ScreensaverEntityIconOn); + } + + if (parseFloat(val + "") == val) { + val = parseFloat(val); + } + + if (typeof (val) == 'number') { + val = (val * (leftScreensaverEntity.ScreensaverEntityFactor ? leftScreensaverEntity.ScreensaverEntityFactor! : 0)).toFixed(leftScreensaverEntity.ScreensaverEntityDecimalPlaces) + leftScreensaverEntity.ScreensaverEntityUnitText; + iconColor = GetScreenSaverEntityColor(leftScreensaverEntity); + } + else if (typeof (val) == 'boolean') { + iconColor = GetScreenSaverEntityColor(leftScreensaverEntity); + if (!val && leftScreensaverEntity.ScreensaverEntityIconOff != null) { + icon = Icons.GetIcon(leftScreensaverEntity.ScreensaverEntityIconOff) + } + } + else if (typeof (val) == 'string') { + iconColor = GetScreenSaverEntityColor(leftScreensaverEntity); + let pformat = parseFormat(val); + if (Debug) log('moments.js --> Datum ' + val + ' valid?: ' + moment(val, pformat, true).isValid(), 'info'); + if (moment(val, pformat, true).isValid()) { + let DatumZeit = moment(val, pformat).unix(); // Umwandlung in Unix Time-Stamp + if (leftScreensaverEntity.ScreensaverEntityDateFormat !== undefined) { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val, leftScreensaverEntity.ScreensaverEntityDateFormat); + } else { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val); + } + } + } + const temp = leftScreensaverEntity.ScreensaverEntityIconColor; + if (temp && typeof temp == 'string' && existsObject(temp)) { + iconColor = getState(temp).val; + } + + payloadString += '~' + + '~' + + icon + '~' + + iconColor + '~' + + leftScreensaverEntity.ScreensaverEntityText + '~' + + val + '~'; + } } if (checkpoint == false) { for (let j = i; j < 3; j++) { @@ -8466,7 +8444,7 @@ function HandleScreensaverUpdate(): void { } //Alternativ Layout bekommt zusätzlichen Status - if (getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { + if (config.bottomScreensaverEntity[4] && getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { let val = getState(config.bottomScreensaverEntity[4].ScreensaverEntity).val; if (parseFloat(val+"") == val) { val = parseFloat(val); @@ -8585,37 +8563,38 @@ function HandleScreensaverUpdate(): void { // 5 indicatorScreensaverEntities for (let i = 0; i < 5; i++) { let checkpoint = true; - if (config.indicatorScreensaverEntity[i] == null) { + const indicatorScreensaverEntity:ScreenSaverElementWithUndefined = config.indicatorScreensaverEntity[i]; + if (indicatorScreensaverEntity == null) { checkpoint = false; break; } - RegisterScreensaverEntityWatcher(config.indicatorScreensaverEntity[i].ScreensaverEntity) + RegisterScreensaverEntityWatcher(indicatorScreensaverEntity.ScreensaverEntity) - let val = getState(config.indicatorScreensaverEntity[i].ScreensaverEntity).val; + let val = getState(indicatorScreensaverEntity.ScreensaverEntity).val; if (parseFloat(val+"") == val) { val = parseFloat(val); } let iconColor = rgb_dec565(White); let icon; - if (config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn && existsObject(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn!)) { - let iconName = getState(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn!).val; + if (indicatorScreensaverEntity.ScreensaverEntityIconOn && existsObject(indicatorScreensaverEntity.ScreensaverEntityIconOn!)) { + let iconName = getState(indicatorScreensaverEntity.ScreensaverEntityIconOn!).val; icon = Icons.GetIcon(iconName); } else { - icon = Icons.GetIcon(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn); + icon = Icons.GetIcon(indicatorScreensaverEntity.ScreensaverEntityIconOn); } if (typeof(val) == 'number') { - val = (val * (config.indicatorScreensaverEntity[i].ScreensaverEntityFactor ? config.indicatorScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.indicatorScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.indicatorScreensaverEntity[i].ScreensaverEntityUnitText; - iconColor = GetScreenSaverEntityColor(config.indicatorScreensaverEntity[i]); + val = (val * (indicatorScreensaverEntity.ScreensaverEntityFactor ? indicatorScreensaverEntity.ScreensaverEntityFactor! : 0)).toFixed(indicatorScreensaverEntity.ScreensaverEntityDecimalPlaces) + indicatorScreensaverEntity.ScreensaverEntityUnitText; + iconColor = GetScreenSaverEntityColor(indicatorScreensaverEntity); } else if (typeof(val) == 'boolean') { - iconColor = GetScreenSaverEntityColor(config.indicatorScreensaverEntity[i]); - if (!val && config.indicatorScreensaverEntity[i].ScreensaverEntityIconOff != null) { - icon = Icons.GetIcon(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOff) + iconColor = GetScreenSaverEntityColor(indicatorScreensaverEntity); + if (!val && indicatorScreensaverEntity.ScreensaverEntityIconOff != null) { + icon = Icons.GetIcon(indicatorScreensaverEntity.ScreensaverEntityIconOff) } } - const temp = config.indicatorScreensaverEntity[4].ScreensaverEntityIconColor + const temp = indicatorScreensaverEntity.ScreensaverEntityIconColor if (temp && typeof temp == 'string' && existsObject(temp)) { iconColor = getState(temp).val; } @@ -8623,7 +8602,7 @@ function HandleScreensaverUpdate(): void { '~' + icon + '~' + iconColor + '~' + - config.indicatorScreensaverEntity[i].ScreensaverEntityText + '~' + + indicatorScreensaverEntity.ScreensaverEntityText + '~' + val + '~'; } } @@ -9275,6 +9254,7 @@ function GetDasWetterIconColor(icon: number): number { } //------------------Begin Read Internal Sensor Data +//mqttCallback (topic: string, message: string): Promise { on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'SENSOR' }, async (obj) => { try { const Tasmota_Sensor = JSON.parse(obj.state.val); @@ -9613,7 +9593,7 @@ type PageBaseItem = { unit?: string, navigate?: boolean, colormode?: string, - colorScale?: any, + colorScale?: IconScaleElement, //adapterPlayerInstance?: adapterPlayerInstanceType, mediaDevice?: string, targetPage?: string, @@ -9641,15 +9621,12 @@ type PageBaseItem = { yAxis?: string, yAxisTicks?: number[] | string, xAxisDecorationId?: string, - popupType?: string, - popupOptions?: string[], useValue?: boolean, monobutton?: boolean, inSel_ChoiceState?: boolean, iconArray?: string[], fontSize?: number, actionStringArray?: string[], - popupTimerType?: string, alwaysOnDisplay?: boolean, crossfade?: boolean, } @@ -9673,9 +9650,9 @@ type Config = { panelRecvTopic: string, panelSendTopic: string, weatherEntity: string, - leftScreensaverEntity: ScreenSaverElement[], + leftScreensaverEntity: leftScreensaverEntityType bottomScreensaverEntity: ScreenSaverElement[], - indicatorScreensaverEntity: ScreenSaverElement[], + indicatorScreensaverEntity: indicatorScreensaverEntityType mrIcon1ScreensaverEntity: ScreenSaverMRElement, mrIcon2ScreensaverEntity: ScreenSaverMRElement, defaultColor: RGB, @@ -9687,16 +9664,18 @@ type Config = { button1: ConfigButtonFunction, button2: ConfigButtonFunction } - +type leftScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; +type indicatorScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; +type ScreenSaverElementWithUndefined = null | undefined | ScreenSaverElement type ScreenSaverElement = { ScreensaverEntity: string, + ScreensaverEntityText: string, ScreensaverEntityFactor?: number, ScreensaverEntityDecimalPlaces?: number, - ScreensaverEntityDateFormat?: any | null, + ScreensaverEntityDateFormat?: Intl.DateTimeFormatOptions, ScreensaverEntityIconOn?: string | null, ScreensaverEntityIconOff?: string | null, - ScreensaverEntityText: string, - ScreensaverEntityUnitText?: string | null, + ScreensaverEntityUnitText?: string, ScreensaverEntityIconColor?: RGB | IconScaleElement | string ScreensaverEntityOnColor?: RGB ScreensaverEntityOffColor?: RGB From bc330d5aafb15244cc65d692259d39c0e57e366d Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Thu, 4 Jan 2024 22:14:03 +0100 Subject: [PATCH 37/99] Create NSPanelTs.ts --- ioBroker/DEV/NSPanelTs.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 ioBroker/DEV/NSPanelTs.ts diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/ioBroker/DEV/NSPanelTs.ts @@ -0,0 +1 @@ + From fc3d4adc7240d9b29693ed997b12436113d51aae Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Thu, 4 Jan 2024 22:15:47 +0100 Subject: [PATCH 38/99] Update NSPanelTs.ts --- ioBroker/DEV/NSPanelTs.ts | 9756 +++++++++++++++++++++++++++++++++++++ 1 file changed, 9756 insertions(+) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 8b137891..5a0b514e 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1 +1,9757 @@ +/*----------------------------------------------------------------------- +TypeScript v4.3.3.31 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +- abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.0 +@joBr99 Projekt: https://github.com/joBr99/nspanel-lovelace-ui/tree/main/ioBroker +NsPanelTs.ts (dieses TypeScript in ioBroker) Stable: https://github.com/joBr99/nspanel-lovelace-ui/blob/main/ioBroker/NsPanelTs.ts +icon_mapping.ts: https://github.com/joBr99/nspanel-lovelace-ui/blob/main/ioBroker/icon_mapping.ts (TypeScript muss in global liegen) +ioBroker-Unterstützung: https://forum.iobroker.net/topic/50888/sonoff-nspanel +@Kuckuckmann: WIKI zu diesem Projekt unter: https://github.com/joBr99/nspanel-lovelace-ui/wiki (siehe Sidebar) +*************************************************************************************************************** +Achtung: Keine Beispiele mehr im Script. Die Beispiele sind jetzt unter nachfolgendem Link zu finden: +- https://github.com/joBr99/nspanel-lovelace-ui/wiki/NSPanel-Page-%E2%80%90-Typen_How-2_Beispiele +*************************************************************************************************************** + +Icons unter: https://htmlpreview.github.io/?https://github.com/jobr99/Generate-HASP-Fonts/blob/master/cheatsheet.html + +************************************************************************************************ +Achtung Änderung des Sonoff ESP-Temperatursensors +!!! Bitte "SetOption146 1" in der Tasmota-Console ausführen !!! +************************************************************************************************ +In bestimmten Situationen kommt es vor, dass sich das Panel mit FlashNextion +unter Tasmota > 12.2.0 nicht flashen lässt. Für den Fall ein Tasmota Downgrade +durchführen und FlashNextion wiederholen. +************************************************************************************************ +Ab Tasmota > 13.0.0 ist für ein Upgrade ggfs. eine Umpartitionierung erforderlich +https://github.com/joBr99/nspanel-lovelace-ui/wiki/NSPanel-Tasmota-FAQ#3-tasmota-update-probleme +***************************************************************************************************************************** +Ab Script Version 4.3.2.1 muss in der JavaScript Instanz die npm Module 'moment', 'moment-parseformat' und 'dayjs' eingetragen sein +https://github.com/joBr99/nspanel-lovelace-ui/wiki/iobroker---Basisinstallation#8--einstellungen-in-js-adapter-instanz +***************************************************************************************************************************** + +ReleaseNotes: + Bugfixes und Erweiterungen: + + - 17.09.2023 - v4.3.1 Upgrade TFT 53 / 4.3.1 + - 17.09.2023 - v4.3.1.1 Add Parameter fontSize (0-4) to cardGrid (with useValue) + - 23.09.2023 - v4.3.1.2 Upgrade BerryDriver v9 + - 23.09.2023 - v4.3.1.3 Fix - Change ServivceMenu from Fake-SSId to real Tasmota-SSIdParam + - 03.10.2023 - v4.3.1.4 Removing the examples from the NSPanelTs.ts --> https://github.com/joBr99/nspanel-lovelace-ui/wiki/NSPanel-Page-%E2%80%90-Typen_How-2_Beispiele + - 03.10.2023 - v4.3.1.4 Delete NsPanelTs_without_Examples.ts + - 12.10.2023 - v4.3.1.5 Fix Datapoint for Role timetable -> Attention use new script from TT-Tom https://github.com/tt-tom17/MyScripts/blob/main/Sonoff_NSPanel/Fahrplan_to_NSPanel.ts + - 19.10.2023 - v4.3.1.6 Add more Alias Device-Types to Navigation / Minor Fixes + - 22.10.2023 - v4.3.1.7 Fix CreateEntity (navigate) role 'light' and 'socket' and 'temperature' + - 30.10.2023 - v4.3.2 Upgrade TFT 53 / 4.3.2 + - 30.10.2023 - v4.3.2.1 Fix formatDate/Date.parse with moment.js (Bugs in JS-Methodes) + - 07.11.2023 - v4.3.2.2 Fix Selection of screensaver layout (alternative / advanced) + - 08.11.2023 - v4.3.2.3 Fix Issues #1013 by laluz742 -> Parameter count mismatch: screensaver color + - 08.11.2023 - v4.3.3 Upgrade TFT 53 / 4.3.3 + - 11.11.2023 - v4.3.3.1 Fix for Issues #1020 HandleHardwareButton buttonConfig.mode -> 'toggle' and 'set' + - 12.11.2023 - v4.3.3.2 Add autoCreateALias to cardUnlock + - 12.11.2023 - v4.3.3.2 Change NodeJS to at least v18.X.X + - 13.11.2023 - v4.3.3.3 if setOption = false, do not create autoAlias (Functional/Servicemenu) and Datapoints + - 15.11.2023 - v4.3.3.4 New Service Page -> ioBroker Info + - 16.11.2023 - v4.3.3.5 Add Multilingualism to Service Menu (39 languages) + - 17.11.2023 - v4.3.3.5 Add Multilingualism to cardUnlock, cardQR, popupFan, popupTimer (39 languages) + - 18.11.2023 - v4.3.3.6 Add autoCreateALias to PageAlarm + - 20.11.2023 - v4.3.3.6 Add actionStringArray to PageAlarm + - 20.11.2023 - v4.3.3.6 Add Multilingualism to cardAlarm (39 languages) + - 20.11.2023 - v4.3.3.7 Add Multilingualism to cardMedia (39 languages) + - 20.11.2023 - v4.3.3.8 Add Method dayjs (Multilingualism) + - 20.11.2023 - v4.3.3.9 Add ScreensaverEntityOnColor, ...OffColor, ...OnText, ...OffText + - 23.11.2023 - v4.3.3.10 Code Optimization in Config Area + - 24.11.2023 - v4.3.3.11 Add autoCreateALias to PageQR + - 24.11.2023 - v4.3.3.12 Separation of page creation and page updates in cardPower + - 24.11.2023 - v4.3.3.12 Add alwaysOnDisplay to cardPower - Leave display on if the alwaysOnDisplay parameter is "true" + - 25.11.2023 - v4.3.3.13 Separation of page creation and page updates in cardMedia + - 25.11.2023 - v4.3.3.13 Add alwaysOnDisplay to cardMedia - Leave display on if the alwaysOnDisplay parameter is "true" + - 25.11.2023 - v4.3.3.13 Fix Sonos Repeat/Shuffle + - 25.11.2023 - v4.3.3.14 Refactoring Sonos-Player (with Playlist, Tracklist, Favorites, Eqalizer (if no Favorites)) + - 29.11.2023 - v4.3.3.15 Fix cardMedia Volume-Slider / Add Init Release to Startup + - 30.11.2023 - v4.3.3.16 Beautification of the Sonos player Strings / Add Duration & Elapsed + - 01.12.2023 - v4.3.3.16 Fix Datapoints with Value null + - 02.12.2023 - v4.3.3.16 Request replaced by Axios + - 04.12.2023 - v4.3.3.17 Add SEEK and CROSSFADE to Sonos cardMedia + - 05.12.2023 - v4.3.3.18 Add (ELAPSED/DURATION) to v2Adapter alexa2 + - 06.12.2023 - v4.3.3.18 Replace missing Type console.log --> log(message, 'serverity') + - 07.12.2023 - v4.3.3.19 Fix Trigger activeDimmodeBrightness if Dimmode = -1 + - 08.12.2023 - v4.3.3.20 add Role AlarmTime for Alarm Clock + - 09.12.2023 - v4.3.3.21 Add createAutoAlias to popupTimer only for Time + - 14.12.2023 - v4.3.3.22 Add UpdateMessage => disable the update messages + - 14.12.2023 - v4.3.3.22 Fix name by static Navi Icon + - 17.12.2023 - v4.3.3.23 Optimization of the blind control (enable or disable Up/Stop/Down) + - 18.12.2023 - v4.3.3.24 Hotfix Update Message / Add Icon Colors to Entity Button + - 21.12.2023 - v4.3.3.25 Add switch of cardQR by hidePassword: true + - 26.12.2023 - v4.3.3.26 Fix Log output payload -> Json.stringify + - 28.12.2023 - v4.3.3.27 Fix Payload (pageItem.id -> placeId) by Function CreateEntity + - 28.12.2023 - v4.3.3.27 Fix Fallback PageItem.name by Function CreateEntity --> Many Bugs + - 30.12.2023 - v4.3.3.28 Fix short ID's in v4.3.3.27 + - 30.12.2023 - v4.3.3.28 Fix window Icons in CreateEntity + - 30.12.2023 - v4.3.3.28 Add MQTT-Client Check + - 02.01.2024 - v4.3.3.29 Add Tasmota Buzzer for NotifyPage + - 02.02.2024 - v4.3.3.29 Fix ThermoPage -> UnSubScribsWatcher + - 02.02.2024 - v4.3.3.30 Add stronger config type checks + - 03.02.2024 - v4.3.3.31 Remove: autoCreateAlias from cardMedia + - 03.02.2024 - v4.3.3.31 Remove: adapterPlayerInstance from every card except cardMedia + - 03.02.2024 - v4.3.3.31 [dev]: optional with type - cardMedia has adapterPlayerInstance all other not + - 03.02.2024 - v4.3.3.31 [dev]: add PlayerType some more work to do + - 03.02.2024 - v4.3.3.31 changed: adapterPlayerInstance instance 0-9 allowed. Always require a '.' at the end. + + Todo: + - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined + +*************************************************************************************************************** +* DE: Für die Erstellung der Aliase durch das Skript, muss in der JavaScript Instanz "setObject" gesetzt sein! * +* EN: In order for the script to create the aliases, “setObject” must be set in the JavaScript instance! * +*************************************************************************************************************** + +Wenn Rule definiert, dann können die Hardware-Tasten ebenfalls für Seitensteuerung (dann nicht mehr als Relais) genutzt werden + +Tasmota Konsole: + Rule2 on Button1#state do Publish %topic%/tele/RESULT {"CustomRecv":"event,button1"} endon on Button2#state do Publish %topic%/tele/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öchsttemperatur) oder zur Anzeige definierter Infos konfiguriert werden) + cardEntities Page - 4 vertikale angeordnete Steuerelemente - auch als Subpage + cardGrid Page - 6 horizontal angeordnete Steuerelemente in 2 Reihen a 3 Steuerelemente - auch als Subpage + cardGrid2 Page - 8 horizontal angeordnete Steuerelemente in 2 Reihen a 4 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-Verzeichnis Player angelegt werden + cardAlarm Page - Alarmseite mit Zustand und Tastenfeld + cardPower Page - Energiefluss + cardChart Page - Balken-Diagramme aus History, SQL oder InfluxDB + cardLChart Page - Linien-Diagramme aus History, SQL oder InfluxDB + + Vollständige Liste zur Einrichtung unter: + https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Card-Definitionen-(Seiten) + +Popup-Pages: + popupLight Page - in Abhängigkeit zum gewählten Alias werden "Helligkeit", "Farbtemperatur" und "Farbauswahl" bereitgestellt + popupShutter Page - die Shutter-Position (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 + popupInSel Page - Auswahlliste (InputSelect) + +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 + Tor - Sensor open + Bewegung - Sensor Presence + Verschluss - Türschloss SET/ACTUAL/OPEN + Taste - Für Szenen oder Radiosender, etc. --> Nur Funktionsaufruf - Kein Taster wie MonoButton - True/False + Tastensensor - Für Auswahlmenü (popupInSel) + Thermostat - Aktuelle Raumtemperatur, Setpoint, etc. + Temperatur - Temperatur aus Datenpunkt, analog Info + Klimaanlage - Buttons zur Steuerung der Klimaanlage im unteren Bereich + Temperatur - Anzeige von Temperatur - Datenpunkten, analog Info + Feuchtigkeit - Anzeige von Humidity - Datenpunkten, analog Info + Medien - Steuerung von Alexa, etc. - Über Alias-Manager im Verzeichnis Player automatisch anlegen (Geräte-Manager funktioniert nicht) + Wettervorhersage - Aktuelle Außen-Temperatur (Temp) und aktuelles AccuWeather-Icon (Icon) für Screensaver + Warnung - Abfall, etc. -- Info mit IconColor + + Timer (siehe Wiki) + + Vollständige Liste zur Einrichtung unter: + https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-ALIAS-Definitionen + +Interne Sonoff-Sensoren (über Tasmota): + ESP-Temperatur - wird in 0_userdata.0. abgelegt, kann als Alias importiert werden --> SetOption146 1 + Temperatur - Raumtemperatur - wird in 0_userdata.0. abgelegt, kann als Alias importiert 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: + + AccuWeather oder DasWetter: - 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 + 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-v4.3.3.tft +--------------------------------------------------------------------------------------- +*/ + +/******************************* Begin CONFIG Parameter *******************************/ + +// DE: liefert bei true detailliertere Meldundgen im Log. +// EN: if true, provides more detailed messages in the log. +let Debug: boolean = false; + + +/***** 1. Tasmota-Config *****/ + + // DE: Anpassen an die Verzeichnisse der MQTT-Adapter-Instanz + // EN: Adapt to the MQTT adapter instance directories + const NSPanelReceiveTopic: string = 'mqtt.0.SmartHome.NSPanel_1.tele.RESULT'; + const NSPanelSendTopic: string = 'mqtt.0.SmartHome.NSPanel_1.cmnd.CustomSend'; + + // DE: nur ändern, falls der User im Tasmota vor dem Kompilieren umbenannt wurde (Standard Tasmota: admin) + // EN: only change if the user was renamed in Tasmota before compiling (default Tasmota: admin) + const tasmota_web_admin_user: string = 'admin'; + + // DE: setzten, falls "Web Admin Password" in Tasmota vergeben + // EN set if "Web Admin Password" is assigned in Tasmota + const tasmota_web_admin_password: string = ''; + + // DE: Setzen der bevorzugten Tasmota32-Version (für Updates) + // EN: Set preferred Tasmota32 version (for updates) + const tasmotaOtaVersion: string = 'tasmota32-DE.bin'; + // DE: Es können ebenfalls andere Versionen verwendet werden wie zum Beispiel: + // EN: Other versions can also be used, such as: + // 'tasmota32-nspanel.bin' or 'tasmota32.bin' or 'tasmota32-DE.bin' or etc. + + +/***** 2. Directories in 0_userdata.0... *****/ + + // DE: Anpassen an das jeweilige NSPanel + // EN: Adapt to the respective NSPanel + const NSPanel_Path = '0_userdata.0.NSPanel.1.'; + + // DE: Pfad für gemeinsame Nutzung durch mehrere Panels (bei Nutzung der cardAlarm/cardUnlock) + // EN: Path for sharing between multiple panels (when using cardAlarm/cardUnlock) + const NSPanel_Alarm_Path = '0_userdata.0.NSPanel.'; + + +/***** 3. Weather adapter Config *****/ + + // DE: Mögliche Wetteradapter 'accuweather.0.' oder 'daswetter.0.' + // EN: Possible weather adapters 'accuweather.0.' or 'the weather.0.' + const weatherAdapterInstance: string = 'accuweather.0.'; + + // DE: Mögliche Werte: 'Min', 'Max' oder 'MinMax' im Screensaver + // EN: Possible values: 'Min', 'Max' or 'MinMax' in the screensaver + const weatherScreensaverTempMinMax: string = 'MinMax'; + + // DE: Dieser Alias wird automatisch für den gewählten Wetter erstellt und kann entsprechend angepasst werden + // EN: This alias is automatically created for the selected weather and can be adjusted accordingly + const weatherEntityPath: string = 'alias.0.Wetter'; + + +/***** 4. Color constants for use in the PageItems *****/ + + // DE: Bei Bedarf können weitere Farben definiert werden + // EN: If necessary, additional colors can be defined + const HMIOff: RGB = { red: 68, green: 115, blue: 158 }; // Blue-Off - Original Entity Off + const HMIOn: RGB = { red: 3, green: 169, blue: 244 }; // Blue-On + const HMIDark: RGB = { red: 29, green: 29, blue: 29 }; // Original Background Color + const Off: RGB = { red: 253, green: 128, blue: 0 }; // Orange-Off - nicer color transitions + const On: RGB = { red: 253, green: 216, blue: 53 }; + const MSRed: RGB = { red: 251, green: 105, blue: 98 }; + const MSYellow: RGB = { red: 255, green: 235, blue: 156 }; + const MSGreen: RGB = { red: 121, green: 222, blue: 121 }; + const Red: RGB = { red: 255, green: 0, blue: 0 }; + const White: RGB = { red: 255, green: 255, blue: 255 }; + const Yellow: RGB = { red: 255, green: 255, blue: 0 }; + const Green: RGB = { red: 0, green: 255, blue: 0 }; + const Blue: RGB = { red: 0, green: 0, blue: 255 }; + const DarkBlue: RGB = { red: 0, green: 0, blue: 136 }; + const Gray: RGB = { red: 136, green: 136, blue: 136 }; + const Black: RGB = { red: 0, green: 0, blue: 0 }; + const Cyan: RGB = { red: 0, green: 255, blue: 255 }; + const Magenta: RGB = { red: 255, green: 0, blue: 255 }; + const colorSpotify: RGB = { red: 30, green: 215, blue: 96 }; + const colorAlexa: RGB = { red: 49, green: 196, blue: 243 }; + const colorSonos: RGB = { red: 216, green: 161, blue: 88 }; + 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 }; + + //Menu Icon Colors + const Menu: RGB = { red: 150, green: 150, blue: 100 }; + const MenuLowInd: RGB = { red: 255, green: 235, blue: 156 }; + const MenuHighInd: RGB = { red: 251, green: 105, blue: 98 }; + + //Dynamische Indikatoren (Abstufung grün nach gelb nach rot) + const colorScale0: RGB = { red: 99, green: 190, blue: 123 }; + const colorScale1: RGB = { red: 129, green: 199, blue: 126 }; + const colorScale2: RGB = { red: 161, green: 208, blue: 127 }; + const colorScale3: RGB = { red: 129, green: 217, blue: 126 }; + const colorScale4: RGB = { red: 222, green: 226, blue: 131 }; + const colorScale5: RGB = { red: 254, green: 235, blue: 132 }; + const colorScale6: RGB = { red: 255, green: 210, blue: 129 }; + const colorScale7: RGB = { red: 251, green: 185, blue: 124 }; + const colorScale8: RGB = { red: 251, green: 158, blue: 117 }; + const colorScale9: RGB = { red: 248, green: 131, blue: 111 }; + const colorScale10: RGB = { red: 248, green: 105, blue: 107 }; + + //Screensaver Default Theme Colors + const scbackground: RGB = { red: 0, green: 0, blue: 0}; + const scbackgroundInd1: RGB = { red: 255, green: 0, blue: 0}; + const scbackgroundInd2: RGB = { red: 121, green: 222, blue: 121}; + const scbackgroundInd3: RGB = { red: 255, green: 255, blue: 0}; + const sctime: RGB = { red: 255, green: 255, blue: 255}; + const sctimeAMPM: RGB = { red: 255, green: 255, blue: 255}; + const scdate: RGB = { red: 255, green: 255, blue: 255}; + const sctMainIcon: RGB = { red: 255, green: 255, blue: 255}; + const sctMainText: RGB = { red: 255, green: 255, blue: 255}; + const sctForecast1: RGB = { red: 255, green: 255, blue: 255}; + const sctForecast2: RGB = { red: 255, green: 255, blue: 255}; + const sctForecast3: RGB = { red: 255, green: 255, blue: 255}; + const sctForecast4: RGB = { red: 255, green: 255, blue: 255}; + const sctF1Icon: RGB = { red: 255, green: 235, blue: 156}; + const sctF2Icon: RGB = { red: 255, green: 235, blue: 156}; + const sctF3Icon: RGB = { red: 255, green: 235, blue: 156}; + const sctF4Icon: RGB = { red: 255, green: 235, blue: 156}; + const sctForecast1Val: RGB = { red: 255, green: 255, blue: 255}; + const sctForecast2Val: RGB = { red: 255, green: 255, blue: 255}; + const sctForecast3Val: RGB = { red: 255, green: 255, blue: 255}; + const sctForecast4Val: RGB = { red: 255, green: 255, blue: 255}; + const scbar: RGB = { red: 255, green: 255, blue: 255}; + const sctMainIconAlt: RGB = { red: 255, green: 255, blue: 255}; + const sctMainTextAlt: RGB = { red: 255, green: 255, blue: 255}; + const sctTimeAdd: RGB = { red: 255, green: 255, blue: 255}; + + //Auto-Weather-Colors + const swClearNight: RGB = { red: 150, green: 150, blue: 100}; + const swCloudy: RGB = { red: 75, green: 75, blue: 75}; + const swExceptional: RGB = { red: 255, green: 50, blue: 50}; + const swFog: RGB = { red: 150, green: 150, blue: 150}; + const swHail: RGB = { red: 200, green: 200, blue: 200}; + const swLightning: RGB = { red: 200, green: 200, blue: 0}; + const swLightningRainy: RGB = { red: 200, green: 200, blue: 150}; + const swPartlycloudy: RGB = { red: 150, green: 150, blue: 150}; + const swPouring: RGB = { red: 50, green: 50, blue: 255}; + const swRainy: RGB = { red: 100, green: 100, blue: 255}; + const swSnowy: RGB = { red: 150, green: 150, blue: 150}; + const swSnowyRainy: RGB = { red: 150, green: 150, blue: 255}; + const swSunny: RGB = { red: 255, green: 255, blue: 0}; + const swWindy: RGB = { red: 150, green: 150, blue: 150}; + + +/***** 5. Script - Parameters *****/ + + // DE: Für diese Option muss der Haken in setObjects in deiner javascript.X. Instanz gesetzt sein. + // EN: This option requires the check mark in setObjects in your javascript.X. instance must be set. + const autoCreateAlias = true; + + // DE: Verzeichnis für Auto-Aliase (wird per Default aus dem NSPanel-Verzeichnis gebildet und muss nicht verändert werden) + // EN: Directory for auto aliases (is created by default from the NSPanel directory and does not need to be changed) + const AliasPath: string = 'alias.0.' + NSPanel_Path.substring(13, NSPanel_Path.length); + + // DE: Default-Farbe für Off-Zustände + // EN: Default color for off states + const defaultOffColorParam: any = Off; + + // DE: Default-Farbe für On-Zustände + // EN: Default color for on states + const defaultOnColorParam: any = On; + + const defaultColorParam: any = Off; + + // DE: Default-Hintergrundfarbe HMIDark oder Black + // EN: Default background color HMIDark or Black + const defaultBackgroundColorParam: any = HMIDark; + +/******************************** End CONFIG Parameter ********************************/ + +//-- Anfang für eigene Seiten -- z.T. selbstdefinierte Aliase erforderlich ---------------- +//-- Start for your own pages -- some self-defined aliases required ---------------- + + //-- https://github.com/joBr99/nspanel-lovelace-ui/wiki/NSPanel-Page-%E2%80%90-Typen_How-2_Beispiele + +//-- ENDE für eigene Seiten -- z.T. selbstdefinierte Aliase erforderlich ------------------------- +//-- END for your own pages -- some self-defined aliases required ------------------------ + + +/*********************************************************************************************** + ** Service Pages mit Auto-Alias (Nachfolgende Seiten werden mit Alias automatisch angelegt) ** + ** https://github.com/joBr99/nspanel-lovelace-ui/wiki/NSPanel-Service-Men%C3%BC ** + ***********************************************************************************************/ + +/* DE: German + Wenn das Service Menü abgesichert werden soll, kann eine cardUnlock vorgeschaltet werden. + Für diesen Fall ist folgende Vorgehensweise erforderlich: + - cardUnlock Seite "Unlock_Service" in der Config unter pages auskommentieren ("//" entfernen) + - Servicemenü aus pages "NSPanel_Service" unter pages kommentieren ("//" hinzufügen) +*/ + +/************************************************************************************************* + ** Service pages with auto alias (subsequent pages are automatically created with alias) ** + ** https://github.com/joBr99/nspanel-lovelace-ui/wiki/NSPanel-Service-Men%C3%BC ** + ************************************************************************************************/ + +/* EN: English + If the service menu needs to be secured, a cardUnlock can be installed upstream. + In this case, the following procedure is required: + - comment out cardUnlock page "Unlock_Service" in the config under pages (remove "//") + - Comment service menu from pages "NSPanel_Service" under pages (add "//") +*/ + +//Level 0 (if service pages are used with cardUnlock) +let Unlock_Service: PageType = +{ + 'type': 'cardUnlock', + 'heading': findLocaleServMenu('service_pages'), + 'useColor': true, + 'items': [/*PageItem*/{ id: 'alias.0.NSPanel.Unlock', + targetPage: 'NSPanel_Service_SubPage', + autoCreateALias: true } + ] +}; + +//Level_0 (if service pages are used without cardUnlock) +let NSPanel_Service: PageType = +{ + 'type': 'cardEntities', + 'heading': findLocaleServMenu('service_menu'), + 'useColor': true, + 'items': [ + /*PageItem*/{ navigate: true, id: 'NSPanel_Infos', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('infos'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Einstellungen', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('settings'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Firmware', icon: 'update', offColor: Menu, onColor: Menu, name: findLocaleServMenu('firmware'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ id: AliasPath + 'Config.rebootNSPanel', name: findLocaleServMenu('reboot') ,icon: 'refresh', offColor: MSRed, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + ] +}; + +//Level_0 (if service pages are used with cardUnlock) +let NSPanel_Service_SubPage: PageType = +{ + 'type': 'cardEntities', + 'heading': findLocaleServMenu('service_menu'), + 'useColor': true, + 'subPage': true, + 'parent': Unlock_Service, + 'home': 'Unlock_Service', + 'items': [ + /*PageItem*/{ navigate: true, id: 'NSPanel_Infos', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('infos'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Einstellungen', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('settings'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Firmware', icon: 'update', offColor: Menu, onColor: Menu, name: findLocaleServMenu('firmware'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ id: AliasPath + 'Config.rebootNSPanel', name: findLocaleServMenu('reboot') ,icon: 'refresh', offColor: MSRed, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + ] +}; + + //Level_1 + let NSPanel_Infos: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('nspanel_infos'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Service, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ navigate: true, id: 'NSPanel_Wifi_Info_1', icon: 'wifi', offColor: Menu, onColor: Menu, name: findLocaleServMenu('wifi'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Sensoren', icon: 'memory', offColor: Menu, onColor: Menu, name: findLocaleServMenu('sensors_hardware'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_IoBroker', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('info_iobroker'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ id: AliasPath + 'Config.Update.UpdateMessage', name: findLocaleServMenu('update_message') ,icon: 'message-alert-outline', offColor: HMIOff, onColor: MSGreen}, + ] + }; + //Level_2 + let NSPanel_Wifi_Info_1: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('nspanel_wifi1'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Infos, + 'next': 'NSPanel_Wifi_Info_2', + 'items': [ + /*PageItem*/{ id: AliasPath + 'ipAddress', name: findLocaleServMenu('ip_address'), icon: 'ip-network-outline', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.BSSId', name: findLocaleServMenu('mac_address'), icon: 'check-network', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.RSSI', name: findLocaleServMenu('rssi'), icon: 'signal', unit: '%', colorScale: {'val_min': 100, 'val_max': 0} }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.Signal', name: findLocaleServMenu('wifi_signal'), icon: 'signal-distance-variant', unit: 'dBm', colorScale: {'val_min': 0, 'val_max': -100} }, + ] + }; + + let NSPanel_Wifi_Info_2: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('nspanel_wifi2'), + 'useColor': true, + 'subPage': true, + 'prev': 'NSPanel_Wifi_Info_1', + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.SSId', name: findLocaleServMenu('ssid'), icon: 'signal-distance-variant', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.Mode', name: findLocaleServMenu('mode'), icon: 'signal-distance-variant', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.Channel', name: findLocaleServMenu('channel'), icon: 'timeline-clock-outline', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.AP', name: findLocaleServMenu('accesspoint'), icon: 'router-wireless-settings', offColor: Menu, onColor: Menu }, + ] + }; + + let NSPanel_Sensoren: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('sensors1'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Infos, + 'next': 'NSPanel_Hardware', + 'items': [ + /*PageItem*/{ id: AliasPath + 'Sensor.ANALOG.Temperature', name: findLocaleServMenu('room_temperature'), icon: 'home-thermometer-outline', unit: '°C', colorScale: {'val_min': 0, 'val_max': 40, 'val_best': 22 } }, + /*PageItem*/{ id: AliasPath + 'Sensor.ESP32.Temperature', name: findLocaleServMenu('esp_temperature'), icon: 'thermometer', unit: '°C', colorScale: {'val_min': 0, 'val_max': 100, 'val_best': 50 } }, + /*PageItem*/{ id: AliasPath + 'Sensor.TempUnit', name: findLocaleServMenu('temperature_unit'), icon: 'temperature-celsius', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Sensor.Time', name: findLocaleServMenu('refresh'), icon: 'clock-check-outline', offColor: Menu, onColor: Menu }, + ] + }; + + let NSPanel_Hardware: PageEntities = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('hardware2'), + 'useColor': true, + 'subPage': true, + 'prev': 'NSPanel_Sensoren', + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'Tasmota.Product', name: findLocaleServMenu('product'), icon: 'devices', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Hardware', name: findLocaleServMenu('esp32_hardware'), icon: 'memory', offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Display.Model', name: findLocaleServMenu('nspanel_version'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota.Uptime', name: findLocaleServMenu('operating_time'), icon: 'timeline-clock-outline', offColor: Menu, onColor: Menu }, + ] + }; + + let NSPanel_IoBroker: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('info_iobroker'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Infos, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'IoBroker.ScriptVersion', name: findLocaleServMenu('script_version_nspanelts'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'IoBroker.NodeJSVersion', name: findLocaleServMenu('nodejs_version'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'IoBroker.JavaScriptVersion', name: findLocaleServMenu('instance_javascript'), offColor: Menu, onColor: Menu }, + ] + }; + + //Level_1 + let NSPanel_Einstellungen: PageType = + { + 'type': 'cardGrid', + 'heading': findLocaleServMenu('settings'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Service, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ navigate: true, id: 'NSPanel_Screensaver', icon: 'monitor-dashboard',offColor: Menu, onColor: Menu, name: findLocaleServMenu('screensaver'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Relays', icon: 'electric-switch', offColor: Menu, onColor: Menu, name: findLocaleServMenu('relays'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ id:AliasPath + 'Config.temperatureUnitNumber', icon: 'gesture-double-tap', name: findLocaleServMenu('temp_unit'), offColor: Menu, onColor: Menu, + modeList: ['°C', '°F', 'K']}, + /*PageItem*/{ id: AliasPath + 'Config.localeNumber', icon: 'select-place', name: findLocaleServMenu('language'), offColor: Menu, onColor: Menu, + modeList: ['en-US', 'de-DE', 'nl-NL', 'da-DK', 'es-ES', 'fr-FR', 'it-IT', 'ru-RU', 'nb-NO', 'nn-NO', 'pl-PL', 'pt-PT', 'af-ZA', 'ar-SY', + 'bg-BG', 'ca-ES', 'cs-CZ', 'el-GR', 'et-EE', 'fa-IR', 'fi-FI', 'he-IL', 'hr-xx', 'hu-HU', 'hy-AM', 'id-ID', 'is-IS', 'lb-xx', + 'lt-LT', 'ro-RO', 'sk-SK', 'sl-SI', 'sv-SE', 'th-TH', 'tr-TR', 'uk-UA', 'vi-VN', 'zh-CN', 'zh-TW']}, + /*PageItem*/{ navigate: true, id: 'NSPanel_Script', icon: 'code-json',offColor: Menu, onColor: Menu, name: findLocaleServMenu('script'), buttonText: findLocaleServMenu('more')}, + ] + }; + + //Level_2 + let NSPanel_Screensaver: PageType = + { + 'type': 'cardGrid', + 'heading': findLocaleServMenu('screensaver'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Einstellungen, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverDimmode', icon: 'sun-clock', offColor: Menu, onColor: Menu, name: findLocaleServMenu('dimmode')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverBrightness', icon: 'brightness-5', offColor: Menu, onColor: Menu, name: findLocaleServMenu('brightness')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverLayout', icon: 'page-next-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('layout')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverWeather', icon: 'weather-partly-rainy', offColor: Menu, onColor: Menu, name: findLocaleServMenu('weather')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverDateformat', icon: 'calendar-expand-horizontal', offColor: Menu, onColor: Menu, name: findLocaleServMenu('date_format')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverIndicators', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('indicators')} + ] + }; + + //Level_3 + let NSPanel_ScreensaverDimmode: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('dimmode'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Screensaver, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'Dimmode.brightnessDay', name: findLocaleServMenu('brightness_day'), icon: 'brightness-5', offColor: Menu, onColor: Menu, minValue: 5, maxValue: 10}, + /*PageItem*/{ id: AliasPath + 'Dimmode.brightnessNight', name: findLocaleServMenu('brightness_night'), icon: 'brightness-4', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 4}, + /*PageItem*/{ id: AliasPath + 'Dimmode.hourDay', name: findLocaleServMenu('hour_day'), icon: 'sun-clock', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 23}, + /*PageItem*/{ id: AliasPath + 'Dimmode.hourNight', name: findLocaleServMenu('hour_night'), icon: 'sun-clock-outline', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 23} + ] + }; + + //Level_3 + let NSPanel_ScreensaverBrightness: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('brightness'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Screensaver, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'ScreensaverInfo.activeBrightness', name: findLocaleServMenu('brightness_activ'), icon: 'brightness-5', offColor: Menu, onColor: Menu, minValue: 20, maxValue: 100}, + /*PageItem*/{ id: AliasPath + 'Config.Screensaver.timeoutScreensaver', name: findLocaleServMenu('screensaver_timeout'), icon: 'clock-end', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 60}, + /*PageItem*/{ id: AliasPath + 'Config.Screensaver.screenSaverDoubleClick', name: findLocaleServMenu('wakeup_doublecklick') ,icon: 'gesture-two-double-tap', offColor: HMIOff, onColor: HMIOn} + ] + }; + + //Level_3 + let NSPanel_ScreensaverLayout: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('layout'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Screensaver, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'Config.Screensaver.alternativeScreensaverLayout', name: findLocaleServMenu('alternative_layout') ,icon: 'page-previous-outline', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Config.Screensaver.ScreensaverAdvanced', name: findLocaleServMenu('advanced_layout') ,icon: 'page-next-outline', offColor: HMIOff, onColor: HMIOn}, + ] + }; + + //Level_3 + let NSPanel_ScreensaverWeather: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('weather_parameters'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Screensaver, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'ScreensaverInfo.weatherForecast', name: findLocaleServMenu('weather_forecast_offon') ,icon: 'weather-sunny-off', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'ScreensaverInfo.weatherForecastTimer', name: findLocaleServMenu('weather_forecast_change_switch') ,icon: 'devices', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'ScreensaverInfo.entityChangeTime', name: findLocaleServMenu('weather_forecast_change_time'), icon: 'cog-sync', offColor: Menu, onColor: Menu, minValue: 15, maxValue: 60}, + /*PageItem*/{ id: AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout', name: findLocaleServMenu('weather_forecast_icon_colors') ,icon: 'format-color-fill', offColor: HMIOff, onColor: HMIOn}, + ] + }; + + //Level_3 + let NSPanel_ScreensaverDateformat: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('date_format'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Screensaver, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'Config.Dateformat.Switch.weekday', name: findLocaleServMenu('weekday_large') ,icon: 'calendar-expand-horizontal', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Config.Dateformat.Switch.month', name: findLocaleServMenu('month_large') ,icon: 'calendar-expand-horizontal', offColor: HMIOff, onColor: HMIOn}, + ] + }; + + //Level_3 + let NSPanel_ScreensaverIndicators: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('indicators'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Screensaver, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'Config.MRIcons.alternateMRIconSize.1', name: findLocaleServMenu('mr_icon1_size') ,icon: 'format-size', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Config.MRIcons.alternateMRIconSize.2', name: findLocaleServMenu('mr_icon2_size') ,icon: 'format-size', offColor: HMIOff, onColor: HMIOn}, + ] + }; + + //Level_2 + let NSPanel_Relays: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('relays'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Einstellungen, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'Relay.1', name: findLocaleServMenu('relay1_onoff'), icon: 'power', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Relay.2', name: findLocaleServMenu('relay2_onoff'), icon: 'power', offColor: HMIOff, onColor: HMIOn}, + ] + }; + + //Level_2 + let NSPanel_Script: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('script'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Einstellungen, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'Config.ScripgtDebugStatus', name: findLocaleServMenu('debugmode_offon') ,icon: 'code-tags-check', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ id: AliasPath + 'Config.MQTT.portCheck', name: findLocaleServMenu('port_check_offon') ,icon: 'check-network', offColor: HMIOff, onColor: HMIOn}, + ] + }; + + //Level_1 + let NSPanel_Firmware: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('firmware'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Service, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'autoUpdate', name: findLocaleServMenu('automatically_updates') ,icon: 'power', offColor: HMIOff, onColor: HMIOn}, + /*PageItem*/{ navigate: true, id: 'NSPanel_FirmwareTasmota', icon: 'usb-flash-drive', offColor: Menu, onColor: Menu, name: findLocaleServMenu('tasmota_firmware'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_FirmwareBerry', icon: 'usb-flash-drive', offColor: Menu, onColor: Menu, name: findLocaleServMenu('berry_driver'), buttonText: findLocaleServMenu('more')}, + /*PageItem*/{ navigate: true, id: 'NSPanel_FirmwareNextion', icon: 'cellphone-cog', offColor: Menu, onColor: Menu, name: findLocaleServMenu('nextion_tft_firmware'), buttonText: findLocaleServMenu('more')} + ] + }; + + let NSPanel_FirmwareTasmota: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('tasmota'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Firmware, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'Tasmota.Version', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Tasmota_Firmware.onlineVersion', name: findLocaleServMenu('available_release'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: 'Divider' }, + /*PageItem*/{ id: AliasPath + 'Config.Update.UpdateTasmota', name: findLocaleServMenu('update_tasmota') ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + ] + }; + + let NSPanel_FirmwareBerry: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('berry_driver'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Firmware, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'Display.BerryDriver', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Berry_Driver.onlineVersion', name: findLocaleServMenu('available_release'), offColor: Menu, onColor: Menu}, + /*PageItem*/{ id: 'Divider' }, + /*PageItem*/{ id: AliasPath + 'Config.Update.UpdateBerry', name: findLocaleServMenu('update_berry_driver') ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + ] + }; + + let NSPanel_FirmwareNextion: PageType = + { + 'type': 'cardEntities', + 'heading': findLocaleServMenu('nextion_tft'), + 'useColor': true, + 'subPage': true, + 'parent': NSPanel_Firmware, + 'home': 'NSPanel_Service', + 'items': [ + /*PageItem*/{ id: AliasPath + 'Display_Firmware.TFT.currentVersion', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Display_Firmware.TFT.desiredVersion', name: findLocaleServMenu('desired_release'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Display.Model', name: findLocaleServMenu('nspanel_model'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'Config.Update.UpdateNextion', name: 'Nextion TFT Update' ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + ] + }; + +// End of Service Pages + +/*********************************************************************** + ** ** + ** Configuration ** + ** ** + ***********************************************************************/ + +export const config: Config = { + // Seiteneinteilung / Page division + // Hauptseiten / Mainpages + pages: [ + NSPanel_Service, //Auto-Alias Service Page + //Unlock_Service //Auto-Alias Service Page (Service Pages used with cardUnlock) + ], + // Unterseiten / Subpages + subPages: [ + NSPanel_Service_SubPage, //Auto-Alias Service Page (only used with cardUnlock) + NSPanel_Infos, //Auto-Alias Service Page + NSPanel_Wifi_Info_1, //Auto-Alias Service Page + NSPanel_Wifi_Info_2, //Auto-Alias Service Page + NSPanel_Sensoren, //Auto-Alias Service Page + NSPanel_Hardware, //Auto-Alias Service Page + NSPanel_IoBroker, //Auot-Alias Service Page + NSPanel_Einstellungen, //Auto-Alias Service Page + NSPanel_Screensaver, //Auto-Alias Service Page + NSPanel_ScreensaverDimmode, //Auto-Alias Service Page + NSPanel_ScreensaverBrightness, //Auto-Alias Service Page + NSPanel_ScreensaverLayout, //Auto-Alias Service Page + NSPanel_ScreensaverWeather, //Auto-Alias Service Page + NSPanel_ScreensaverDateformat, //Auto-Alias Service Page + NSPanel_ScreensaverIndicators, //Auto-Alias Service Page + NSPanel_Relays, //Auto-Alias Service Page + NSPanel_Script, //Auto-Alias Service Page + NSPanel_Firmware, //Auto-Alias Service Page + NSPanel_FirmwareTasmota, //Auto-Alias Service Page + NSPanel_FirmwareBerry, //Auto-Alias Service Page + NSPanel_FirmwareNextion, //Auto-Alias Service Page + ], + + /*********************************************************************** + ** ** + ** Screensaver Configuration ** + ** ** + ***********************************************************************/ + leftScreensaverEntity: [ + // Examples for Advanced-Screensaver: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Config-Screensaver#entity-status-icons-ab-v400 + ], + + bottomScreensaverEntity: [ + // bottomScreensaverEntity 1 + { + ScreensaverEntity: 'accuweather.0.Daily.Day1.Sunrise', + ScreensaverEntityFactor: 1, + ScreensaverEntityDecimalPlaces: 0, + ScreensaverEntityDateFormat: {hour: '2-digit', minute: '2-digit'}, // Description at Wiki-Pages + ScreensaverEntityIconOn: 'weather-sunset-up', + ScreensaverEntityIconOff: null, + ScreensaverEntityText: 'Sonne', + ScreensaverEntityUnitText: '%', + ScreensaverEntityIconColor: MSYellow //{'val_min': 0, 'val_max': 100} + }, + // bottomScreensaverEntity 2 + { + ScreensaverEntity: 'accuweather.0.Current.WindSpeed', + ScreensaverEntityFactor: (1000 / 3600), + ScreensaverEntityDecimalPlaces: 1, + ScreensaverEntityIconOn: 'weather-windy', + ScreensaverEntityIconOff: null, + ScreensaverEntityText: "Wind", + ScreensaverEntityUnitText: 'm/s', + ScreensaverEntityIconColor: {'val_min': 0, 'val_max': 120} + }, + // bottomScreensaverEntity 3 + { + ScreensaverEntity: 'accuweather.0.Current.WindGust', + ScreensaverEntityFactor: (1000 / 3600), + ScreensaverEntityDecimalPlaces: 1, + ScreensaverEntityIconOn: 'weather-tornado', + ScreensaverEntityIconOff: null, + ScreensaverEntityText: 'Böen', + ScreensaverEntityUnitText: 'm/s', + ScreensaverEntityIconColor: {'val_min': 0, 'val_max': 120} + }, + // bottomScreensaverEntity 4 + { + ScreensaverEntity: 'accuweather.0.Current.WindDirectionText', + ScreensaverEntityFactor: 1, + ScreensaverEntityDecimalPlaces: 0, + ScreensaverEntityIconOn: 'windsock', + ScreensaverEntityIconOff: null, + ScreensaverEntityText: 'Windr.', + ScreensaverEntityUnitText: '°', + ScreensaverEntityIconColor: White + }, + // bottomScreensaverEntity 5 (for Alternative and Advanced Screensaver) + { + ScreensaverEntity: 'accuweather.0.Current.RelativeHumidity', + ScreensaverEntityFactor: 1, + ScreensaverEntityDecimalPlaces: 1, + ScreensaverEntityIconOn: 'water-percent', + ScreensaverEntityIconOff: null, + ScreensaverEntityText: 'Feuchte', + ScreensaverEntityUnitText: '%', + ScreensaverEntityIconColor: {'val_min': 0, 'val_max': 100, 'val_best': 65} + }, + // bottomScreensaverEntity 6 (for Advanced Screensaver) + { + ScreensaverEntity: NSPanel_Path + 'Relay.1', + ScreensaverEntityIconOn: 'coach-lamp-variant', + ScreensaverEntityText: 'Street', + ScreensaverEntityOnColor: Yellow, + ScreensaverEntityOffColor: White, + ScreensaverEntityOnText: 'Is ON', + ScreensaverEntityOffText: 'Not ON' + }, + // Examples for Advanced-Screensaver: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Config-Screensaver#entity-status-icons-ab-v400 + ], + + indicatorScreensaverEntity: [ + // Examples for Advanced-Screensaver: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Config-Screensaver#entity-status-icons-ab-v400 + ], + + // Status Icon + mrIcon1ScreensaverEntity: { + ScreensaverEntity: NSPanel_Path + 'Relay.1', + ScreensaverEntityIconOn: 'lightbulb', + ScreensaverEntityIconOff: null, + ScreensaverEntityValue: null, + ScreensaverEntityValueDecimalPlace: 0, + ScreensaverEntityValueUnit: null, + ScreensaverEntityOnColor: On, + ScreensaverEntityOffColor: HMIOff + }, + mrIcon2ScreensaverEntity: { + ScreensaverEntity: NSPanel_Path + 'Relay.2', + ScreensaverEntityIconOn: 'lightbulb', + ScreensaverEntityIconOff: null, + ScreensaverEntityValue: null, + ScreensaverEntityValueDecimalPlace: 0, + ScreensaverEntityValueUnit: null, + ScreensaverEntityOnColor: On, + ScreensaverEntityOffColor: HMIOff + }, + // ------ DE: Ende der Screensaver Einstellungen -------------------- + // ------ EN: End of screensaver settings --------------------------- + //-------DE: Anfang Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- + //-------EN: Start Settings for Hardware Button, if used in software (Rule2) -------------------------------------- + // DE: Konfiguration des linken Schalters des NSPanels + // EN: Configuration of the left switch of the NSPanel + button1: { + // DE: Mögliche Werte wenn Rule2 definiert: 'page', 'toggle', 'set' - Wenn nicht definiert --> mode: null + // EN: Possible values if Rule2 defined: 'page', 'toggle', 'set' - If not defined --> mode: null + mode: null, + // DE: Zielpage - Verwendet wenn mode = page + // EN: Target page - Used if mode = page + page: null, + // DE: Zielentity - Verwendet wenn mode = set oder toggle + // EN: Target entity - Used if mode = set or toggle + entity: null, + // DE: Zielwert - Verwendet wenn mode = set + // EN: Target value - Used if mode = set + setValue: null + }, + + // DE: Konfiguration des rechten Schalters des NSPanels + // EN: Configuration of the right switch of the NSPanel + button2: { + mode: null, + page: null, + entity: null, + setValue: null + }, + //--------- DE: Ende - Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- + //--------- EN: End - settings for hardware button if they are used in software (Rule2) ------------------------------ + // DE: WICHTIG !! Parameter nicht ändern WICHTIG!! + // EN: IMPORTANT !! Do not change parameters IMPORTANT!! + panelRecvTopic: NSPanelReceiveTopic, + panelSendTopic: NSPanelSendTopic, + weatherEntity: weatherEntityPath, + defaultOffColor: defaultOffColorParam, + defaultOnColor: defaultOnColorParam, + defaultColor: defaultColorParam, + defaultBackgroundColor: defaultBackgroundColorParam, +}; + +// _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ +// _________________________________ EN: No more configuration from here _____________________________________ + +const scriptVersion: string = 'v4.3.3.31'; +const tft_version: string = 'v4.3.3'; +const desired_display_firmware_version = 53; +const berry_driver_version = 9; + +const tasmotaOtaUrl: string = 'http://ota.tasmota.com/tasmota32/release/'; + +const Icons = new IconsSelector(); +let timeoutSlider: any; +let vwIconColor: number[] = []; +let weatherForecast: boolean; +let pageCounter: number = 0; +let alwaysOn: boolean = false; + +const axios = require('axios'); +const dayjs = require('dayjs'); +const moment = require('moment'); +const parseFormat = require('moment-parseformat'); +moment.locale(getState(NSPanel_Path + 'Config.locale').val); + +const globalTextColor: any = White; +const Sliders2: number = 0; +let checkBlindActive: boolean = false; + +async function Init_dayjs() { + try { + //Loading dayjs + const dayjs = require('dayjs'); + const dayjsLanguages: any = ['en','de','nl','da','es','fr','it','ru','nb','nn', + 'pl','pt','af','ar','bg','ca','cs','el','et','fa', + 'fi','he','hr','hu','hy-am','id','is','lb','lt','ro', + 'sk','sl','sv','th','tr','uk','vi','zh-cn','zh-tw'] + for (let i=0; i> is not reachable. Please Check Parameters!','error'); + } + if (existsObject(config.panelSendTopic) == false) { + log('Config-Parameter: << config.panelSendTopic - ' + config.panelSendTopic + ' >> is not reachable. Please Check Parameters!','error'); + } + if (weatherAdapterInstance.substring(0, weatherAdapterInstance.length - 3) == 'daswetter') { + if (existsObject(weatherAdapterInstance + 'NextHours.Location_1.Day_1.current.symbol_value') == false) { + log('Weather adapter: << weatherAdapterInstance - ' + weatherAdapterInstance + ' >> is not installed. Please Check Adapter!','error'); + } + } + if (weatherAdapterInstance.substring(0, weatherAdapterInstance.length - 3) == 'accuweather') { + if (existsObject(weatherAdapterInstance + 'Current.WeatherIcon') == false) { + log('Weather adapter: << weatherAdapterInstance - ' + weatherAdapterInstance + ' >> is not installed. Please Check Adapter!','error'); + } + } + + let weatherAdapterInstanceArray: any = weatherAdapterInstance.split("."); + weatherAdapterInstanceNumber = weatherAdapterInstanceArray[1]; + if (Debug) log('Number of weatherAdapterInstance: ' + weatherAdapterInstanceNumber,'info'); + + const adapterList = $('system.adapter.*.alive'); + adapterList.each(function(id, i) { + id = id.substring(0, id.lastIndexOf('.')); + if(existsObject(id)) { + let common = getObject(id).common; + if (common.name == 'javascript') { + javaScriptVersion = common.version; + setIfExists(NSPanel_Path + 'IoBroker.JavaScriptVersion', 'v' + javaScriptVersion); + let jsVersion = common.version.split('.'); + let jsV = 10*parseInt(jsVersion[0]) + parseInt(jsVersion[1]); + if (jsV<61) log('JS-Adapter: ' + common.name + ' must be at least v6.1.3. Currently: v' + common.version, 'error'); + } + } + }); + + const hostList = $('system.host.*.nodeCurrent'); + hostList.each(function(id, i) { + nodeVersion = getState(id).val; + setIfExists(NSPanel_Path + 'IoBroker.NodeJSVersion', 'v' + nodeVersion); + let nodeJSVersion = (getState(id).val).split('.'); + if (parseInt(nodeJSVersion[0]) < 18) { + log('nodeJS must be at least v18.X.X. Currently: v' + getState(id).val + '! Please Update your System! --> iob nodejs-update 18', ); + } + if (parseInt(nodeJSVersion[0])%2 != 0) { + log('nodeJS does not have an even version number. An odd version number is a developer version. Please correct nodeJS version','info'); + } + }); + if (config.mrIcon1ScreensaverEntity.ScreensaverEntity != null && existsObject(config.mrIcon1ScreensaverEntity.ScreensaverEntity) == false ) { + log('mrIcon1ScreensaverEntity data point in the config not available - please adjust','warn'); + } + if (config.mrIcon2ScreensaverEntity.ScreensaverEntity != null && existsObject(config.mrIcon2ScreensaverEntity.ScreensaverEntity) == false) { + log('mrIcon2ScreensaverEntity data point in the config not available - please adjust','warn'); + } + if (CheckEnableSetObject()) { + log('setObjects enabled - create Alias Channels possible','info'); + isSetOptionActive = true; + } else { + log('setObjects disabled - Please enable setObjects in JS-Adapter Instance - create Alias Channels not possible', 'warn'); + } + } catch (err: any) { + log('error at function CheckConfigParameters: ' + err.message, 'warn'); + } +} +CheckConfigParameters(); + +async function InitIoBrokerInfo() { + try { + if (isSetOptionActive) { + // Script Version + await createStateAsync(NSPanel_Path + 'IoBroker.ScriptVersion', scriptVersion, { type: 'string' }); + setObject(AliasPath + 'IoBroker.ScriptVersion', {type: 'channel', common: {role: 'info', name:'Version NSPanelTS'}, native: {}}); + await createAliasAsync(AliasPath + 'IoBroker.ScriptVersion.ACTUAL', NSPanel_Path + 'IoBroker.ScriptVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + // NodeJS Verion + await createStateAsync(NSPanel_Path + 'IoBroker.NodeJSVersion', 'v' + nodeVersion, { type: 'string' }); + setObject(AliasPath + 'IoBroker.NodeJSVersion', {type: 'channel', common: {role: 'info', name:'Version NodeJS'}, native: {}}); + await createAliasAsync(AliasPath + 'IoBroker.NodeJSVersion.ACTUAL', NSPanel_Path + 'IoBroker.NodeJSVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + // JavaScript Version + await createStateAsync(NSPanel_Path + 'IoBroker.JavaScriptVersion', 'v' + javaScriptVersion, { type: 'string' }); + setObject(AliasPath + 'IoBroker.JavaScriptVersion', {type: 'channel', common: {role: 'info', name:'Version JavaScript Instanz'}, native: {}}); + await createAliasAsync(AliasPath + 'IoBroker.JavaScriptVersion.ACTUAL', NSPanel_Path + 'IoBroker.JavaScriptVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + } + setIfExists(NSPanel_Path + 'IoBroker.ScriptVersion', scriptVersion); + } catch (err: any) { + log('error at funktion InitIoBrokerInfo ' + err.message, 'warn'); + } +} +InitIoBrokerInfo(); + +async function CheckDebugMode() { + try { + if (isSetOptionActive) { + await createStateAsync(NSPanel_Path + 'Config.ScripgtDebugStatus', false, { type: 'boolean' }); + setObject(AliasPath + 'Config.ScripgtDebugStatus', {type: 'channel', common: {role: 'socket', name:'ScripgtDebugStatus'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.ScripgtDebugStatus.ACTUAL', NSPanel_Path + 'Config.ScripgtDebugStatus', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Config.ScripgtDebugStatus.SET', NSPanel_Path + 'Config.ScripgtDebugStatus', true, { type: 'boolean', role: 'switch', name: 'SET' }); + } + + if(getState(NSPanel_Path + 'Config.ScripgtDebugStatus').val){ + Debug = true; + log('Debug mode activated','info'); + }else{ + Debug = false; + log('Debug mode disabled','info'); + } + + } catch (err: any) { + log('error at function CheckDebugModus: ' + err.message,'warn'); + } +} +CheckDebugMode(); + +async function CheckMQTTPorts() { + try { + let instanceName: string = config.panelRecvTopic.substring(0,6); + + if (isSetOptionActive) { + await createStateAsync(NSPanel_Path + 'Config.MQTT.portCheck', true, { type: 'boolean' }); + setObject(AliasPath + 'Config.MQTT.portCheck', {type: 'channel', common: {role: 'socket', name:'mqttPortCheck'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.MQTT.portCheck.ACTUAL', NSPanel_Path + 'Config.MQTT.portCheck', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Config.MQTT.portCheck.SET', NSPanel_Path + 'Config.MQTT.portCheck', true, { type: 'boolean', role: 'switch', name: 'SET' }); + } + + if (getState(NSPanel_Path + 'Config.MQTT.portCheck').val) { + let adapterArray: any = []; + let portArray: any = []; + exec('iob l i --port --enabled', async (error, result, stderr) => { + if (error == null){ + if (result != undefined) { + log('Start MQTT-Port-Check -------------------------------------', 'info'); + let resultString1 = result.split('+'); + for (let i: number = 1; i < resultString1.length -1; i++) { + let resultString2: any = resultString1[i].split(':') + let adapterInstanceName: string = resultString2[0].substring(16); + let adapterInstancePort: string = resultString2[3].substring(1,5); + log('-- '+ adapterInstanceName + ' - ' + adapterInstancePort, 'info'); + adapterArray[i] = adapterInstanceName.trim(); + portArray[i] = adapterInstancePort.trim(); + } + let mqttInstance = adapterArray.indexOf(instanceName); + + const mqttConfig = getObject(`system.adapter.${adapterArray[mqttInstance]}`) + if (mqttConfig && mqttConfig.native && mqttConfig.native.type == 'client') { + log('- MQTT-Port-Check OK: Instance of Adapter: ' +adapterArray[mqttInstance] + ' is running as client!','info'); + } else { + for (let j: number = 1; j < portArray.length; j++) { + if (portArray[j] == portArray[mqttInstance] && adapterArray[j] == adapterArray[mqttInstance]) { + log('- MQTT-Port-Check OK: Instance of Adapter: ' + adapterArray[j] + ' is running on Port:' + portArray[j], 'info'); + } else if (portArray[j] == portArray[mqttInstance] && adapterArray[j] != adapterArray[mqttInstance]) { + log('Instance of Adapter: ' + adapterArray[j] + ' is running on same Port:' + portArray[j] + ' as ' + adapterArray[mqttInstance], 'warn'); + log('Please Change Port of Instance: ' + adapterArray[j], 'warn'); + } + } + } + log('End MQTT-Port-Check ---------------------------------------','info'); + } + + } else if (error.toString().substring(0,21) == 'exec is not available') { + log('MQTT-Portcheck not possible - exec is not available. Please enable exec option in JS-Adapter instance settings', 'warn'); + log('MQTT-Portcheck nicht möglich - exec ist nicht verfügbar. Bitte Haken bei -- Kommando Exec erlauben -- in JS-Adapter-Instanz setzen', 'warn'); + } + }); + } + } catch (err: any) { + log('error at function CheckMQTTPorts: ' + err.message, 'warn'); + } +} + +CheckMQTTPorts(); + +async function Init_Release() { + const FWVersion = [41,42,43,44,45,46,47,48,49,50,51,52,53,54,55]; + const FWRelease = ['3.3.1','3.4.0','3.5.0','3.5.X','3.6.0','3.7.3','3.8.0','3.8.3','3.9.4','4.0.5','4.1.4','4.2.1','4.3.3','4.4.0','4.5.0']; + try { + if (existsObject(NSPanel_Path + 'Display_Firmware.desiredVersion') == false) { + await createStateAsync(NSPanel_Path + 'Display_Firmware.desiredVersion', desired_display_firmware_version, { type: 'number' }); + } else { + await setStateAsync(NSPanel_Path + 'Display_Firmware.desiredVersion', desired_display_firmware_version); + } + + if (existsObject(NSPanel_Path + 'Config.Update.activ') == false) { + await createStateAsync(NSPanel_Path + 'Config.Update.activ', 1, { type: 'number' }); + } else { + await setStateAsync(NSPanel_Path + 'Config.Update.activ', 0); + } + + let currentFW = 0; + let findFWIndex = 0; + log('Desired TFT Firmware: ' + desired_display_firmware_version + ' / ' + tft_version, 'info'); + if (existsObject(NSPanel_Path + 'Display_Firmware.currentVersion')) { + currentFW = parseInt(getState(NSPanel_Path + 'Display_Firmware.currentVersion').val); + findFWIndex = FWVersion.indexOf(currentFW); + log('Installed TFT Firmware: ' + currentFW + ' / v' + FWRelease[findFWIndex], 'info'); + } + //Create Long Term + if (existsObject(NSPanel_Path + 'Display_Firmware.TFT.desiredVersion') == false) { + //Create TFT DP's + if (isSetOptionActive) { + await createStateAsync(NSPanel_Path + 'Display_Firmware.TFT.currentVersion', currentFW + ' / v' + FWRelease[findFWIndex], { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Display_Firmware.TFT.desiredVersion', desired_display_firmware_version, { type: 'string' }); + setObject(AliasPath + 'Display_Firmware.TFT.currentVersion', {type: 'channel', common: {role: 'info', name:'current TFT-Version'}, native: {}}); + setObject(AliasPath + 'Display_Firmware.TFT.desiredVersion', {type: 'channel', common: {role: 'info', name:'desired TFT-Version'}, native: {}}); + await createAliasAsync(AliasPath + 'Display_Firmware.TFT.currentVersion.ACTUAL', NSPanel_Path + 'Display_Firmware.TFT.currentVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Display_Firmware.TFT.desiredVersion.ACTUAL', NSPanel_Path + 'Display_Firmware.TFT.desiredVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + } + } else { + //Create TFT DP's + await setStateAsync(NSPanel_Path + 'Display_Firmware.TFT.currentVersion', currentFW + ' / v' + FWRelease[findFWIndex]); + await setStateAsync(NSPanel_Path + 'Display_Firmware.TFT.desiredVersion', desired_display_firmware_version + ' / ' + tft_version); + } + } catch (err: any) { + log('error at function Init_Release: ' + err.message, 'warn'); + } +} +Init_Release(); + +async function InitConfigParameters() { + try { + if (isSetOptionActive) { + // alternativeScreensaverLayout (socket) + await createStateAsync(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', false, { type: 'boolean' }); + setObject(AliasPath + 'Config.Screensaver.alternativeScreensaverLayout', {type: 'channel', common: {role: 'socket', name:'alternativeScreensaverLayout'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.Screensaver.alternativeScreensaverLayout.ACTUAL', NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Config.Screensaver.alternativeScreensaverLayout.SET', NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', true, { type: 'boolean', role: 'switch', name: 'SET' }); + + await createStateAsync(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false, { type: 'boolean' }); + setObject(AliasPath + 'Config.Screensaver.ScreensaverAdvanced', {type: 'channel', common: {role: 'socket', name:'ScreensaverAdvanced'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.Screensaver.ScreensaverAdvanced.ACTUAL', NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Config.Screensaver.ScreensaverAdvanced.SET', NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', true, { type: 'boolean', role: 'switch', name: 'SET' }); + + // autoWeatherColorScreensaverLayout (socket) + await createStateAsync(NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout', true, { type: 'boolean' }); + setObject(AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout', {type: 'channel', common: {role: 'socket', name:'alternativeScreensaverLayout'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout.ACTUAL', NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout.SET', NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout', true, { type: 'boolean', role: 'switch', name: 'SET' }); + + // timeoutScreensaver 0-60 (Slider) + await createStateAsync(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver', 10, { type: 'number' }); + setObject(AliasPath + 'Config.Screensaver.timeoutScreensaver', {type: 'channel', common: {role: 'slider', name:'timeoutScreensaver'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.Screensaver.timeoutScreensaver.ACTUAL', NSPanel_Path + 'Config.Screensaver.timeoutScreensaver', true, { type: 'number', role: 'value', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Config.Screensaver.timeoutScreensaver.SET', NSPanel_Path + 'Config.Screensaver.timeoutScreensaver', true, { type: 'number', role: 'level', name: 'SET' }); + + // screenSaverDoubleClick (socket) + await createStateAsync(NSPanel_Path + 'Config.Screensaver.screenSaverDoubleClick', true, { type: 'boolean' }); + setObject(AliasPath + 'Config.Screensaver.screenSaverDoubleClick', {type: 'channel', common: {role: 'socket', name:'screenSaverDoubleClick'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.Screensaver.screenSaverDoubleClick.ACTUAL', NSPanel_Path + 'Config.Screensaver.screenSaverDoubleClick', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Config.Screensaver.screenSaverDoubleClick.SET', NSPanel_Path + 'Config.Screensaver.screenSaverDoubleClick', true, { type: 'boolean', role: 'switch', name: 'SET' }); + + if (existsObject(NSPanel_Path + 'Config.locale') == false) { + // en-US, de-DE, nl-NL, da-DK, es-ES, fr-FR, it-IT, ru-RU, etc. + await createStateAsync(NSPanel_Path + 'Config.locale', 'de-DE', { type: 'string' }); + setStateAsync(NSPanel_Path + 'Config.locale', 'de-DE'); + } + + if (existsObject(NSPanel_Path + 'Config.temperatureUnit') == false) { + // '°C', '°F', 'K' + await createStateAsync(NSPanel_Path + 'Config.temperatureUnit', '°C', { type: 'string' }); + } + + // locale Tastensensor popupInSel buttonSensor + if (existsObject(NSPanel_Path + 'Config.localeNumber') == false) { + await createStateAsync(NSPanel_Path + 'Config.localeNumber', 1, { type: 'number' }); + setObject(AliasPath + 'Config.localeNumber', {type: 'channel', common: {role: 'buttonSensor', name:'localeNumber'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.localeNumber.VALUE', NSPanel_Path + 'Config.localeNumber', true, { type: 'number', role: 'state', name: 'VALUE' }); + } + // temperatureUnit popupInSel buttonSensor + if (existsObject(NSPanel_Path + 'Config.temperatureUnitNumber') == false) { + await createStateAsync(NSPanel_Path + 'Config.temperatureUnitNumber', 0, { type: 'number' }); + setObject(AliasPath + 'Config.temperatureUnitNumber', {type: 'channel', common: {role: 'buttonSensor', name:'temperatureUnitNumber'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.temperatureUnitNumber.VALUE', NSPanel_Path + 'Config.temperatureUnitNumber', true, { type: 'number', role: 'state', name: 'VALUE' }); + } + } + } catch (err: any) { + log('error at function InitConfigParameters: ' + err.message, 'warn'); + } +} +InitConfigParameters(); + +on({id: [NSPanel_Path + 'Config.ScripgtDebugStatus'], change: "ne"}, async function (obj) { + try { + obj.state.val ? log('Debug mode activated', 'info') : log('Debug mode disabled', 'info'); + Debug = obj.state.val + } catch (err: any) { + log('error at Trigger ScripgtDebugStatus: ' + err.message, 'warn'); + } +}); + +on({id: [NSPanel_Path + 'Config.localeNumber', + NSPanel_Path + 'Config.temperatureUnitNumber'], change: "ne"}, async function (obj) { + try { + if (obj.id == NSPanel_Path + 'Config.localeNumber') { + let localesList = [ 'en-US', 'de-DE', 'nl-NL', 'da-DK', 'es-ES', 'fr-FR', 'it-IT', 'ru-RU', 'nb-NO', 'nn-NO', 'pl-PL', 'pt-PT', 'af-ZA', 'ar-SY', + 'bg-BG', 'ca-ES', 'cs-CZ', 'el-GR', 'et-EE', 'fa-IR', 'fi-FI', 'he-IL', 'hr-xx', 'hu-HU', 'hy-AM', 'id-ID', 'is-IS', 'lb-xx', + 'lt-LT', 'ro-RO', 'sk-SK', 'sl-SI', 'sv-SE', 'th-TH', 'tr-TR', 'uk-UA', 'vi-VN', 'zh-CN', 'zh-TW']; + setStateAsync(NSPanel_Path + 'Config.locale', localesList[obj.state.val]); + SendDate(); + } + if (obj.id == NSPanel_Path + 'Config.temperatureUnitNumber') { + let tempunitList = ['°C', '°F', 'K']; + setStateAsync(NSPanel_Path + 'Config.temperatureUnit', tempunitList[obj.state.val]); + } + } catch (err: any) { + log('error at Trigger temperatureUnitNumber + localeNumber: ' + err.message, 'warn'); + } +}); + +//switch for Screensaver 1 and Screensaver 2 +async function Init_ScreensaverAdvanced() { + try { + if (existsState(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced') == false ) { + await createStateAsync(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false, true, { type: 'boolean' }); + } + } catch (err: any) { + log('error at function Init_ScreensaverAdvanced: ' + err.message, 'warn'); + } +} +Init_ScreensaverAdvanced(); + +// checks whether setObjects() is available for the instance (true/false) +function CheckEnableSetObject() { + var enableSetObject = getObject("system.adapter.javascript." + instance).native.enableSetObject; + return enableSetObject; +} + +//switch BackgroundColors for Screensaver Indicators +async function Init_ActivePageData() { + try { + if (existsState(NSPanel_Path + 'ActivePage.heading') == false ) { + await createStateAsync(NSPanel_Path + 'ActivePage.heading', '', true, { type: 'string' }); + } + if (existsState(NSPanel_Path + 'ActivePage.type') == false ) { + await createStateAsync(NSPanel_Path + 'ActivePage.type', '', true, { type: 'string' }); + } + if (existsState(NSPanel_Path + 'ActivePage.id0') == false ) { + await createStateAsync(NSPanel_Path + 'ActivePage.id0', '', true, { type: 'string' }); + } + } catch (err: any) { + log('error at function Init_ActivePageData: ' + err.message, 'warn'); + } +} +Init_ActivePageData(); + +//switch BackgroundColors for Screensaver Indicators +async function Init_Screensaver_Backckground_Color_Switch() { + try { + if (existsState(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator') == false ) { + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator', 0, true, { type: 'number' }); + } + } catch (err: any) { + log('error at function Init_Screensaver_Backckground_Color_Switch: ' + err.message, 'warn'); + } +} +Init_Screensaver_Backckground_Color_Switch(); + +on({id: NSPanel_Path + 'ScreensaverInfo.bgColorIndicator', change: "ne"}, async function (obj) { + try { + bgColorScrSaver = obj.state.val; + if (bgColorScrSaver < 4) { + HandleScreensaverUpdate(); + } + } catch (err: any) { + log('error at trigger bgColorIndicator: ' + err.message, 'warn'); + } +}); + +// switch selection of screensaver layout +on({id: NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', change: "ne"}, async function (obj) { + try { + if (obj.state.val) setState( NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', false ); + //setState(config.panelSendTopic, 'pageType~pageStartup'); + } catch (err: any) { + log('error at trigger Screensaver Advanced: ' + err.message, 'warn'); + } +}); + +on({id: NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', change: "ne"}, async function (obj) { + try { + if (obj.state.val) setState( NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false ); + //setState(config.panelSendTopic, 'pageType~pageStartup'); + } catch (err: any) { + log('error at trigger Screensaver Alternativ: ' + err.message, 'warn'); + } +}); + +//go to Page X after bExit +async function Init_bExit_Page_Change() { + try { + alwaysOn = false; + pageCounter = 0; + if (existsState(NSPanel_Path + 'ScreensaverInfo.bExitPage') == false ) { + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.bExitPage', -1, true, { type: 'number' }); + } + } catch (err: any) { + log('error at function Init_bExit_Page_Change: ' + err.message, 'warn'); + } +} +Init_bExit_Page_Change(); + +//Dim mode via trigger via motion detector +async function Init_Dimmode_Trigger() { + try { + if (existsState(NSPanel_Path + 'ScreensaverInfo.Trigger_Dimmode') == false ) { + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.Trigger_Dimmode', false, true, { type: 'boolean' }); + } + } catch (err: any) { + log('error at function Init_Dimmode_Trigger: ' + err.message, 'warn'); + } +} +Init_Dimmode_Trigger(); + +async function InitActiveBrightness() { + try { + if (isSetOptionActive) { + if (existsState(NSPanel_Path + 'ScreensaverInfo.activeBrightness') == false || + existsState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness') == false) { + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.activeBrightness', 100, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness', -1, { type: 'number' }); + } + //Create Alias activeBrightness + setObject(AliasPath + 'ScreensaverInfo.activeBrightness', {type: 'channel', common: {role: 'slider', name:'activeBrightness'}, native: {}}); + await createAliasAsync(AliasPath + 'ScreensaverInfo.activeBrightness.ACTUAL', NSPanel_Path + 'ScreensaverInfo.activeBrightness', true, { type: 'number', role: 'value', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'ScreensaverInfo.activeBrightness.SET', NSPanel_Path + 'ScreensaverInfo.activeBrightness', true, { type: 'number', role: 'level', name: 'SET' }); + } + } catch (err: any) { + log('error at function InitActiveBrightness: ' + err.message, 'warn'); + } +} +InitActiveBrightness(); + +on({id: [NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness'], change: "ne"}, async function (obj) { + try { + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val; + if (obj.state.val != null && obj.state.val != -1) { + if (obj.state.val < -1 || obj.state.val > 100) { + log('activeDimmodeBrightness value only between -1 and 100', 'info'); + setStateAsync(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness', -1, true); + alwaysOn = false; + pageCounter = 0; + useMediaEvents = false; + screensaverEnabled = true; + InitDimmode(); + HandleMessage('event', 'startup',undefined, undefined); + } else { + log('action at trigger activeDimmodeBrightness: ' + obj.state.val + ' - activeBrightness: ' + active, 'info'); + SendToPanel({ payload: 'dimmode~' + obj.state.val + '~' + active + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); + } + } else { + alwaysOn = false; + pageCounter = 0; + useMediaEvents = false; + screensaverEnabled = true; + InitDimmode(); + HandleMessage('event', 'startup',undefined, undefined); + } + } catch (err: any) { + log('error at trigger activeDimmodeBrightness: ' + err.message, 'warn'); + } +}); + +on({id: String(NSPanel_Path) + 'ScreensaverInfo.Trigger_Dimmode', change: "ne"}, async function (obj) { + try { + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val; + if (obj.state.val) { + SendToPanel({ payload: 'dimmode~' + 100 + '~' + active + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); + } else { + InitDimmode(); + } + } catch (err: any) { + log('error at trigger Trigger_Dimmode: ' + err.message, 'warn'); + } +}); + +async function InitRebootPanel() { + try { + if (existsState(NSPanel_Path + 'Config.rebootNSPanel') == false) { + await createStateAsync(NSPanel_Path + 'Config.rebootNSPanel', false, { type: 'boolean' }); + setObject(AliasPath + 'Config.rebootNSPanel', {type: 'channel', common: {role: 'button', name:'Reboot NSPanel'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.rebootNSPanel.SET', NSPanel_Path + 'Config.rebootNSPanel', true, { type: 'boolean', role: 'state', name: 'SET' }); + } + } catch (err: any) { + log('error at function InitRebootPanel: ' + err.message, 'warn'); + } +} +InitRebootPanel(); + +on({id: AliasPath + 'Config.rebootNSPanel.SET', change: "any"}, async function (obj) { + if (obj.state.val) { + try { + let urlString = `http://${get_current_tasmota_ip_address()}/cm?cmnd=Backlog Restart 1`; + if (tasmota_web_admin_password != '') { + urlString = `http://${get_current_tasmota_ip_address()}/cm?user=${tasmota_web_admin_user}&password=${tasmota_web_admin_password}&cmnd=Backlog Restart 1;`; + } + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + SendToPanel({ payload: 'pageType~pageStartup' }); + log('Tasmota Reboot', 'info'); + setStateAsync(AliasPath + 'Config.rebootNSPanel.SET', false); + log("Name: " + name, 'info'); + log("Instanz: " + instance, 'info'); + } else { + log('Axios Status - Requesting locales: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }) + .finally(function () { + if (Debug) { + log('Reboot NSPanel... done', 'info'); + } + }); + } catch (err: any) { + log('error at Trigger Restart NSPanel: ' + err.message, 'warn'); + } + } +}); + +async function InitUpdateDatapoints() { + try { + if (existsState(NSPanel_Path + 'Config.Update.UpdateTasmota') == false) { + if (isSetOptionActive) { + await createStateAsync(NSPanel_Path + 'Config.Update.UpdateTasmota', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Update.UpdateBerry', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Update.UpdateNextion', false, { type: 'boolean' }); + setObject(AliasPath + 'Config.Update.UpdateTasmota', {type: 'channel', common: {role: 'button', name:'Tassmota update'}, native: {}}); + setObject(AliasPath + 'Config.Update.UpdateBerry', {type: 'channel', common: {role: 'button', name:'Berry-Driver update'}, native: {}}); + setObject(AliasPath + 'Config.Update.UpdateNextion', {type: 'channel', common: {role: 'button', name:'Nextion TFT update'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.Update.UpdateTasmota.SET', NSPanel_Path + 'Config.Update.UpdateTasmota', true, { type: 'boolean', role: 'state', name: 'SET' }); + await createAliasAsync(AliasPath + 'Config.Update.UpdateBerry.SET', NSPanel_Path + 'Config.Update.UpdateBerry', true, { type: 'boolean', role: 'state', name: 'SET' }); + await createAliasAsync(AliasPath + 'Config.Update.UpdateNextion.SET', NSPanel_Path + 'Config.Update.UpdateNextion', true, { type: 'boolean', role: 'state', name: 'SET' }); + } + } + } catch (err: any) { + log('function InitUpdateDatapoints: ' + err.message, 'warn'); + } +} +InitUpdateDatapoints(); + +on({id: [NSPanel_Path + 'Config.Update.UpdateTasmota', + NSPanel_Path + 'Config.Update.UpdateBerry', + NSPanel_Path + 'Config.Update.UpdateNextion'], change: "any"}, async function (obj) { + try { + switch (obj.id) { + case NSPanel_Path + 'Config.Update.UpdateTasmota': + if (Debug) log('Tasmota Upgrade durchführen', 'info'); + update_tasmota_firmware(); + break; + case NSPanel_Path + 'Config.Update.UpdateBerry': + if (Debug) log('Berry Driver Update durchführen', 'info') + update_berry_driver_version(); + break; + case NSPanel_Path + 'Config.Update.UpdateNextion': + if (Debug) log('FlashNextion durchführen', 'info') + update_tft_firmware(); + break; + } + } catch (err: any) { + log('error at Trigger Update Firmware: ' + err.message, 'warn'); + } +}); + +//switch Relays 1 + 2 with DP's +async function Init_Relays() { + try { + if (isSetOptionActive) { + if (existsState(NSPanel_Path + 'Relay.1') == false || + existsState(NSPanel_Path + 'Relay.2') == false) { + await createStateAsync(NSPanel_Path + 'Relay.1', true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Relay.2', true, { type: 'boolean' }); + } + setObject(AliasPath + 'Relay.1', {type: 'channel', common: {role: 'socket', name:'Relay.1'}, native: {}}); + await createAliasAsync(AliasPath + 'Relay.1.ACTUAL', NSPanel_Path + 'Relay.1', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Relay.1.SET', NSPanel_Path + 'Relay.1', true, { type: 'boolean', role: 'switch', name: 'SET' }); + //Create Alias alternateMRIconSize 2 + setObject(AliasPath + 'Relay.2', {type: 'channel', common: {role: 'socket', name:'Relay.2'}, native: {}}); + await createAliasAsync(AliasPath + 'Relay.2.ACTUAL', NSPanel_Path + 'Relay.2', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Relay.2.SET', NSPanel_Path + 'Relay.2', true, { type: 'boolean', role: 'switch', name: 'SET' }); + } + } catch (err: any) { + log('error at function Init_Relays: ' + err.message, 'warn'); + } +} +Init_Relays(); + +//Change MRIconsFont small/large +async function InitAlternateMRIconsSize() { + try { + if (isSetOptionActive) { + if (existsState(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1') == false || + existsState(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2') == false) { + await createStateAsync(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2', false, { type: 'boolean' }); + } + //Create Alias alternateMRIconSize 1 + setObject(AliasPath + 'Config.MRIcons.alternateMRIconSize.1', {type: 'channel', common: {role: 'socket', name:'alternateMRIconSize.1'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.MRIcons.alternateMRIconSize.1.ACTUAL', NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Config.MRIcons.alternateMRIconSize.1.SET', NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1', true, { type: 'boolean', role: 'switch', name: 'SET' }); + //Create Alias alternateMRIconSize 2 + setObject(AliasPath + 'Config.MRIcons.alternateMRIconSize.2', {type: 'channel', common: {role: 'socket', name:'alternateMRIconSize.2'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.MRIcons.alternateMRIconSize.2.ACTUAL', NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Config.MRIcons.alternateMRIconSize.2.SET', NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2', true, { type: 'boolean', role: 'switch', name: 'SET' }); + } + } catch (err: any) { + log('error at function InitAlternateMRIconsSize: ' + err.message, 'warn'); + } +} +InitAlternateMRIconsSize(); + +//DateString short/long +async function InitDateformat() { + try { + if (isSetOptionActive) { + if (existsState(NSPanel_Path + 'Config.Dateformat.weekday') == false || + existsState(NSPanel_Path + 'Config.Dateformat.month') == false || + existsState(NSPanel_Path + 'Config.Dateformat.customFormat') == false) { + await createStateAsync(NSPanel_Path + 'Config.Dateformat.weekday', 'long', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.month', 'long', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.customFormat', '', { type: 'string' }); + } + if (existsState(NSPanel_Path + 'Config.Dateformat.Switch.weekday') == false || + existsState(NSPanel_Path + 'Config.Dateformat.Switch.month') == false) { + await createStateAsync(NSPanel_Path + 'Config.Dateformat.Switch.weekday', true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.Switch.month', true, { type: 'boolean' }); + setObject(AliasPath + 'Config.Dateformat.Switch.weekday', {type: 'channel', common: {role: 'socket', name:'Dateformat Switch weekday'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.Dateformat.Switch.weekday.ACTUAL', NSPanel_Path + 'Config.Dateformat.Switch.weekday', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Config.Dateformat.Switch.weekday.SET', NSPanel_Path + 'Config.Dateformat.Switch.weekday', true, { type: 'boolean', role: 'switch', name: 'SET' }); + setObject(AliasPath + 'Config.Dateformat.Switch.month', {type: 'channel', common: {role: 'socket', name:'Dateformat Switch month'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.Dateformat.Switch.month.ACTUAL', NSPanel_Path + 'Config.Dateformat.Switch.month', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Config.Dateformat.Switch.month.SET', NSPanel_Path + 'Config.Dateformat.Switch.month', true, { type: 'boolean', role: 'switch', name: 'SET' }); + } + } + } catch (err: any) { + log('error at function InitDateformat: ' + err.message, 'warn'); + } +} +InitDateformat(); +//Control Dateformat short/long from DP's +on({id: [String(NSPanel_Path) + 'Config.Dateformat.Switch.weekday', + String(NSPanel_Path) + 'Config.Dateformat.Switch.month'], change: "ne"}, async function (obj) { + try { + if (obj.id == NSPanel_Path + 'Config.Dateformat.Switch.weekday') { + if (getState(NSPanel_Path + 'Config.Dateformat.Switch.weekday').val) { + setStateAsync(NSPanel_Path + 'Config.Dateformat.weekday', 'long'); + } else { + setStateAsync(NSPanel_Path + 'Config.Dateformat.weekday', 'short'); + } + } else if (obj.id == NSPanel_Path + 'Config.Dateformat.Switch.month') { + if (getState(NSPanel_Path + 'Config.Dateformat.Switch.month').val) { + setStateAsync(NSPanel_Path + 'Config.Dateformat.month', 'long'); + } else { + setStateAsync(NSPanel_Path + 'Config.Dateformat.month', 'short'); + } + } + SendDate(); + } catch (err: any) { + log('error at Trigger Config.Dateformat: ' + err.message, 'warn'); + } +}); + +//Control Relays from DP's +on({id: [String(NSPanel_Path) + 'Relay.1',String(NSPanel_Path) + 'Relay.2'], change: "ne"}, async function (obj) { + try { + let Button = obj.id!.split('.'); + let urlString: string = ['http://',get_current_tasmota_ip_address(),'/cm?cmnd=Power',Button[Button.length - 1],' ',(obj.state ? obj.state.val : "")].join(''); + + axios.get(urlString) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(response.data, 'info'); + } + } + }) + .catch(function (error) { + log(error, 'warn'); + }) + + } catch (err: any) { + log('error at Trigger Relay1/2: ' + err.message, 'warn'); + } +}); + +async function SubscribeMRIcons () { + try { + if (config.mrIcon1ScreensaverEntity.ScreensaverEntity != null) { + on({id: config.mrIcon1ScreensaverEntity.ScreensaverEntity, change: "ne"}, async function (obj) { + if (obj.id!.substring(0,4) == 'mqtt') { + let Button = obj.id!.split('.'); + if (getState(NSPanel_Path + 'Relay.' + Button[Button.length - 1].substring(5,6)).val != obj.state.val) { + await setStateAsync(NSPanel_Path + 'Relay.' + Button[Button.length - 1].substring(5,6), obj.state.val == 'ON' ? true : false); + } + } else { + HandleScreensaverStatusIcons(); + } + }); + } + if (config.mrIcon2ScreensaverEntity.ScreensaverEntity != null) { + on({id: config.mrIcon2ScreensaverEntity.ScreensaverEntity, change: "ne"}, async function (obj) { + if (obj.id!.substring(0,4) == 'mqtt') { + let Button = obj.id!.split('.'); + if (getState(NSPanel_Path + 'Relay.' + Button[Button.length - 1].substring(5,6)).val != obj.state.val) { + await setStateAsync(NSPanel_Path + 'Relay.' + Button[Button.length - 1].substring(5,6), obj.state.val == 'ON' ? true : false); + } + } else { + HandleScreensaverStatusIcons(); + } + }); + } + } catch (err: any) { + log('error at function SubscribeMRIcons: ' + err.message, 'warn'); + } +} +SubscribeMRIcons(); + +// Create atomatically Wheather-Alias, if exists accuweather.0. and is not exists Config-Wheather-Alias +async function CreateWeatherAlias () { + try { + if (autoCreateAlias) { + if (weatherAdapterInstance == 'daswetter.' + weatherAdapterInstanceNumber + '.') { + try { + if (isSetOptionActive) { + if (!existsState(config.weatherEntity + '.ICON') && existsState('daswetter.' + weatherAdapterInstanceNumber + '.NextHours.Location_1.Day_1.current.symbol_value')) { + log('Weather alias for daswetter.' + weatherAdapterInstanceNumber + '. does not exist yet, will be created now', 'info'); + setObject(config.weatherEntity, {_id: config.weatherEntity, type: 'channel', common: {role: 'weatherCurrent', name:'media'}, native: {}}); + await createAliasAsync(config.weatherEntity + '.ICON', 'daswetter.' + weatherAdapterInstanceNumber + '.NextHours.Location_1.Day_1.current.symbol_value', true, { type: 'number', role: 'value', name: 'ICON' }); + await createAliasAsync(config.weatherEntity + '.TEMP', 'daswetter.' + weatherAdapterInstanceNumber + '.NextHours.Location_1.Day_1.current.temp_value', true, { type: 'number', role: 'value.temperature', name: 'TEMP' }); + await createAliasAsync(config.weatherEntity + '.TEMP_MIN', 'daswetter.' + weatherAdapterInstanceNumber + '.NextDays.Location_1.Day_1.Minimale_Temperatur_value', true, { type: 'number', role: 'value.temperature.forecast.0', name: 'TEMP_MIN' }); + await createAliasAsync(config.weatherEntity + '.TEMP_MAX', 'daswetter.' + weatherAdapterInstanceNumber + '.NextDays.Location_1.Day_1.Maximale_Temperatur_value', true, { type: 'number', role: 'value.temperature.max.forecast.0', name: 'TEMP_MAX' }); + } else { + log('weather alias for daswetter.' + weatherAdapterInstanceNumber + '. already exists', 'info'); + } + } + } catch (err: any) { + log('error at function CreateWeatherAlias daswetter.' + weatherAdapterInstanceNumber + '. : ' + err.message, 'warn'); + } + } else if (weatherAdapterInstance == 'accuweather.' + weatherAdapterInstanceNumber + '.') { + try { + if (isSetOptionActive) { + if (!existsState(config.weatherEntity + '.ICON') && existsState('accuweather.' + weatherAdapterInstanceNumber + '.Current.WeatherIcon')) { + log('Weather alias for accuweather.' + weatherAdapterInstanceNumber + '. does not exist yet, will be created now', 'info'); + setObject(config.weatherEntity, {_id: config.weatherEntity, type: 'channel', common: {role: 'weatherCurrent', name:'media'}, native: {}}); + await createAliasAsync(config.weatherEntity + '.ICON', 'accuweather.' + weatherAdapterInstanceNumber + '.Current.WeatherIcon', true, { type: 'number', role: 'value', name: 'ICON' }); + await createAliasAsync(config.weatherEntity + '.TEMP', 'accuweather.' + weatherAdapterInstanceNumber + '.Current.Temperature', true, { type: 'number', role: 'value.temperature', name: 'TEMP' }); + await createAliasAsync(config.weatherEntity + '.TEMP_MIN', 'accuweather.' + weatherAdapterInstanceNumber + '.Daily.Day1.Temperature.Minimum', true, { type: 'number', role: 'value.temperature.forecast.0', name: 'TEMP_MIN' }); + await createAliasAsync(config.weatherEntity + '.TEMP_MAX', 'accuweather.' + weatherAdapterInstanceNumber + '.Daily.Day1.Temperature.Maximum', true, { type: 'number', role: 'value.temperature.max.forecast.0', name: 'TEMP_MAX' }); + } else { + log('weather alias for accuweather.' + weatherAdapterInstanceNumber + '. already exists', 'info'); + } + } + } catch (err: any) { + log('error at function CreateWeatherAlias accuweather.' + weatherAdapterInstanceNumber + '.: ' + err.message, 'warn'); + } + } + } + } catch (err: any) { + log('error at function CreateWeatherAlias: ' + err.message, 'warn'); + } +} +CreateWeatherAlias(); + +//---------------------Begin PageNavi +async function InitPageNavi() { + try { + if (!existsState(NSPanel_Path + 'PageNavi')) { + await createStateAsync(NSPanel_Path + 'PageNavi', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'PageNavi', { val: {"pagetype": "page","pageId": 0}, ack: true }); + } + } catch (err: any) { + log('error at function InitPageNavi: ' + err.message, 'warn'); + } +} +InitPageNavi(); + +//PageNavi +on({id: [NSPanel_Path + 'PageNavi'], change: "any"}, async function (obj) { + try { + if (existsState(NSPanel_Path + 'PageNavi')) { + let vObj = JSON.parse(obj.state.val); + if (vObj.pagetype == 'page') { + GeneratePage(config.pages[vObj.pageId]); + } else if (vObj.pagetype == 'subpage') { + GeneratePage(config.subPages[vObj.pageId]); + } + } + } catch (err: any) { + log('error at Trigger PageNavi: ' + err.message, 'warn'); + } +}); + +//----------------------Begin Dimmode +function ScreensaverDimmode(timeDimMode: DimMode) { + try { + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val + let dimmode = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val + if (Debug) { + log('function ScreensaverDimmode RGB-Wert HMIDark' + rgb_dec565(HMIDark), 'info'); + } + if (Debug) { + log('function ScreensaverDimmode Dimmode=' + timeDimMode.dimmodeOn, 'info'); + } + if (timeDimMode.dimmodeOn != undefined ? timeDimMode.dimmodeOn : false) { + if (compareTime(timeDimMode.timeNight != undefined ? timeDimMode.timeNight : '22:00', timeDimMode.timeDay != undefined ? timeDimMode.timeDay : '07:00', 'not between', undefined)) { + SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessDay + '~' + active + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); + if (Debug) { + log('function ScreensaverDimmode -> Day Payload: ' + 'dimmode~' + timeDimMode.brightnessDay + '~' + active, 'info'); + } + } else { + SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessNight + '~' + active + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); + if (Debug) { + log('function ScreensaverDimmode -> Night Payload: ' + 'dimmode~' + timeDimMode.brightnessNight + '~' + active, 'info'); + } + } + } else { + SendToPanel({ payload: 'dimmode~' + dimmode + '~' + active + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); + } + } catch (err: any) { + log('error at function ScreensaverDimmode: ' + err.message, 'warn'); + } +} + +async function InitWeatherForecast() { + try { + if (isSetOptionActive) { + //----Ability to choose between Accu-Weather Forecast or self-defined values in the screensaver--------------------------------- + if (existsState(NSPanel_Path + "ScreensaverInfo.weatherForecast") == false || + existsState(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer") == false || + existsState(NSPanel_Path + "ScreensaverInfo.entityChangeTime") == false) { + await createStateAsync(NSPanel_Path + "ScreensaverInfo.weatherForecast", true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer", true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + "ScreensaverInfo.entityChangeTime", 60, { type: 'number' }); + } + //Create Alias weatherForecast + setObject(AliasPath + 'ScreensaverInfo.weatherForecast', {type: 'channel', common: {role: 'socket', name:'weatherForecast'}, native: {}}); + await createAliasAsync(AliasPath + 'ScreensaverInfo.weatherForecast.ACTUAL', NSPanel_Path + 'ScreensaverInfo.weatherForecast', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'ScreensaverInfo.weatherForecast.SET', NSPanel_Path + 'ScreensaverInfo.weatherForecast', true, { type: 'boolean', role: 'switch', name: 'SET' }); + //Create Alias weatherForecastTimer + setObject(AliasPath + 'ScreensaverInfo.weatherForecastTimer', {type: 'channel', common: {role: 'socket', name:'weatherForecastTimer'}, native: {}}); + await createAliasAsync(AliasPath + 'ScreensaverInfo.weatherForecastTimer.ACTUAL', NSPanel_Path + 'ScreensaverInfo.weatherForecastTimer', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'ScreensaverInfo.weatherForecastTimer.SET', NSPanel_Path + 'ScreensaverInfo.weatherForecastTimer', true, { type: 'boolean', role: 'switch', name: 'SET' }); + //Create Alias entityChangeTime + setObject(AliasPath + 'ScreensaverInfo.entityChangeTime', {type: 'channel', common: {role: 'slider', name:'entityChangeTime'}, native: {}}); + await createAliasAsync(AliasPath + 'ScreensaverInfo.entityChangeTime.ACTUAL', NSPanel_Path + 'ScreensaverInfo.entityChangeTime', true, { type: 'number', role: 'value', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'ScreensaverInfo.entityChangeTime.SET', NSPanel_Path + 'ScreensaverInfo.entityChangeTime', true, { type: 'number', role: 'level', name: 'SET' }); + } + } catch (err: any) { + log('error at function InitWeatherForecast: ' + err.message, 'warn'); + } +} +InitWeatherForecast(); + +async function InitDimmode() { + try { + if (isSetOptionActive) { + // Screensaver on dark at night ("brightnessNight: e.g. 2") or off ("brightnessNight:0") + if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay')) { + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', { type: 'number' }); + await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', { val: 8, ack: true }); + setObject(AliasPath + 'Dimmode.brightnessDay', {type: 'channel', common: {role: 'slider', name:'brightnessDay'}, native: {}}); + await createAliasAsync(AliasPath + 'Dimmode.brightnessDay.ACTUAL', NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', true, { type: 'number', role: 'value', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Dimmode.brightnessDay.SET', NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', true, { type: 'number', role: 'level', name: 'SET' }); + } + if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_hourDay')) { + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourDay', { type: 'number' }); + await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourDay', { val: 7, ack: true }); + setObject(AliasPath + 'Dimmode.hourDay', {type: 'channel', common: {role: 'slider', name:'hourDay'}, native: {}}); + await createAliasAsync(AliasPath + 'Dimmode.hourDay.ACTUAL', NSPanel_Path + 'NSPanel_Dimmode_hourDay', true, { type: 'number', role: 'value', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Dimmode.hourDay.SET', NSPanel_Path + 'NSPanel_Dimmode_hourDay', true, { type: 'number', role: 'level', name: 'SET' }); + } + if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight')) { + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', { type: 'number' }); + await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', { val: 1, ack: true }); + setObject(AliasPath + 'Dimmode.brightnessNight', {type: 'channel', common: {role: 'slider', name:'brightnessNight'}, native: {}}); + await createAliasAsync(AliasPath + 'Dimmode.brightnessNight.ACTUAL', NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', true, { type: 'number', role: 'value', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Dimmode.brightnessNight.SET', NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', true, { type: 'number', role: 'level', name: 'SET' }); + } + if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_hourNight')) { + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourNight', { type: 'number' }); + await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourNight', { val: 22, ack: true }); + setObject(AliasPath + 'Dimmode.hourNight', {type: 'channel', common: {role: 'slider', name:'hourNight'}, native: {}}); + await createAliasAsync(AliasPath + 'Dimmode.hourNight.ACTUAL', NSPanel_Path + 'NSPanel_Dimmode_hourNight', true, { type: 'number', role: 'value', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Dimmode.hourNight.SET', NSPanel_Path + 'NSPanel_Dimmode_hourNight', true, { type: 'number', role: 'level', name: 'SET' }); + } + const vTimeDay = getState(NSPanel_Path + 'NSPanel_Dimmode_hourDay').val; + const vTimeNight = getState(NSPanel_Path + 'NSPanel_Dimmode_hourNight').val; + const timeDimMode: DimMode = { + dimmodeOn: true, + brightnessDay: getState(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay').val, + brightnessNight: getState(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight').val, + timeDay: (vTimeDay < 10) ? `0${vTimeDay}:00` : `${vTimeDay}:00`, + timeNight: (vTimeNight < 10) ? `0${vTimeNight}:00` : `${vTimeNight}:00` + }; + // timeDimMode Day + scheduleInitDimModeDay = schedule({ hour: getState(NSPanel_Path + 'NSPanel_Dimmode_hourDay').val, minute: 0 }, () => { + ScreensaverDimmode(timeDimMode); + }); + // timeDimMode Night + scheduleInitDimModeNight = schedule({ hour: getState(NSPanel_Path + 'NSPanel_Dimmode_hourNight').val, minute: 0 }, () => { + ScreensaverDimmode(timeDimMode); + }); + if (getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val != null && getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val != -1) { + SendToPanel({ payload: 'dimmode~' + getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val + '~' + getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); + } else { + if (isDimTimeInRange(timeDimMode.timeDay,timeDimMode.timeNight)) { + SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessDay + '~' + getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); + } else { + SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessNight + '~' + getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); + } + ScreensaverDimmode(timeDimMode); + } + } + } catch (err: any) { + log('error at function InitDimmode: ' + err.message, 'warn'); + } +} +InitDimmode(); + +function currentDimDate() { + let d = new Date(); + return new Date(d.getFullYear(), d.getMonth(), d.getDate()); +} + +function addDimTime(strTime) { + let time = strTime.split(':'); + let d = currentDimDate(); + d.setHours(time[0]); + d.setMinutes(time[1]); + d.setSeconds(time[2]); + return d; +} + +function isDimTimeInRange(strLower, strUpper) { + let now = new Date(); + let lower = addDimTime(strLower); + let upper = addDimTime(strUpper); + let inRange = false; + if (upper > lower) { + // opens and closes in same day + inRange = (now >= lower && now <= upper) ? true : false; + } else { + // closes in the following day + inRange = (now >= upper && now <= lower) ? false : true; + } + return inRange; +} + +//--------------------End Dimmode + +// Data points for message to screensaver +const screensaverNotifyHeading = NSPanel_Path + 'ScreensaverInfo.popupNotifyHeading'; +const screensaverNotifyText = NSPanel_Path + 'ScreensaverInfo.popupNotifyText'; + +// Data points for message popupNotify Page +const popupNotifyHeading = NSPanel_Path + 'popupNotify.popupNotifyHeading'; +const popupNotifyHeadingColor = NSPanel_Path + 'popupNotify.popupNotifyHeadingColor'; +const popupNotifyText = NSPanel_Path + 'popupNotify.popupNotifyText'; +const popupNotifyTextColor = NSPanel_Path + 'popupNotify.popupNotifyTextColor'; +const popupNotifyInternalName = NSPanel_Path + 'popupNotify.popupNotifyInternalName'; // Written back with button action +const popupNotifyButton1TextColor = NSPanel_Path + 'popupNotify.popupNotifyButton1TextColor'; +const popupNotifyButton1Text = NSPanel_Path + 'popupNotify.popupNotifyButton1Text'; +const popupNotifyButton2TextColor = NSPanel_Path + 'popupNotify.popupNotifyButton2TextColor'; +const popupNotifyButton2Text = NSPanel_Path + 'popupNotify.popupNotifyButton2Text'; +const popupNotifySleepTimeout = NSPanel_Path + 'popupNotify.popupNotifySleepTimeout'; // in sec. / if 0, then the message remains +const popupNotifyAction = NSPanel_Path + 'popupNotify.popupNotifyAction'; // Response from the panel true/false +const popupNotifyLayout = NSPanel_Path + 'popupNotify.popupNotifyLayout'; +const popupNotifyFontIdText = NSPanel_Path + 'popupNotify.popupNotifyFontIdText'; // 1 - 5 +const popupNotifyIcon = NSPanel_Path + 'popupNotify.popupNotifyIcon'; // 1 - 5 +const popupNotifyIconColor = NSPanel_Path + 'popupNotify.popupNotifyIconColor'; // 1 - 5 +const popupNotifyBuzzer = NSPanel_Path + 'popupNotify.popupNotifyBuzzer'; // 1,1,1 -> off 0 + +async function InitPopupNotify() { + try { + + if (!existsState(screensaverNotifyHeading)) { + await createStateAsync(screensaverNotifyHeading, { type: 'string' }); + await setStateAsync(screensaverNotifyHeading, { val: '', ack: true }); + } + + if (!existsState(screensaverNotifyText)) { + await createStateAsync(screensaverNotifyText, { type: 'string' }); + await setStateAsync(screensaverNotifyText, { val: '', ack: true }); + } + + await createStateAsync(popupNotifyHeading, { type: 'string' }); + await createStateAsync(popupNotifyHeadingColor, { type: 'string' }); + await createStateAsync(popupNotifyText, { type: 'string' }); + await createStateAsync(popupNotifyTextColor, { type: 'string' }); + await createStateAsync(popupNotifyInternalName, { type: 'string' }); + await createStateAsync(popupNotifyButton1Text, { type: 'string' }); + await createStateAsync(popupNotifyButton1TextColor, { type: 'string' }); + await createStateAsync(popupNotifyButton2Text, { type: 'string' }); + await createStateAsync(popupNotifyButton2TextColor, { type: 'string' }); + await createStateAsync(popupNotifySleepTimeout, { type: 'number' }); + await createStateAsync(popupNotifyAction, { type: 'boolean' }); + await createStateAsync(popupNotifyLayout, { type: 'number' }); + await createStateAsync(popupNotifyFontIdText, { type: 'number' }); + await createStateAsync(popupNotifyIcon, { type: 'string' }); + await createStateAsync(popupNotifyIconColor, { type: 'string' }); + await createStateAsync(popupNotifyBuzzer,{type: 'string', def: '0'}); + + // Notification to screensaver + on({ id: [screensaverNotifyHeading, screensaverNotifyText], change: 'ne', ack: false }, async (obj) => { + const heading = getState(screensaverNotifyHeading).val; + const text = getState(screensaverNotifyText).val; + + if (screensaverEnabled) { + setIfExists(config.panelSendTopic, `notify~${heading}~${text}`); + } + + if (obj.id) { + await setStateAsync(obj.id, { val: obj.state.val, ack: true }); // ack new value + } + }); + + // popupNotify - Notification to a separate page + //on({ id: [popupNotifyInternalName], change: 'ne' }, async () => { + on({ id: [popupNotifyText], change: 'any' }, async() => { + + + let notification: string; + + let v_popupNotifyHeadingColor = (getState(popupNotifyHeadingColor).val != null) ? getState(popupNotifyHeadingColor).val : '65504'// Farbe Headline - gelb 65504 + let v_popupNotifyButton1TextColor = (getState(popupNotifyButton1TextColor).val != null) ? getState(popupNotifyButton1TextColor).val : '63488'// Farbe Button 1 - rot 63488 + let v_popupNotifyButton2TextColor = (getState(popupNotifyButton2TextColor).val != null) ? getState(popupNotifyButton2TextColor).val : '2016'// Farbe Button 2 - grün 2016 + let v_popupNotifyTextColor = (getState(popupNotifyTextColor).val != null) ? getState(popupNotifyTextColor).val : '65535'// Farbe Text - weiss 65535 + let v_popupNotifyIconColor = (getState(popupNotifyIconColor).val != null) ? getState(popupNotifyIconColor).val : '65535'// Farbe Icon - weiss 65535 + let v_popupNotifyFontIdText = (getState(popupNotifyFontIdText).val != null) ? getState(popupNotifyFontIdText).val : '1' + let v_popupNotifyIcon = (getState(popupNotifyIcon).val != null) ? getState(popupNotifyIcon).val : 'alert' + let v_popupNotifyBuzzer = (getState(popupNotifyBuzzer).val != null) ? getState(popupNotifyBuzzer).val : '0'; + + notification = 'entityUpdateDetail' + '~' + + getState(popupNotifyInternalName).val + '~' + + getState(popupNotifyHeading).val + '~' + + v_popupNotifyHeadingColor + '~' + + getState(popupNotifyButton1Text).val + '~' + + v_popupNotifyButton1TextColor + '~' + + getState(popupNotifyButton2Text).val + '~' + + v_popupNotifyButton2TextColor + '~' + + getState(popupNotifyText).val + '~' + + v_popupNotifyTextColor + '~' + + getState(popupNotifySleepTimeout).val; + + if (getState(popupNotifyLayout).val == 2) { + notification = notification + '~' + + v_popupNotifyFontIdText + '~' + + Icons.GetIcon(v_popupNotifyIcon) + '~' + + v_popupNotifyIconColor; + } + + setIfExists(config.panelSendTopic, 'pageType~popupNotify'); + setIfExists(config.panelSendTopic, notification); + + //------ Tasmota Buzzer ------ + + if (v_popupNotifyBuzzer != '0') { + if (Debug){ + log('Tasmota Buzzer enabled. Value: ' + v_popupNotifyBuzzer, 'info'); + } + let urlString = `http://${get_current_tasmota_ip_address()}/cm?cmnd=Buzzer ${v_popupNotifyBuzzer}`; + if (tasmota_web_admin_password != '') { + urlString = `http://${get_current_tasmota_ip_address()}/cm?user=${tasmota_web_admin_user}&password=${tasmota_web_admin_password}&cmnd=Buzzer ${v_popupNotifyBuzzer}`; + } + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + log('Axios Data: ' + JSON.stringify(response.data), 'info'); + } else { + log('Axios Status - Tasmota Buzzer: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + } else { + if (Debug){ + log('Tasmota Buzzer disabled', 'info'); + } + } + //---- Tasmota Buzzer ----- + + }); + } catch (err: any) { + log('error at function InitPopupNotify: ' + err.message, 'warn'); + } +} +InitPopupNotify(); + +let subscriptions: any = {}; +let screensaverEnabled: boolean = false; +let pageId = 0; +let activePage: PageType | undefined = undefined; + +//Send time to NSPanel +let scheduleSendTime = schedule('* * * * *', () => { + try { + SendTime(); + HandleScreensaverUpdate(); + } catch (err: any) { + log('error at schedule SendTime: ' + err.message, 'warn'); + } +}); + +//Switch between Screensaver Entities and WeatherForecast +let scheduleSwichScreensaver = schedule('*/' + getState(NSPanel_Path + 'ScreensaverInfo.entityChangeTime').val + ' * * * * *', () => { + try { + //WeatherForecast true/false Switchover delayed + if (getState(NSPanel_Path + "ScreensaverInfo.popupNotifyHeading").val == '' && getState(NSPanel_Path + "ScreensaverInfo.popupNotifyText").val == '' && getState(NSPanel_Path + "ScreensaverInfo.weatherForecast").val == true && getState(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer").val == true) { + setStateDelayed(NSPanel_Path + "ScreensaverInfo.weatherForecast", false, (getState(NSPanel_Path + 'ScreensaverInfo.entityChangeTime').val / 2 * 1000), false); + } else if (getState(NSPanel_Path + "ScreensaverInfo.popupNotifyHeading").val == '' && getState(NSPanel_Path + "ScreensaverInfo.popupNotifyText").val == '' && getState(NSPanel_Path + "ScreensaverInfo.weatherForecast").val == false && getState(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer").val == true) { + setStateDelayed(NSPanel_Path + "ScreensaverInfo.weatherForecast", true, (getState(NSPanel_Path + 'ScreensaverInfo.entityChangeTime').val / 2 * 1000), false); + } + } catch (err: any) { + log('error at schedule entityChangeTime: ' + err.message, 'warn'); + } +}); + +function InitHWButton1Color() { + try { + if (config.mrIcon1ScreensaverEntity.ScreensaverEntity != null || config.mrIcon1ScreensaverEntity.ScreensaverEntity != undefined) { + on({id: config.mrIcon1ScreensaverEntity.ScreensaverEntity, change: "ne"}, async function () { + HandleScreensaverUpdate(); + }); + } + } catch (err: any) { + log('error at function InitHWButton1Color: ' + err.message, 'warn'); + } +} +InitHWButton1Color(); + +function InitHWButton2Color() { + try { + if (config.mrIcon2ScreensaverEntity.ScreensaverEntity != null || config.mrIcon2ScreensaverEntity.ScreensaverEntity != undefined) { + on({id: config.mrIcon2ScreensaverEntity.ScreensaverEntity, change: "ne"}, async function () { + HandleScreensaverUpdate(); + }); + } + } catch (err: any) { + log('error at function InitHWButton2Color: ' + err.message, 'warn'); + } +} +InitHWButton2Color(); + +//Switch between data points and weather forecast in the screensaver +on({id: [NSPanel_Path + "ScreensaverInfo.weatherForecast"], change: "ne"}, async function (obj) { + try { + weatherForecast = obj.state.val; + HandleScreensaverUpdate(); + } catch (err: any) { + log('error at trigger weatherForecast: ' + err.message, 'warn'); + } +}); + +//Update if Changing Values on Wheather Alias +on({id: [config.weatherEntity + '.TEMP', + config.weatherEntity + '.ICON'], change: "ne"}, async function (obj) { + try { + HandleScreensaverUpdate(); + } catch (err: any) { + log('error at trigger weatherForecast .TEMP + .ICON: ' + err.message, 'warn'); + } +}); + +let scheduleSendDate = schedule('0 * * * *', () => { + SendDate(); +}); + +// 3:30 a.m. Perform startup and receive current TFT version +let scheduleStartup = schedule({ hour: 3, minute: 30 }, async () => { + await setStateAsync(config.panelSendTopic, 'pageType~pageStartup'); +}); + +// Updates currently compare every 12 hours +let scheduleCheckUpdates = schedule('{"time":{"start":"00:00","end":"23:59","mode":"hours","interval":12},"period":{"days":1}}', () => { + get_tasmota_status0(); + get_panel_update_data(); + check_updates(); +}); + +// Check for updates with Start +get_locales(); +get_locales_servicemenu(); +setState(config.panelSendTopic, 'pageType~pageStartup'); +get_tasmota_status0(); +get_panel_update_data(); +check_updates(); +/* +setTimeout(async function () { + setState(config.panelSendTopic, 'pageType~pageStartup'); +}, 90000); +*/ + +//------------------Begin Update Functions + +function getDayjsLocale(): String { + try { + let locale = getState(NSPanel_Path + 'Config.locale').val; + if (locale == "hy-AM" || locale == "zh-CN" || locale == "zh-TW") { + return locale.toLowerCase(); + } else { + return locale.substring(0, 2); + } + } catch (err: any) { + log('error in function getDayjsLocale: ' + err.message, 'warn'); + // hier muß eine Return oder ein neuer throw err hin + return ''; + } +} + +async function get_locales() { + try { + if (Debug) { + log('Requesting locales', 'info'); + } + let urlString: string = 'https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/ioBroker/ioBroker_NSPanel_locales.json'; + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(JSON.stringify(response.data), 'info'); + } + await createStateAsync(NSPanel_Path + 'NSPanel_locales_json', { type: 'string', role: 'json' }); + await setStateAsync(NSPanel_Path + 'NSPanel_locales_json', { val: JSON.stringify(response.data), ack: true }); + } else { + log('Axios Status - Requesting locales: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + } catch (err: any) { + log('error requesting locales in function get_locales: ' + err.message, 'warn'); + } +} + +async function get_locales_servicemenu() { + try { + if (Debug) { + log('Requesting locales Service Menu', 'info'); + } + let urlString: string = 'https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/ioBroker/ioBroker_NSPanel_locales_service.json'; + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(JSON.stringify(response.data), 'info'); + } + await createStateAsync(NSPanel_Path + 'NSPanel_locales_service_json', { type: 'string', role: 'json' }); + await setStateAsync(NSPanel_Path + 'NSPanel_locales_service_json', { val: JSON.stringify(response.data), ack: true }); + } else { + log('Axios Status - Requesting locales Service Menu: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + } catch (err: any) { + log('error requesting locales in function get_locales_servicemenu: ' + err.message, 'warn'); + } +} + +async function check_updates() { + try { + if (Debug) log('Check-Updates', 'info'); + + let Update: boolean = false; + + let InternalName: string = ''; + let Headline: string = ''; + let Text: string = ''; + + const HeadlineColor: string = '63488'; // Farbe Rot + const Button1: string = 'Nein'; + const Button1Color: string = '63488'; // Farbe Rot + const Button2: string = 'Ja'; + const Button2Color: string = '2016'; // Farbe Grün + const Timeout: number = 0; + const Layout: number = 1; + + // Tasmota-Firmware-Vergleich + if (existsObject(NSPanel_Path + 'Tasmota_Firmware.currentVersion') && existsObject(NSPanel_Path + 'Tasmota_Firmware.onlineVersion')) { + let splitTasmotaVersion = (getState(NSPanel_Path + 'Tasmota_Firmware.currentVersion').val).split('.'); + let shortTasmoataVersion = splitTasmotaVersion[0] + '.' + splitTasmotaVersion[1] + '.' + splitTasmotaVersion[2] + if (shortTasmoataVersion !== getState(NSPanel_Path + 'Tasmota_Firmware.onlineVersion').val) { + if (existsState(NSPanel_Path + 'NSPanel_autoUpdate')) { + if (getState(NSPanel_Path + 'NSPanel_autoUpdate').val) { + + if (Debug) log('Auto-Updates eingeschaltet - Update Tasmota wird durchgeführt', 'info'); + + // Perform Tasmota upgrade + update_tasmota_firmware(); + // Current Tasmota version = online Tasmota version + + await setStateAsync(NSPanel_Path + 'Tasmota_Firmware.currentVersion', { val: getState(NSPanel_Path + 'Tasmota_Firmware.onlineVersion').val, ack: true }); + } else { + // Point out Tasmota updates + if (Debug) log('Tasmota-Firmware => Automatische Updates aus, manuelles Update nötig', 'info'); + + InternalName = 'TasmotaFirmwareUpdate'; + Headline = 'Tasmota-Firmware Update'; + 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(''); + Update = true; + } + } + } else { + if (Debug) log('Already the latest Tasmota version on NSPanel', 'info'); + } + } + + // Tasmota-Berry-Driver-Vergleich + if (existsObject(NSPanel_Path + 'Berry_Driver.currentVersion')) { + if (parseFloat(getState(NSPanel_Path + 'Berry_Driver.currentVersion').val) < berry_driver_version) { + if (existsState(NSPanel_Path + 'NSPanel_autoUpdate')) { + if (getState(NSPanel_Path + 'NSPanel_autoUpdate').val) { + + if (Debug) log('Auto-updates switched on - Berry driver update is carried out', 'info'); + + // Tasmota Berry-Driver Update durchführen + update_berry_driver_version(); + // Aktuelle Berry-Driver Version = Online Berry-Driver Version + await setStateAsync(NSPanel_Path + 'Berry_Driver.currentVersion', { val: getState(NSPanel_Path + 'Berry_Driver.onlineVersion').val, ack: true }); + + if (Debug) log('Berry driver updated automatically', 'info'); + + } else { + //Auf BerryDriver-Update hinweisen + if (Debug) log('Berry Driver => Automatic updates off, manual update required', 'info'); + + InternalName = 'BerryDriverUpdate'; + Headline = 'Berry-Driver Update'; + 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(''); + Update = true; + } + } + } else { + if (Debug) log('Already the latest Berry driver on NSPanel', 'info'); + } + } + + // 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) { + + if (Debug) log('Auto-updates switched on - update TFT firmware is carried out', 'info'); + + // TFT-Firmware Update durchführen + update_tft_firmware(); + // Aktuelle TFT-Firmware Version = Online TFT-Firmware Version + await setStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { val: getState(NSPanel_Path + 'Display_Firmware.onlineVersion').val, ack: true }); + + if (Debug) log('Display firmware updated automatically', 'info'); + + } else { + // Auf TFT-Firmware hinweisen + if (Debug) log('Display firmware => Automatic updates off, manual update required', 'info'); + + InternalName = 'TFTFirmwareUpdate'; + Headline = 'TFT-Firmware Update'; + 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(''); + Update = true; + } + } + } else { + if (Debug) log('Already the latest display firmware on NSPanel', 'info'); + } + } + let update_message: boolean = getState(NSPanel_Path + 'Config.Update.UpdateMessage').val; + if (Update && update_message) { + await setStateAsync(popupNotifyHeading, { val: Headline, ack: false }); + await setStateAsync(popupNotifyHeadingColor, { val: HeadlineColor, ack: false }); + await setStateAsync(popupNotifyButton1Text, { val: Button1, ack: false }); + await setStateAsync(popupNotifyButton1TextColor, { val: Button1Color, ack: false }); + await setStateAsync(popupNotifyButton2Text, { val: Button2, ack: false }); + await setStateAsync(popupNotifyButton2TextColor, { val: Button2Color, ack: false }); + await setStateAsync(popupNotifySleepTimeout, { val: Timeout, ack: false }); + await setStateAsync(popupNotifyInternalName, { val: InternalName, ack: false }); + await setStateAsync(popupNotifyLayout, { val: Layout, ack: false }); + await setStateAsync(popupNotifyText, { val: [formatDate(getDateObject((new Date().getTime())), 'TT.MM.JJJJ SS:mm:ss'), '\r\n', '\r\n', Text].join(''), ack: false }); + } else if (Update && !update_message) { + log('Updates for NSPanel available', 'info'); + } else { + log('No Updates for NSPanel available', 'info'); + } + + } catch (err: any) { + log('error at function check_updates: ' + err.message, 'warn'); + } +} + +on({ id: NSPanel_Path + 'popupNotify.popupNotifyAction', change: 'any' }, async function (obj) { + try { + const val = obj.state ? obj.state.val : false; + if (!val) { + if (Debug) { + log('Button1 was pressed', 'info'); + } + } else if (val) { + + const internalName: string = getState(NSPanel_Path + 'popupNotify.popupNotifyInternalName').val; + if (internalName.includes('Update')) { + if (internalName == 'TasmotaFirmwareUpdate') { + update_tasmota_firmware(); + } else if (internalName == 'BerryDriverUpdate') { + update_berry_driver_version(); + } else if (internalName == 'TFTFirmwareUpdate') { + update_tft_firmware(); + } + } + if (Debug) { + log('Button2 was pressed', 'info'); + } + } + } catch (err: any) { + log('error at Trigger popupNotifyAction: ' + err.message, 'warn'); + } +}); + +async function get_panel_update_data() { + try { + if (isSetOptionActive) { + await createStateAsync(NSPanel_Path + 'Config.Update.UpdateMessage', true, { read: true, write: true, name: 'Update-Message', type: 'boolean', def: true }); + if (autoCreateAlias) { + setObject(AliasPath + 'Config.Update.UpdateMessage', {type: 'channel', common: {role: 'socket', name:'UpdateMesssage'}, native: {}}); + await createAliasAsync(AliasPath + 'Config.Update.UpdateMessage.ACTUAL', NSPanel_Path + 'Config.Update.UpdateMessage', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Config.Update.UpdateMessage.SET', NSPanel_Path + 'Config.Update.UpdateMessage', true, { type: 'boolean', role: 'switch', name: 'SET' }); + } + await createStateAsync(NSPanel_Path + 'NSPanel_autoUpdate', false, { read: true, write: true, name: 'Auto-Update', type: 'boolean', def: false }); + if (autoCreateAlias) { + setObject(AliasPath + 'autoUpdate', {type: 'channel', common: {role: 'socket', name:'AutoUpdate'}, native: {}}); + await createAliasAsync(AliasPath + 'autoUpdate.ACTUAL', NSPanel_Path + 'NSPanel_autoUpdate', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'autoUpdate.SET', NSPanel_Path + 'NSPanel_autoUpdate', true, { type: 'boolean', role: 'switch', name: 'SET' }); + } + await createStateAsync(NSPanel_Path + 'NSPanel_ipAddress', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'NSPanel_ipAddress', { val: get_current_tasmota_ip_address(), ack: true }); + if (autoCreateAlias) { + setObject(AliasPath + 'ipAddress', {type: 'channel', common: {role: 'info', name:'ipAddress'}, native: {}}); + await createAliasAsync(AliasPath + 'ipAddress.ACTUAL', NSPanel_Path + 'NSPanel_ipAddress', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + } + get_online_tasmota_firmware_version(); + get_current_berry_driver_version(); + get_online_berry_driver_version(); + check_version_tft_firmware(); + check_online_display_firmware(); + } + } catch (err: any) { + log('error at function get_panel_update_data: ' + err.message, 'warn'); + } +} + +function get_current_tasmota_ip_address() { + try { + const infoObjId = config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'INFO2'; + const infoObj = JSON.parse(getState(infoObjId).val); + + if (Debug) { + log(`get_current_tasmota_ip_address: ${infoObj.Info2.IPAddress}`, 'info'); + } + + return infoObj.Info2.IPAddress; + } catch (err: any) { + log('error at function get_current_tasmota_ip_address: ' + err.message, 'warn'); + } +} + +function get_online_tasmota_firmware_version() { + try { + if (Debug) { + log('Requesting tasmota firmware version', 'info'); + } + + let urlString: string = 'https://api.github.com/repositories/80286288/releases/latest'; + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(JSON.stringify(response.data), 'info'); + } + if (isSetOptionActive) { + const Tasmota_JSON = JSON.parse(JSON.stringify(response.data));// Write JSON result to variable + const TasmotaTagName = Tasmota_JSON.tag_name; // Filter JSON by "tag_name" and write to variable + const TasmotaVersionOnline = TasmotaTagName.replace(/v/i, ''); // Filter unnecessary "v" from variable and write to release variable + await createStateAsync(NSPanel_Path + 'Tasmota_Firmware.onlineVersion', { type: 'string' }); + setObject(AliasPath + 'Tasmota_Firmware.onlineVersion', {type: 'channel', common: {role: 'info', name:'onlineVersion'}, native: {}}); + await createAliasAsync(AliasPath + 'Tasmota_Firmware.onlineVersion.ACTUAL', NSPanel_Path + 'Tasmota_Firmware.onlineVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + await setStateAsync(NSPanel_Path + 'Tasmota_Firmware.onlineVersion', { val: TasmotaVersionOnline, ack: true }); + if (Debug) log('online tasmota firmware version => ' + TasmotaVersionOnline, 'info'); + } + } else { + log('Axios Status - online tasmota firmware version: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + } catch (err: any) { + log('error requesting firmware in function get_online_tasmota_firmware_version: ' + err.message, 'warn'); + } +} + +function get_current_berry_driver_version() { + try { + if (Debug) { + log('Requesting current berry driver version', 'info'); + } + + let urlString = `http://${get_current_tasmota_ip_address()}/cm?cmnd=GetDriverVersion`; + if (tasmota_web_admin_password != '') { + urlString = `http://${get_current_tasmota_ip_address()}/cm?user=${tasmota_web_admin_user}&password=${tasmota_web_admin_password}&cmnd=GetDriverVersion`; + } + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(JSON.stringify(response.data), 'info'); + } + if (isSetOptionActive) { + const BerryDriverVersionCurrent: string = JSON.parse(JSON.stringify(response.data)).nlui_driver_version; + await createStateAsync(NSPanel_Path + 'Berry_Driver.currentVersion', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'Berry_Driver.currentVersion', { val: JSON.parse(JSON.stringify(response.data)).nlui_driver_version, ack: true }); + if (autoCreateAlias) { + setObject(AliasPath + 'Display.BerryDriver', {type: 'channel', common: {role: 'info', name: 'Berry Driver'}, native: {}}); + await createAliasAsync(AliasPath + 'Display.BerryDriver.ACTUAL', NSPanel_Path + 'Berry_Driver.currentVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + } + if (Debug) log('current berry driver version => ' + BerryDriverVersionCurrent, 'info'); + } + } else { + log('Axios Status - current berry driver version: ' + response.state, 'info'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + } catch (err: any) { + log('error requesting firmware in function get_current_berry_driver_version: ' + err.message, 'warn'); + } +} + +function get_tasmota_status0() { + try { + if (Debug) { + log('Requesting tasmota status0', 'info'); + } + + let urlString = `http://${get_current_tasmota_ip_address()}/cm?cmnd=Status0`; + if (tasmota_web_admin_password != '') { + urlString = `http://${get_current_tasmota_ip_address()}/cm?user=${tasmota_web_admin_user}&password=${tasmota_web_admin_password}&cmnd=Status0`; + } + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(JSON.stringify(response.data), 'info'); + } + if (isSetOptionActive) { + await createStateAsync(NSPanel_Path + 'Tasmota_Firmware.currentVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Uptime', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Version', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Hardware', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.AP', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.SSId', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.BSSId', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Channel', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Mode', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.RSSI', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Signal', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Tasmota.Product', { type: 'string' }); + + try { + const Tasmota_JSON = JSON.parse(JSON.stringify(response.data)); + const tasmoVersion = Tasmota_JSON.StatusFWR.Version.indexOf('(') > -1 ? Tasmota_JSON.StatusFWR.Version.split('(')[0] : Tasmota_JSON.StatusFWR.Version; + + await setStateAsync(NSPanel_Path + 'Tasmota_Firmware.currentVersion', { val: tasmoVersion, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Uptime', { val: Tasmota_JSON.StatusPRM.Uptime, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Version', { val: Tasmota_JSON.StatusFWR.Version, ack: true }); + let TasmotaHardware: string = Tasmota_JSON.StatusFWR.Hardware.split(' '); + await setStateAsync(NSPanel_Path + 'Tasmota.Hardware', { val: TasmotaHardware[0] + '\r\n' + TasmotaHardware[1], ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.AP', { val: Tasmota_JSON.StatusSTS.Wifi.AP, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.SSId', { val: Tasmota_JSON.StatusSTS.Wifi.SSId, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.BSSId', { val: Tasmota_JSON.StatusSTS.Wifi.BSSId, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.Channel', { val: Tasmota_JSON.StatusSTS.Wifi.Channel, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.Mode', { val: Tasmota_JSON.StatusSTS.Wifi.Mode, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.RSSI', { val: Tasmota_JSON.StatusSTS.Wifi.RSSI, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Wifi.Signal', { val: Tasmota_JSON.StatusSTS.Wifi.Signal, ack: true }); + await setStateAsync(NSPanel_Path + 'Tasmota.Product', { val: 'SONOFF NSPanel', ack: true }); + if (Debug) log('current tasmota firmware version => ' + tasmoVersion, 'info'); + } catch (err: any) { + log('error setState in function get_tasmota_status0' + err.message, 'warn'); + } + if (autoCreateAlias) { + setObject(AliasPath + 'Tasmota.Uptime', {type: 'channel', common: {role: 'info', name: 'Uptime'}, native: {}}); + setObject(AliasPath + 'Tasmota.Version', {type: 'channel', common: {role: 'info', name:'Version'}, native: {}}); + setObject(AliasPath + 'Tasmota.Hardware', {type: 'channel', common: {role: 'info', name: 'Hardware'}, native: {}}); + setObject(AliasPath + 'Tasmota.Wifi.AP', {type: 'channel', common: {role: 'info', name:'AP'}, native: {}}); + setObject(AliasPath + 'Tasmota.Wifi.SSId', {type: 'channel', common: {role: 'info', name:'SSId'}, native: {}}); + setObject(AliasPath + 'Tasmota.Wifi.BSSId', {type: 'channel', common: {role: 'info', name: 'BSSId'}, native: {}}); + setObject(AliasPath + 'Tasmota.Wifi.Channel', {type: 'channel', common: {role: 'info', name:'Channel'}, native: {}}); + setObject(AliasPath + 'Tasmota.Wifi.Mode', {type: 'channel', common: {role: 'info', name: 'Mode'}, native: {}}); + setObject(AliasPath + 'Tasmota.Wifi.RSSI', {type: 'channel', common: {role: 'info', name:'RSSI'}, native: {}}); + setObject(AliasPath + 'Tasmota.Wifi.Signal', {type: 'channel', common: {role: 'info', name:'Signal'}, native: {}}); + setObject(AliasPath + 'Tasmota.Product', {type: 'channel', common: {role: 'info', name:'Product'}, native: {}}); + await createAliasAsync(AliasPath + 'Tasmota.Uptime.ACTUAL', NSPanel_Path + 'Tasmota.Uptime', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Tasmota.Version.ACTUAL', NSPanel_Path + 'Tasmota.Version', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Tasmota.Hardware.ACTUAL', NSPanel_Path + 'Tasmota.Hardware', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Tasmota.Wifi.AP.ACTUAL', NSPanel_Path + 'Tasmota.Wifi.AP', true, { type: 'number', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Tasmota.Wifi.SSId.ACTUAL', NSPanel_Path + 'Tasmota.Wifi.SSId', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Tasmota.Wifi.BSSId.ACTUAL', NSPanel_Path + 'Tasmota.Wifi.BSSId', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Tasmota.Wifi.Channel.ACTUAL', NSPanel_Path + 'Tasmota.Wifi.Channel', true, { type: 'number', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Tasmota.Wifi.Mode.ACTUAL', NSPanel_Path + 'Tasmota.Wifi.Mode', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Tasmota.Wifi.RSSI.ACTUAL', NSPanel_Path + 'Tasmota.Wifi.RSSI', true, { type: 'number', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Tasmota.Wifi.Signal.ACTUAL', NSPanel_Path + 'Tasmota.Wifi.Signal', true, { type: 'number', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Tasmota.Product.ACTUAL', NSPanel_Path + 'Tasmota.Product', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + } + } + } else { + log('Axios Status - get_tasmota_status0: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + } catch (err: any) { + log('error requesting firmware in function get_tasmota_status0: ' + err.message, 'warn'); + } +} + +function get_online_berry_driver_version() { + try { + if (NSPanel_Path + 'Config.Update.activ') { + if (Debug) { + log('Requesting online berry driver version', 'info'); + } + + let urlString = 'https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/tasmota/autoexec.be'; + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(response.data, 'info'); + } + if (isSetOptionActive) { + const BerryDriverVersionOnline = response.data.substring((response.data.indexOf('version_of_this_script = ') + 24), response.data.indexOf('version_of_this_script = ') + 27).replace(/\s+/g, ''); + await createStateAsync(NSPanel_Path + 'Berry_Driver.onlineVersion', { type: 'string' }); + setObject(AliasPath + 'Berry_Driver.onlineVersion', {type: 'channel', common: {role: 'info', name:'onlineVersion'}, native: {}}); + await createAliasAsync(AliasPath + 'Berry_Driver.onlineVersion.ACTUAL', NSPanel_Path + 'Berry_Driver.onlineVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + await setStateAsync(NSPanel_Path + 'Berry_Driver.onlineVersion', { val: BerryDriverVersionOnline, ack: true }); + if (Debug) log('online berry driver version => ' + BerryDriverVersionOnline, 'info'); + } + } else { + log('Axios Status - get_online_berry_driver_version: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + } + } catch (err: any) { + log('error requesting firmware in function get_online_berry_driver_version: ' + err.message, 'warn'); + } +} + +function check_version_tft_firmware() { + try { + if (Debug) { + log('Requesting online TFT version', 'info'); + } + + let urlString = 'https://api.github.com/repos/joBr99/nspanel-lovelace-ui/releases/latest'; + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(JSON.stringify(response.data), 'info'); + } + let NSPanel_JSON = JSON.parse(JSON.stringify(response.data)); // Write JSON result to variable + let NSPanelTagName = NSPanel_JSON.tag_name; // created_at; published_at; name ; draft ; prerelease + let NSPanelVersion = NSPanelTagName.replace(/v/i, ''); // Filter unnecessary "v" from variable and write to release variable + + await createStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { val: NSPanelVersion, ack: true }); + if (Debug) log('online TFT firmware version => ' + NSPanelVersion, 'info'); + } else { + log('Axios Status - check_version_tft_firmware: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + } catch (err: any) { + log('error requesting firmware in function check_version_tft_firmware: ' + err.message, 'warn'); + } +} + +function check_online_display_firmware() { + try { + if (Debug) { + log('Requesting online firmware version', 'info'); + } + + let urlString = 'https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/apps/nspanel-lovelace-ui/nspanel-lovelace-ui.py'; + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(response.data, 'info'); + } + let desired_display_firmware_version = response.data.substring((response.data.indexOf('desired_display_firmware_version =') + 34), response.data.indexOf('desired_display_firmware_version =') + 38).replace(/\s+/g, ''); + + await createStateAsync(NSPanel_Path + 'Display_Firmware.onlineVersion', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'Display_Firmware.onlineVersion', { val: desired_display_firmware_version, ack: true }); + if (Debug) log('online display firmware version => ' + desired_display_firmware_version, 'info'); + } else { + log('Axios Status - check_online_display_firmware: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + } catch (err: any) { + log('error requesting firmware in function check_online_display_firmware: ' + err.message, 'warn'); + } +} + +on({ id: config.panelRecvTopic }, async (obj) => { + if (obj.state.val.startsWith('\{"CustomRecv":')) { + try { + if (isSetOptionActive) { + let json = JSON.parse(obj.state.val); + let split = json.CustomRecv.split(','); + if (split[0] == 'event' && split[1] == 'startup') { + await createStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'NSPanel_Version', { type: 'string' }); + + await setStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { val: split[2], ack: true }); + await setStateAsync(NSPanel_Path + 'NSPanel_Version', { val: split[3], ack: true }); + + if (autoCreateAlias) { + setObject(AliasPath + 'Display.TFTVersion', {type: 'channel', common: {role: 'info', name:'Display.TFTVersion'}, native: {}}); + setObject(AliasPath + 'Display.Model', {type: 'channel', common: {role: 'info', name:'Display.Model'}, native: {}}); + await createAliasAsync(AliasPath + 'Display.TFTVersion.ACTUAL', NSPanel_Path + 'Display_Firmware.currentVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(AliasPath + 'Display.Model.ACTUAL', NSPanel_Path + 'NSPanel_Version', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + } + } + } + } catch (err: any) { + log('error at trigger rceiving CustomRecv: ' + err.message, 'warn'); + } + } +}); + +function update_berry_driver_version() { + try { + + let urlString = `http://${get_current_tasmota_ip_address()}/cm?cmnd=Backlog UpdateDriverVersion https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/tasmota/autoexec.be; Restart 1`; + if (tasmota_web_admin_password != '') { + urlString = `http://${get_current_tasmota_ip_address()}/cm?user=${tasmota_web_admin_user}&password=${tasmota_web_admin_password}&cmnd=Backlog UpdateDriverVersion https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/tasmota/autoexec.be; Restart 1`; + } + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(response.data, 'info'); + } + } else { + log('Axios Status - update_berry_driver_version: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + } catch (err: any) { + log('error at function update_berry_driver_version: ' + err.message, 'warn'); + } +} + +function update_tft_firmware() { + if (getState(NSPanel_Path + 'Config.Update.activ').val == 0) { + + let desired_display_firmware_url ="" + + if(getState(NSPanel_Path + 'NSPanel_Version').val =="us-l"){ + desired_display_firmware_url = `http://nspanel.pky.eu/lovelace-ui/github/nspanel-us-l-${tft_version}.tft`; + }else if (getState(NSPanel_Path + 'NSPanel_Version').val =="us-p"){ + desired_display_firmware_url = `http://nspanel.pky.eu/lovelace-ui/github/nspanel-us-p-${tft_version}.tft`; + }else{ + desired_display_firmware_url = `http://nspanel.pky.eu/lovelace-ui/github/nspanel-${tft_version}.tft`; + } + + log('Start TFT-Upgrade for: ' + getState(NSPanel_Path + 'NSPanel_Version').val + ' Version', 'info'); + log('Install NextionTFT: ' + desired_display_firmware_url, 'info'); + + try { + + let urlString = `http://${get_current_tasmota_ip_address()}/cm?cmnd=FlashNextion ${desired_display_firmware_url}`; + if (tasmota_web_admin_password != '') { + urlString = `http://${get_current_tasmota_ip_address()}/cm?user=${tasmota_web_admin_user}&password=${tasmota_web_admin_password}&cmnd=FlashNextion ${desired_display_firmware_url}`; + } + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(response.data, 'info'); + } + await createStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { type: 'string' }); + await setStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { val: tft_version, ack: true }); + Init_Release(); + } else { + log('Axios Status - update_tft_firmware: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + } catch (err: any) { + log('error request in function update_tft_firmware: ' + err.message, 'warn'); + } + } +} + +function update_tasmota_firmware() { + try { + if (getState(NSPanel_Path + 'Config.Update.activ').val == 0) { + let urlString = `http://${get_current_tasmota_ip_address()}/cm?cmnd=OtaUrl ${tasmotaOtaUrl}${tasmotaOtaVersion}`; + if (tasmota_web_admin_password != '') { + urlString = `http://${get_current_tasmota_ip_address()}/cm?user=${tasmota_web_admin_user}&password=${tasmota_web_admin_password}&cmnd=OtaUrl ${tasmotaOtaUrl}${tasmotaOtaVersion}`; + } + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(response.data, 'info'); + } + } else { + log('Axios Status - update_tasmota_firmware ==> set OTA: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + urlString = `http://${get_current_tasmota_ip_address()}/cm?cmnd=Upgrade 1`; + if (tasmota_web_admin_password != '') { + urlString = `http://${get_current_tasmota_ip_address()}/cm?user=${tasmota_web_admin_user}&password=${tasmota_web_admin_password}&cmnd=Upgrade 1`; + } + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(response.data, 'info'); + } + } else { + log('Axios Status - update_tasmota_firmware: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + } + } catch (err: any) { + log('error request in function update_tasmota_firmware: ' + err.message, 'warn'); + } +} + +on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'INFO1', change: 'ne'}, async (obj) => { + try { + if (getState(NSPanel_Path + 'Config.Update.activ').val == 0) { + let Tasmota_JSON: any = JSON.parse(obj.state.val); + if (Tasmota_JSON.Info1.Version.indexOf('safeboot') != -1) { + log('Tasmota in Safeboot - Please wait while upgrading', 'warn'); + update_tasmota_firmware(); + } else { + log('Tasmota upgrade complete. New Version: ' + Tasmota_JSON.Info1.Version, 'info'); + get_tasmota_status0(); + //check_updates(); + } + } + } catch (err: any) { + log('error at trigger with reading senor-data: '+ err.message, 'warn'); + } +}); + +//------------------End Update Functions + +on({ id: config.panelRecvTopic, change: 'any' }, async function (obj) { + try { + if (obj.state.val.startsWith('\{"CustomRecv":')) { + try { + let json = JSON.parse(obj.state.val); + + let split = json.CustomRecv.split(','); + HandleMessage(split[0], split[1], parseInt(split[2]), split); + } catch (err: any) { + log('error json.split in Trigger panelRecTopic: ' + err.message, 'warn'); + } + } + } catch (err: any) { + log('error at Trigger panelRecTopic: ' + err.message, 'warn'); + } +}); + +async function SendToPanel(val: Payload | Payload[]) { + try { + if (Array.isArray(val)) { + val.forEach(function (id) { + setStateAsync(config.panelSendTopic, id.payload); + if (Debug) { + log('function SendToPanel payload: ' + id.payload, 'info'); + } + }); + } else { + setState(config.panelSendTopic, val.payload); + } + + } catch (err: any) { + log('error at function SendToPanel: ' + err.message, 'warn'); + } +} + +on({ id: NSPanel_Alarm_Path + 'Alarm.AlarmState', change: 'ne' }, async (obj) => { + try { + if ((obj.state ? obj.state.val : '') == 'armed' || (obj.state ? obj.state.val : '') == 'disarmed' || (obj.state ? obj.state.val : '') == 'triggered') { + if (Debug) { + log('Trigger AlarmState aktivePage: ' + activePage, 'info'); + } + if (NSPanel_Path == getState(NSPanel_Alarm_Path + 'Alarm.PANEL').val) { + if (activePage != undefined) GeneratePage(activePage!); + } + } + } catch (err: any) { + log('error at Trigger AlarmState: ' + err.message, 'warn'); + } +}); + +function HandleMessage(typ: string, method: string, page: number | undefined, words: Array | undefined): void { + try { + if (typ == 'event') { + switch (method) { + case 'startup': + screensaverEnabled = false; + UnsubscribeWatcher(); + HandleStartupProcess(); + pageId = 0; + GeneratePage(config.pages[0]); + if (Debug) log('HandleMessage -> Startup', 'info'); + Init_Release(); + break; + case 'sleepReached': + useMediaEvents = false; + screensaverEnabled = true; + if (pageId < 0) + pageId = 0; + HandleScreensaver(); + if (Debug) log('HandleMessage -> sleepReached', 'info'); + break; + case 'pageOpenDetail': + if (words != undefined) { + screensaverEnabled = false; + UnsubscribeWatcher(); + if (Debug) { + log('HandleMessage -> pageOpenDetail ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4], 'info'); + } + let tempId: PageItem['id']; + let tempPageItem = words[3].split('?'); + let placeId: number | undefined = undefined; + if (!isNaN(parseInt(tempPageItem[0]))){ + tempId = activePage!.items[tempPageItem[0]].id; + placeId = parseInt(tempPageItem[0]) + if (tempId == undefined) { + throw new Error(`Missing id in HandleMessage!`) + } + } else { + tempId = tempPageItem[0]; + } + let pageItem: PageItem = findPageItem(tempId); + if (pageItem !== undefined) { + let temp: string | mediaOptional | undefined = tempPageItem[1] + if (isMediaOptional(temp)) SendToPanel(GenerateDetailPage(words[2], temp, pageItem, placeId)); + else SendToPanel(GenerateDetailPage(words[2], undefined, pageItem, placeId)); + } + } + break; + case 'buttonPress2': + screensaverEnabled = false; + HandleButtonEvent(words); + if (Debug) { + if (words != undefined) log('HandleMessage -> buttonPress2 ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4], 'info'); + } + break; + case 'renderCurrentPage': + // Event only for HA at this Moment + if (Debug) log('renderCurrentPage', 'info'); + break; + case 'button1': + case 'button2': + screensaverEnabled = false; + HandleHardwareButton(method); + if (Debug) log('HandleMessage -> button1 / button2', 'info') + break; + default: + break; + } + } + } catch (err: any) { + log('error at function HandleMessage: ' + err.message, 'warn'); + } +} +//@ts-ignore ticaki bitte lösen, rückgabe kann undefined sein und ist es wenn ins catch gesprungen wird. +function findPageItem(searching: String): PageItem { + try { + + let pageItem = activePage!.items.find(e => e.id === searching); + + if (pageItem !== undefined) { + if (Debug) log('findPageItem -> pageItem ' + JSON.stringify(pageItem), 'info'); + return pageItem; + } + + config.subPages.every(sp => { + pageItem = sp.items.find(e => e.id === searching); + + return pageItem === undefined; + }); + + if (Debug) log('findPageItem -> pageItem SubPage ' + JSON.stringify(pageItem), 'info'); + //@ts-ignore ticaki bitte lösen, pageItem kann undefined sein. + return pageItem; + } catch (err: any) { + log('error at function findPageItem: ' + err.message, 'warn'); + } +} + +function GeneratePage(page: PageType): void { + try { + activePage = page; + setIfExists(NSPanel_Path + 'ActivePage.type', activePage!.type); + setIfExists(NSPanel_Path + 'ActivePage.heading', activePage!.heading); + setIfExists(NSPanel_Path + 'ActivePage.id0', activePage!.items[0].id); + switch (page.type) { + case 'cardEntities': + SendToPanel(GenerateEntitiesPage(page)); + break; + case 'cardThermo': + SendToPanel(GenerateThermoPage(page)); + break; + case 'cardGrid': + SendToPanel(GenerateGridPage(page)); + break; + case 'cardGrid2': + SendToPanel(GenerateGridPage2(page)); + break; + case 'cardMedia': + useMediaEvents = true; + SendToPanel(GenerateMediaPage(page)); + break; + case 'cardAlarm': + SendToPanel(GenerateAlarmPage(page)); + break; + case 'cardQR': + SendToPanel(GenerateQRPage(page)); + break; + case 'cardPower': + SendToPanel(GeneratePowerPage(page)); + break; + case 'cardChart': + SendToPanel(GenerateChartPage(page)); + break; + case 'cardLChart': + SendToPanel(GenerateChartPage(page)); + break; + case 'cardUnlock': + SendToPanel(GenerateUnlockPage(page)); + break; + } + } catch (err: any) { + if (err.message == "Cannot read properties of undefined (reading 'type')") { + log('Please wait a few seconds longer when launching the NSPanel. Not all parameters are loaded yet.', 'warn'); + } else { + log('error at function GeneratePage: ' + err.message, 'warn'); + } + } +} + +function HandleHardwareButton(method: string): void { + try { + let buttonConfig: ConfigButtonFunction = config[method]; + if(buttonConfig.mode === null) { + return; + } + switch(buttonConfig.mode) { + case 'page': + if (Debug) log('HandleHardwareButton -> Mode Page', 'info'); + if (buttonConfig.page) { + if(method == 'button1') { + pageId = -1; + } else if (method == 'button2') { + pageId = -2; + } + GeneratePage(buttonConfig.page); + break; + } + case 'toggle': + if (Debug) log('HandleHardwareButton -> Mode Toggle', 'info'); + if (buttonConfig.entity) { + let current = getState(buttonConfig.entity).val; + setState(buttonConfig.entity, !current); + } + screensaverEnabled = true; + break; + case 'set': + if (Debug) log('HandleHardwareButton -> Mode Set', 'info'); + if (buttonConfig.entity) { + setState(buttonConfig.entity, buttonConfig.setValue); + } + screensaverEnabled = true; + break; + } + } catch (err: any) { + log('error at function HandleHardwareButton: ' + err.message, 'warn'); + } +} + +function HandleStartupProcess(): void { + SendDate(); + SendTime(); + SendToPanel({ payload: 'timeout~' + getState(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver').val }); +} + +function SendDate(): void { + try { + if (existsObject(NSPanel_Path + 'Config.locale')) { + let dpWeekday = existsObject(NSPanel_Path + 'Config.Dateformat.weekday') ? getState(NSPanel_Path + 'Config.Dateformat.weekday').val : 'short'; + let dpMonth = existsObject(NSPanel_Path + 'Config.Dateformat.month') ? getState(NSPanel_Path + 'Config.Dateformat.month').val : 'short'; + let dpCustomFormat = existsObject(NSPanel_Path + 'Config.Dateformat.customFormat') ? getState(NSPanel_Path + 'Config.Dateformat.customFormat').val : ''; + + const date = new Date(); + const options: any = { weekday: dpWeekday, year: 'numeric', month: dpMonth, day: 'numeric' }; + const _SendDate = dpCustomFormat != '' ? dayjs().format(dpCustomFormat) : date.toLocaleDateString(getState(NSPanel_Path + 'Config.locale').val, options); + + SendToPanel({ payload: 'date~' + _SendDate }); + } + } catch (err: any) { + if (err.message = 'Cannot convert undefined or null to object') { + log('Datumsformat noch nicht initialisiert', 'info'); + } else { + log('error at function SendDate: ' + err.message, 'warn'); + } + } +} + +function SendTime(): void { + try { + const d = new Date(); + const hr = (d.getHours() < 10 ? '0' : '') + d.getHours(); + const min = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); + + SendToPanel({ payload: 'time~' + hr + ':' + min }); + } catch (err: any) { + log('error at function SendTime: ' + err.message, 'warn'); + } +} + +function GenerateEntitiesPage(page: PageEntities): Payload[] { + try { + let out_msgs: Array; + out_msgs = [{ payload: 'pageType~cardEntities' }] + out_msgs.push({ payload: GeneratePageElements(page) }); + return out_msgs + } catch (err: any) { + log('error at function GenerateEntitiesPage: ' + err.message, 'warn'); + return []; + } +} + +function GenerateGridPage(page: PageGrid): Payload[] { + try { + let out_msgs: Array = [{ payload: 'pageType~cardGrid' }]; + out_msgs.push({ payload: GeneratePageElements(page) }); + return out_msgs; + } catch (err: any) { + log('error at function GenerateGridPage: ' + err.message, 'warn'); + return []; + } +} + +function GenerateGridPage2(page: PageGrid2): Payload[] { + try { + let out_msgs: Array = [{ payload: 'pageType~cardGrid2' }]; + out_msgs.push({ payload: GeneratePageElements(page) }); + return out_msgs; + } catch (err: any) { + log('error at function GenerateGridPage2: ' + err.message, 'warn'); + return []; + } +} + +function GeneratePageElements(page: PageType): string { + try { + activePage = page; + let maxItems = 0; + switch (page.type) { + case 'cardThermo': + maxItems = 1; + break; + case 'cardAlarm': + maxItems = 1; + break; + case 'cardUnlock': + maxItems = 1; + break; + case 'cardMedia': + maxItems = 1; + break; + case 'cardQR': + maxItems = 1; + break; + case 'cardPower': + maxItems = 1; + break; + case 'cardChart': + maxItems = 1; + break; + case 'cardEntities': + if (getState(NSPanel_Path + 'NSPanel_Version').val == 'eu') { + maxItems = 4; + } else { + maxItems = 5; + } + break; + case 'cardGrid': + maxItems = 6; + break; + case 'cardGrid2': + maxItems = 8; + break; + } + + let pageData = 'entityUpd~' + page.heading + '~' + GetNavigationString(pageId); + + for (let index = 0; index < maxItems; index++) { + if (page.items[index] !== undefined) { + pageData += CreateEntity(page.items[index], index, 'useColor' in page ? page.useColor : false ); + } + } + if (Debug) log('GeneratePageElements pageData ' + pageData, 'info'); + return pageData; + } catch (err: any) { + log('error at function GeneratePageElements: ' + err.message, 'warn'); + return ''; + } +} + +function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = false): string { + try { + let iconId = '0'; + let iconId2 = '0'; + if (pageItem.id == 'delete') { + return '~delete~~~~~'; + } + + let name: string; + let buttonText: string = 'PRESS'; + let type: string; + + if (pageItem.id && existsState(pageItem.id + '.ACTUAL') == false) { + if (pageItem.popupTimerType == 'TimeCard' && pageItem.autoCreateALias == true) { + log(NSPanel_Path + 'Userdata.' + pageItem.id + '.Time') + createStateAsync(NSPanel_Path + 'Userdata.' + pageItem.id + '.Time', '0', { type: 'number' }); + createStateAsync(NSPanel_Path + 'Userdata.' + pageItem.id + '.State', 'idle', { type: 'string' }); + setObject(pageItem.id, { type: 'channel', common: { role: 'value.time', name: 'Time' }, native: {} }); + createAliasAsync(pageItem.id + '.ACTUAL', NSPanel_Path + 'Userdata.' + pageItem.id + '.Time', true, { type: 'number', role: 'state', name: 'ACTUAL' }); + createAliasAsync(pageItem.id + '.STATE', NSPanel_Path + 'Userdata.' + pageItem.id + '.State', true, { type: 'string', role: 'state', name: 'STATE' }); + } + } + + // ioBroker + if (pageItem.id && existsObject(pageItem.id) || pageItem.navigate === true) { + + let iconColor = rgb_dec565(config.defaultColor); + let optVal = '0'; + let val: any = null; + + let o:any + if (pageItem.id != null && existsObject(pageItem.id)) { + o = getObject(pageItem.id); + } + + // Fallback if no name is given + name = pageItem.name !== undefined ? pageItem.name : o.common.name.de == undefined ? o.common.name : o.common.name.de; + let prefix = pageItem.prefixName !== undefined ? pageItem.prefixName : ''; + let suffix = pageItem.suffixName !== undefined ? pageItem.suffixName : ''; + + // If name is used with changing values + if ((name || '').indexOf('getState(') != -1) { + let dpName: string = name.slice(10, name.length -6); + name = getState(dpName).val; + RegisterEntityWatcher(dpName); + } + name = prefix + name + suffix; + + if (existsState(pageItem.id + '.GET')) { + val = getState(pageItem.id + '.GET').val; + RegisterEntityWatcher(pageItem.id + '.GET'); + } + if(pageItem.monobutton != undefined && pageItem.monobutton == true){ + if (existsState(pageItem.id + '.ACTUAL')) { + val = getState(pageItem.id + '.ACTUAL').val; + RegisterEntityWatcher(pageItem.id + '.ACTUAL'); + } + } else { + if (existsState(pageItem.id + '.ACTUAL')) { + val = getState(pageItem.id + '.ACTUAL').val; + RegisterEntityWatcher(pageItem.id + '.ACTUAL'); + } + if (existsState(pageItem.id + '.SET')) { + val = getState(pageItem.id + '.SET').val; + RegisterEntityWatcher(pageItem.id + '.SET'); + } + } + if (existsState(pageItem.id + '.ON_ACTUAL')) { + val = getState(pageItem.id + '.ON_ACTUAL').val; + RegisterEntityWatcher(pageItem.id + '.ON_ACTUAL'); + } + if (existsState(pageItem.id + '.ON_SET')) { + val = getState(pageItem.id + '.ON_SET').val; + RegisterEntityWatcher(pageItem.id + '.ON_SET'); + } + if (existsState(pageItem.id + '.ON')) { + val = getState(pageItem.id + '.ON').val; + RegisterEntityWatcher(pageItem.id + '.ON'); + } + + if (pageItem.navigate) { + + if (pageItem.id == null && pageItem.targetPage != undefined) { + buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; + type = 'button'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('gesture-tap-button'); + iconColor = GetIconColor(pageItem, true, useColors); + + if (Debug) log('CreateEntity statisch Icon Navi ~' + type + '~' + 'navigate.' + pageItem.targetPage + '~' + iconId + '~' + iconColor + '~' + pageItem.name + '~' + buttonText, 'info') + return '~' + type + '~' + 'navigate.' + pageItem.targetPage + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; + + } else if (pageItem.id != null && pageItem.targetPage != undefined) { + + type = 'button'; + + switch (o.common.role) { + case 'socket': + case 'light': + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : iconId; + + buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : existsState(pageItem.id + '.BUTTONTEXT') ? getState(pageItem.id + '.BUTTONTEXT').val : 'PRESS'; + if (existsState(pageItem.id + '.COLORDEC')) { + iconColor = getState(pageItem.id + '.COLORDEC').val; + } else { + if (val === true || val === 'true') { + iconColor = GetIconColor(pageItem, true, useColors); + } else { + iconColor = GetIconColor(pageItem, false, useColors); + } + } + if (val === true || val === 'true') { iconId = iconId2 }; + break; + + case 'blind': + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('window-open'); + iconColor = existsState(pageItem.id + '.COLORDEC') ? getState(pageItem.id + '.COLORDEC').val : GetIconColor(pageItem, existsState(pageItem.id + '.ACTUAL') ? getState(pageItem.id + '.ACTUAL').val : true, useColors); + buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : existsState(pageItem.id + '.BUTTONTEXT') ? getState(pageItem.id + '.BUTTONTEXT').val : 'PRESS'; + break; + + case 'door': + case 'window': + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); + iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : o.common.role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); + + buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : existsState(pageItem.id + '.BUTTONTEXT') ? getState(pageItem.id + '.BUTTONTEXT').val : 'PRESS'; + if (existsState(pageItem.id + '.COLORDEC')) { + iconColor = getState(pageItem.id + '.COLORDEC').val; + } else { + if (val === true || val === 'true') { + iconColor = GetIconColor(pageItem, true, useColors); + } else { + iconColor = GetIconColor(pageItem, false, useColors); + } + } + if (val === true || val === 'true') { iconId = iconId2 }; + break; + + case 'info': + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('gesture-tap-button'); + iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : iconId; + + buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : existsState(pageItem.id + '.BUTTONTEXT') ? getState(pageItem.id + '.BUTTONTEXT').val : 'PRESS'; + if (existsState(pageItem.id + '.COLORDEC')) { + iconColor = getState(pageItem.id + '.COLORDEC').val; + } else { + if (val === true || val === 'true') { + iconColor = GetIconColor(pageItem, false, useColors); + } else { + iconColor = GetIconColor(pageItem, true, useColors); + } + } + + if (pageItem.colorScale != undefined) { + let iconvalmin = (pageItem.colorScale.val_min != undefined) ? pageItem.colorScale.val_min : 0 ; + let iconvalmax = (pageItem.colorScale.val_max != undefined) ? pageItem.colorScale.val_max : 100 ; + let iconvalbest = (pageItem.colorScale.val_best != undefined) ? pageItem.colorScale.val_best : iconvalmin ; + let valueScale = val; + + if (iconvalmin == 0 && iconvalmax == 1) { + iconColor = (getState(pageItem.id).val == 1) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); + } else { + if (iconvalbest == iconvalmin) { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0); + } else { + if (valueScale < iconvalbest) { + valueScale = scale(valueScale,iconvalmin, iconvalbest, 0, 10); + } else if (valueScale > iconvalbest || iconvalbest != iconvalmin) { + valueScale = scale(valueScale,iconvalbest, iconvalmax, 10, 0); + } else { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0); + } + } + let valueScaletemp = (Math.round(valueScale)).toFixed(); + iconColor = HandleColorScale(valueScaletemp); + } + } + + if (val === true || val === 'true') { iconId = iconId2 }; + break; + + case 'humidity': + + case 'temperature': + + case 'value.temperature': + + case 'value.humidity': + + case 'sensor.door': + + case 'sensor.window': + + case 'thermostat': + + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'temperature' || o.common.role == 'value.temperature' || o.common.role == 'thermostat' ? Icons.GetIcon('thermometer') : Icons.GetIcon('information-outline'); + + let unit = ''; + optVal = '0'; + + if (existsState(pageItem.id + '.ON_ACTUAL')) { + optVal = getState(pageItem.id + '.ON_ACTUAL').val; + unit = pageItem.unit !== undefined ? pageItem.unit : GetUnitOfMeasurement(pageItem.id + '.ON_ACTUAL'); + } else if (existsState(pageItem.id + '.ACTUAL')) { + optVal = getState(pageItem.id + '.ACTUAL').val; + unit = pageItem.unit !== undefined ? pageItem.unit : GetUnitOfMeasurement(pageItem.id + '.ACTUAL'); + } + + iconColor = GetIconColor(pageItem, parseInt(optVal), useColors); + + if (pageItem.colorScale != undefined) { + let iconvalmin = (pageItem.colorScale.val_min != undefined) ? pageItem.colorScale.val_min : 0 ; + let iconvalmax = (pageItem.colorScale.val_max != undefined) ? pageItem.colorScale.val_max : 100 ; + let iconvalbest = (pageItem.colorScale.val_best != undefined) ? pageItem.colorScale.val_best : iconvalmin ; + let valueScale = val; + + if (iconvalmin == 0 && iconvalmax == 1) { + iconColor = (getState(pageItem.id).val == 1) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); + } else { + if (iconvalbest == iconvalmin) { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0); + } else { + if (valueScale < iconvalbest) { + valueScale = scale(valueScale,iconvalmin, iconvalbest, 0, 10); + } else if (valueScale > iconvalbest || iconvalbest != iconvalmin) { + valueScale = scale(valueScale,iconvalbest, iconvalmax, 10, 0); + } else { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0); + } + } + let valueScaletemp = (Math.round(valueScale)).toFixed(); + iconColor = HandleColorScale(valueScaletemp); + } + } + + if (existsState(pageItem.id + '.USERICON')) { + iconId = Icons.GetIcon(getState(pageItem.id + '.USERICON').val); + if (Debug) log('iconid von ' + pageItem.id + '.USERICON: ' + getState(pageItem.id + '.USERICON').val, 'info'); + RegisterEntityWatcher(pageItem.id + '.USERICON'); + } + + if (pageItem.useValue) { + if (pageItem.fontSize != undefined) { + iconId = optVal + '¬' + pageItem.fontSize; + } else { + iconId = optVal; + } + } + + buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : existsState(pageItem.id + '.BUTTONTEXT') ? getState(pageItem.id + '.BUTTONTEXT').val : 'PRESS'; + break; + + case 'warning': + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('gesture-tap-button'); + iconColor = pageItem.onColor !== undefined ? GetIconColor(pageItem, true, useColors) : getState(pageItem.id + '.LEVEL').val; + name = pageItem.name !== undefined ? pageItem.name : getState(pageItem.id + '.INFO').val; + break; + + default: + buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : existsState(pageItem.id + '.BUTTONTEXT') ? getState(pageItem.id + '.BUTTONTEXT').val : 'PRESS'; + iconColor = pageItem.onColor !== undefined ? GetIconColor(pageItem, true, useColors) : existsState(pageItem.id + '.COLORDEC') ? getState(pageItem.id + '.COLORDEC').val : 65535; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('gesture-tap-button'); + break; + // return '~delete~~~~~'; + } + + if (Debug) log('CreateEntity Dynamische Icon Navi ~' + type + '~' + 'navigate.' + pageItem.targetPage + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText, 'info') + return '~' + type + '~' + 'navigate.' + pageItem.targetPage + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; + + } else { + type = 'button'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('gesture-tap-button'); + iconColor = GetIconColor(pageItem, true, useColors); + buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; + + if (Debug) log('CreateEntity Standard ~' + type + '~' + 'navigate.' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText, 'info') + return '~' + type + '~' + 'navigate.' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; + } + } + + switch (o.common.role) { + case 'socket': + case 'light': + type = 'light'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : o.common.role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + optVal = '0'; + + if (val === true || val === 'true') { + optVal = '1'; + iconColor = GetIconColor(pageItem, true, useColors); + } else { + iconColor = GetIconColor(pageItem, false, useColors); + if (pageItem.icon !== undefined) { + if (pageItem.icon2 !== undefined) { + iconId = iconId2; + } + } + } + + if (Debug) log('CreateEntity Icon role socket/light ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'hue': + type = 'light'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lightbulb'); + optVal = '0'; + + if (val === true || val === 'true') { + optVal = '1'; + iconColor = GetIconColor(pageItem, existsState(pageItem.id + '.DIMMER') ? getState(pageItem.id + '.DIMMER').val : true, useColors); + } else { + iconColor = GetIconColor(pageItem, false, useColors); + if (pageItem.icon !== undefined) { + if (pageItem.icon2 !== undefined) { + iconId = iconId2; + } + } + } + + if (pageItem.interpolateColor != undefined && pageItem.interpolateColor == true && val) { + if (existsState(pageItem.id + '.HUE')) { + if (getState(pageItem.id + '.HUE').val != null) { + let huecolor = hsv2rgb(getState(pageItem.id + '.HUE').val, 1, 1); + let rgb: 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); + } + } + } + + if (Debug) log('CreateEntity Icon role hue ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'ct': + type = 'light'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lightbulb'); + optVal = '0'; + + if (val === true || val === 'true') { + optVal = '1'; + iconColor = GetIconColor(pageItem, existsState(pageItem.id + '.DIMMER') ? getState(pageItem.id + '.DIMMER').val : true, useColors); + } else { + iconColor = GetIconColor(pageItem, false, useColors); + if (pageItem.icon !== undefined) { + if (pageItem.icon2 !== undefined) { + iconId = iconId2; + } + } + } + + if (Debug) log('CreateEntity Icon role ct ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'rgb': + type = 'light'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lightbulb'); + optVal = '0'; + + if (val === true || val === 'true') { + optVal = '1'; + iconColor = GetIconColor(pageItem, existsState(pageItem.id + '.DIMMER') ? getState(pageItem.id + '.DIMMER').val : true, useColors); + } else { + iconColor = GetIconColor(pageItem, false, useColors); + if (pageItem.icon !== undefined) { + if (pageItem.icon2 !== undefined) { + iconId = iconId2; + } + } + } + + if (existsState(pageItem.id + '.RED') && existsState(pageItem.id + '.GREEN') && existsState(pageItem.id + '.BLUE') && val) { + if (getState(pageItem.id + '.RED').val != null && getState(pageItem.id + '.GREEN').val != null && getState(pageItem.id + '.BLUE').val != null) { + let rgbRed = getState(pageItem.id + '.RED').val; + let rgbGreen = getState(pageItem.id + '.GREEN').val; + let rgbBlue = getState(pageItem.id + '.BLUE').val; + let rgb: RGB = { red: Math.round(rgbRed), green: Math.round(rgbGreen), blue: Math.round(rgbBlue) }; + iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); + } + } + + if (Debug) log('CreateEntity Icon role rgb ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'cie': + case 'rgbSingle': + type = 'light'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lightbulb'); + optVal = '0'; + + if (val === true || val === 'true') { + optVal = '1' + iconColor = GetIconColor(pageItem, existsState(pageItem.id + '.DIMMER') ? getState(pageItem.id + '.DIMMER').val : true, useColors); + } else { + iconColor = GetIconColor(pageItem, false, useColors); + if (pageItem.icon !== undefined) { + if (pageItem.icon2 !== undefined) { + iconId = iconId2; + } + } + } + + if (existsState(pageItem.id + '.RGB') && val) { + if (getState(pageItem.id + '.RGB').val != null) { + let hex = getState(pageItem.id + '.RGB').val; + let hexRed = parseInt(hex[1] + hex[2], 16); + let hexGreen = parseInt(hex[3] + hex[4], 16); + let hexBlue = parseInt(hex[5] + hex[6], 16); + let rgb: RGB = { red: Math.round(hexRed), green: Math.round(hexGreen), blue: Math.round(hexBlue) }; + iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); + } + } + + if (Debug) log('CreateEntity Icon role cie/rgbSingle ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'dimmer': + type = 'light'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lightbulb'); + optVal = '0'; + + if (val === true || val === 'true') { + optVal = '1'; + iconColor = GetIconColor(pageItem, existsState(pageItem.id + '.ACTUAL') ? getState(pageItem.id + '.ACTUAL').val : true, useColors); + } else { + iconColor = GetIconColor(pageItem, false, useColors); + if (pageItem.icon !== undefined) { + if (pageItem.icon2 !== undefined) { + iconId = iconId2; + } + } + } + + if (Debug) log('CreateEntity Icon role dimmer ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + 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); + + let min_Level: number = 0; + let max_Level: number = 100; + if (pageItem.minValueLevel !== undefined && pageItem.maxValueLevel !== undefined) { + min_Level = pageItem.minValueLevel; + max_Level = pageItem.maxValueLevel; + val = Math.trunc(scale(getState(pageItem.id + '.ACTUAL').val, pageItem.minValueLevel, pageItem.maxValueLevel, 100, 0)); + } + + let icon_up = Icons.GetIcon('arrow-up'); + let icon_stop = Icons.GetIcon('stop'); + let icon_down = Icons.GetIcon('arrow-down'); + + if (Debug) log('pageItem.id: ' + getState(pageItem.id + '.ACTUAL').val, 'info'); + if (Debug) log('min_Level: ' + min_Level, 'info'); + if (Debug) log('max_Level: ' + max_Level, 'info'); + + let tempVal: number = getState(pageItem.id + '.ACTUAL').val + let icon_up_status = tempVal === min_Level ? 'disable' : 'enable'; + let icon_stop_status = 'enable'; + if (tempVal === min_Level || tempVal === max_Level || checkBlindActive === false) { + icon_stop_status = 'disable'; + } + let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; + let value = icon_up + '|' + icon_stop + '|' + icon_down + '|' + icon_up_status + '|' + icon_stop_status + '|' + icon_down_status + + if (Debug) log('CreateEntity Icon role blind ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + value, 'info'); + + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + value; + + case 'gate': + type = 'text'; + let gateState: string | undefined = undefined; + if (existsState(pageItem.id + '.ACTUAL')) { + + if (getState(pageItem.id + '.ACTUAL').val == 0 || getState(pageItem.id + '.ACTUAL').val === false) { + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('garage'); + iconColor = GetIconColor(pageItem, false, useColors); + gateState = findLocale('window', 'closed'); + } else { + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('garage-open'); + iconId = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : Icons.GetIcon('garage-open'); + iconColor = GetIconColor(pageItem, true, useColors); + gateState = findLocale('window', 'opened'); + } + + } + if (gateState == undefined) { + throw new Error(`Missing ${pageItem.id}.ACTUAL for type ${type}`) + } + + if (Debug) log('CreateEntity Icon role gate ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + gateState; + + case 'door': + case 'window': + type = 'text'; + let windowState; + + if (existsState(pageItem.id + '.ACTUAL')) { + if (getState(pageItem.id + '.ACTUAL').val) { + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); + iconColor = GetIconColor(pageItem, true, useColors); + windowState = findLocale('window', 'opened'); + } else { + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); + iconId = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : iconId; + iconColor = GetIconColor(pageItem, false, useColors); + windowState = findLocale('window', 'closed'); + } + } + + if (Debug) log('CreateEntity Icon role door/window ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + windowState; + + case 'motion': + type = 'text'; + if (val === true) { + optVal = 'On'; + iconColor = GetIconColor(pageItem, true, useColors); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('motion-sensor'); + } else { + optVal = 'Off'; + iconColor = GetIconColor(pageItem, false, useColors); + iconId = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : Icons.GetIcon('motion-sensor'); + } + + if (Debug) log('CreateEntity Icon role motion ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'info': + + case 'humidity': + + case 'temperature': + + case 'value.temperature': + + case 'value.humidity': + + case 'sensor.door': + + case 'sensor.window': + + case 'thermostat': + type = 'text'; + + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'temperature' || o.common.role == 'value.temperature' || o.common.role == 'thermostat' ? Icons.GetIcon('thermometer') : Icons.GetIcon('information-outline'); + + let unit = ''; + optVal = '0'; + + if (existsState(pageItem.id + '.ON_ACTUAL')) { + optVal = getState(pageItem.id + '.ON_ACTUAL').val; + unit = pageItem.unit !== undefined ? pageItem.unit : GetUnitOfMeasurement(pageItem.id + '.ON_ACTUAL'); + } else if (existsState(pageItem.id + '.ACTUAL')) { + optVal = getState(pageItem.id + '.ACTUAL').val; + unit = pageItem.unit !== undefined ? pageItem.unit : GetUnitOfMeasurement(pageItem.id + '.ACTUAL'); + } + + iconColor = GetIconColor(pageItem, parseInt(optVal), useColors); + + if (pageItem.colorScale != undefined) { + let iconvalmin = (pageItem.colorScale.val_min != undefined) ? pageItem.colorScale.val_min : 0 ; + let iconvalmax = (pageItem.colorScale.val_max != undefined) ? pageItem.colorScale.val_max : 100 ; + let iconvalbest = (pageItem.colorScale.val_best != undefined) ? pageItem.colorScale.val_best : iconvalmin ; + let valueScale = val; + + if (iconvalmin == 0 && iconvalmax == 1) { + iconColor = (!pageItem.id || getState(pageItem.id).val == 1) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); + } else { + if (iconvalbest == iconvalmin) { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0); + } else { + if (valueScale < iconvalbest) { + valueScale = scale(valueScale,iconvalmin, iconvalbest, 0, 10); + } else if (valueScale > iconvalbest || iconvalbest != iconvalmin) { + valueScale = scale(valueScale,iconvalbest, iconvalmax, 10, 0); + } else { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0); + } + } + let valueScaletemp = (Math.round(valueScale)).toFixed(); + iconColor = HandleColorScale(valueScaletemp); + } + } + + if (existsState(pageItem.id + '.USERICON')) { + iconId = Icons.GetIcon(getState(pageItem.id + '.USERICON').val); + if (Debug) log('iconid von ' + pageItem.id + '.USERICON: ' + getState(pageItem.id + '.USERICON').val, 'info'); + RegisterEntityWatcher(pageItem.id + '.USERICON'); + } + + if (pageItem.useValue) { + if (pageItem.fontSize != undefined) { + iconId = optVal + '¬' + pageItem.fontSize; + } else { + iconId = optVal; + } + } + + if (Debug) log('CreateEntity Icon role info, humidity, temperature, value.temperature, value.humidity, sensor.door, sensor.window, thermostat', 'info'); + if (Debug) log('CreateEntity ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal+ ' ' + unit, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal + ' ' + unit; + + case 'buttonSensor': + + type = 'input_sel'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('gesture-tap-button'); + iconColor = GetIconColor(pageItem, true, useColors); + let inSelText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; + + if (Debug) log('CreateEntity Icon role buttonSensor ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + inSelText; + + case 'button': + type = 'button'; + + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('gesture-tap-button'); + iconColor = GetIconColor(pageItem, true, useColors); + if (val === false) { + iconColor = GetIconColor(pageItem, false, useColors); + } + + let buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; + + if (Debug) log('CreateEntity Icon role button ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; + case 'value.time': + case 'level.timer': + type = 'timer'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('gesture-tap-button'); + iconColor = GetIconColor(pageItem, true, useColors); + let timerText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; + + if (existsState(pageItem.id + '.STATE')) { + val = getState(pageItem.id + '.STATE').val; + RegisterEntityWatcher(pageItem.id + '.STATE'); + } + + if (Debug) log('CreateEntity Icon role level.timer ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + timerText; + + case 'value.alarmtime': + type = 'timer'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('timer-outline'); + let alarmtimerText = pageItem.buttonText !== undefined ? pageItem.buttonText : 'PRESS'; + + if (existsState(pageItem.id + '.STATE')) { + val = getState(pageItem.id + '.STATE').val; + iconColor = (val == 'paused') ? rgb_dec565(colorScale10) : rgb_dec565(colorScale0); + } + + if (existsState(pageItem.id + '.ACTUAL')) { + let timer_actual = getState(pageItem.id + '.ACTUAL').val + name = ('0' + String(Math.floor(timer_actual / 60))).slice(-2) + ':' + ('0' + String(timer_actual % 60)).slice(-2); + } + + if (Debug) log('CreateEntity Icon role value.alarmtime ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText + ' ' + val, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + alarmtimerText; + + case 'level.mode.fan': + + type = 'fan'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('fan'); + optVal = '0'; + + if (val === true || val === 'true') { + optVal = '1'; + iconColor = GetIconColor(pageItem, true, useColors); + } else { + iconColor = GetIconColor(pageItem, false, useColors); + if (pageItem.icon !== undefined) { + if (pageItem.icon2 !== undefined) { + iconId = iconId2; + } + } + } + + if (Debug) log('CreateEntity Icon role level.mode.fan ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + optVal; + + case 'lock': + type = 'button'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('lock'); + iconColor = GetIconColor(pageItem, true, useColors); + let lockState; + + 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); + lockState = findLocale('lock', 'UNLOCK'); + } else { + iconId = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : Icons.GetIcon('lock-open-variant'); + iconColor = GetIconColor(pageItem, false, useColors); + lockState = findLocale('lock', 'LOCK'); + } + lockState = pageItem.buttonText !== undefined ? pageItem.buttonText : lockState; + } + + if (Debug) log('CreateEntity Icon role lock ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + lockState; + + case 'slider': + type = 'number'; + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : Icons.GetIcon('plus-minus-variant'); + + iconColor = GetIconColor(pageItem, false, useColors); + + if (Debug) log('CreateEntity Icon role slider ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); + return '~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue; + + case 'volumeGroup': + case 'volume': + type = 'number'; + 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'); + } + + if (Debug) log('CreateEntity Icon role volumeGroup/volume ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + val + '|' + pageItem.minValue + '|' + pageItem.maxValue, 'info'); + return '~' + type + '~' + placeId + '~' + 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; + + RegisterEntityWatcher(pageItem.id + '.LEVEL'); + RegisterEntityWatcher(pageItem.id + '.INFO'); + + if (pageItem.useValue) { + iconId = itemInfo; + } + + if (Debug) log('CreateEntity Icon role warning ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + itemName + '~' + itemInfo, 'info'); + return '~' + type + '~' + itemName + '~' + iconId + '~' + iconColor + '~' + itemName + '~' + itemInfo; + + case 'timeTable': + type = 'text'; + let itemFahrzeug:string = getState(pageItem.id + '.VEHICLE').val; + let itemUhrzeit:string = getState(pageItem.id + '.ACTUAL').val; + let itemRichtung:string = getState(pageItem.id + '.DIRECTION').val; + let itemVerspaetung:boolean = getState(pageItem.id + '.DELAY').val; + + if (Icons.GetIcon(itemFahrzeug) != "") { + iconId = Icons.GetIcon(itemFahrzeug) + }else { + iconId='' + }; + + iconColor = (!itemVerspaetung) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); + + if (Debug) log('CreateEntity Icon role timeTable ~' + type + '~' + itemRichtung + '~' + iconId + '~' + iconColor + '~' + itemRichtung + '~' + itemUhrzeit, 'info'); + return '~' + type + '~' + itemRichtung + '~' + iconId + '~' + iconColor + '~' + itemRichtung + '~' + itemUhrzeit; + + default: + if (Debug) log('CreateEntity Icon keine passende Rolle gefunden', 'warn'); + return '~delete~~~~~'; + } + } + if (Debug) log('CreateEntity return ~delete~~~~~', 'info'); + return '~delete~~~~~'; + } catch (err: any) { + if (err.message == "Cannot read properties of undefined (reading 'common')") { + log('Found Alias without channel: ' + pageItem.id + '! Please correct the Alias', 'warn'); + return ''; + } else { + log('error at function CreateEntity: ' + err.message, 'warn'); + return ''; + } + } +} + +function findLocale(controlsObject: string, controlsState: string): string { + const locale = getState(NSPanel_Path + 'Config.locale').val; + const strJson = getState(NSPanel_Path + 'NSPanel_locales_json').val; + + if (Debug) { + log(controlsObject + ' - ' + controlsState, 'info'); + } + + try { + const obj = JSON.parse(strJson); + const strLocale = obj[controlsObject][controlsState][locale]; + + if (strLocale != undefined) { + return strLocale; + } else { + return controlsState; + } + + } catch (err: any) { + if (err.message.substring(0, 35) == 'Cannot read properties of undefined') { + if (Debug) { + log('function findLocale: missing translation: ' + controlsObject + ' - ' + controlsState, 'info'); + } + } else { + log('error at function findLocale: ' + err.message, 'warn'); + } + return controlsState; + } +} + +function findLocaleServMenu(controlsState: string): string { + const locale = getState(NSPanel_Path + 'Config.locale').val; + const strJson = getState(NSPanel_Path + 'NSPanel_locales_service_json').val; + + if (Debug) { + log(controlsState, 'info'); + } + + try { + const obj = JSON.parse(strJson); + const strLocale = obj[controlsState][locale]; + + if (strLocale != undefined) { + return strLocale; + } else { + if (obj[controlsState]['en-US'] != undefined) { + return obj[controlsState]['en-US']; + } else { + return controlsState; + } + } + + } catch (err: any) { + if (err.message.substring(0, 35) == 'Cannot read properties of undefined') { + if (Debug) { + log('function findLocale: missing translation: ' + controlsState, 'info'); + } + } else { + log('error at function findLocale: ' + err.message, 'warn'); + } + return controlsState; + } +} + +function GetIconColor(pageItem: PageItem, value: (boolean | number), useColors: boolean): number { + try { + // dimmer + if ((pageItem.useColor || useColors) && pageItem.interpolateColor && typeof (value) === 'number') { + let maxValue = pageItem.maxValueBrightness !== undefined ? pageItem.maxValueBrightness : 100; + let minValue = pageItem.minValueBrightness !== undefined ? pageItem.minValueBrightness : 0; + if (pageItem.maxValue !== undefined) maxValue = pageItem.maxValue; + if (pageItem.minValue !== undefined) minValue = pageItem.minValue; + value = value > maxValue ? maxValue : value; + value = value < minValue ? minValue : value; + + return rgb_dec565( + Interpolate( + pageItem.offColor !== undefined ? pageItem.offColor : config.defaultOffColor, + pageItem.onColor !== undefined ? pageItem.onColor : config.defaultOnColor, + scale(100 - value, minValue, maxValue, 0, 1) + ) + ); + } + + if ((pageItem.useColor || useColors) && (typeof (value) === 'boolean' && value) || ((typeof (value) === 'number') && (value > (pageItem.minValueBrightness !== undefined ? pageItem.minValueBrightness : 0)))) { + return rgb_dec565(pageItem.onColor !== undefined ? pageItem.onColor : config.defaultOnColor); + } + + return rgb_dec565(pageItem.offColor !== undefined ? pageItem.offColor : config.defaultOffColor); + } catch (err: any) { + log('error at function GetIconColor: ' + err.message, 'warn'); + return -1; + } +} + +function RegisterEntityWatcher(id: string): void { + try { + if (subscriptions.hasOwnProperty(id)) { + return; + } + + subscriptions[id] = (on({ id: id, change: 'any' }, () => { + if (pageId == -1 && config.button1.page) { + SendToPanel({ payload: GeneratePageElements(config.button1.page) }); + } + if (pageId == -2 && config.button2.page) { + SendToPanel({ payload: GeneratePageElements(config.button2.page) }); + } + if (activePage !== undefined) { + SendToPanel({ payload: GeneratePageElements(activePage!) }); + } + })); + } catch (err: any) { + log('error at function RegisterEntityWatcher: ' + err.message, 'warn'); + } +} + +function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: string, placeId: number | undefined): void { + try { + if (subscriptions.hasOwnProperty(id)) { + return; + } + + if (Debug) log('id: ' + id + ' - pageItem: ' + JSON.stringify(pageItem) + ' - type: ' + type + ' - placeId: ' + placeId, 'info'); + + subscriptions[id] = (on({ id: id, change: 'any' }, () => { + SendToPanel(GenerateDetailPage(type, undefined, pageItem, placeId)); + })) + } catch (err: any) { + log('error at function RegisterDetailEntityWatcher: ' + err.message, 'warn'); + } +} + +function GetUnitOfMeasurement(id: string): string { + try { + if (!existsObject(id)) + return ''; + + let obj = getObject(id); + if (typeof obj.common.unit !== 'undefined') { + return obj.common.unit; + } + + if (typeof obj.common.alias !== 'undefined' && typeof obj.common.alias.id !== 'undefined') { + return GetUnitOfMeasurement(obj.common.alias.id); + } + + return ''; + } catch (err: any) { + log('error at function GetUnitOfMeasurement: ' + err.message, 'warn'); + return '' + } +} + +function GenerateThermoPage(page: PageThermo): Payload[] { + try { + UnsubscribeWatcher(); + let id = page.items[0].id + let out_msgs: Array = []; + out_msgs.push({ payload: 'pageType~cardThermo' }); + + // ioBroker + if (id && existsObject(id)) { + let o = getObject(id); + let name = page.heading !== undefined ? page.heading : o.common.name.de; + let currentTemp = 0; + if (existsState(id + '.ACTUAL')) { + currentTemp = (Math.round(parseFloat(getState(id + '.ACTUAL').val) * 10) / 10); + } + + let 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 = page.items[0].stepValue !== undefined ? page.items[0].stepValue : 5; //Default 0,5° Schritte + + let destTemp = 0; + if (existsState(id + '.SET')) { + // using minValue, if .SET is null (e.g. for tado AWAY or tado is off) + let setValue = getState(id + '.SET').val; + if (setValue == null) { + setValue = minTemp; + } + + destTemp = setValue.toFixed(2) * 10; + } + let statusStr: String = 'MANU'; + + if (existsState(id + '.MODE') && getState(id + '.MODE').val != null) { + if (getState(id + '.MODE').val === 1) { + statusStr = 'MANU'; + } else { + statusStr = 'AUTO'; + } + } + + //Add attributes if defined in alias + let i_list = Array.prototype.slice.apply($('[state.id="' + id + '.*"]')); + let bt = ['~~~~', '~~~~', '~~~~', '~~~~', '~~~~', '~~~~', '~~~~', '~~~~', '~~~~']; + + let tempIcon: string = ''; + + if ((i_list.length - 3) != 0) { + + let i = 0; + switch (o.common.role) { + case 'thermostat': { + + if (existsState(id + '.AUTOMATIC') && getState(id + '.AUTOMATIC').val != null) { + if (getState(id + '.AUTOMATIC').val) { + bt[i++] = Icons.GetIcon('alpha-a-circle') + '~' + rgb_dec565(On) + '~1~' + 'AUTT' + '~'; + statusStr = 'AUTO'; + } else { + bt[i++] = Icons.GetIcon('alpha-a-circle') + '~33840~1~' + 'AUTT' + '~'; + } + } + if (existsState(id + '.MANUAL') && getState(id + '.MANUAL').val != null) { + if (getState(id + '.MANUAL').val) { + bt[i++] = Icons.GetIcon('alpha-m-circle') + '~' + rgb_dec565(On) + '~1~' + 'MANT' + '~'; + statusStr = 'MANU'; + } else { + bt[i++] = Icons.GetIcon('alpha-m-circle') + '~33840~1~' + 'MANT' + '~'; + } + } + if (existsState(id + '.PARTY') && getState(id + '.PARTY').val != null) { + if (getState(id + '.PARTY').val) { + bt[i++] = Icons.GetIcon('party-popper') + '~' + rgb_dec565(On) + '~1~' + 'PART' + '~'; + statusStr = 'PARTY'; + } else { + bt[i++] = Icons.GetIcon('party-popper') + '~33840~1~' + 'PART' + '~'; + } + } + if (existsState(id + '.VACATION') && getState(id + '.VACATION').val != null) { + if (getState(id + '.VACATION').val) { + bt[i++] = Icons.GetIcon('palm-tree') + '~' + rgb_dec565(On) + '~1~' + 'VACT' + '~'; + statusStr = 'VAC'; + } else { + bt[i++] = Icons.GetIcon('palm-tree') + '~33840~1~' + 'VACT' + '~'; + } + } + if (existsState(id + '.BOOST') && getState(id + '.BOOST').val != null) { + if (getState(id + '.BOOST').val) { + bt[i++] = Icons.GetIcon('fast-forward-60') + '~' + rgb_dec565(On) + '~1~' + 'BOOT' + '~'; + statusStr = 'BOOST'; + } else { + bt[i++] = Icons.GetIcon('fast-forward-60') + '~33840~1~' + 'BOOT' + '~'; + } + } + + for (let i_index in i_list) { + let thermostatState = i_list[i_index].split('.'); + if ( + thermostatState[thermostatState.length - 1] != 'SET' && + thermostatState[thermostatState.length - 1] != 'ACTUAL' && + thermostatState[thermostatState.length - 1] != 'MODE' + ) { + i++; + + switch (thermostatState[thermostatState.length - 1]) { + case 'HUMIDITY': + if (existsState(id + '.HUMIDITY') && getState(id + '.HUMIDITY').val != null) { + if (parseInt(getState(id + '.HUMIDITY').val) < 40) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~65504~1~' + 'HUM' + '~'; + } else if (parseInt(getState(id + '.HUMIDITY').val) < 30) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~63488~1~' + 'HUM' + '~'; + } else if (parseInt(getState(id + '.HUMIDITY').val) >= 40) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~2016~1~' + 'HUM' + '~'; + } else if (parseInt(getState(id + '.HUMIDITY').val) > 65) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~65504~1~' + 'HUM' + '~'; + } else if (parseInt(getState(id + '.HUMIDITY').val) > 75) { + bt[i - 1] = Icons.GetIcon('water-percent') + '~63488~1~' + 'HUM' + '~'; + } + } else i--; + break; + case 'LOWBAT': + if (existsState(id + '.LOWBAT') && getState(id + '.LOWBAT').val != null) { + if (getState(id + '.LOWBAT').val) { + bt[i - 1] = Icons.GetIcon('battery-low') + '~63488~1~' + 'LBAT' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('battery-high') + '~2016~1~' + 'LBAT' + '~'; + } + } else i--; + break; + case 'MAINTAIN': + if (existsState(id + '.MAINTAIN') && getState(id + '.MAINTAIN').val != null) { + if (getState(id + '.MAINTAIN').val >> .1) { + bt[i - 1] = Icons.GetIcon('account-wrench') + '~60897~1~' + 'MAIN' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('account-wrench') + '~33840~1~' + 'MAIN' + '~'; + } + } else i--; + break; + case 'UNREACH': + if (existsState(id + '.UNREACH') && getState(id + '.UNREACH').val != null) { + if (getState(id + '.UNREACH').val) { + bt[i - 1] = Icons.GetIcon('wifi-off') + '~63488~1~' + 'WLAN' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('wifi') + '~2016~1~' + 'WLAN' + '~'; + } + } else i--; + break; + case 'POWER': + if (existsState(id + '.POWER') && getState(id + '.POWER').val != null) { + if (getState(id + '.POWER').val) { + bt[i - 1] = Icons.GetIcon('power-standby') + '~2016~1~' + '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~' + 'ERR' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('alert-circle') + '~33840~1~' + 'ERR' + '~'; + } + } else i--; + break; + case 'WORKING': + if (existsState(id + '.WORKING') && getState(id + '.WORKING').val != null) { + if (getState(id + '.WORKING').val) { + bt[i - 1] = Icons.GetIcon('briefcase-check') + '~2016~1~' + 'WORK' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('briefcase-check') + '~33840~1~' + 'WORK' + '~'; + } + } else i--; + break; + case 'WINDOWOPEN': + if (existsState(id + '.WINDOWOPEN') && getState(id + '.WINDOWOPEN').val != null) { + if (getState(id + '.WINDOWOPEN').val) { + bt[i - 1] = Icons.GetIcon('window-open-variant') + '~63488~1~' + 'WIN' + '~'; + } else { + bt[i - 1] = Icons.GetIcon('window-closed-variant') + '~2016~1~' + 'WIN' + '~'; + } + } else i--; + break; + default: + i--; + break; + } + } + } + + for (let j = i; j < 9; j++) { + bt[j] = '~~~~'; + } + } + break; + case 'airCondition': { + if (existsState(id + '.MODE') && getState(id + '.MODE').val != null) { + let Mode = getState(id + '.MODE').val + let States = getObject(id + '.MODE').common.states; + + let iconIndex: number = 1; + for (const statekey in States) { + let stateName: string = States[statekey]; + let stateKeyNumber: number = parseInt(statekey); + if (stateName == 'OFF' || stateKeyNumber > 6) { + continue; + } + if (stateKeyNumber == Mode) { + statusStr = stateName.replace('_', ' '); + } + + switch (stateName) { + case 'AUTO': + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[1] !== '') { + tempIcon = page.items[0].iconArray[1]; + } else { + tempIcon = 'air-conditioner'; + } + if (stateKeyNumber == Mode) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~1024~1~' + 'AUTO' + '~'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'AUTO' + '~'; + } + break; + case 'COOL': + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[2] !== '') { + tempIcon = page.items[0].iconArray[2]; + } else { + tempIcon = 'snowflake'; + } + if (stateKeyNumber == Mode) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~11487~1~' + 'COOL' + '~'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'COOL' + '~'; + } + break; + case 'HEAT': + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[3] !== '') { + tempIcon = page.items[0].iconArray[3]; + } else { + tempIcon = 'fire'; + } + if (stateKeyNumber == Mode) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~64512~1~' + 'HEAT' + '~'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'HEAT' + '~'; + } + break; + case 'ECO': + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[4] !== '') { + tempIcon = page.items[0].iconArray[4]; + } else { + tempIcon = 'alpha-e-circle-outline'; + } + if (stateKeyNumber == Mode) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~2016~1~' + 'ECO' + '~'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'ECO' + '~'; + } + break; + case 'FAN_ONLY': + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[5] !== '') { + tempIcon = page.items[0].iconArray[5]; + } else { + tempIcon = 'fan'; + } + if (stateKeyNumber == Mode) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~11487~1~' + 'FAN_ONLY' + '~'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'FAN_ONLY' + '~'; + } + break; + case 'DRY': + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[6] !== '') { + tempIcon = page.items[0].iconArray[6]; + } else { + tempIcon = 'water-percent'; + } + if (stateKeyNumber == Mode) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~60897~1~' + 'DRY' + '~'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'DRY' + '~'; + } + break; + } + iconIndex++; + } + + if (iconIndex <= 7 && existsState(id + '.ECO') && getState(id + '.ECO').val != null) { + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[4] !== '') { + tempIcon = page.items[0].iconArray[4]; + } else { + tempIcon = 'alpha-e-circle-outline'; + } + if (getState(id + '.ECO').val && getState(id + '.ECO').val == 1) { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~2016~1~' + 'ECO' + '~'; + statusStr = 'ECO'; + } else { + bt[iconIndex] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'ECO' + '~'; + } + iconIndex++; + } + + if (iconIndex <= 7 && existsState(id + '.SWING') && getState(id + '.SWING').val != null) { + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[7] !== '') { + tempIcon = page.items[0].iconArray[7]; + } else { + tempIcon = 'swap-vertical-bold'; + } + if (getState(id + '.POWER').val && getState(id + '.SWING').val == 1) { //0=ON oder .SWING = true + bt[7] = Icons.GetIcon(tempIcon) + '~2016~1~' + 'SWING' + '~'; + } else { + bt[7] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'SWING' + '~'; + } + iconIndex++; + } + + // Power Icon zuletzt pruefen, damit der Mode ggf. mit OFF ueberschrieben werden kann + if (existsState(id + '.POWER') && getState(id + '.POWER').val != null) { + if (page.items[0].iconArray !== undefined && page.items[0].iconArray[0] !== '') { + tempIcon = page.items[0].iconArray[0]; + } else { + tempIcon = 'power-standby'; + } + if (States[Mode] == 'OFF' || !getState(id + '.POWER').val) { + bt[0] = Icons.GetIcon(tempIcon) + '~35921~0~' + 'POWER' + '~'; + statusStr = 'OFF'; + } + else { + bt[0] = Icons.GetIcon(tempIcon) + '~2016~1~' + 'POWER' + '~'; + } + } + } + } + break; + } + } + + let destTemp2 = ''; + if (page.items[0].setThermoDestTemp2 != undefined) { + let setValue2 = getState(id + '.' + page.items[0].setThermoDestTemp2).val; + destTemp2 = '' + setValue2.toFixed(2) * 10; + } + + let thermoPopup = 1; + if (page.items[0].popupThermoMode1 != undefined) { + thermoPopup = 0; + } + + let temperatureUnit = getState(NSPanel_Path + 'Config.temperatureUnit').val; + + let icon_res = bt[0] + bt[1] + bt[2] + bt[3] + bt[4] + bt[5] + bt[6] + bt[7]; + + out_msgs.push({ + payload: 'entityUpd~' + + name + '~' // Heading + + GetNavigationString(pageId) + '~' // Page Navigation + + id + '~' // internalNameEntity + + currentTemp + temperatureUnit+ '~' // Actual temperature (string) + + destTemp + '~' // Target temperature (numeric without comma) + + statusStr + '~' // Mode + + minTemp + '~' // Thermostat min temperature + + maxTemp + '~' // Thermostat max temperatur + + stepTemp + '~' // Steps for Target (5°C) + + icon_res // Icons Status + + findLocale('thermostat', 'Currently') + '~' // Identifier in front of Current room temperature + + findLocale('thermostat', 'State') + '~~' // Bezeichner vor State + + temperatureUnit + '~' // iconTemperature dstTempTwoTempMode + + destTemp2 + '~' // dstTempTwoTempMode --> Wenn Wert, dann 2 Temp + + thermoPopup // PopUp + + }); + + } + + if (Debug) { + log('GenerateThermoPage payload: ' + out_msgs, 'info'); + } + return out_msgs; + } catch (err: any) { + log('error at function GenerateThermoPage: ' + err.message, 'warn'); + return []; + } +} + +function unsubscribeMediaSubscriptions(): void { + for (let i = 0; i < config.pages.length; i++) { + if (config.pages[i].type == 'cardMedia') { + let mediaID = config.pages[i].items[0].id; + unsubscribe(mediaID + '.STATE'); + unsubscribe(mediaID + '.ARTIST'); + unsubscribe(mediaID + '.TITLE'); + unsubscribe(mediaID + '.ALBUM'); + unsubscribe(mediaID + '.VOLUME'); + unsubscribe(mediaID + '.REPEAT'); + unsubscribe(mediaID + '.SHUFFLE'); + unsubscribe(mediaID + '.QUEUE'); + unsubscribe(mediaID + '.DURATION'); + unsubscribe(mediaID + '.ELAPSED'); + } + } + for (let i = 0; i < config.subPages.length; i++) { + if (config.subPages[i].type == 'cardMedia') { + let mediaID = config.subPages[i].items[0].id; + unsubscribe(mediaID + '.STATE'); + unsubscribe(mediaID + '.ARTIST'); + unsubscribe(mediaID + '.TITLE'); + unsubscribe(mediaID + '.ALBUM'); + unsubscribe(mediaID + '.VOLUME'); + unsubscribe(mediaID + '.REPEAT'); + unsubscribe(mediaID + '.SHUFFLE'); + unsubscribe(mediaID + '.QUEUE'); + unsubscribe(mediaID + '.DURATION'); + unsubscribe(mediaID + '.ELAPSED'); + } + } + if (Debug) log('unsubscribeMediaSubscriptions gestartet', 'info'); +} + +function subscribeMediaSubscriptions(id: string): void { + on({id: [id + '.STATE', + id + '.VOLUME', + id + '.ARTIST', + id + '.ALBUM', + id + '.TITLE', + id + '.REPEAT', + id + '.SHUFFLE'], change: "any"}, async function () { + (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); + timeoutMedia = setTimeout(async function () { + if (useMediaEvents) { + GeneratePage(activePage!); + setTimeout(async function () { + GeneratePage(activePage!); + }, 3000); + } + },50) + }); +} + +function subscribeMediaSubscriptionsSonosAdd(id: string): void { + on({id: [id + '.QUEUE', + id + '.DURATION', + id + '.ELAPSED'], change: "any"}, async function () { + (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); + timeoutMedia = setTimeout(async function () { + if (useMediaEvents) { + GeneratePage(activePage!); + setTimeout(async function () { + GeneratePage(activePage!); + }, 50); + } + },50) + }); +} + +function subscribeMediaSubscriptionsAlexaAdd(id: string): void { + on({id: [id + '.DURATION', + id + '.ELAPSED'], change: "any"}, async function () { + (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); + timeoutMedia = setTimeout(async function () { + if (useMediaEvents) { + GeneratePage(activePage!); + setTimeout(async function () { + GeneratePage(activePage!); + }, 50); + } + },50) + }); +} + +async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPlayerInstance: adapterPlayerInstanceType) { + if (autoCreateAlias) { + if (isSetOptionActive) { + switch (adapterPlayerInstance) { + case "alexa2.0.": + case "alexa2.1.": + case "alexa2.2.": + case "alexa2.3.": + case "alexa2.4.": + case "alexa2.5.": + case "alexa2.6.": + case "alexa2.7.": + case "alexa2.8.": + case "alexa2.9.": { + if (existsObject(id) == false) { + log('Alexa Alias ' + id + ' does not exist - will be created now', 'info'); + + const dpPath: string = adapterPlayerInstance + 'Echo-Devices.' + mediaDevice; + try { + setObject(id, {_id: id, type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); + await createAliasAsync(id + '.ACTUAL', dpPath + '.Player.volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); + await createAliasAsync(id + '.ALBUM', dpPath + '.Player.currentAlbum', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); + await createAliasAsync(id + '.ARTIST', dpPath + '.Player.currentArtist', true, {type: 'string', role: 'media.artist', name: 'ARTIST'}); + await createAliasAsync(id + '.TITLE', dpPath + '.Player.currentTitle', true, {type: 'string', role: 'media.title', name: 'TITLE'}); + await createAliasAsync(id + '.NEXT', dpPath + '.Player.controlNext', true, {type: 'boolean', role: 'button.next', name: 'NEXT'}); + await createAliasAsync(id + '.PREV', dpPath + '.Player.controlPrevious', true, {type: 'boolean', role: 'button.prev', name: 'PREV'}); + await createAliasAsync(id + '.PLAY', dpPath + '.Player.controlPlay', true, {type: 'boolean', role: 'button.play', name: 'PLAY'}); + await createAliasAsync(id + '.PAUSE', dpPath + '.Player.controlPause', true, {type: 'boolean', role: 'button.pause', name: 'PAUSE'}); + await createAliasAsync(id + '.STOP', dpPath + '.Commands.deviceStop', true, {type: 'boolean', role: 'button.stop', name: 'STOP'}); + await createAliasAsync(id + '.STATE', dpPath + '.Player.currentState', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); + await createAliasAsync(id + '.VOLUME', dpPath + '.Player.volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.REPEAT', dpPath + '.Player.controlRepeat', true, {type: 'boolean', role: 'media.mode.repeat', name: 'REPEAT'}); + await createAliasAsync(id + '.SHUFFLE', dpPath + '.Player.controlShuffle', true, {type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE'}); + } catch (err: any) { + log('error at function createAutoMediaAlias Adapter Alexa2: ' + err.message, 'warn'); + } + } + //Add Alexa Datapoints > v4.3.3.18 + if (existsObject(id + '.DURATION') == false) { + let dpPath: string = adapterPlayerInstance + 'Echo-Devices.' + mediaDevice; + await createAliasAsync(id + '.DURATION', dpPath + '.Player.mediaLength', true, {type: 'string', role: 'media.duration.text', name: 'DURATION'}); + await createAliasAsync(id + '.ELAPSED', dpPath + '.Player.mediaProgressStr', true, {type: 'string', role: 'media.elapsed.text', name: 'ELAPSED'}); + } + + } + break; + case "sonos.0.": + case "sonos.1.": + case "sonos.2.": + case "sonos.3.": + case "sonos.4.": + case "sonos.5.": + case "sonos.6.": + case "sonos.7.": + case "sonos.8.": + case "sonos.9.": { + if (existsObject(id) == false) { + log('Sonos Alias ' + id + ' does not exist - will be created now', 'info'); + + const dpPath: string = adapterPlayerInstance + 'root.' + mediaDevice; + try { + setObject(id, {_id: id, type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); + await createAliasAsync(id + '.ACTUAL', dpPath + '.volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); + await createAliasAsync(id + '.ALBUM', dpPath + '.current_album', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); + await createAliasAsync(id + '.ARTIST', dpPath + '.current_artist', true, {type: 'string', role: 'media.artist', name: 'ARTIST'}); + await createAliasAsync(id + '.TITLE', dpPath + '.current_title', true, {type: 'string', role: 'media.title', name: 'TITLE'}); + await createAliasAsync(id + '.CONTEXT_DESCRIPTION', dpPath + '.current_station', true, {type: 'string', role: 'media.station', name: 'CONTEXT_DESCRIPTION'}); + await createAliasAsync(id + '.NEXT', dpPath + '.next', true, {type: 'boolean', role: 'button.next', name: 'NEXT'}); + await createAliasAsync(id + '.PREV', dpPath + '.prev', true, {type: 'boolean', role: 'button.prev', name: 'PREV'}); + await createAliasAsync(id + '.PLAY', dpPath + '.play', true, {type: 'boolean', role: 'button.play', name: 'PLAY'}); + await createAliasAsync(id + '.PAUSE', dpPath + '.pause', true, {type: 'boolean', role: 'button.pause', name: 'PAUSE'}); + await createAliasAsync(id + '.STOP', dpPath + '.stop', true, {type: 'boolean', role: 'button.stop', name: 'STOP'}); + await createAliasAsync(id + '.STATE', dpPath + '.state_simple', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); + await createAliasAsync(id + '.VOLUME', dpPath + '.volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.REPEAT', dpPath + '.repeat', true, {type: 'number', role: 'media.mode.repeat', name: 'REPEAT'}); + await createAliasAsync(id + '.SHUFFLE', dpPath + '.shuffle', true, {type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE'}); + } catch (err: any) { + log('error at function createAutoMediaAlias Adapter sonos: ' + err.message, 'warn'); + } + } + //Add Sonos Datapoints > v4.3.3.15 + if (existsObject(id + '.QUEUE') == false) { + let dpPath: string = adapterPlayerInstance + 'root.' + mediaDevice; + await createAliasAsync(id + '.QUEUE', dpPath + '.queue', true, {type: 'string', role: 'state', name: 'QUEUE'}); + await createAliasAsync(id + '.DURATION', dpPath + '.current_duration_s', true, {type: 'string', role: 'media.duration.text', name: 'DURATION'}); + await createAliasAsync(id + '.ELAPSED', dpPath + '.current_elapsed_s', true, {type: 'string', role: 'media.elapsed.text', name: 'ELAPSED'}); + } + + } + break; + case "spotify-premium.0.": + case "spotify-premium.1.": + case "spotify-premium.2.": + case "spotify-premium.3.": + case "spotify-premium.4.": + case "spotify-premium.5.": + case "spotify-premium.6.": + case "spotify-premium.7.": + case "spotify-premium.8.": + case "spotify-premium.9.": { + if (existsObject(id) == false) { + log('Spotify Alias ' + id + ' does not exist - will be created now', 'info'); + + const dpPath: string = adapterPlayerInstance; + try { + setObject(id, {_id: id + 'player', type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); + await createAliasAsync(id + '.ACTUAL', dpPath + 'player.volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); + await createAliasAsync(id + '.ALBUM', dpPath + 'player.album', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); + await createAliasAsync(id + '.ARTIST', dpPath + 'player.artistName', true, {type: 'string', role: 'media.artist', name: 'ARTIST'}); + await createAliasAsync(id + '.TITLE', dpPath + 'player.trackName', true, {type: 'string', role: 'media.title', name: 'TITLE'}); + await createAliasAsync(id + '.CONTEXT_DESCRIPTION', dpPath + 'player.contextDescription', true, {type: 'string', role: 'media.station', name: 'CONTEXT_DESCRIPTION'}); + await createAliasAsync(id + '.NEXT', dpPath + 'player.skipPlus', true, {type: 'boolean', role: 'button.next', name: 'NEXT'}); + await createAliasAsync(id + '.PREV', dpPath + 'player.skipMinus', true, {type: 'boolean', role: 'button.prev', name: 'PREV'}); + await createAliasAsync(id + '.PLAY', dpPath + 'player.play', true, {type: 'boolean', role: 'button.play', name: 'PLAY'}); + await createAliasAsync(id + '.PAUSE', dpPath + 'player.pause', true, {type: 'boolean', role: 'button.pause', name: 'PAUSE'}); + await createAliasAsync(id + '.STOP', dpPath + 'player.pause', true, {type: 'boolean', role: 'button.stop', name: 'STOP'}); + await createAliasAsync(id + '.STATE', dpPath + 'player.isPlaying', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); + await createAliasAsync(id + '.VOLUME', dpPath + 'player.volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.REPEAT', dpPath + 'player.repeat', true, {type: 'string', role: 'value', name: 'REPEAT'}); + await createAliasAsync(id + '.SHUFFLE', dpPath + 'player.shuffle', true, {type: 'string', role: 'value', name: 'SHUFFLE'}); + + } catch (err: any) { + log('error at function createAutoMediaAlias Adapter spotify-premium: ' + err.message, 'warn'); + } + } + + } + break; + case "volumio.0.": + case "volumio.1.": + case "volumio.2.": + case "volumio.3.": + case "volumio.4.": + case "volumio.5.": + case "volumio.6.": + case "volumio.7.": + case "volumio.8.": + case "volumio.9.": { + if (existsObject(id) == false) { + log('Volumio Alias ' + id + ' does not exist - will be created now', 'info'); + + const dpPath: string = adapterPlayerInstance; + try { + setObject(id, {_id: id, type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); + await createAliasAsync(id + '.ACTUAL', dpPath + 'playbackInfo.volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); + await createAliasAsync(id + '.ALBUM', dpPath + 'playbackInfo.album', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); + await createAliasAsync(id + '.ARTIST', dpPath + 'playbackInfo.artist', true, {type: 'string', role: 'media.artist', name: 'ARTIST'}); + await createAliasAsync(id + '.TITLE', dpPath + 'playbackInfo.title', true, {type: 'string', role: 'media.title', name: 'TITLE'}); + await createAliasAsync(id + '.NEXT', dpPath + 'player.next', true, {type: 'boolean', role: 'button.next', name: 'NEXT'}); + await createAliasAsync(id + '.PREV', dpPath + 'player.prev', true, {type: 'boolean', role: 'button.prev', name: 'PREV'}); + await createAliasAsync(id + '.PLAY', dpPath + 'player.play', true, {type: 'boolean', role: 'button.play', name: 'PLAY'}); + await createAliasAsync(id + '.PAUSE', dpPath + 'player.toggle', true, {type: 'boolean', role: 'button.pause', name: 'PAUSE'}); + await createAliasAsync(id + '.STOP', dpPath + 'player.stop', true, {type: 'boolean', role: 'button.stop', name: 'STOP'}); + await createAliasAsync(id + '.STATE', dpPath + 'playbackInfo.status', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); + await createAliasAsync(id + '.VOLUME', dpPath + 'playbackInfo.volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.REPEAT', dpPath + 'playbackInfo.repeat', true, {type: 'number', role: 'media.mode.repeat', name: 'REPEAT'}); + await createAliasAsync(id + '.SHUFFLE', dpPath + 'queue.shuffle', true, {type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE'}); + await createAliasAsync(id + '.status', dpPath + 'playbackInfo.status', true, {type: 'string', role: 'media.state', name: 'status'}); + } catch (err: any) { + log('error function createAutoMediaAlias Adapter volumio: ' + err.message, 'warn'); + } + } + + } + break; + case "squeezeboxrpc.0.": + case "squeezeboxrpc.1.": + case "squeezeboxrpc.2.": + case "squeezeboxrpc.3.": + case "squeezeboxrpc.4.": + case "squeezeboxrpc.5.": + case "squeezeboxrpc.6.": + case "squeezeboxrpc.7.": + case "squeezeboxrpc.8.": + case "squeezeboxrpc.9.": { + if (existsObject(id) == false) { + log('Squeezebox Alias ' + id + ' does not exist - will be created now', 'info'); + + const dpPath: string = adapterPlayerInstance + 'Players.' + mediaDevice; + try { + setObject(id, {_id: id, type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); + await createAliasAsync(id + '.ALBUM', dpPath + '.Album', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); + await createAliasAsync(id + '.ARTIST', dpPath + '.Artist', true, {type: 'string', role: 'media.artist', name: 'ARTIST'}); + await createAliasAsync(id + '.TITLE', dpPath + '.Title', true, {type: 'string', role: 'media.title', name: 'TITLE'}); + await createAliasAsync(id + '.NEXT', dpPath + '.btnForward', true, {type: 'boolean', role: 'button.forward', name: 'NEXT'}); + await createAliasAsync(id + '.PREV', dpPath + '.btnRewind', true, {type: 'boolean', role: 'button.reverse', name: 'PREV'}); + await createAliasAsync(id + '.PLAY', dpPath + '.state', true, {type: 'boolean', role: 'media.state', name: 'PLAY', alias: {id: dpPath + '.state', read: 'val === 1 ? true : false'}}); + await createAliasAsync(id + '.PAUSE', dpPath + '.state', true, {type: 'boolean', role: 'media.state', name: 'PAUSE', alias: {id: dpPath + '.state', read: 'val === 0 ? true : false'}}); + await createAliasAsync(id + '.STOP', dpPath + '.state', true, {type: 'boolean', role: 'media.state', name: 'STOP', alias: {id: dpPath + '.state', read: 'val === 0 ? true : false'}}); + await createAliasAsync(id + '.STATE', dpPath + '.Power', true, {type: 'number', role: 'switch', name: 'STATE'}); + await createAliasAsync(id + '.VOLUME', dpPath + '.Volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.VOLUME_ACTUAL', dpPath + '.Volume', true, {type: 'number', role: 'value.volume', name: 'VOLUME_ACTUAL'}); + await createAliasAsync(id + '.SHUFFLE', dpPath + '.PlaylistShuffle', true, {type: 'string', role: 'media.mode.shuffle', name: 'SHUFFLE', alias: {id: dpPath + '.PlaylistShuffle', read: 'val !== 0 ? \'on\' : \'off\'', write: 'val === \'off\' ? 0 : 1'}}); + await createAliasAsync(id + '.REPEAT', dpPath + '.PlaylistRepeat', true, {type: 'number', role: 'media.mode.repeat', name: 'REPEAT'}); + } catch (err: any) { + log('error at function createAutoMediaAlias Adapter Squeezebox: ' + err.message, 'warn'); + } + } + + } + break; + case "bosesoundtouch.0.": + case "bosesoundtouch.1.": + case "bosesoundtouch.2.": + case "bosesoundtouch.3.": + case "bosesoundtouch.4.": + case "bosesoundtouch.5.": + case "bosesoundtouch.6.": + case "bosesoundtouch.7.": + case "bosesoundtouch.8.": + case "bosesoundtouch.9.": { + if (existsObject(id) == false) { + log('bosesoundtouch Alias ' + id + ' does not exist - will be created now', 'info'); + + try { + let dpPath: string = adapterPlayerInstance + 'keys'; + await extendObjectAsync(id, {_id: id, type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); + await createAliasAsync(id + '.ACTUAL', dpPath + '.volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); + await createAliasAsync(id + '.VOLUME', dpPath + '.volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + + dpPath = adapterPlayerInstance + 'nowPlaying'; + await createAliasAsync(id + '.ALBUM', dpPath + '.album', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); + await createAliasAsync(id + '.ARTIST', dpPath + '.artist', true, {type: 'string', role: 'media.artist', name: 'ARTIST'}); + await createAliasAsync(id + '.TITLE', dpPath + '.track', true, {type: 'string', role: 'media.title', name: 'TITLE'}); + await createAliasAsync(id + '.DURATION', dpPath + '.total', true, {type: 'string', role: 'media.duration.text', name: 'DURATION'}); + await createAliasAsync(id + '.ELAPSED', dpPath + '.time', true, {type: 'string', role: 'media.elapsed.text', name: 'ELAPSED'}); + await createAliasAsync(id + '.REPEAT', dpPath + '.repeat', true, {type: 'boolean', role: 'media.mode.repeat', name: 'REPEAT'}); + await createAliasAsync(id + '.SHUFFLE', dpPath + '.shuffle', true, {type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE'}); + + dpPath = adapterPlayerInstance + 'keys'; + await createAliasAsync(id + '.STATE', dpPath + '.POWER', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); + await createAliasAsync(id + '.NEXT', dpPath + '.NEXT_TRACK', true, {type: 'boolean', role: 'button.next', name: 'NEXT'}); + await createAliasAsync(id + '.PREV', dpPath + '.PREV_TRACK', true, {type: 'boolean', role: 'button.prev', name: 'PREV'}); + await createAliasAsync(id + '.PLAY', dpPath + '.PLAY', true, {type: 'boolean', role: 'button.play', name: 'PLAY'}); + await createAliasAsync(id + '.PAUSE', dpPath + '.PAUSE', true, {type: 'boolean', role: 'button.pause', name: 'PAUSE'}); + await createAliasAsync(id + '.STOP', dpPath + '.STOP', true, {type: 'boolean', role: 'button.stop', name: 'STOP'}); + } catch (err: any) { + log('error at function createAutoMediaAlias Adapter bosesoundtouch: ' + err.message, 'warn'); + } + } + break; + } + default: { + log(`Dont find adapterPlayerInstance: ${adapterPlayerInstance}!`, 'warn') + } + } + } + } +} + +function GenerateMediaPage(page: PageMedia): Payload[] { + try { + unsubscribeMediaSubscriptions(); + + if (!page.items[0].id) throw new Error ('Missing page id for cardMedia!'); + + let id = page.items[0].id; + let out_msgs: Array = []; + + if (!page.items[0].adapterPlayerInstance!) throw new Error('page.items[0].adapterPlayerInstance is undefined!') + let vInstance = page.items[0].adapterPlayerInstance!; + let v1Adapter = vInstance.split('.'); + let v2Adapter:PlayerType = v1Adapter[0] as PlayerType; + + // Some magic to change the ID of the alias, since speakers are not a property but separate objects + if(v2Adapter == 'squeezeboxrpc') { + if(id && getObject(id).type != 'channel') { + id = id + '.' + page.items[0].mediaDevice; + page.items[0].id = id; + page.heading = page.items[0].mediaDevice ?? ''; + } else { + let idParts = id.split('.'); + if(idParts[idParts.length-1] !== page.items[0].mediaDevice) { + idParts[idParts.length-1] = page.items[0].mediaDevice ?? ''; + id = idParts.join('.'); + page.items[0].id = id; + page.heading = page.items[0].mediaDevice ?? ''; + } + } + } + + let vMediaDevice = (page.items[0].mediaDevice != undefined) ? page.items[0].mediaDevice : ''; + if (!vMediaDevice) throw new Error(`Error in cardMedia! mediaDevice is empty! Page: ${JSON.stringify(page)}`); + createAutoMediaAlias(id, vMediaDevice, page.items[0].adapterPlayerInstance!); + + // Leave the display on if the alwaysOnDisplay parameter is specified (true) + if (page.type == 'cardMedia' && pageCounter == 0 && page.items[0].alwaysOnDisplay != undefined) { + out_msgs.push({ payload: 'pageType~cardMedia' }); + if (page.items[0].alwaysOnDisplay != undefined) { + if (page.items[0].alwaysOnDisplay) { + pageCounter = 1; + if (alwaysOn == false) { + alwaysOn = true; + SendToPanel({ payload: 'timeout~0' }); + subscribeMediaSubscriptions(page.items[0].id); + if (v2Adapter == 'sonos') { + subscribeMediaSubscriptionsSonosAdd(page.items[0].id); + } else if (v2Adapter == 'alexa2') { + subscribeMediaSubscriptionsAlexaAdd(page.items[0].id); + } + } + } + } + } else if (page.type == 'cardMedia' && pageCounter == 1) { + alwaysOn = true; + subscribeMediaSubscriptions(page.items[0].id); + if (v2Adapter == 'sonos') { + subscribeMediaSubscriptionsSonosAdd(page.items[0].id); + } else if (v2Adapter == 'alexa2') { + subscribeMediaSubscriptionsAlexaAdd(page.items[0].id); + } + } else if (page.type == 'cardMedia' && pageCounter == -1) { + //Do Nothing + } else { + out_msgs.push({ payload: 'pageType~cardMedia' }); + } + + if (existsObject(id)) { + let name = getState(id + '.ALBUM').val; + let title = getState(id + '.TITLE').val; + if (title.length > 27) { + title = title.slice(0, 27) + '...'; + } + if (existsObject(id + '.DURATION') && existsObject(id + '.ELAPSED')) { + if (v2Adapter == 'alexa2') { + if (Debug) log(getState(id + '.DURATION').val, 'info'); + let Seconds = parseInt(getState(id + '.DURATION').val)%60 < 10 ? '0' : '' + let Duration = Math.floor(getState(id + '.DURATION').val/60) + ":" + Seconds + getState(id + '.DURATION').val%60 + let vElapsed = getState(id + '.ELAPSED').val; + if (vElapsed.length == 5) { + if(parseInt(vElapsed.slice(0,2)) < 9) { + vElapsed = vElapsed.slice(1); + } + } + let vDuration = Duration; + if (vDuration.length == 5) { + if(parseInt(vDuration.slice(0,2)) < 9) { + vDuration = vDuration.slice(1); + } + } + title = title + ' (' + vElapsed + '|' + vDuration + ')'; + } else if (v2Adapter == 'sonos' && getState(page.items[0].adapterPlayerInstance + 'root.' + page.items[0].mediaDevice + '.current_type').val == 0) { + let vElapsed = getState(id + '.ELAPSED').val; + if (vElapsed.length == 5) { + if(parseInt(vElapsed.slice(0,2)) < 9) { + vElapsed = vElapsed.slice(1); + } + } else if (vElapsed.length == 8) { + vElapsed = vElapsed.slice(4); + } + let vDuration = getState(id + '.DURATION').val; + if (vDuration.length == 5) { + if(parseInt(vDuration.slice(0,2)) < 9) { + vDuration = vDuration.slice(1); + } + } else if (vDuration.length == 8) { + vDuration = vDuration.slice(4); + } + title = title + ' (' + vElapsed + '|' + vDuration + ')'; + } + } + let author = getState(id + '.ARTIST').val; + let shuffle = getState(id + '.SHUFFLE').val; + + //New Adapter/Player + let media_icon = Icons.GetIcon('playlist-music'); + + //Spotify-Premium + if (v2Adapter == 'spotify-premium') { + media_icon = Icons.GetIcon('spotify'); + name = getState(id + '.CONTEXT_DESCRIPTION').val; + let nameLength = name.length; + if (name.substring(0,9) == 'Playlist:') { + name = name.slice(10, 26) + '...'; + } else if (name.substring(0,6) == 'Album:') { + name = name.slice(7, 23) + '...'; + } else if (name.substring(0,6) == 'Track') { + name = 'Spotify-Premium'; + } + if (nameLength == 0) { + name = 'Spotify-Premium'; + } + author = getState(id + '.ARTIST').val + ' | ' + getState(id + '.ALBUM').val; + if (author.length > 30) { + author = getState(id + '.ARTIST').val; + } + if ((getState(id + '.ARTIST').val).length == 0) { + author = findLocale('media','no_music_to_control'); + } + } + + //Sonos + if (v2Adapter == 'sonos') { + media_icon = Icons.GetIcon('alpha-s-circle'); + name = getState(id + '.CONTEXT_DESCRIPTION').val; + let nameLenght = name.length; + if (nameLenght == 0) { + name = page.heading; + } else if (nameLenght > 16) { + name = name.slice(0,16) + '...' + } + if ((getState(id + '.ALBUM').val).length > 0) { + author = getState(id + '.ARTIST').val + ' | ' + getState(id + '.ALBUM').val; + if (author.length > 37) { + author = author.slice(0,37) + '...'; + } + } else { + author = getState(id + '.ARTIST').val; + } + if ((getState(id + '.ARTIST').val).length == 0) { + author = findLocale('media','no_music_to_control'); + } + } + + //Logitech Squeezebox RPC + if (v2Adapter == 'squeezeboxrpc') { + media_icon = Icons.GetIcon('dlna'); + let nameLength = name.length; + if (nameLength == 0) { + name = page.items[0].mediaDevice; + } + } + + //Alexa2 + if (v2Adapter == 'alexa2') { + media_icon = Icons.GetIcon('alpha-a-circle'); + name = getState(id + '.ALBUM').val; + let nameLength = name.length; + if (name.substring(0,9) == 'Playlist:') { + name = name.slice(10, 26) + '...'; + } else if (name.substring(0,6) == 'Album:') { + name = name.slice(7, 23) + '...'; + } else if (name.substring(0,6) == 'Track') { + name = 'Alexa Player'; + } + if (nameLength == 0) { + name = 'Alexa Player'; + } + author = getState(id + '.ARTIST').val + ' | ' + getState(id + '.ALBUM').val; + if (author.length > 30) { + author = getState(id + '.ARTIST').val; + } + if ((getState(id + '.ARTIST').val).length == 0) { + author = findLocale('media','no_music_to_control'); + } + } + + //Volumio + if (v2Adapter == 'volumio') { + if (name != undefined) { author = author + " [" + name + "]"; } + name = getState(vInstance + 'info.name').val; /* page.heading; + getState(id + '.TRACK').val; */ + } + + let volume = getState(id + '.VOLUME').val; + let iconplaypause = Icons.GetIcon('pause'); //pause + let shuffle_icon = Icons.GetIcon('shuffle-variant'); //shuffle + let onoffbutton = 1374; + + if (shuffle == 'off' || shuffle == false || shuffle == 0) { + shuffle_icon = Icons.GetIcon('shuffle-disabled'); //shuffle + } + if (v2Adapter == 'volumio') { shuffle_icon = Icons.GetIcon('refresh'); } //Volumio: refresh playlist + + + //For all players + if (getState(id + '.STATE').val) { + onoffbutton = 65535; + iconplaypause = Icons.GetIcon('pause'); //pause + } else { + iconplaypause = Icons.GetIcon('play'); //play + } + + //Ausnahme für squeezebox, da State = Power + if (v2Adapter == 'squeezeboxrpc') { + if (getState(id + '.PAUSE').val === false) { + onoffbutton = 65535; + iconplaypause = Icons.GetIcon('pause'); //pause + } else { + iconplaypause = Icons.GetIcon('play'); //play + } + } + + //Ausnahme Volumio: status = string: play, pause, stop usw. + if (v2Adapter == 'volumio') { + if (getState(id + '.status').val == 'play') { + onoffbutton = 65535; + iconplaypause = Icons.GetIcon('pause'); //pause + } else { + iconplaypause = Icons.GetIcon('play'); //play + } + } + + let currentSpeaker = findLocale('media','no_speaker_found'); + + if (v2Adapter == 'alexa2') { + currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'Echo-Devices.', page.items[0].mediaDevice, '.Info.name'].join(''))).val; + } else if (v2Adapter == 'spotify-premium') { + currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'player.device.name'].join(''))).val; + } else if (v2Adapter == 'sonos') { + currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'root.', page.items[0].mediaDevice, '.members'].join(''))).val; + } else if (v2Adapter == 'squeezeboxrpc') { + currentSpeaker = getState(([page.items[0].adapterPlayerInstance, '.Players.', page.items[0].mediaDevice, '.Playername'].join(''))).val; + } + //------------------------------------------------------------------------------------------------------------- + // All Alexa devices (the online / player and commands directory is available) are listed and linked below + // If the constant alexaSpeakerList contains at least one entry, the constant is used - otherwise all devices from the Alexa adapter + let speakerListArray: Array = []; + if (page.items[0].speakerList && page.items[0].speakerList.length > 0) { + for (let i_index in page.items[0].speakerList) { + speakerListArray.push(page.items[0].speakerList[i_index]); + } + } else if (v2Adapter == 'squeezeboxrpc') { + // Beim Squeezeboxrpc ist jeder Player ein eigener Knoten im Objektbaum. Somit werden einzelne Aliase benötigt. + const squeezeboxPlayerQuery: iobJS.QueryResult = $('channel[state.id=' + page.items[0].adapterPlayerInstance + '.Players.*.Playername]'); + squeezeboxPlayerQuery.each((playerId: string, playerIndex: number) => { + speakerListArray.push(getState(playerId).val); + page.items[0].speakerList = speakerListArray; + }); + } else { + let i_list = Array.prototype.slice.apply($('[state.id="' + page.items[0].adapterPlayerInstance + 'Echo-Devices.*.Info.name"]')); + for (let i_index in i_list) { + let i = i_list[i_index]; + let deviceId = i; + deviceId = deviceId.split('.'); + if (getState(([page.items[0].adapterPlayerInstance, 'Echo-Devices.', deviceId[3], '.online'].join(''))).val && + existsObject(([page.items[0].adapterPlayerInstance, 'Echo-Devices.', deviceId[3], '.Player'].join(''))) && + existsObject(([page.items[0].adapterPlayerInstance, 'Echo-Devices.', deviceId[3], '.Commands'].join('')))) { + speakerListArray.push(getState(i).val); + } + } + } + //-------------------------------------------------------------------------------------------------------------- + + let colMediaIcon = (page.items[0].colorMediaIcon != undefined) ? page.items[0].colorMediaIcon : White; + let colMediaTitle = (page.items[0].colorMediaTitle != undefined) ? page.items[0].colorMediaTitle : White; + let colMediaArtist = (page.items[0].colorMediaArtist != undefined) ? page.items[0].colorMediaArtist : White; + + //InSel Speaker + let speakerListString: string = '~~~~~~' + let speakerListIconCol = rgb_dec565(HMIOff); + if (speakerListArray.length > 0) { + speakerListIconCol = rgb_dec565(HMIOn); + speakerListString = 'input_sel' + '~' + + id + '?speakerlist' + '~' + + Icons.GetIcon('speaker') + '~' + + speakerListIconCol + '~' + + findLocale('media','speaker') + '~' + + 'media0~' + } + + //InSel Playlist + let playListString: string = '~~~~~~' + let playListIconCol = rgb_dec565(HMIOff); + if (page.items[0].playList != undefined) { + /* Volumio: get actual playlist if empty */ + if (v2Adapter == 'volumio') { + if (page.items[0].playList.length == 0) { + + let urlString: string = `${getState(vInstance+'info.host').val}/api/listplaylists`; + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(JSON.stringify(response.data), 'info'); + } + page.items[0].playList = JSON.parse(JSON.stringify(response.data)); + if (Debug) log('volumio-playlist: ' + page.items[0].playList, 'info'); + } else { + log('Axios Status - get_volumio-playlist: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + } + } + playListIconCol = rgb_dec565(HMIOn); + playListString = 'input_sel' + '~' + + id + '?playlist' + '~' + + Icons.GetIcon('playlist-play') + '~' + + playListIconCol + '~' + + //'PlayL ' + page.heading + '~' + + findLocale('media','playlist') + '~' + + 'media1~' + } + + //InSel Tracklist + globalTracklist = '' + if (v2Adapter == 'spotify-premium') { + globalTracklist = ' ' //Todo + } + let trackListString: string = '~~~~~~' + let trackListIconCol = rgb_dec565(HMIOff); + if (v2Adapter == 'volumio') { /* Volumio: get queue */ + setTimeout(async function () { + + let urlString: string = `${getState(vInstance+'info.host').val}/api/getQueue`; + + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(JSON.stringify(response.data), 'info'); + } + const QUEUELIST = JSON.parse(JSON.stringify(response.data)); + page.items[0].globalTracklist = QUEUELIST.queue; + if (Debug) { + for (let i_index in QUEUELIST.queue) { + log('volumio-queue: ' + QUEUELIST.queue[i_index], 'info'); + } + } + } else { + log('Axios Status - get_volumio-queue: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + + }, 2000); + globalTracklist = page.items[0].globalTracklist; + } else if(v2Adapter == 'squeezeboxrpc' && existsObject(([page.items[0].adapterPlayerInstance, '.Players.', page.items[0].mediaDevice, '.Playlist'].join('')))) { + let lmstracklist = JSON.parse(getState(([page.items[0].adapterPlayerInstance, '.Players.', page.items[0].mediaDevice, '.Playlist'].join(''))).val); + globalTracklist = lmstracklist; + } else if(v2Adapter == 'sonos' && existsObject(([page.items[0].adapterPlayerInstance, 'root.', page.items[0].mediaDevice, '.playlist_set'].join('')))) { + let lmstracklist = getState(([page.items[0].adapterPlayerInstance, 'root.', page.items[0].mediaDevice, '.queue'].join(''))).val; + lmstracklist = lmstracklist.replace(/\s*[\[{(].*?[)}\]]\s*/g, ''); + let lmstracklistTemp = lmstracklist.split(', '); + let trackList: string = '['; + if (getState(page.items[0].adapterPlayerInstance + 'root.' + page.items[0].mediaDevice + '.current_type').val == 0) { + for (let i=0; i < lmstracklistTemp.length; i++) { + let trackTemp = lmstracklistTemp[i].split(' - '); + trackList = trackList + '{"id":"' + i + '","name":"' + trackTemp[0] + '","title":"' + trackTemp[1] + '"}' + if (i < lmstracklistTemp.length -1) { + trackList = trackList + ','; + } + } + } + trackList = trackList + ']'; + if (Debug) log(trackList, 'info'); + globalTracklist = trackList; + } + + if (globalTracklist != null && globalTracklist.length != 0) { + trackListIconCol = rgb_dec565(HMIOn); + trackListString = 'input_sel' + '~' + + id + '?tracklist' + '~' + + Icons.GetIcon('animation-play-outline') + '~' + + trackListIconCol + '~' + + findLocale('media','tracklist') + '~' + + 'media2~' + } + + //InSel EQ + let equalizerListString: string = '~~~~~~' + let equalizerListIconCol = rgb_dec565(HMIOff); + if (page.items[0].equalizerList != undefined) { + equalizerListIconCol = rgb_dec565(HMIOn); + equalizerListString = 'input_sel' + '~' + + id + '?equalizer' + '~' + + Icons.GetIcon('equalizer-outline') + '~' + + equalizerListIconCol + '~' + + findLocale('media','equalizer') + '~' + + 'media3~' + } else if (page.items[0].equalizerList == undefined && v2Adapter == 'sonos') { + let equalizerListIconCol = rgb_dec565(HMIOn); + //equalizerListString is used for favariteList + equalizerListString = 'input_sel' + '~' + + id + '?favorites' + '~' + + Icons.GetIcon('playlist-star') + '~' + + equalizerListIconCol + '~' + + findLocale('media','favorites') + '~' + + 'media3~' + } + + //Repeat Control Button + let repeatIcon = Icons.GetIcon('repeat-variant'); + let repeatIconCol = rgb_dec565(HMIOff); + let repeatButtonString: string = '~~~~~~' + + if (v2Adapter == 'spotify-premium') { + if (getState(id + '.REPEAT').val == 'context') { + repeatIcon = Icons.GetIcon('repeat-variant'); + repeatIconCol = rgb_dec565(HMIOn); + } else if (getState(id + '.REPEAT').val == 'track') { + repeatIcon = Icons.GetIcon('repeat-once'); + repeatIconCol = rgb_dec565(HMIOn); + } + } else if (v2Adapter == 'alexa2') { + if (getState(id + '.REPEAT').val == true) { + repeatIcon = Icons.GetIcon('repeat-variant'); + repeatIconCol = rgb_dec565(HMIOn); + } + } else if (v2Adapter == 'sonos') { + if (getState(id + '.REPEAT').val == 1) { + repeatIcon = Icons.GetIcon('repeat-variant'); + repeatIconCol = rgb_dec565(HMIOn); + } else if (getState(id + '.REPEAT').val == 2) { + repeatIcon = Icons.GetIcon('repeat-once'); + repeatIconCol = rgb_dec565(HMIOn); + } + } else if (v2Adapter == 'squeezeboxrpc') { + if (getState(id + '.REPEAT').val == 1) { + repeatIcon = Icons.GetIcon('repeat-once'); + repeatIconCol = rgb_dec565(HMIOn); + } else if (getState(id + '.REPEAT').val == 2) { + repeatIcon = Icons.GetIcon('repeat'); + repeatIconCol = rgb_dec565(HMIOn); + } + else { + repeatIcon = Icons.GetIcon('repeat-off'); + } + } else if (v2Adapter == 'volumio') { /* Volumio: only Repeat true/false with API */ + if (getState(id + '.REPEAT').val == true) { + repeatIcon = Icons.GetIcon('repeat-variant'); + repeatIconCol = rgb_dec565(colMediaIcon); + } + } + + if (v2Adapter == 'spotify-premium' || v2Adapter == 'alexa2' || v2Adapter == 'sonos' || v2Adapter == 'volumio' || v2Adapter == 'squeezeboxrpc') { + repeatButtonString = 'button' + '~' + + id + '?repeat' + '~' + + repeatIcon + '~' + + repeatIconCol + '~' + + 'Repeat' + '~' + + 'media4' + } + + //popUp Tools + let toolsString: string = '~~~~~~' + let toolsIconCol = rgb_dec565(colMediaIcon); + if (v2Adapter == 'sonos') { + if (page.items[0].crossfade == undefined || page.items[0].crossfade == false) { + toolsString = 'input_sel' + '~' + + id + '?seek' + '~' + + media_icon + '~' + + toolsIconCol + '~' + + findLocale('media','seek') + '~' + + 'media5~' + } else { + toolsString = 'input_sel' + '~' + + id + '?crossfade' + '~' + + media_icon + '~' + + toolsIconCol + '~' + + findLocale('media','crossfade') + '~' + + 'media5~' + } + } else { + toolsString = 'button' + '~' + + id + '' + '~' + + media_icon + '~' + + toolsIconCol + '~' + + findLocale('media','tools') + '~' + + 'media5~' + } + + out_msgs.push({ + payload: 'entityUpd~' + //entityUpd + name + '~' + //heading + GetNavigationString(pageId) + '~' + //navigation + id + '~' + //internalNameEntiy + title + '~' + //title + rgb_dec565(colMediaTitle) + '~' + //titleColor + author + '~' + //author + rgb_dec565(colMediaArtist) + '~' + //authorColor + volume + '~' + //volume + iconplaypause + '~' + //playpauseicon + onoffbutton + '~' + //On/Off Button Color + shuffle_icon + '~' + //iconShuffle --> Code + toolsString + + speakerListString + + playListString + + trackListString + + equalizerListString + + repeatButtonString + }); + } + if (Debug) { + log('GenerateMediaPage payload: ' + JSON.stringify(out_msgs), 'info'); + } + return out_msgs + } catch (err: any) { + log('error at function GenerateMediaPage: ' + err.message, 'warn'); + return []; + } +} + +async function createAutoAlarmAlias (id: string, nsPath: string){ + try { + if (Debug){ + log('Alarm Alias Path: ' + id, 'info'); + log('Alarm 0_userdata Path: ' + nsPath, 'info'); + } + if (autoCreateAlias) { + if (isSetOptionActive) { + if (existsState(nsPath + '.AlarmPin') == false || existsState(nsPath + '.AlarmState') == false || existsState(nsPath + '.AlarmType') == false || existsState(nsPath + '.PIN_Failed') == false || existsState(nsPath + '.PANEL') == false) { + await createStateAsync(nsPath + '.AlarmPin', '0000', { type: 'string' }); + await createStateAsync(nsPath + '.AlarmState', 'disarmed', { type: 'string' }); + await createStateAsync(nsPath + '.AlarmType', 'D1', { type: 'string' }); + await createStateAsync(nsPath + '.PIN_Failed', 0, { type: 'number' }); + await createStateAsync(nsPath + '.PANEL', NSPanel_Path, { type: 'string' }); + setObject(id, {_id: id, type: 'channel', common: {role: 'sensor.fire.alarm', name:'alarm'}, native: {}}); + await createAliasAsync(id + '.ACTUAL', nsPath + '.AlarmState', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(id + '.PIN', nsPath + '.AlarmPin', true, { type: 'string', role: 'state', name: 'PIN' }); + await createAliasAsync(id + '.TYPE', nsPath + '.AlarmType', true, { type: 'string', role: 'state', name: 'TYPE' }); + await createAliasAsync(id + '.PIN_Failed', nsPath + '.PIN_Failed', true, { type: 'number', role: 'state', name: 'PIN_Failed' }); + await createAliasAsync(id + '.PANEL', nsPath + '.PANEL', true, { type: 'string', role: 'state', name: 'PANEL' }); + } + } + } + } catch (err: any) { + log('error at function createAutoAlarmAlias: ' + err.message, 'warn'); + } +} + +function GenerateAlarmPage(page: PageAlarm): Payload[] { + try { + activePage = page; + + let id = page.items[0].id + let name = page.heading; + + let out_msgs: Array = []; + out_msgs.push({ payload: 'pageType~cardAlarm' }); + let nsPath = NSPanel_Alarm_Path + 'Alarm'; + + if (page.items[0].autoCreateALias) { + if (!id) throw new Error ('Missing pageItem.id for cardAlarm! Property autoCreateAlias is true!'); + createAutoAlarmAlias(id, nsPath); + } + + type AlarmEntityType = 'triggered' | 'armed' | 'disarmed' | 'pending' | 'arming'; + const AlarmEntityElements: AlarmEntityType[] = ['triggered', 'armed', 'disarmed', 'pending', 'arming'] + + if (existsState(nsPath + '.AlarmPin') && existsState(nsPath + '.AlarmState') && existsState(nsPath + '.AlarmType')) { + //let entityPin = getState(nsPath + 'AlarmPin').val; + let entityState: AlarmEntityType = getState(nsPath + '.AlarmState').val as AlarmEntityType; + if ( AlarmEntityElements.indexOf(entityState) == -1 ) { + throw new Error(`Invalid value in state ${nsPath}.AlarmPin!`) + } + //let entityType = getState(nsPath + 'AlarmType').val; + let arm1: string, arm2: string, arm3: string, arm4: string; + let arm1ActionName: string, arm2ActionName: string, arm3ActionName: string, arm4ActionName: string; + let icon = '0'; + let iconcolor = 63488; + let numpadStatus = 'disable'; + let flashing = 'disable'; + + if (Debug) { + log('GenerateAlarmPage pageid: ' + id, 'info'); + } + + if (entityState == 'armed' || entityState == 'triggered') { + if (page.items[0].actionStringArray !== undefined && page.items[0].actionStringArray[4] !== '') { + arm1 = page.items[0].actionStringArray[4]; + } else { + arm1 = findLocale('alarm_control_panel', 'disarm'); //'Deactivate'; //arm1*~* + } + arm1ActionName = 'D1'; //arm1ActionName*~* + arm2 = ''; //arm2*~* + arm2ActionName = ''; //arm2ActionName*~* + arm3 = ''; //arm3*~* + arm3ActionName = ''; //arm3ActionName*~* + arm4 = ''; //arm4*~* + arm4ActionName = ''; //arm4ActionName*~* + } else/* if (entityState == 'disarmed' || entityState == 'arming' || entityState == 'pending')*/ { + if (page.items[0].actionStringArray !== undefined && page.items[0].actionStringArray[0] !== '') { + arm1 = page.items[0].actionStringArray[0]; + } else { + arm1 = formatInSelText(findLocale('alarm_control_panel', 'arm_away')); //'Vollschutz' //arm1*~* + } + arm1ActionName = 'A1'; //arm1ActionName*~* + if (page.items[0].actionStringArray !== undefined && page.items[0].actionStringArray[1] !== '') { + arm2 = page.items[0].actionStringArray[1]; + } else { + arm2 = formatInSelText(findLocale('alarm_control_panel', 'arm_home')); //'Zuhause'; //arm2*~* + } + arm2ActionName = 'A2'; //arm2ActionName*~* + if (page.items[0].actionStringArray !== undefined && page.items[0].actionStringArray[2] !== '') { + arm3 = page.items[0].actionStringArray[2]; + } else { + arm3 = formatInSelText(findLocale('alarm_control_panel', 'arm_night')); //'Nacht'; //arm3*~* + } + arm3ActionName = 'A3'; //arm3ActionName*~* + if (page.items[0].actionStringArray !== undefined && page.items[0].actionStringArray[3] !== '') { + arm4 = page.items[0].actionStringArray[3]; + } else { + arm4 = formatInSelText(findLocale('alarm_control_panel', 'arm_vacation')); //'Besuch'; //arm4*~* + } + arm4ActionName = 'A4'; //arm4ActionName*~* + if (Debug) { + log('GenerateAlarmPage String for arm1: ' + arm1 + ', arm2: ' + arm2 + ', arm3: ' + arm3 + ', arm4: ' + arm4, 'info'); + } + } + + 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~* + name + '~' + //heading + GetNavigationString(pageId) + '~' + //navigation*~* --> hiddenCardsv + id + '~' + //internalNameEntity*~* + 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) { + log('GenerateAlarmPage payload: ' + JSON.stringify(out_msgs), 'info'); + } + return out_msgs; + } + return []; + } catch (err: any) { + log('error at function GenerateAlarmPage: ' + err.message, 'warn'); + return []; + } +} + +async function createAutoUnlockAlias(id: string, dpPath: string) { + try { + if (Debug){ + log('Unlock Alias Path: ' + id, 'info'); + log('Unlock 0_userdata Path: ' + dpPath, 'info'); + } + if (autoCreateAlias) { + if (isSetOptionActive) { + if (existsState(dpPath + 'UnlockPin') == false || existsState(dpPath + 'Access') == false) { + await createStateAsync(dpPath + 'UnlockPin', '0000', { type: 'string' }); + await createStateAsync(dpPath + 'Access', 'false', { type: 'boolean' }); + setObject(id, { _id: id, type: 'channel', common: { role: 'sensor.fire.alarm', name: 'sensor.fire.alarm' }, native: {} }); + await createAliasAsync(id + '.PIN', dpPath + 'UnlockPin', true, { type: 'string', role: 'state', name: 'PIN' }); + await createAliasAsync(id + '.ACTUAL', dpPath + 'Access', true, { type: 'boolean', role: 'sensor.fire.alarm', name: 'ACTUAL' }); + } + } + } + } catch (err: any) { + log('error at function createAutoUnlockAlias: ' + err.message, 'warn'); + } + +} + +function GenerateUnlockPage(page: PageUnlock): Payload[] { + try { + activePage = page; + let id = page.items[0].id + let name = page.heading; + + let out_msgs: Array = []; + out_msgs.push({ payload: 'pageType~cardAlarm' }); + + let dpPath : string = '' + let dpTempPath: any = NSPanel_Path.split('.'); + for (let i=0; i < dpTempPath.length - 2; i++) { + dpPath = dpPath + dpTempPath[i] + '.'; + } + dpPath = (dpPath + 'Unlock.'); + + if (page.items[0].autoCreateALias) { + if (!id) throw new Error ('Missing pageItem.id for cardUnlock! Property autoCreateAlias is true!'); + createAutoUnlockAlias(id, dpPath) + } + + let unlock1 = findLocale('lock', 'UNLOCK'); //unlock1*~* + let unlock1ActionName = 'U1'; //unlock1ActionName*~* + + let iconcolor = rgb_dec565({ red: 223, green: 76, blue: 30 }); //icon*~* + let icon = Icons.GetIcon('lock-remove'); //iconcolor*~* + let numpadStatus = 'enable'; //numpadStatus*~* + let flashing = 'disable' //flashing* + + out_msgs.push({ + payload: 'entityUpd~' + //entityUpd~* + name + '~' + //heading + GetNavigationString(pageId) + '~' + //navigation*~* --> hiddenCardsv + id + '~' + //internalNameEntity*~* + unlock1 + '~' + //unlock1*~* + unlock1ActionName + '~' + //unlock1ActionName*~* + '~' + + '~' + + '~' + + '~' + + '~' + + '~' + + icon + '~' + //icon*~* + iconcolor + '~' + //iconcolor*~* + numpadStatus + '~' + //numpadStatus*~* + flashing //flashing* + }); + + if (Debug) { + log('GenerateUnlockPage payload: ' + JSON.stringify(out_msgs), 'info'); + } + return out_msgs; + + } catch (err: any) { + log('error at function GenerateUnlockPage: ' + err.message, 'warn'); + return []; + } +} + +async function createAutoQRAlias(id:string, dpPath:string) { + try { + if (Debug){ + log('QRPage Alias Path: ' + id, 'info'); + log('QRPage 0_userdata Path: ' + dpPath, 'info'); + } + if (autoCreateAlias) { + if (isSetOptionActive) { + if (existsState(dpPath + 'Daten') == false) { + await createStateAsync(dpPath + 'Daten', 'WIFI:T:undefined;S:undefined;P:undefined;H:undefined;', { type: 'string' }); + await createStateAsync(dpPath + 'Switch', false, { type: 'boolean' }); + setObject(id, { _id: id, type: 'channel', common: { role: 'switch.mode.wlan', name: 'QR Page' }, native: {} }); + await createAliasAsync(id + '.ACTUAL', dpPath + 'Daten', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + await createAliasAsync(id + '.SWITCH', dpPath + 'Switch', true, { type: 'boolean', role: 'state', name: 'SWITCH' }); + log('Adjust data for the QR page under ' + dpPath + 'data. Follow the instructions in the wiki.', 'warn'); + } + } + } + } catch (err: any) { + log('error at function createAutoQRkAlias: ' + err.message, 'warn'); + } +} + +function GenerateQRPage(page: PageQR): Payload[] { + try { + activePage = page; + if (!page.items[0].id) throw new Error ('Missing pageItem.id for cardQRPage!'); + let id = page.items[0].id; + let out_msgs: Array = []; + out_msgs.push({ payload: 'pageType~cardQR' }); + + let dpPath : string = '' + let dpTempPath: any = NSPanel_Path.split('.'); + for (let i=0; i < dpTempPath.length - 2; i++) { + dpPath = dpPath + dpTempPath[i] + '.'; + } + dpPath = (dpPath + 'GuestWiFi.'); + + if (page.items[0].autoCreateALias) { + createAutoQRAlias(id, dpPath) + } + + let o = getObject(id); + + let heading = page.heading !== undefined ? page.heading : o.common.name.de; + let textQR = page.items[0].id + '.ACTUAL' !== undefined ? getState(page.items[0].id + '.ACTUAL').val : 'WIFI:T:undefined;S:undefined;P:undefined;H:undefined;'; + let hiddenPWD = false; + if (page.items[0].hidePassword !== undefined && page.items[0].hidePassword == true) { + hiddenPWD = true; + } + + const tempstr = textQR.split(';'); + let optionalValue1: any; + let optionalValue2: any; + for (let w = 0; w < tempstr.length - 1; w++) { + if (tempstr[w].substring(5, 6) == 'T') { + tempstr[w].slice(7) == 'undefined' ? log('Adjust data (T) for the QR page under ' + dpPath + 'data. Follow the instructions in the wiki.', 'warn') : '' ; + } + if (tempstr[w].substring(0, 1) == 'S') { + tempstr[w].slice(2) == 'undefined' ? log('Adjust data (S) for the QR page under ' + dpPath + 'data. Follow the instructions in the wiki.', 'warn') : optionalValue1 = tempstr[w].slice(2); + } + if (tempstr[w].substring(0, 1) == 'P') { + optionalValue2 = tempstr[w].slice(2); + } + } + + let type1 = 'text'; + let internalName1 = findLocale('qr', 'ssid'); + let iconId1 = Icons.GetIcon('wifi'); + let iconColor1 = 65535; + let displayName1 = findLocale('qr', 'ssid'); + let type2 = 'text'; + let internalName2 = findLocale('qr', 'password'); + let iconColor2 = 65535; + let iconId2 = Icons.GetIcon('key'); + let displayName2 = findLocale('qr', 'password'); + + if (hiddenPWD) { + iconColor1 = getState(page.items[0].id + '.SWITCH').val ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); + type2 = 'switch'; + internalName2 = id + iconId2 = ''; + displayName2 = getState(page.items[0].id + '.SWITCH').val ? findLocale('qr', 'Wlan enabled') : findLocale('qr', 'Wlan disabled'); + optionalValue2 = getState(page.items[0].id + '.SWITCH').val ? 1 : 0; + } + + out_msgs.push({ + payload: 'entityUpd~' + //entityUpd + heading + '~' + //heading + GetNavigationString(pageId) + '~' + //navigation + textQR + '~' + //textQR + type1 + '~' + //type + internalName1 + '~' + //internalName + iconId1 + '~' + //iconId + iconColor1 + '~' + //iconColor + displayName1 + '~' + //displayName + optionalValue1 + '~' + //optionalValue + type2 + '~' + //type + internalName2 + '~' + //internalName + iconId2 + '~' + //iconId + iconColor2 + '~' + //iconColor + displayName2 + '~' + //displayName + optionalValue2 + }); + + if (Debug) { + log('GenerateQRPage payload: ' + JSON.stringify(out_msgs), 'info'); + } + return out_msgs; + + } catch (err: any) { + log('error at function GenerateQRPage: ' + err.message, 'warn'); + return []; + } +} + +function unsubscribePowerSubscriptions(): void { + for (let i = 0; i < config.pages.length; i++) { + if (config.pages[i].type == 'cardPower') { + let powerID = config.pages[i].items[0].id; + unsubscribe(powerID + '.ACTUAL'); + } + } + for (let i = 0; i < config.subPages.length; i++) { + if (config.subPages[i].type == 'cardPower') { + let powerID = config.subPages[i].items[0].id; + unsubscribe(powerID + '.ACTUAL'); + } + } + if (Debug) log('unsubscribePowerSubscriptions getstartet', 'info'); +} + +function subscribePowerSubscriptions(id: string): void { + on({id: id + '.ACTUAL', change: "ne"}, async function () { + (function () { if (timeoutPower) { clearTimeout(timeoutPower); timeoutPower = null; } })(); + timeoutPower = setTimeout(async function () { + GeneratePage(activePage!); + },25) + }); +} + +function GeneratePowerPage(page: PagePower): Payload[] { + try { + + if (!page.items[0].id) throw new Error ('Missing pageItem.id for PowerPage!'); + + let obj:object = {}; + let demoMode = false; + if (page.items[0].id == undefined){ + log('No PageItem defined - cardPower demo mode active', 'info'); + demoMode = true; + } + + activePage = page; + if (Debug) { + log('GeneratePowerPage PageItem.id = ' + page.items[0].id, 'info'); + } + + let heading = 'cardPower Example'; + if (demoMode != true) { + let id = page.items[0].id + unsubscribePowerSubscriptions(); + + let o = getObject(id); + heading = page.heading !== undefined ? page.heading : o.common.name.de; + + obj = JSON.parse((getState(page.items[0].id + '.ACTUAL').val)); + } + + let out_msgs: Array = []; + + // Leave the display on if the alwaysOnDisplay parameter is specified (true) + if (page.type == 'cardPower' && pageCounter == 0 && page.items[0].alwaysOnDisplay != undefined) { + out_msgs.push({ payload: 'pageType~cardPower' }); + if (page.items[0].alwaysOnDisplay != undefined) { + if (page.items[0].alwaysOnDisplay) { + pageCounter = 1; + if (alwaysOn == false) { + alwaysOn = true; + SendToPanel({ payload: 'timeout~0' }); + subscribePowerSubscriptions(page.items[0].id); + } + } + } + } else if (page.type == 'cardPower' && pageCounter == 1) { + subscribePowerSubscriptions(page.items[0].id); + } else { + out_msgs.push({ payload: 'pageType~cardPower' }); + } + + if (Debug) { + log('GeneratePowerPage PageItem.id = ' + page.items[0].id, 'info'); + } + + //Demo Data if no pageItem present + let array_icon_color = [White, MSGreen, MSYellow, MSGreen, MSYellow, MSGreen, MSRed]; + let array_icon = ['home', 'battery-charging-60', 'solar-power-variant', 'wind-turbine', 'shape', 'transmission-tower', 'car']; + let array_powerspeed = ['', '10', '-20', '-40', '-10', '-10', '-50']; + let array_powerstate = ['', '0,5 kW', '0,9 kW', '2,8 kW', '0,2 kW', '0,1 kW', '4,6 kW']; + + let arrayColorScale = [colorScale0, colorScale1, colorScale2, colorScale3, colorScale4, colorScale5, colorScale6, colorScale7, colorScale8, colorScale9, colorScale10, White]; + + if (!demoMode) { + for (let obji = 1; obji < 7; obji++) { + const color = obj[obji].iconColor !== '' ? obj[obji].iconColor : 0; + array_icon_color[obji] = arrayColorScale[color]; + array_icon[obji] = obj[obji].icon; + array_powerspeed[obji] = obj[obji].speed; + array_powerstate[obji] = obj[obji].value + ' ' + obj[obji].unit ; + } + array_icon[0] = obj[0].icon; + array_powerstate[0] = obj[0].value + ' ' + obj[0].unit; + array_icon_color[0] = arrayColorScale[obj[0].iconColor]; + } + + let power_string : any = ''; + + for (let i = 0; i < 6; i++ ) { + power_string = power_string + '~'; // type (ignored) + power_string = power_string + '~'; // intNameEntity (ignored) + power_string = power_string + Icons.GetIcon(array_icon[i+1]) + '~'; // icon~ + power_string = power_string + rgb_dec565(array_icon_color[i+1]) + '~'; // icon_color~ + power_string = power_string + '~'; // display (ignored in TS) + power_string = power_string + array_powerstate[i+1] + '~'; // optionalValue~ + power_string = power_string + array_powerspeed[i+1] + '~'; // speed~ + + if (Debug) log(power_string, 'info'); + } + + power_string = power_string.substring(0, power_string.length - 1); + + out_msgs.push({ + payload: 'entityUpd~' + //entityUpd~* + heading + '~' + //internalNameEntity*~* + GetNavigationString(pageId) + '~' + //navigation*~* + // Home Icon / Value below Home Icon + '' + '~' + // type (ignored) + '' + '~' + // intNameEntity (ignored) + Icons.GetIcon(array_icon[0]) + '~' + // icon + rgb_dec565(array_icon_color[0]) + '~' + // icon_color + '' + '~' + // display (ignored in TS) + array_powerstate[0] + '~' + // optionalValue + '' + '~' + // speed + // Value above Home Icon + '' + '~' + // type (ignored) + '' + '~' + // intNameEntity (ignored) + '' + '~' + // icon + '' + '~' + // icon_color + '' + '~' + // display (ignored in TS) + '' + '~' + // optionalValue + '' + '~' + // speed~ + // 1st to 6th Item + power_string + }); + if (Debug) log('GeneratePowerPage payload: ' + JSON.stringify(out_msgs), 'info'); + return out_msgs; + + } catch (err: any) { + log('error at function GeneratePowerPage: ' + err.message, 'warn'); + return []; + } +} + +function GenerateChartPage(page: PageChart): Payload[] { + try { + activePage = page; + + let id = page.items[0].id; + let out_msgs: Array = []; + out_msgs.push({ payload: 'pageType~' + page.type }); + + let heading = page.heading !== undefined ? page.heading : "Chart..."; + + let txt = getState(id + '.ACTUAL').val; + if (!page.items[0].yAxisTicks) { + throw new Error (`Page item ${id} yAxisTicks is undefined!`) + } + if (!page.items[0].onColor) { + throw new Error (`Page item ${id} onColor is undefined!`) + } + + let yAxisTicks = (typeof page.items[0].yAxisTicks == 'object') ? page.items[0].yAxisTicks : JSON.parse(getState(page.items[0].yAxisTicks).val); + + out_msgs.push({ + payload: 'entityUpd~' + //entityUpd + heading + '~' + //heading + GetNavigationString(pageId) + '~' + //navigation + rgb_dec565(page.items[0].onColor) + '~' + //color + page.items[0].yAxis + '~' + + yAxisTicks.join(':') + '~' + + txt + }); + + if (Debug) log('GenerateChartPage payload: ' + JSON.stringify(out_msgs), 'info'); + return out_msgs; + + } catch (err: any) { + log('error at function GenerateChartPage: ' + err.message, 'warn'); + return []; + } +} + +function setIfExists(id: string, value: any, type: string | null = null): boolean { + try { + if (type === null) { + if (existsState(id)) { + setState(id, value); + return true; + } + } else { + const obj = getObject(id); + if (existsState(id) && obj.common.type !== undefined && obj.common.type === type) { + setState(id, value); + return true; + } + } + } catch (err: any) { + log('error at function setIfExists: ' + err.message, 'warn'); + } + return false; +} + +function toggleState(id: string): boolean { + try { + const obj = getObject(id); + if (existsState(id) && obj.common.type !== undefined && obj.common.type === 'boolean') { + setIfExists(id, !getState(id).val); + return true; + } + } catch (err: any) { + log('error at function toggleState: ' + err.message, 'warn'); + } + return false; +} + +// Begin Monobutton +function triggerButton(id: string): boolean{ + try { + let obj = getObject(id); + if (existsState(id) && obj.common.type !== undefined && obj.common.type === "boolean") { + setState(id, true); + setTimeout(function() { setState(id, false) }, 250); + return true; + } + + } catch (err: any) { + log('error at function triggerButton: ' + err.message, 'warn'); + } + return false; +} +// End Monobutton + +function HandleButtonEvent(words: any): void { + try { + + // Turn off the display if the alwaysOnDisplay parameter was specified + if (alwaysOn == true) { + unsubscribePowerSubscriptions(); + unsubscribeMediaSubscriptions(); + } + + let tempid = words[2].split('?'); + let id = tempid[0]; + let buttonAction = words[3]; + let pageItemID: string = ''; + + if (!isNaN(id)) { + if (activePage!.items[id].id == undefined) throw new Error ('Missing pageItem.id in HandleButtonEvent!'); + pageItemID = activePage!.items[id].id!; + if (Debug) { + log('HandleButtonEvent activePage: ' + activePage!.items.length + ' id: ' + id + ' tempid: ' + tempid + ' pageItemId: ' + pageItemID); + } + id = pageItemID + }; + + if (Debug) { + log('HandleButtonEvent übergebene Werte ' + words[0] + ' - ' + words[1] + ' - ' + words[2] + ' - ' + words[3] + ' - ' + words[4] + ' - PageId: ' + pageId, 'info'); + } + + if ((words[2]).substring(0, 8) == 'navigate') { + GeneratePage(eval((words[2]).substring(9, (words[2]).length))); + return; + } + + if (words[2] == 'bNext' || words[2] == 'bPrev' || words[2] == 'bUp' || words[2] == 'bHome' || words[2] == 'bSubNext' || words[2] == 'bSubPrev' ) { + buttonAction = words[2]; + pageCounter = 0; + // Turn off the display if the alwaysOnDisplay parameter was specified + if (alwaysOn == true) { + alwaysOn = false; + SendToPanel({ payload: 'timeout~' + getState(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver').val }); + } + } + + if (Debug) { + log('HandleButtonEvent buttonAction: ' + buttonAction, 'info'); + } + + if (buttonAction.startsWith('swipe')) { + buttonAction = 'bExit'; + } + + let pageNum:number = 0; + + switch (buttonAction) { + case 'bUp': + if (pageId < 0) { // Check whether button1page or button2page + pageId = 0; + UnsubscribeWatcher(); + GeneratePage(config.pages[pageId]); + } else { + pageNum = (((pageId - 1) % config.pages.length) + config.pages.length) % config.pages.length; + pageId = pageNum; + UnsubscribeWatcher(); + if (activePage != undefined && activePage!.parent != undefined) { + //update pageID + for (let i = 0; i < config.pages.length; i++) { + if (config.pages[i] == activePage!.parent) { + pageId = i; + break; + } + } + GeneratePage(activePage!.parent); + } + else { + GeneratePage(config.pages[pageId]); + } + break; + } + break; + case 'bNext': + pageNum = (((pageId + 1) % config.pages.length) + config.pages.length) % config.pages.length; + pageId = pageNum; + UnsubscribeWatcher(); + GeneratePage(config.pages[pageId]); + break; + case 'bSubNext': + UnsubscribeWatcher(); + // check this please + GeneratePage(eval(activePage!.next!)); + break; + case 'bPrev': + pageNum = (((pageId - 1) % config.pages.length) + config.pages.length) % config.pages.length; + pageId = pageNum; + UnsubscribeWatcher(); + if (activePage != undefined && activePage!.parent != undefined) { + //update pageID + for (let i = 0; i < config.pages.length; i++) { + if (config.pages[i] == activePage!.parent) { + pageId = i; + break; + } + } + GeneratePage(activePage!.parent); + } + else { + GeneratePage(config.pages[pageId]); + } + break; + case 'bSubPrev': + UnsubscribeWatcher(); + // check this please + GeneratePage(eval(activePage!.prev!)); + break; + case 'bExit': + if (Debug) { + log('HandleButtonEvent -> bExit: ' + words[2] + ' - ' + words[4] + ' - ' + pageId, 'info'); + } + if (words[2] == 'screensaver') { + if (getState(NSPanel_Path + 'Config.Screensaver.screenSaverDoubleClick').val) { + if (words[4] >= 2) { + if (existsObject(NSPanel_Path + 'ScreensaverInfo.bExitPage') && getState(NSPanel_Path + 'ScreensaverInfo.bExitPage').val != null && getState(NSPanel_Path + 'ScreensaverInfo.bExitPage').val != -1) { + pageId = getState(NSPanel_Path + 'ScreensaverInfo.bExitPage').val; + } + } else { + if (getState(NSPanel_Path + 'ScreensaverInfo.popupNotifyHeading').val != '') { + setIfExists(NSPanel_Path + 'ScreensaverInfo.popupNotifyHeading', ''); + } + if (getState(NSPanel_Path + 'ScreensaverInfo.popupNotifyText').val != '') { + setIfExists(NSPanel_Path + 'ScreensaverInfo.popupNotifyText', ''); + } + screensaverEnabled = true; + break; + } + } else { + if (getState(NSPanel_Path + 'ScreensaverInfo.popupNotifyHeading').val != '') { + setIfExists(NSPanel_Path + 'ScreensaverInfo.popupNotifyHeading', ''); + } + if (getState(NSPanel_Path + 'ScreensaverInfo.popupNotifyText').val != '') { + setIfExists(NSPanel_Path + 'ScreensaverInfo.popupNotifyText', ''); + } + if (existsObject(NSPanel_Path + 'ScreensaverInfo.bExitPage') && getState(NSPanel_Path + 'ScreensaverInfo.bExitPage').val != null && getState(NSPanel_Path + 'ScreensaverInfo.bExitPage').val != -1) { + pageId = getState(NSPanel_Path + 'ScreensaverInfo.bExitPage').val + } + } + activePage = config.pages[pageId]; + } + if (words[2] == 'popupInSel' && activePage!.type == 'cardMedia') { + if (Debug) log('Leave popupInsel without any action', 'info') + pageCounter = 0; + GeneratePage(activePage!); + setTimeout(async function () { + pageCounter = 1; + GeneratePage(activePage!); + }, 3000); + } else { + pageCounter = 0; + GeneratePage(activePage!); + } + break; + case 'bHome': + if (Debug) { + log('HandleButtonEvent -> bHome: ' + words[4] + ' - ' + pageId, 'info'); + } + UnsubscribeWatcher(); + if (activePage!.home != undefined) { + GeneratePage(eval(activePage!.home)); + } else { + GeneratePage(config.pages[0]); + } + break; + case 'notifyAction': + if (words[4] == 'yes') { + setState(popupNotifyInternalName, { val: words[2], ack: true }); + setState(popupNotifyAction, { val: true, ack: true }); + } else if (words[4] == 'no') { + setState(popupNotifyInternalName, { val: words[2], ack: true }); + setState(popupNotifyAction, { val: false, ack: true }); + } + + setIfExists(config.panelSendTopic, 'exitPopup'); + + break; + case 'OnOff': + if (existsObject(id)) { + let action = false; + if (words[4] == '1') + action = true; + let o = getObject(id); + if (Debug) { + log('HandleButtonEvent -> OnOff: ' + words[4] + ' - ' + id + ' - Role - ' + o.common.role, 'info') + } + switch (o.common.role) { + case 'level.mode.fan': + case 'socket': + case 'light': + let pageItem = findPageItem(id); + if(pageItem.monobutton != undefined && pageItem.monobutton == true){ + triggerButton(id + ".SET"); + } + else { + setIfExists(id + '.SET', action); + } + break; + case 'dimmer': + setIfExists(id + '.ON_SET', action) ? true : setIfExists(id + '.ON_ACTUAL', action); + break; + case 'ct': + setIfExists(id + '.ON', action); + break; + case 'rgb': + case 'rgbSingle': + case 'hue': + setIfExists(id + '.ON_ACTUAL', action); + break; + case 'switch.mode.wlan': + setIfExists(id + '.SWITCH', action); + GeneratePage(activePage!); + break; + } + } + break; + case 'button': + if (existsObject(id)) { + let 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': + if (existsObject(id + '.ACTUAL')) { + toggleState(id + '.ACTUAL'); + } + break; + case 'socket': + case 'light': + // Change for monobutton + let pageItem = findPageItem(id); + if(pageItem.monobutton != undefined && pageItem.monobutton == true){ + triggerButton(id + ".SET"); + } + else { + 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': + toggleState(id + '.ON_ACTUAL'); + case 'media': + if (!activePage || activePage.type != 'cardMedia') { + if (activePage) throw new Error(`Found channel role media for card: ${activePage.type} not allowed`) + else throw new Error(`Something went wrong! Active Page is empty!`); + } + if (tempid[1] == undefined) { + if (Debug) log('Logo click', 'info'); + GeneratePage(activePage!); + } else if (tempid[1] == 'repeat') { + + let pageItemRepeat = findPageItem(id); + if (isPageMediaItem(pageItemRepeat)) { + let adapterInstanceRepeat = pageItemRepeat.adapterPlayerInstance; + let adapterRepeat = adapterInstanceRepeat.split('.'); + const deviceAdapterRP: PlayerType = adapterRepeat[0] as PlayerType; + + switch (deviceAdapterRP) { + case 'spotify-premium': + let stateSpotifyRepeat = getState(id + '.REPEAT').val + if (stateSpotifyRepeat == 'none') { + setIfExists(id + '.REPEAT', 'all'); + } else if (stateSpotifyRepeat == 'all') { + setIfExists(id + '.REPEAT', 'one'); + } else if (stateSpotifyRepeat == 'one') { + setIfExists(id + '.REPEAT', 'none'); + } + GeneratePage(activePage!); + break; + case 'sonos': + let stateSonosRepeat = getState(id + '.REPEAT').val + if (stateSonosRepeat == 0) { + setIfExists(id + '.REPEAT', 1); + } else if (stateSonosRepeat == 1) { + setIfExists(id + '.REPEAT', 2); + } else if (stateSonosRepeat == 2) { + setIfExists(id + '.REPEAT', 0); + } + GeneratePage(activePage!); + break; + case 'alexa2': + try { + setIfExists(id + '.REPEAT', !getState(id + '.REPEAT').val); + } catch (err: any) { + log('ALEXA2: Repeat kann nicht verändert werden', 'warn'); + } + GeneratePage(activePage!); + break; + case 'volumio': + let urlString: string = `${getState(adapterInstanceRepeat + 'info.host').val}/api/commands/?cmd=repeat`; + axios.get(urlString, {headers: {'User-Agent': 'ioBroker'}}) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(response.data, 'info'); + } + GeneratePage(activePage!); + } else { + log('Axios Status - adapterInstanceRepeat: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + break; + case 'squeezeboxrpc': + try { + switch (getState(id + '.REPEAT').val) { + case 0: + setIfExists(id + '.REPEAT', 1); + GeneratePage(activePage!); + break; + case 1: + setIfExists(id + '.REPEAT', 2) + GeneratePage(activePage!); + break; + case 2: + setIfExists(id + '.REPEAT', 0); + GeneratePage(activePage!); + break; + } + } catch (err: any) { + log('Squeezebox: Repeat kann nicht verändert werden', 'warn'); + } + break; + } + } + } + } + } + break; + case 'up': + setIfExists(id + '.OPEN', true); + checkBlindActive = true; + break; + case 'stop': + setIfExists(id + '.STOP', true); + checkBlindActive = false; + break; + case 'down': + setIfExists(id + '.CLOSE', true); + checkBlindActive = true; + break; + case 'positionSlider': + (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); + timeoutSlider = setTimeout(async function () { + let pageItem = findPageItem(id); + if (pageItem.minValueLevel != undefined && pageItem.maxValueLevel != undefined) { + let sliderPos = Math.trunc(scale(parseInt(words[4]), 0, 100, pageItem.maxValueLevel, pageItem.minValueLevel)); + setIfExists(id + '.SET', sliderPos) ? true : setIfExists(id + '.ACTUAL', sliderPos); + checkBlindActive = true; + } else { + setIfExists(id + '.SET', parseInt(words[4])) ? true : setIfExists(id + '.ACTUAL', parseInt(words[4])); + checkBlindActive = true; + } + }, 250); + break; + case 'tiltOpen': + setIfExists(id + '.TILT_OPEN', true); + break; + case 'tiltStop': + setIfExists(id + '.TILT_STOP', true); + break; + case 'tiltClose': + setIfExists(id + '.TILT_CLOSE', true); + break; + case 'tiltSlider': + (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); + timeoutSlider = setTimeout(async function () { + let pageItem = findPageItem(id); + if (pageItem.minValueTilt != undefined && pageItem.maxValueTilt != undefined) { + let sliderPos = Math.trunc(scale(parseInt(words[4]), 0, 100, pageItem.maxValueTilt, pageItem.minValueTilt)); + setIfExists(id + '.TILT_SET', sliderPos) ? true : setIfExists(id + '.TILT_ACTUAL', sliderPos); + } else { + setIfExists(id + '.TILT_SET', parseInt(words[4])) ? true : setIfExists(id + '.TILT_ACTUAL', parseInt(words[4])); + } + }, 250); + break; + case 'brightnessSlider': + (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); + timeoutSlider = setTimeout(async function () { + if (existsObject(id)) { + let o = getObject(id); + let pageItem = findPageItem(id); + + switch (o.common.role) { + case 'dimmer': + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + let sliderPos = Math.trunc(scale(parseInt(words[4]), 0, 100, pageItem.maxValueBrightness, pageItem.minValueBrightness)); + setIfExists(id + '.SET', sliderPos) ? true : setIfExists(id + '.ACTUAL', sliderPos); + } else { + setIfExists(id + '.SET', parseInt(words[4])) ? true : setIfExists(id + '.ACTUAL', parseInt(words[4])); + } + break; + case 'rgb': + case 'ct': + case 'rgbSingle': + case 'hue': + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + let sliderPos = Math.trunc(scale(parseInt(words[4]), 0, 100, pageItem.maxValueBrightness, pageItem.minValueBrightness)); + setIfExists(id + '.DIMMER', sliderPos); + } else { + setIfExists(id + '.DIMMER', parseInt(words[4])); + } + break; + } + } + }, 250); + break; + case 'colorTempSlider': + (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); + timeoutSlider = setTimeout(async function () { + let pageItem = findPageItem(id); + if (pageItem.minValueColorTemp !== undefined && pageItem.maxValueColorTemp !== undefined) { + let colorTempK = Math.trunc(scale(parseInt(words[4]), 100, 0, pageItem.minValueColorTemp, pageItem.maxValueColorTemp)); + setIfExists(id + '.TEMPERATURE', (colorTempK)); + } else { + setIfExists(id + '.TEMPERATURE', parseInt(words[4])); + } + }, 250); + break; + case 'colorWheel': + let colorCoordinates = words[4].split('|'); + let rgb = pos_to_color(colorCoordinates[0], colorCoordinates[1]); + if (Debug) { + log('HandleButtonEvent colorWeel -> rgb-Wert: ' + rgb, 'info'); + } + if (Debug) { + log('HandleButtonEvent colorWeel -> getHue-Werte: ' + getHue(rgb.red, rgb.green, rgb.blue), 'info'); + } + let o = getObject(id); + switch (o.common.role) { + case 'hue': + setIfExists(id + '.HUE', getHue(rgb.red, rgb.green, rgb.blue)); + break; + case 'rgb': + setIfExists(id + '.RED', rgb.red); + setIfExists(id + '.GREEN', rgb.green); + setIfExists(id + '.BLUE', rgb.blue); + break; + case 'rgbSingle': + let pageItem = findPageItem(id); + if (pageItem.colormode == "xy") { + //For e.g. Deconz XY + setIfExists(id + ".RGB", rgb_to_cie(rgb.red, rgb.green, rgb.blue)); + if (Debug) { + log('HandleButtonEvent colorWeel colorMode=xy -> rgb_to_cie Wert: ' + rgb_to_cie(rgb.red, rgb.green, rgb.blue), 'info'); + } + } + else { + //For RGB + setIfExists(id + ".RGB", ConvertRGBtoHex(rgb.red, rgb.green, rgb.blue)); + } + break; + } + break; + case 'tempUpd': + setIfExists(id + '.SET', parseInt(words[4]) / 10); + break; + case 'tempUpdHighLow': + let temps = words[4].split('|'); + if (getState(id + '.ACTUAL2').val * 10 != parseInt(temps[1])) { // avoid writing if not needed + setIfExists(id + '.ACTUAL2', parseInt(temps[1]) / 10); + } + if (getState(id + '.SET').val * 10 != parseInt(temps[0])) { + setIfExists(id + '.SET', parseInt(temps[0]) / 10); + } + break; + case 'media-back': + setIfExists(id + '.PREV', true); + GeneratePage(activePage!); + break; + case 'media-pause': + let pageItemTemp = findPageItem(id); + if (isPageMediaItem(pageItemTemp)) { + let adaInstanceSplit = pageItemTemp.adapterPlayerInstance!.split('.'); + if (adaInstanceSplit[0] == 'squeezeboxrpc') { + let adapterPlayerInstanceStateSeceltor: string = [pageItemTemp.adapterPlayerInstance, 'Players', pageItemTemp.mediaDevice, 'state'].join('.'); + if (Debug) log('HandleButtonEvent media-pause Squeezebox-> adapterPlayerInstanceStateSeceltor: ' + adapterPlayerInstanceStateSeceltor, 'info'); + let stateVal = getState(adapterPlayerInstanceStateSeceltor).val; + if (stateVal == 0) { + setState(adapterPlayerInstanceStateSeceltor, 1); + } else if (stateVal == 1) { + setState(adapterPlayerInstanceStateSeceltor, 0); + } else if (stateVal == null) { + setState(adapterPlayerInstanceStateSeceltor, 1); + } + } else { + if (Debug) log('HandleButtonEvent media-pause -> .STATE Value: ' + getState(id + '.STATE').val, 'info'); + if (getState(id + '.STATE').val === true) { + setIfExists(id + '.PAUSE', true); + } else { + setIfExists(id + '.PLAY', true); + } + } + GeneratePage(activePage!); + } + break; + case 'media-next': + setIfExists(id + '.NEXT', true); + GeneratePage(activePage!); + break; + case 'media-shuffle': + const tempPage = findPageItem(id); + if (isPageMediaItem(tempPage)) { + if (tempPage.adapterPlayerInstance.startsWith("volumio")) { + findPageItem(id).playList = []; break; + } //Volumio: empty playlist $uha-20230103 + if ((tempPage.adapterPlayerInstance).startsWith("spotify")) { + if (getState(id + '.SHUFFLE').val == 'off') { + setIfExists(id + '.SHUFFLE', 'on'); + } else { + setIfExists(id + '.SHUFFLE', 'off'); + } + } + if ((tempPage.adapterPlayerInstance).startsWith("alexa")) { + if (getState(id + '.SHUFFLE').val == false) { + setIfExists(id + '.SHUFFLE', true); + } else { + setIfExists(id + '.SHUFFLE', false); + } + } + if ((tempPage.adapterPlayerInstance).startsWith("sonos")) { + if (getState(id + '.SHUFFLE').val == false) { + setIfExists(id + '.SHUFFLE', true); + } else { + setIfExists(id + '.SHUFFLE', false); + } + } + GeneratePage(activePage!); + } + break; + case 'volumeSlider': + pageCounter = -1; + (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); + timeoutSlider = setTimeout(async function () { + setIfExists(id + '.VOLUME', parseInt(words[4])); + setTimeout(async function () { + pageCounter = 1; + GeneratePage(activePage!); + }, 3000); + }, 20); + break; + case 'mode-speakerlist': + let pageItem = findPageItem(id); + if (isPageMediaItem(pageItem)) { + let adapterInstance = pageItem.adapterPlayerInstance!; + let adapter = adapterInstance!.split('.'); + const deviceAdapter: PlayerType = adapter[0] as PlayerType; + + switch (deviceAdapter) { + case 'spotify-premium': + let strDevicePI = pageItem.speakerList![words[4]]; + let strDeviceID = spotifyGetDeviceID(strDevicePI); + setState(adapterInstance + 'devices.' + strDeviceID + ".useForPlayback", true); + break; + case 'alexa2': + let i_list = Array.prototype.slice.apply($('[state.id="' + adapterInstance + 'Echo-Devices.*.Info.name"]')); + for (let i_index in i_list) { + let i = i_list[i_index]; + if ((getState(i).val) === pageItem.speakerList![words[4]]) { + if (Debug) log('HandleButtonEvent mode-Speakerlist Alexa2: ' + getState(i).val + ' - ' + pageItem.speakerList![words[4]], 'info'); + let deviceId = i; + deviceId = deviceId.split('.'); + setIfExists(adapterInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Commands.textCommand', 'Schiebe meine Musik auf ' + pageItem.speakerList![words[4]]); + pageItem.mediaDevice = deviceId[3]; + } + } + break; + case 'sonos': + break; + /*case 'chromecast': + break;*/ + case 'squeezeboxrpc': + pageItem.mediaDevice = pageItem.speakerList![words[4]]; + break; + case "volumio": + break; + case "bosesoundtouch": + break; + } + pageCounter = 0; + GeneratePage(activePage!); + setTimeout(async function () { + pageCounter = 1; + GeneratePage(activePage!); + }, 3000); + } + break; + case 'mode-playlist': + let pageItemPL = findPageItem(id); + if (!isPageMediaItem(pageItemPL)) break; + let adapterInstancePL = pageItemPL.adapterPlayerInstance!; + let adapterPL = adapterInstancePL.split('.'); + const deviceAdapterPL: PlayerType = adapterPL[0] as PlayerType; + + switch (deviceAdapterPL) { + case 'spotify-premium': + let strDevicePI = pageItemPL.playList![words[4]]; + if (Debug) log('HandleButtonEvent mode-playlist Spotify -> strDevicePI: ' + strDevicePI, 'info'); + let playlistListString = (getState(adapterInstancePL + 'playlists.playlistListString').val).split(';'); + let playlistListIds = (getState(adapterInstancePL + 'playlists.playlistListIds').val).split(';'); + let playlistIndex = playlistListString.indexOf(strDevicePI); + setState(adapterInstancePL + 'playlists.playlistList', playlistListIds[playlistIndex]); + setTimeout(async function () { + globalTracklist = (function () { try {return JSON.parse(getState(adapterInstancePL + 'player.playlist.trackListArray').val);} catch(e) {return {};}})(); + }, 2000); + break; + case 'alexa2': + let tempListItem = pageItemPL.playList![words[4]].split('.'); + setState(adapterInstancePL + 'Echo-Devices.' + pageItemPL.mediaDevice + '.Music-Provider.' + tempListItem[0], tempListItem[1]); + break; + case 'sonos': + let strDevicePLSonos = pageItemPL.playList![words[4]].split('.'); + if (Debug) log(adapterInstancePL + 'root.' + pageItemPL.mediaDevice + '.playlist_set', 'info') + setState(adapterInstancePL + 'root.' + pageItemPL.mediaDevice + '.playlist_set', strDevicePLSonos[0]); + break; + case 'volumio': + let strDevicePL = pageItemPL.playList![words[4]]; + let urlString: string = `${getState(adapterInstancePL+'info.host').val}/api/commands/?cmd=playplaylist&name=${strDevicePL}`; + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(JSON.stringify(response.data), 'info'); + } + } else { + log('Axios Status - mode-playlist: ' + response.state, 'warn'); + } + }) + .catch(function (error) { + log(error, 'warn'); + }); + break; + case 'squeezeboxrpc': + setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'cmdPlayFavorite'].join('.'), words[4]); + break; + case "bosesoundtouch": + break; + default: + log('Hello Mr. Developer u miss in mode-playlist something!', 'warn') + } + pageCounter = 0; + GeneratePage(activePage!); + setTimeout(async function () { + pageCounter = 1; + GeneratePage(activePage!); + }, 3000); + break; + case 'mode-tracklist': + let pageItemTL = findPageItem(id); + if (!isPageMediaItem(pageItemTL)) break; + let adapterInstanceTL = pageItemTL.adapterPlayerInstance!; + let adapterTL = adapterInstanceTL.split('.'); + const deviceAdapterTL: PlayerType = adapterTL[0] as PlayerType; + + switch (deviceAdapterTL) { + case 'spotify-premium': + let trackArray = (function () { try {return JSON.parse(getState(pageItemTL.adapterPlayerInstance + 'player.playlist.trackListArray').val);} catch(e) {return {};}})(); + setState(adapterInstanceTL + 'player.trackId', getAttr(trackArray, words[4] + '.id')); + break; + case 'sonos': + setState(adapterInstanceTL + 'root.' + pageItemTL.mediaDevice + '.current_track_number', parseInt(words[4]) + 1); + case 'alexa2': + if (Debug) log('Aktuell hat alexa2 keine Tracklist', 'info'); + break; + case 'volumio': + let urlString: string = `${getState(adapterInstanceTL+'info.host').val}/api/commands/?cmd=play&N=${words[4]}`; + axios.get(urlString, { headers: { 'User-Agent': 'ioBroker' } }) + .then(async function (response) { + if (response.status === 200) { + if (Debug) { + log(JSON.stringify(response.data), 'info'); + } + } else { + log('Axios Status - mode-tracklist: ' + response.state, 'warn'); + } + }) + .catch(function (error: any) { + log(error, 'warn'); + }); + break; + case 'squeezeboxrpc': + //@ts-ignore Fehler kommt von findPageItem in vscode + setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'PlaylistCurrentIndex'].join('.'), words[4]); + break; + case "bosesoundtouch": + break; + default: + log('Hello Mr. Developer u miss in mode-tracklist something!', 'warn') + } + pageCounter = 0; + GeneratePage(activePage!); + setTimeout(async function () { + pageCounter = 1; + GeneratePage(activePage!); + }, 3000); + break; + case 'mode-repeat': + let pageItemRP = findPageItem(id); + if (!isPageMediaItem(pageItemRP)) break; + let adapterInstanceRP = pageItemRP.adapterPlayerInstance!; + let adapterRP = adapterInstanceRP.split('.'); + let deviceAdapterRP = adapterRP[0]; + + if (Debug) log(pageItemRP.repeatList![words[4]], 'warn'); + switch (deviceAdapterRP) { + case 'spotify-premium': + setIfExists(id + '.REPEAT', pageItemRP.repeatList![words[4]]); + GeneratePage(activePage!); + break; + case 'alexa2': + GeneratePage(activePage!); + break; + } + break; + case 'mode-equalizer': + let pageItemEQ = findPageItem(id); + if (Debug) log('HandleButtonEvent mode-equalizer -> id: ' + id, 'info'); + let lastIndex = (id.split('.')).pop(); + setState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode', pageItemEQ.equalizerList![words[4]]); + pageCounter = 0; + GeneratePage(activePage!); + setTimeout(async function () { + pageCounter = 1; + GeneratePage(activePage!); + }, 3000); + break; + case 'mode-seek': + let pageItemSeek = findPageItem(id); + if (!isPageMediaItem(pageItemSeek)) break; + let adapterInstanceSK = pageItemSeek.adapterPlayerInstance!; + let adapterSK = adapterInstanceSK.split('.'); + let deviceAdapterSK = adapterSK[0]; + switch (deviceAdapterSK) { + case 'spotify-premium': + break; + case 'sonos': + if (Debug) log('HandleButtonEvent mode-seek -> id: ' + id, 'info'); + setState(adapterInstanceSK + 'root.' + pageItemSeek.mediaDevice + '.seek', parseInt(words[4]) * 10); + break; + } + pageCounter = 0; + GeneratePage(activePage!); + setTimeout(async function () { + pageCounter = 1; + GeneratePage(activePage!); + }, 3000); + break; + case 'mode-crossfade': + let pageItemCrossfade = findPageItem(id); + if (!isPageMediaItem(pageItemCrossfade)) break; + let adapterInstanceCF = pageItemCrossfade.adapterPlayerInstance!; + let adapterCF = adapterInstanceCF.split('.'); + let deviceAdapterCF = adapterCF[0]; + switch (deviceAdapterCF) { + case 'spotify-premium': + break; + case 'sonos': + if (Debug) log('HandleButtonEvent mode-crossfade -> id: ' + id, 'info'); + let cfState: boolean = false; + if (parseInt(words[4]) == 0 ) { + cfState = true; + } + setState(adapterInstanceCF + 'root.' + pageItemCrossfade.mediaDevice + '.crossfade', cfState); + break; + } + pageCounter = 0; + GeneratePage(activePage!); + setTimeout(async function () { + pageCounter = 1; + GeneratePage(activePage!); + }, 3000); + break; + case 'mode-favorites': + let pageItemFav = findPageItem(id); + if (!isPageMediaItem(pageItemFav)) break; + if (Debug) log(getState(pageItemFav.adapterPlayerInstance + 'root.' + pageItemFav.mediaDevice + '.favorites_set').val, 'info'); + let favListArray = getState(pageItemFav.adapterPlayerInstance + 'root.' + pageItemFav.mediaDevice + '.favorites_list_array').val; + setState(pageItemFav.adapterPlayerInstance + 'root.' + pageItemFav.mediaDevice + '.favorites_set', favListArray[words[4]]); + pageCounter = 0; + GeneratePage(activePage!); + setTimeout(async function () { + pageCounter = 1; + GeneratePage(activePage!); + }, 3000); + break; + case 'mode-insel': + setIfExists(id + '.VALUE', parseInt(words[4])); + break; + case 'media-OnOff': + let pageItemTem = findPageItem(id); + if (!isPageMediaItem(pageItemTem)) break; + let adaInstanceSpli = pageItemTem.adapterPlayerInstance.split('.'); + if (adaInstanceSpli[0] == 'squeezeboxrpc') { + let adapterPlayerInstancePowerSelector: string = [pageItemTem.adapterPlayerInstance, 'Players', pageItemTem.mediaDevice, 'Power'].join('.'); + let stateVal = getState(adapterPlayerInstancePowerSelector).val; + if (stateVal === 0) { + setState(adapterPlayerInstancePowerSelector, 1); + setIfExists(id + '.STOP', false); + setIfExists(id + '.STATE', 1); + } else { + setState(adapterPlayerInstancePowerSelector, 0); + setIfExists(id + '.STOP', true); + setIfExists(id + '.STATE', 0); + } + } else { + setIfExists(id + '.STOP', true); + } + GeneratePage(activePage!); + break; + case 'timer-start': + if (words[4] != undefined) { + let timer_panel = words[4].split(':'); + setIfExists(id + '.ACTUAL', (parseInt(timer_panel[1]) * 60) + parseInt(timer_panel[2])); + } + setIfExists(id + '.STATE', 'active'); + break; + case 'timer-pause': + setIfExists(id + '.STATE', 'paused'); + break; + case 'timer-cancle': + setIfExists(id + '.STATE', 'idle'); + setIfExists(id + '.ACTUAL', 0); + break; + case 'timer-finish': + setIfExists(id + '.STATE', 'idle'); + setIfExists(id + '.ACTUAL', 0); + break; + case 'hvac_action': + if (words[4] == 'BOOT' || words[4] == 'PART' || words[4] == 'AUTT' || words[4] == 'MANT' || words[4] == 'VACT') { + + switch (words[4]) { + case 'BOOT': + setIfExists(words[2] + '.' + 'BOOST', !getState(words[2] + '.' + 'BOOST').val); + break; + case 'PART': + setIfExists(words[2] + '.' + 'PARTY', !getState(words[2] + '.' + 'PARTY').val); + break; + case 'AUTT': + setIfExists(words[2] + '.' + 'AUTOMATIC', !getState(words[2] + '.' + 'AUTOMATIC').val); + break; + case 'MANT': + setIfExists(words[2] + '.' + 'MANUAL', !getState(words[2] + '.' + 'MANUAL').val); + break; + case 'VACT': + setIfExists(words[2] + '.' + 'VACATION', !getState(words[2] + '.' + 'VACATION').val); + break; + } + let modes = ['BOOT', 'PART', 'AUTT', 'MANT', 'VACT']; + let modesDP = ['BOOST', 'PARTY', 'AUTOMATIC', 'MANUAL', 'VACATION']; + for (let mode=0; mode < 5; mode++) { + if (words[4] != modes[mode]) { + setIfExists(words[2] + '.' + modesDP[mode], false); + } + } + GeneratePage(activePage!); + } else { + let HVACMode = getState(words[2] + '.MODE').val; + + // Event is bound to its own object + if(existsObject(words[2] + '.' + words[4])) { + switch(words[4]) { + case 'SWING': + if (getState(words[2] + '.SWING').val == 0) { + setIfExists(words[2] + '.SWING', 1); + } else { + setIfExists(words[2] + '.' + 'SWING', 0); + } + break; + default: // Power and Eco can easily be toggled + setIfExists(words[2] + '.' + words[4], !getState(words[2] + '.' + words[4]).val); + break; + } + } + + // Event is a mode of the list (mode change) + let HVACModeList = getObject(words[2] + '.MODE').common.states; + for(const statekey in HVACModeList) { + if(HVACModeList[statekey] == words[4]) { + HVACMode = parseInt(statekey); + break; + } + } + + setIfExists(words[2] + '.' + 'MODE', HVACMode); + GeneratePage(activePage!); + } + break; + case 'mode-modus1': + let pageItemT1 = findPageItem(id); + setIfExists(id + '.' + pageItemT1.setThermoAlias![0], pageItemT1.popupThermoMode1![parseInt(words[4])]); + break; + case 'mode-modus2': + let pageItemT2 = findPageItem(id); + setIfExists(id + '.' + pageItemT2.setThermoAlias![1], pageItemT2.popupThermoMode2![parseInt(words[4])]); + break; + case 'mode-modus3': + let pageItemT3 = findPageItem(id); + setIfExists(id + '.' + pageItemT3.setThermoAlias![2], pageItemT3.popupThermoMode3![parseInt(words[4])]); + break; + case 'number-set': + let nobj = getObject(id); + switch (nobj.common.role) { + case 'level.mode.fan': + (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); + timeoutSlider = setTimeout(async function () { + setIfExists(id + '.SPEED', parseInt(words[4])); + }, 250); + break; + default: + (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); + timeoutSlider = setTimeout(async function () { + setIfExists(id + '.SET', parseInt(words[4])) ? true : setIfExists(id + '.ACTUAL', parseInt(words[4])); + }, 250); + break; + } + break; + case 'mode-preset_modes': + setIfExists(id + '.MODE', parseInt(words[4])); + break; + case 'A1': // Alarm page - activate alarm 1 + if (words[4] != '') { + setIfExists(id + '.TYPE', 'A1'); + setIfExists(id + '.PIN', words[4]); + setIfExists(id + '.ACTUAL', 'arming'); + setIfExists(id + '.PANEL', NSPanel_Path); + } + setTimeout(function(){ + GeneratePage(activePage!); + },250); + break; + case 'A2': // Alarm page - activate alarm 2 + if (words[4] != '') { + setIfExists(id + '.TYPE', 'A2'); + setIfExists(id + '.PIN', words[4]); + setIfExists(id + '.ACTUAL', 'arming'); + setIfExists(id + '.PANEL', NSPanel_Path); + } + setTimeout(function(){ + GeneratePage(activePage!); + },250); + break; + case 'A3': // Alarm page - activate alarm 3 + if (words[4] != '') { + setIfExists(id + '.TYPE', 'A3'); + setIfExists(id + '.PIN', words[4]); + setIfExists(id + '.ACTUAL', 'arming'); + setIfExists(id + '.PANEL', NSPanel_Path); + } + setTimeout(function(){ + GeneratePage(activePage!); + },250); + break; + case 'A4': // Alarm page - activate alarm 4 + if (words[4] != '') { + setIfExists(id + '.TYPE', 'A4'); + setIfExists(id + '.PIN', words[4]); + setIfExists(id + '.ACTUAL', 'arming'); + setIfExists(id + '.PANEL', NSPanel_Path); + } + setTimeout(function(){ + GeneratePage(activePage!); + },250); + break; + case 'D1': // Alarm page - deactivate alarm 4 + if (Debug) { + log('HandleButtonEvent Alarmpage D1 -> PIN: ' + getState(id + '.PIN').val, 'info'); + } + if (Debug) { + log('HandleButtonEvent Alarmpage D1 -> words[4]: ' + words[4], 'info'); + } + if (words[4] != '') { + if (getState(id + '.PIN').val == words[4]) { + setIfExists(id + '.PIN', '0000'); + setIfExists(id + '.TYPE', 'D1'); + setIfExists(id + '.ACTUAL', 'pending'); + setIfExists(id + '.PIN_Failed', 0); + } else { + setIfExists(id + '.PIN_Failed', getState(id + '.PIN_Failed').val + 1); + setIfExists(id + '.ACTUAL', 'triggered'); + } + setIfExists(id + '.PANEL', NSPanel_Path); + setTimeout(function(){ + GeneratePage(activePage!); + },500); + } + break; + case 'U1': // Unlock-Page + let pageItemUnlock = findPageItem(id); + if (words[4] == getState(id + '.PIN').val) { + UnsubscribeWatcher(); + GeneratePage(eval(pageItemUnlock.targetPage!)); + setIfExists(id + '.ACTUAL', true) + } else { + setIfExists(id + '.ACTUAL', false) + } + break; + default: + break; + } + } catch (err: any) { + log('error at function HandleButtonEvent: ' + err.message, 'warn'); + } +} + +//Determination of page navigation (CustomSend-Payload) +function GetNavigationString(pageId: number): string { + try { + + if (Debug) { + log('GetNavigationString Übergabe pageId: ' + pageId, 'info'); + } + + var navigationString:string = ""; + + if (activePage!.subPage){ + //Left icon + if (activePage!.prev == undefined){ + if (activePage!.parentIcon != undefined){ + navigationString = 'button~bUp~' + Icons.GetIcon(activePage!.parentIcon); + if (activePage!.parentIconColor != undefined){ + navigationString += '~' + rgb_dec565(activePage!.parentIconColor); + } else { + navigationString += '~' + rgb_dec565(White); + } + } else { + navigationString = 'button~bUp~' + Icons.GetIcon('arrow-up-bold') + '~' + rgb_dec565(White); + } + } else { + if (activePage!.prevIcon != undefined){ + navigationString = 'button~bSubPrev~' + Icons.GetIcon(activePage!.prevIcon); + if (activePage!.prevIconColor != undefined){ + navigationString += '~' + rgb_dec565(activePage!.prevIconColor); + } else { + navigationString += '~' + rgb_dec565(White); + } + } else { + navigationString = 'button~bSubPrev~' + Icons.GetIcon('arrow-left-bold') + '~' + rgb_dec565(White); + } + } + + //Right icon + if (activePage!.next == undefined){ + if (activePage!.homeIcon != undefined){ + navigationString += '~~~button~bHome~' + Icons.GetIcon(activePage!.homeIcon); + if (activePage!.homeIconColor != undefined){ + navigationString += '~' + rgb_dec565(activePage!.homeIconColor) + '~~';; + } else { + navigationString += '~' + rgb_dec565(White) + '~~'; + } + } else { + navigationString += '~~~button~bHome~' + Icons.GetIcon('home') + '~' + rgb_dec565(White) + '~~'; + } + } else { + if (activePage!.nextIcon != undefined){ + navigationString += '~~~button~bSubNext~' + Icons.GetIcon(activePage!.nextIcon); + if (activePage!.nextIconColor != undefined){ + navigationString += '~' + rgb_dec565(activePage!.nextIconColor) + '~~'; + } else { + navigationString += '~' + rgb_dec565(White) + '~~'; + } + } else { + navigationString += '~~~button~bSubNext~' + Icons.GetIcon('arrow-right-bold') + '~' + rgb_dec565(White) + '~~'; + } + } + } + + if (activePage!.subPage && (navigationString != "")){ + return navigationString + } + + switch (pageId) { + case -1: + return 'button~bUp~' + Icons.GetIcon('arrow-up-bold') + '~' + rgb_dec565(White) + ' ~~~delete~~~~~'; + case -2: + return 'button~bUp~' + Icons.GetIcon('arrow-up-bold') + '~' + rgb_dec565(White) + '~~~delete~~~~~'; + default: + { + if (activePage!.prevIcon != undefined){ + navigationString = 'button~bPrev~' + Icons.GetIcon(activePage!.prevIcon); + } else { + navigationString = 'button~bPrev~' + Icons.GetIcon('arrow-left-bold'); + } + + if (activePage!.prevIconColor != undefined){ + navigationString += '~' + rgb_dec565(activePage!.prevIconColor); + } else { + navigationString += '~' + rgb_dec565(White); + } + + if (activePage!.nextIcon != undefined){ + navigationString += '~~~button~bNext~' + Icons.GetIcon(activePage!.nextIcon); + } else { + navigationString += '~~~button~bNext~' + Icons.GetIcon('arrow-right-bold'); + } + if (activePage!.nextIconColor != undefined){ + navigationString += '~' + rgb_dec565(activePage!.nextIconColor) + '~~'; + } else { + navigationString += '~' + rgb_dec565(White) + '~~'; + } + return navigationString; + } + } + + } catch (err: any) { + log('error at function GetNavigationString: ' + err.message, 'warn'); + } + return ''; +} + +function GenerateDetailPage(type: string, optional: mediaOptional | undefined, pageItem: PageItem, placeId: number | undefined): Payload[] { + if (Debug) log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); + try { + let out_msgs: Array = []; + let id = pageItem.id; + + if (id && existsObject(id)) { + + let o = getObject(id); + let val: (boolean | number) = 0; + let icon = Icons.GetIcon('lightbulb'); + let iconColor = rgb_dec565(config.defaultColor); + + if (type == 'popupLight') { + + let switchVal = '0'; + let brightness = 0; + switch (o.common.role) { + case 'light': + case 'socket': { + if (existsState(id + '.GET')) { + val = getState(id + '.GET').val; + RegisterDetailEntityWatcher(id + '.GET', pageItem, type, placeId); + } else if (existsState(id + '.SET')) { + if(pageItem.monobutton != undefined && pageItem.monobutton == true){ + val = getState(id + ".STATE").val; + RegisterDetailEntityWatcher(id + ".STATE", pageItem, type, placeId); + } + else { + val = getState(id + '.SET').val; + RegisterDetailEntityWatcher(id + '.SET', pageItem, type, placeId); + } + } + + icon = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + + if (val) { + switchVal = '1'; + iconColor = GetIconColor(pageItem, true, true); + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + let effect_supported = 'disable'; + if (pageItem.modeList != undefined) { + effect_supported = 'enable'; + } + + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' // entityUpdateDetail + + tempId + '~' + + icon + '~' // iconId + + iconColor + '~' // iconColor + + switchVal + '~' // buttonState + + 'disable' + '~' // sliderBrightnessPos + + 'disable' + '~' // sliderColorTempPos + + 'disable' + '~' // colorMode + + '' + '~' // Color identifier + + findLocale('lights', 'Temperature') + '~' // Temperature identifier + + findLocale('lights', 'Brightness') + '~' // Brightness identifier + + effect_supported + }); + } + break; + // Dimmer + case 'dimmer': { + if (existsState(id + '.ON_ACTUAL')) { + val = getState(id + '.ON_ACTUAL').val; + RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type, placeId); + } else if (existsState(id + '.ON_SET')) { + val = getState(id + '.ON_SET').val; + RegisterDetailEntityWatcher(id + '.ON_SET', pageItem, type, placeId); + } + + if (val === true) { + iconColor = GetIconColor(pageItem, val, false); + switchVal = '1' + } + + if (existsState(id + '.ACTUAL')) { + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + brightness = Math.trunc(scale(getState(id + '.ACTUAL').val, pageItem.minValueBrightness, pageItem.maxValueBrightness, 100, 0)); + } else { + brightness = getState(id + '.ACTUAL').val; + } + } else { + log('function GenerateDetailPage role:dimmer -> Alias-Datenpoint: ' + id + '.ACTUAL could not be read', 'warn'); + } + + if (val === true) { + iconColor = GetIconColor(pageItem, brightness, true); + switchVal = '1'; + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + RegisterDetailEntityWatcher(id + '.ACTUAL', pageItem, type, placeId); + + let effect_supported = 'disable'; + if (pageItem.modeList != undefined) { + effect_supported = 'enable'; + } + + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + tempId + '~' + + icon + '~' //iconId + + iconColor + '~' //iconColor + + switchVal + '~' //buttonState + + brightness + '~' //sliderBrightnessPos + + 'disable' + '~' //sliderColorTempPos + + 'disable' + '~' //colorMod + + '' + '~' //Color-identifier + + findLocale('lights', 'Temperature') + '~' //Temperature-identifier + + findLocale('lights', 'Brightness') + '~' //Brightness-identifier + + effect_supported + }); + } + break; + // HUE-Licht + case 'hue': { + + if (existsState(id + '.ON_ACTUAL')) { + val = getState(id + '.ON_ACTUAL').val; + RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type, placeId); + } + + if (existsState(id + '.DIMMER')) { + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + brightness = Math.trunc(scale(getState(id + '.DIMMER').val, pageItem.minValueBrightness, pageItem.maxValueBrightness, 100, 0)); + } else { + brightness = getState(id + '.DIMMER').val; + } + RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type, placeId); + } else { + log('function GenerateDetailPage role:hue -> Alias-Datenpunkt: ' + id + '.DIMMER could not be read', 'warn'); + } + + if (val === true) { + iconColor = GetIconColor(pageItem, brightness, true); + switchVal = '1'; + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + let colorMode = 'disable'; + if (existsState(id + '.HUE')) { + if (getState(id + '.HUE').val != null) { + colorMode = 'enable'; + let huecolor = hsv2rgb(getState(id + '.HUE').val, 1, 1); + let rgb: 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); + } + } + let colorTemp: any; + if (existsState(id + '.TEMPERATURE')) { + colorTemp = 0; + if (getState(id + '.TEMPERATURE').val != null) { + if (pageItem.minValueColorTemp !== undefined && pageItem.maxValueColorTemp !== undefined) { + colorTemp = Math.trunc(scale(getState(id + '.TEMPERATURE').val, pageItem.minValueColorTemp, pageItem.maxValueColorTemp, 100, 0)); + } else { + colorTemp = getState(id + '.TEMPERATURE').val; + } + } + } else { + colorTemp = 'disable'; + } + + let effect_supported = 'disable'; + if (pageItem.modeList != undefined) { + effect_supported = 'enable'; + } + + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + tempId + '~' + + icon + '~' //iconId + + iconColor + '~' //iconColor + + switchVal + '~' //buttonState + + brightness + '~' //sliderBrightnessPos + + colorTemp + '~' //sliderColorTempPos + + colorMode + '~' //colorMode (if hue-alias without hue-datapoint, then disable) + + 'Color' + '~' //Color-identifier + + findLocale('lights', 'Temperature') + '~' //Temperature-identifier + + findLocale('lights', 'Brightness') + '~' //Brightness-identifier + + effect_supported + }); + } + break; + // RGB-Licht + case 'rgb': { + + if (existsState(id + '.ON_ACTUAL')) { + val = getState(id + '.ON_ACTUAL').val; + RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type, placeId); + } + + if (existsState(id + '.DIMMER')) { + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + brightness = Math.trunc(scale(getState(id + '.DIMMER').val, pageItem.minValueBrightness, pageItem.maxValueBrightness, 100, 0)); + } else { + brightness = getState(id + '.DIMMER').val; + } + RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type, placeId); + } else { + log('function GenerateDetailPage role:rgb -> Alias-Datenpunkt: ' + id + '.DIMMER could not be read', 'warn'); + } + + if (val === true) { + iconColor = GetIconColor(pageItem, brightness, true); + switchVal = '1'; + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + let colorMode = 'disable'; + if (existsState(id + '.RED') && existsState(id + '.GREEN') && existsState(id + '.BLUE')) { + if (getState(id + '.RED').val != null && getState(id + '.GREEN').val != null && getState(id + '.BLUE').val != null) { + colorMode = 'enable'; + let rgb: RGB = { red: Math.round(getState(id + '.RED').val), green: Math.round(getState(id + '.GREEN').val), blue: Math.round(getState(id + '.BLUE').val) } + iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); + } + } + let colorTemp: any; + if (existsState(id + '.TEMPERATURE')) { + colorTemp = 0; + if (getState(id + '.TEMPERATURE').val != null) { + if (pageItem.minValueColorTemp !== undefined && pageItem.minValueColorTemp !== undefined) { + colorTemp = Math.trunc(scale(getState(id + '.TEMPERATURE').val, pageItem.minValueColorTemp, pageItem.maxValueColorTemp!, 100, 0)); + } else { + colorTemp = getState(id + '.TEMPERATURE').val; + } + } + } else { + colorTemp = 'disable'; + } + + let effect_supported = 'disable'; + if (pageItem.modeList != undefined) { + effect_supported = 'enable'; + } + + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + tempId + '~' + + icon + '~' //iconId + + iconColor + '~' //iconColor + + switchVal + '~' //buttonState + + brightness + '~' //sliderBrightnessPos + + colorTemp + '~' //sliderColorTempPos + + colorMode + '~' //colorMode (if hue-alias without hue-datapoint, then disable) + + 'Color' + '~' //Color-identifier + + findLocale('lights', 'Temperature') + '~' //Temperature-identifier + + findLocale('lights', 'Brightness') + '~' //Brightness-identifier + + effect_supported + }); + } + break; + // RGB-Licht-einzeln (HEX) + case 'rgbSingle': { + + if (existsState(id + '.ON_ACTUAL')) { + val = getState(id + '.ON_ACTUAL').val; + RegisterDetailEntityWatcher(id + '.ON_ACTUAL', pageItem, type, placeId); + } + + if (existsState(id + '.DIMMER')) { + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + brightness = Math.trunc(scale(getState(id + '.DIMMER').val, pageItem.minValueBrightness, pageItem.maxValueBrightness, 100, 0)); + } else { + brightness = getState(id + '.DIMMER').val; + } + RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type, placeId); + } else { + log('function GenerateDetailPage role:rgbSingle -> Alias-Datenpunkt: ' + id + '.DIMMER could not be read', 'warn'); + } + + if (val === true) { + iconColor = GetIconColor(pageItem, brightness, true); + switchVal = '1'; + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + let colorMode = 'disable'; + if (existsState(id + '.RGB')) { + if (getState(id + '.RGB').val != null) { + colorMode = 'enable'; + let hex = getState(id + '.RGB').val; + let hexRed = parseInt(hex[1] + hex[2], 16); + let hexGreen = parseInt(hex[3] + hex[4], 16); + let hexBlue = parseInt(hex[5] + hex[6], 16); + let rgb: RGB = { red: Math.round(hexRed), green: Math.round(hexGreen), blue: Math.round(hexBlue) } + iconColor = rgb_dec565(pageItem.interpolateColor !== undefined ? rgb : config.defaultOnColor); + } + } + + let colorTemp:any; + if (existsState(id + '.TEMPERATURE')) { + colorTemp = 0; + if (getState(id + '.TEMPERATURE').val != null) { + if (pageItem.minValueColorTemp !== undefined && pageItem.maxValueColorTemp !== undefined) { + colorTemp = Math.trunc(scale(getState(id + '.TEMPERATURE').val, pageItem.minValueColorTemp, pageItem.maxValueColorTemp, 100, 0)); + } else { + colorTemp = getState(id + '.TEMPERATURE').val; + } + } + } else { + colorTemp = 'disable'; + } + + let effect_supported = 'disable'; + if (pageItem.modeList != undefined) { + effect_supported = 'enable'; + } + + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + tempId + '~' + + icon + '~' //iconId + + iconColor + '~' //iconColor + + switchVal + '~' //buttonState + + brightness + '~' //sliderBrightnessPos + + colorTemp + '~' //sliderColorTempPos + + colorMode + '~' //colorMode (if hue-alias without hue-datapoint, then disable) + + 'Color' + '~' //Color-identifier + + findLocale('lights', 'Temperature') + '~' //Temperature-identifier + + findLocale('lights', 'Brightness') + '~' //Brightness-identifier + + effect_supported + }); + } + break; + // Farbtemperatur (CT) + case 'ct': { + + if (existsState(id + '.ON')) { + val = getState(id + '.ON').val; + RegisterDetailEntityWatcher(id + '.ON', pageItem, type, placeId); + } + + if (existsState(id + '.DIMMER')) { + if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { + brightness = Math.trunc(scale(getState(id + '.DIMMER').val, pageItem.minValueBrightness, pageItem.maxValueBrightness, 100, 0)); + } else { + brightness = getState(id + '.DIMMER').val; + } + RegisterDetailEntityWatcher(id + '.DIMMER', pageItem, type, placeId); + } else { + log('function GenerateDetailPage role:ct -> Alias-Datenpunkt: ' + id + '.DIMMER could not be read', 'warn'); + } + + if (val === true) { + iconColor = GetIconColor(pageItem, brightness, true); + switchVal = '1'; + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + let colorMode = 'disable'; + + let colorTemp = 0; + if (existsState(id + '.TEMPERATURE')) { + if (getState(id + '.TEMPERATURE').val != null) { + if (pageItem.minValueColorTemp !== undefined && pageItem.maxValueColorTemp !== undefined) { + colorTemp = Math.trunc(scale(getState(id + '.TEMPERATURE').val, pageItem.minValueColorTemp, pageItem.maxValueColorTemp, 100, 0)); + } else { + colorTemp = getState(id + '.TEMPERATURE').val; + } + } + } else { + log('function GenerateDetailPage role:ct -> Alias-Datenpunkt: ' + id + '.TEMPERATURE could not be read', 'warn'); + } + + let effect_supported = 'disable'; + if (pageItem.modeList != undefined) { + effect_supported = 'enable'; + } + + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + tempId + '~' + + icon + '~' //iconId + + iconColor + '~' //iconColor + + switchVal + '~' //buttonState + + brightness + '~' //sliderBrightnessPos + + colorTemp + '~' //sliderColorTempPos + + colorMode + '~' //colorMode (if hue-alias without hue-datapoint, then disable) + + 'Color' + '~' //Color-identifier + + findLocale('lights', 'Temperature') + '~' //Temperature-identifier + + findLocale('lights', 'Brightness') + '~' //Brightness-identifier + + effect_supported + }); + } + break; + } + } + + 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, placeId); + } else if (existsState(id + '.SET')) { + val = getState(id + '.SET').val; + //RegisterDetailEntityWatcher(id + '.SET', pageItem, type); + } + let tilt_position: any = 'disabled' + if (existsState(id + '.TILT_ACTUAL')) { + tilt_position = getState(id + '.TILT_ACTUAL').val; + RegisterDetailEntityWatcher(id + '.TILT_ACTUAL', pageItem, type, placeId); + } else if (existsState(id + '.TILT_SET')) { + tilt_position = getState(id + '.TILT_SET').val; + //RegisterDetailEntityWatcher(id + '.TILT_SET', pageItem, type); + } + + let min_Level: number = 0; + let max_Level: number = 100; + if (pageItem.minValueLevel !== undefined && pageItem.maxValueLevel !== undefined) { + min_Level = pageItem.minValueLevel; + max_Level = pageItem.maxValueLevel; + val = Math.trunc(scale(getState(id + '.ACTUAL').val, pageItem.minValueLevel, pageItem.maxValueLevel, 100, 0)); + } + let min_Tilt: number = 0; + let max_Tilt: number = 100; + if (pageItem.minValueTilt !== undefined && pageItem.maxValueTilt !== undefined) { + min_Tilt = pageItem.minValueTilt; + max_Tilt = pageItem.maxValueTilt; + tilt_position = Math.trunc(scale(getState(id + '.TILT_ACTUAL').val, pageItem.minValueTilt, pageItem.maxValueTilt, 100, 0)); + } + + if (Debug) log('minLevel '+ min_Level + ' maxLevel ' + max_Level + ' Level ' + val, 'info'); + if (Debug) log('minTilt '+ min_Tilt + ' maxTilt ' + max_Tilt + ' TiltPosition ' + tilt_position, 'info'); + + let textSecondRow = ''; + let icon_id = icon; + let icon_up = Icons.GetIcon('arrow-up'); + let icon_stop = Icons.GetIcon('stop'); + let icon_down = Icons.GetIcon('arrow-down'); + let tempVal: number = getState(pageItem.id + '.ACTUAL').val + let icon_up_status = tempVal === min_Level ? 'disable' : 'enable'; + let icon_stop_status = 'enable'; + if (tempVal === min_Level || tempVal === max_Level || checkBlindActive === false) { + icon_stop_status = 'disable'; + } + let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; + let textTilt = ''; + let iconTiltLeft = ''; + let iconTiltStop = ''; + let iconTiltRight = ''; + let iconTiltLeftStatus = 'disable'; + let iconTiltStopStatus = 'disable'; + let iconTiltRightStatus = 'disable'; + let tilt_pos = 'disable'; + + if (existsState(id + '.TILT_SET')) { + textTilt = findLocale('blinds', 'Tilt'); + iconTiltLeft = Icons.GetIcon('arrow-top-right'); + iconTiltStop = Icons.GetIcon('stop'); + iconTiltRight = Icons.GetIcon('arrow-bottom-left'); + iconTiltLeftStatus = getState(id + '.TILT_ACTUAL').val != max_Tilt ? 'enable' : 'disable'; + iconTiltStopStatus = 'enable'; + iconTiltRightStatus = getState(id + '.TILT_ACTUAL').val != min_Tilt ? 'enable' : 'disable'; + tilt_pos = tilt_position; + } + + if (pageItem.secondRow != undefined) { + textSecondRow = pageItem.secondRow; + } + + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + tempId + '~' //entity_id + + val + '~' //Shutterposition + + textSecondRow + '~' //pos_status 2.line + + findLocale('blinds', 'Position') + '~' //pos_translation + + icon_id + '~' //{icon_id}~ + + icon_up + '~' //{icon_up}~ + + icon_stop + '~' //{icon_stop}~ + + icon_down + '~' //{icon_down}~ + + icon_up_status + '~' //{icon_up_status}~ + + icon_stop_status + '~' //{icon_stop_status}~ + + icon_down_status + '~' //{icon_down_status}~ + + textTilt + '~' //{textTilt}~ + + iconTiltLeft + '~' //{iconTiltLeft}~ + + iconTiltStop + '~' //{iconTiltStop}~ + + iconTiltRight + '~' //{iconTiltRight}~ + + iconTiltLeftStatus + '~' //{iconTiltLeftStatus}~ + + iconTiltStopStatus + '~' //{iconTiltStopStatus}~ + + iconTiltRightStatus + '~' //{iconTiltRightStatus}~ + + tilt_pos //{tilt_pos}") + }); + } + + if (type == 'popupThermo') { + let vIcon = (pageItem.icon != undefined) ? pageItem.icon : 'fan'; + let mode1 = (pageItem.popupThermoMode1 != undefined) ? pageItem.popupThermoMode1.join('?') : ''; + let mode2 = (pageItem.popupThermoMode2 != undefined) ? pageItem.popupThermoMode2.join('?') : ''; + let mode3 = (pageItem.popupThermoMode3 != undefined) ? pageItem.popupThermoMode3.join('?') : ''; + + let payloadParameters1 = '~~~~' + if (pageItem.popupThermoMode1 != undefined) { + RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias![0], pageItem, type, placeId); + payloadParameters1 = pageItem.popUpThermoName![0] + '~' //{heading}~ Mode 1 + + 'modus1' + '~' //{id}~ Mode 1 + + getState(pageItem.id + "." + pageItem.setThermoAlias![0]).val + '~' //{ACTUAL}~ Mode 1 + + mode1 + '~'; //{possible values} Mode 1 (1-n) + } + + let payloadParameters2 = '~~~~' + if (pageItem.popupThermoMode2 != undefined) { + RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias![1], pageItem, type, placeId); + payloadParameters2 = pageItem.popUpThermoName![1] + '~' //{heading}~ Mode 2 + + 'modus2' + '~' //{id}~ Mode 2 + + getState(pageItem.id + "." + pageItem.setThermoAlias![1]).val + '~' //{ACTUAL}~ Mode 2 + + mode2 + '~'; //{possible values} + } + + let payloadParameters3 = '~~~~' + if (pageItem.popupThermoMode3 != undefined) { + RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias![2], pageItem, type, placeId); + payloadParameters3 = pageItem.popUpThermoName![2] + '~' //{heading}~ Mode 3 + + 'modus3' + '~' //{id}~ Mode 3 + + getState(pageItem.id + "." + pageItem.setThermoAlias![2]).val + '~' //{ACTUAL}~ Mode 3 + + mode3; //{possible values} Mode 3 (1-n) + } + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + id + '~' //{entity_id} + + Icons.GetIcon(vIcon) + '~' //{icon_id}~ + + 11487 + '~' //{icon_color}~ + + payloadParameters1 + + payloadParameters2 + + payloadParameters3 + }); + } + + if (type == 'popupTimer') { + + let timer_actual: number = 0; + + if (existsState(id + '.ACTUAL')) { + RegisterDetailEntityWatcher(id + '.ACTUAL', pageItem, type, placeId); + timer_actual = getState(id + '.ACTUAL').val; + } + + if (existsState(id + '.STATE')) { + RegisterDetailEntityWatcher(id + '.STATE', pageItem, type, placeId); + } + + let editable = 1; + let action1 = ''; + let action2 = ''; + let action3 = ''; + let label1 = ''; + let label2 = ''; + let label3 = ''; + let min_remaining = 0; + let sec_remaining = 0; + if (existsState(id + '.STATE')) { + + if (o.common.role == 'value.time') { + if (getState(id + '.STATE').val == 'idle' || getState(id + '.STATE').val == 'paused') { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 1; + } else { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 1; + } + } else if (o.common.role == 'level.timer') { + if (getState(id + '.STATE').val == 'idle' || getState(id + '.STATE').val == 'paused') { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 1; + action2 = 'start'; + label2 = findLocale('timer', 'start'); + } else { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 0; + action1 = 'pause'; + action2 = 'cancle'; + action3 = 'finish'; + label1 = findLocale('timer', 'pause'); + label2 = findLocale('timer', 'cancel'); + label3 = findLocale('timer', 'finish'); + } + } else if (o.common.role == 'value.alarmtime') { + if (getState(id + '.STATE').val == 'paused') { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 1; + action2 = 'start'; + label2 = findLocale('timer', 'on'); + } else { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 0; + action2 = 'pause'; + label2 = findLocale('timer', 'off'); + } + } + + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + tempId + '~~' //{entity_id} + + rgb_dec565(White) + '~' //{icon_color}~ + + tempId + '~' + + min_remaining + '~' + + sec_remaining + '~' + + editable + '~' + + action1 + '~' + + action2 + '~' + + action3 + '~' + + label1 + '~' + + label2 + '~' + + label3 + }); + } + } + + if (type == 'popupFan') { + + let switchVal = '0'; + if (o.common.role == 'level.mode.fan') { + if (existsState(id + '.SET')) { + val = getState(id + '.SET').val; + RegisterDetailEntityWatcher(id + '.SET', pageItem, type, placeId); + } + if (existsState(id + '.MODE')) { + RegisterDetailEntityWatcher(id + '.MODE', pageItem, type, placeId); + } + + icon = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : 'fan'; + + if (val) { + switchVal = '1'; + iconColor = GetIconColor(pageItem, true, true); + } else { + iconColor = GetIconColor(pageItem, false, true); + } + + let actualSpeed = getState(id + '.SPEED').val; + let maxSpeed = (pageItem.maxValue != undefined) ? pageItem.maxValue : 100; + + let modeList = pageItem.modeList!.join('?'); + let actualMode = pageItem.modeList![getState(id + '.MODE').val]; + + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' // entityUpdateDetail + + tempId + '~' + + icon + '~' // iconId + + iconColor + '~' // iconColor + + switchVal + '~' // buttonState + + actualSpeed + '~' + + maxSpeed + '~' + + findLocale('fan', 'speed') + '~' + + actualMode + '~' + + modeList + }); + } + } + + if (type == 'popupInSel') { + if (o.common.role == 'media') { + let actualState: any = ''; + let optionalString: string = 'Kein Eintrag'; + let mode: string = ''; + if (isPageMediaItem(pageItem)) { + const vTempAdapter = (pageItem.adapterPlayerInstance!).split('.'); + const vAdapter: PlayerType = vTempAdapter[0] as PlayerType; + if (optional == 'seek') { + let actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; + if (actualStateTemp >= 95) { + actualState = '100%'; + } else if (actualStateTemp >= 85) { + actualState = '90%'; + } else if (actualStateTemp >= 75) { + actualState = '80%'; + } else if (actualStateTemp >= 65) { + actualState = '70%'; + } else if (actualStateTemp >= 55) { + actualState = '60%'; + } else if (actualStateTemp >= 45) { + actualState = '50%'; + } else if (actualStateTemp >= 35) { + actualState = '40%'; + } else if (actualStateTemp >= 25) { + actualState = '30%'; + } else if (actualStateTemp >= 15) { + actualState = '20%'; + } else if (actualStateTemp >= 5) { + actualState = '10%'; + } else if (actualStateTemp >= 0) { + actualState = '0%'; + } + if (vAdapter == 'sonos') { + optionalString = '0%?10%?20%?30%?40%?50%?60%?70%?80%?90%?100%'; + } + mode = 'seek'; + } else if (optional == 'crossfade') { + if (existsObject(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.crossfade')) { + let actualStateTemp: boolean = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.crossfade').val; + if (actualStateTemp) { + actualState = findLocale('media', 'on'); + } else { + actualState = findLocale('media', 'off'); + } + } + if (vAdapter == 'sonos') { + optionalString = findLocale('media', 'on') + '?' + findLocale('media', 'off'); + } + mode = 'crossfade'; + } else if (optional == 'speakerlist') { + if (vAdapter == 'spotify-premium') { + if (existsObject(pageItem.adapterPlayerInstance + 'player.device.name')) { + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'player.device.name').val); + } + } else if (vAdapter == 'alexa2') { + if (existsObject(pageItem.adapterPlayerInstance + 'player.device.name')) { + //Todo Richtiges Device finden + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Info.name').val); + } + } else if (vAdapter == 'squeezeboxrpc') { + actualState = pageItem.mediaDevice; + } + let tempSpeakerList: string[] = []; + for (let i = 0; i < pageItem.speakerList!.length; i++) { + tempSpeakerList[i] = formatInSelText(pageItem.speakerList![i]).trim(); + } + optionalString = pageItem.speakerList != undefined ? tempSpeakerList.join('?') : ''; + mode = 'speakerlist'; + } else if (optional == 'playlist') { + if (vAdapter == 'spotify-premium') { + if (existsObject(pageItem.adapterPlayerInstance + 'player.playlist.name')) { + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'player.playlist.name').val); + } + let tempPlayList: string[] = []; + for (let i = 0; i < pageItem.playList!.length; i++) { + tempPlayList[i] = formatInSelText(pageItem.playList![i]); + } + optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' + } else if (vAdapter == 'alexa2') { + //Todo Richtiges Device finden + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Player.currentAlbum').val); + + let tPlayList: any = [] + for (let i = 0; i < pageItem.playList!.length; i++) { + if (Debug) log('function GenerateDetailPage role:media -> Playlist ' + pageItem.playList![i], 'info'); + let tempItem = pageItem.playList![i].split('.'); + tPlayList[i] = tempItem[1]; + } + + let tempPlayList: string[] = []; + for (let i = 0; i < tPlayList.length; i++) { + tempPlayList[i] = formatInSelText(tPlayList[i]); + } + optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' + } else if (vAdapter == 'sonos') { + if (Debug) log(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set', 'info'); + if (existsObject(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set')) { + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set').val); + } + let tempPlayList: string[] = []; + for (let i = 0; i < pageItem.playList!.length; i++) { + tempPlayList[i] = formatInSelText(pageItem.playList![i]); + } + optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' + } else if (vAdapter == 'volumio') { /* Volumio: limit 900 chars */ + actualState = ''; //todo: no actual playlistname saving + let tempPlayList: string[] = []; let tempPll = 0; + for (let i = 0; i < pageItem.playList!.length; i++) { + tempPll += pageItem.playList![i].length; if (tempPll > 900) break; + tempPlayList[i] = formatInSelText(pageItem.playList![i]); + } + optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' + } else if (vAdapter == 'squeezeboxrpc') { + // Playlist browsing not supported by squeezeboxrpc adapter. But Favorites can be used + actualState = ''; // Not supported by squeezeboxrpc adapter + let tempPlayList: string[] = []; + let pathParts: Array = pageItem.adapterPlayerInstance!.split('.'); + for (let favorite_index = 0; favorite_index < 45; favorite_index++) { + let favorite_name_selector: string = [pathParts[0], pathParts[1], 'Favorites', favorite_index, 'Name'].join('.'); + if (!existsObject(favorite_name_selector)) { + break; + } + let favoritename: string = getState(favorite_name_selector).val; + tempPlayList.push(formatInSelText(favoritename)); + } + optionalString = tempPlayList.length > 0 ? tempPlayList.join('?') : ''; + } + mode = 'playlist'; + } else if (optional == 'tracklist') { + actualState = ''; + /* Volumio: works for files */ + if (vAdapter == 'volumio') { + actualState = getState(pageItem.id + '.TITLE').val; + globalTracklist = pageItem.globalTracklist; + } else if (vAdapter == 'squeezeboxrpc') { + actualState = getState(pageItem.id + '.TITLE').val; + } else if (vAdapter == 'sonos') { + actualState = getState(pageItem.id + '.TITLE').val; + } else { + actualState = getState(pageItem.adapterPlayerInstance + 'player.trackName').val; + } + actualState = (actualState.replace('?', '')).split(' -'); + actualState = actualState[0].split(" ("); + actualState = formatInSelText(actualState[0]); + if (Debug) log(actualState, 'info'); + if (Debug) log(globalTracklist, 'info'); + //Limit 900 characters, then memory overflow --> Shorten as much as possible + let temp_array: any[] = []; + //let trackArray = (function () { try {return JSON.parse(getState(pageItem.adapterPlayerInstance + 'player.playlist.trackListArray').val);} catch(e) {return {};}})(); + for (let track_index = 0; track_index < 45; track_index++) { + let temp_cut_array = getAttr(globalTracklist, track_index + '.title'); + /* Volumio: @local/NAS no title -> name */ + if (temp_cut_array == undefined) { + temp_cut_array = getAttr(globalTracklist, track_index + '.name'); + } + if (Debug) log('function GenerateDetailPage role:media tracklist -> ' + temp_cut_array, 'info'); + if (temp_cut_array != undefined) { + temp_cut_array = (temp_cut_array.replace('?', '')).split(' -'); + temp_cut_array = temp_cut_array[0].split(" ("); + temp_cut_array = temp_cut_array[0]; + if (String(temp_cut_array[0]).length >= 22) { + temp_array[track_index] = temp_cut_array.substring(0, 20) + '..'; + } else { + temp_array[track_index] = temp_cut_array.substring(0, 23); + } + } + else { + break; + } + } + let tempTrackList: string[] = []; + for (let i = 0; i < temp_array.length; i++) { + tempTrackList[i] = formatInSelText(temp_array[i]); + } + optionalString = pageItem.playList != undefined ? tempTrackList.join('?') : '' + mode = 'tracklist'; + } else if (optional == 'equalizer') { + if (pageItem.id == undefined) throw new Error('Missing pageItem.id in equalizer!'); + let lastIndex = (pageItem.id.split('.')).pop(); + + if (existsObject(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode') == false || + existsObject(NSPanel_Path + 'Media.Player.' + lastIndex + '.Speaker') == false) { + createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode', {type: 'string'}); + createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.Speaker', {type: 'string'}); + } + + actualState = '' + if (getState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode').val != null) { + actualState = formatInSelText(getState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode').val); + } + + let tempEQList: string[] = []; + for (let i = 0; i < pageItem.equalizerList!.length; i++) { + tempEQList[i] = formatInSelText(pageItem!.equalizerList![i]); + } + + optionalString = pageItem.equalizerList != undefined ? tempEQList.join('?') : ''; + mode = 'equalizer'; + } else if (optional == 'repeat') { + actualState = getState(pageItem.adapterPlayerInstance + 'player.repeat').val; + optionalString = pageItem.repeatList!.join('?'); + mode = 'repeat'; + } else if (optional == 'favorites') { + if (Debug) log(getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.favorites_set').val, 'info') + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.favorites_set').val); + + let tempFavList: string[] = []; + let favList = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.favorites_list_array').val; + for (let i = 0; i < favList.length; i++) { + tempFavList[i] = formatInSelText(favList[i]); + } + optionalString = tempFavList != undefined ? tempFavList.join('?') : ''; + mode = 'favorites'; + } + + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail + + tempId + '?' + optional + '~~' //{entity_id} + + rgb_dec565(HMIOn) + '~' //{icon_color}~ + + mode + '~' + + actualState + '~' + + optionalString + }); + GeneratePage(activePage!); + } + } else if (o.common.role == 'buttonSensor') { + + let actualValue: string = ''; + + if (pageItem.inSel_ChoiceState || pageItem.inSel_ChoiceState == undefined) { + if (existsObject(pageItem.id + '.VALUE')) { + actualValue = formatInSelText(pageItem.modeList![getState(pageItem.id + '.VALUE').val]); + RegisterDetailEntityWatcher(id + '.VALUE', pageItem, type, placeId); + } + } + + let tempModeList: string[] = []; + for (let i = 0; i < pageItem.modeList!.length; i++) { + tempModeList[i] = formatInSelText(pageItem.modeList![i]); + } + let valueList = pageItem.modeList != undefined ? tempModeList.join('?') : ''; + + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail2 + + tempId + '~~' //{entity_id} + + rgb_dec565(White) + '~' //{icon_color}~ + + 'insel' + '~' + + actualValue + '~' + + valueList + }); + } else if (o.common.role == 'light' || + o.common.role == 'dimmer' || + o.common.role == 'hue' || + o.common.role == 'rgb' || + o.common.role == 'rgbSingle' || + o.common.role == 'ct') { + + //log(pageItem.id, 'info'); + if (pageItem.modeList != undefined) { + + let actualValue: string = ''; + + if (pageItem.inSel_ChoiceState || pageItem.inSel_ChoiceState == undefined) { + if (existsObject(pageItem.id + '.VALUE')) { + actualValue = formatInSelText(pageItem.modeList[getState(pageItem.id + '.VALUE').val]); + RegisterDetailEntityWatcher(id + '.VALUE', pageItem, type, placeId); + } + } + + let tempModeList: string[] = []; + for (let i = 0; i < pageItem.modeList.length; i++) { + tempModeList[i] = formatInSelText(pageItem.modeList[i]); + } + let valueList = pageItem.modeList != undefined ? tempModeList.join('?') : ''; + + //log(valueList); + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail2 + + tempId + '~~' //{entity_id} + + rgb_dec565(White) + '~' //{icon_color}~ + + 'insel' + '~' + + actualValue + '~' + + valueList + }); + } + } + } + } + if (Debug) log('GenerateDetailPage -> payload: ' + JSON.stringify(out_msgs), 'info'); + return out_msgs; + + } catch (err: any) { + log('error at function GenerateDetailPage: ' + err.message, 'warn'); + } + return []; +} + +function scale(number: number, inMin: number, inMax: number, outMin: number, outMax: number): number { + try { + return (outMax + outMin) - ((number - inMin) * (outMax - outMin) / (inMax - inMin) + outMin); + } catch (err: any) { + log('error at function scale: ' + err.message, 'warn'); + } + return 0 +} + +function UnsubscribeWatcher(): void { + try { + for (const [key, value] of Object.entries(subscriptions)) { + unsubscribe(value); + delete subscriptions[key]; + } + } catch (err: any) { + log('error at function UnsubscribeWatcher: ' + err.message, 'warn'); + } +} + +function HandleScreensaver(): void { + setIfExists(NSPanel_Path + 'ActivePage.type', 'screensaver'); + setIfExists(NSPanel_Path + 'ActivePage.id0', 'screensaver'); + setIfExists(NSPanel_Path + 'ActivePage.heading', 'Screensaver'); + if (existsObject(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced')) { + if (getState(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced').val) { + SendToPanel({ payload: 'pageType~screensaver2' }); + } else { + SendToPanel({ payload: 'pageType~screensaver' }); + } + } else { + SendToPanel({ payload: 'pageType~screensaver' }); //Fallback + } + weatherForecast = getState(NSPanel_Path + 'ScreensaverInfo.weatherForecast').val; + HandleScreensaverUpdate(); + HandleScreensaverStatusIcons(); + HandleScreensaverColors(); +} + +function HandleScreensaverUpdate(): void { + try { + + if (screensaverEnabled) { + + UnsubscribeWatcher(); + + let payloadString: string = ''; + let temperatureUnit = getState(NSPanel_Path + 'Config.temperatureUnit').val; + let screensaverAdvanced = getState(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced').val; + + //Create Weather MainIcon + if (screensaverEnabled && config.weatherEntity != null && existsObject(config.weatherEntity)) { + let icon = getState(config.weatherEntity + '.ICON').val; + RegisterScreensaverEntityWatcher(config.weatherEntity + '.ICON') + let temperature = '0'; + if (existsState(config.weatherEntity + '.ACTUAL')) { + temperature= getState(config.weatherEntity + '.ACTUAL').val; + RegisterScreensaverEntityWatcher(config.weatherEntity + '.ACTUAL') + } else { + if (existsState(config.weatherEntity + '.TEMP')) { + temperature = getState(config.weatherEntity + '.TEMP').val; + } else { + 'null'; + } + } + let optionalValue = temperature + ' ' + temperatureUnit; + let entityIcon = ''; + let entityIconCol = 0; + if (weatherAdapterInstance == 'daswetter.' + weatherAdapterInstanceNumber + '.') { + entityIcon = Icons.GetIcon(GetDasWetterIcon(parseInt(icon))); + entityIconCol = GetDasWetterIconColor(parseInt(icon)); + } else if (weatherAdapterInstance == 'accuweather.' + weatherAdapterInstanceNumber + '.') { + entityIcon = Icons.GetIcon(GetAccuWeatherIcon(parseInt(icon))); + entityIconCol = GetAccuWeatherIconColor(parseInt(icon)); + } + + payloadString += '~' + + '~' + + entityIcon + '~' + + entityIconCol + '~' + + '~' + + optionalValue + '~'; + } + + // 3 leftScreensaverEntities + if (screensaverAdvanced) { + let checkpoint = true; + let i = 0; + for (i = 0; i < 3; i++) { + + if (config.leftScreensaverEntity[i] == null || config.leftScreensaverEntity[i] == undefined) { + checkpoint = false; + break; + } + RegisterScreensaverEntityWatcher(config.leftScreensaverEntity[i].ScreensaverEntity) + + let val = getState(config.leftScreensaverEntity[i].ScreensaverEntity).val; + let iconColor = rgb_dec565(White); + let icon; + if (typeof config.leftScreensaverEntity[i].ScreensaverEntityIconOn == 'string' && existsObject(config.leftScreensaverEntity[i].ScreensaverEntityIconOn as string)) { + let iconName = getState(config.leftScreensaverEntity[i].ScreensaverEntityIconOn!).val; + icon = Icons.GetIcon(iconName); + } else { + icon = Icons.GetIcon(config.leftScreensaverEntity[i].ScreensaverEntityIconOn); + } + + if (parseFloat(val+"") == val) { + val = parseFloat(val); + } + + if (typeof(val) == 'number') { + val = (val * (config.leftScreensaverEntity[i].ScreensaverEntityFactor ? config.leftScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.leftScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.leftScreensaverEntity[i].ScreensaverEntityUnitText; + iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); + } + else if (typeof(val) == 'boolean') { + iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); + if (!val && config.leftScreensaverEntity[i].ScreensaverEntityIconOff != null) { + icon = Icons.GetIcon(config.leftScreensaverEntity[i].ScreensaverEntityIconOff) + } + } + else if (typeof(val) == 'string') { + iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); + let pformat = parseFormat(val); + if (Debug) log('moments.js --> Datum ' + val + ' valid?: ' + moment(val, pformat, true).isValid(), 'info'); + if (moment(val, pformat, true).isValid()) { + let DatumZeit = moment(val, pformat).unix(); // Umwandlung in Unix Time-Stamp + if (config.leftScreensaverEntity[i].ScreensaverEntityDateFormat !== undefined) { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val, config.leftScreensaverEntity[i].ScreensaverEntityDateFormat); + } else { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val); + } + } + } + const temp = config.leftScreensaverEntity[i].ScreensaverEntityIconColor; + if (temp && typeof temp == 'string' && existsObject(temp)) { + iconColor = getState(temp).val; + } + + payloadString += '~' + + '~' + + icon + '~' + + iconColor + '~' + + config.leftScreensaverEntity[i].ScreensaverEntityText + '~' + + val + '~'; + } + if (checkpoint == false) { + for (let j = i; j < 3; j++) { + payloadString += '~~~~~~'; + } + } + } + + // 6 bottomScreensaverEntities + let maxEntities: number = 7; + if (screensaverAdvanced == false) { + maxEntities = 5; + if (getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { + maxEntities = 6; + } + } + + if (weatherForecast) { + + if (getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { + maxEntities = 5; + } + + for (let i = 1; i < maxEntities; i++) { + let TempMin = 0; + let TempMax = 0; + let DayOfWeek = 0; + let WeatherIcon = '0'; + let WheatherColor = 0; + + if (weatherAdapterInstance == 'daswetter.' + weatherAdapterInstanceNumber + '.') { + TempMin = getState('daswetter.' + weatherAdapterInstanceNumber + '.NextDays.Location_1.Day_' + i + '.Minimale_Temperatur_value').val; + TempMax = getState('daswetter.' + weatherAdapterInstanceNumber + '.NextDays.Location_1.Day_' + i + '.Maximale_Temperatur_value').val; + DayOfWeek = (getState('daswetter.' + weatherAdapterInstanceNumber + '.NextDays.Location_1.Day_' + i + '.Tag_value').val).substring(0,2); + WeatherIcon = GetDasWetterIcon(getState('daswetter.' + weatherAdapterInstanceNumber + '.NextDays.Location_1.Day_' + i + '.Wetter_Symbol_id').val); + WheatherColor = GetDasWetterIconColor(getState('daswetter.' + weatherAdapterInstanceNumber + '.NextDays.Location_1.Day_' + i + '.Wetter_Symbol_id').val); + + RegisterScreensaverEntityWatcher('daswetter.' + weatherAdapterInstanceNumber + '.NextDays.Location_1.Day_' + i + '.Minimale_Temperatur_value'); + RegisterScreensaverEntityWatcher('daswetter.' + weatherAdapterInstanceNumber + '.NextDays.Location_1.Day_' + i + '.Maximale_Temperatur_value'); + RegisterScreensaverEntityWatcher('daswetter.' + weatherAdapterInstanceNumber + '.NextDays.Location_1.Day_' + i + '.Tag_value'); + RegisterScreensaverEntityWatcher('daswetter.' + weatherAdapterInstanceNumber + '.NextDays.Location_1.Day_' + i + '.Wetter_Symbol_id'); + } else if (weatherAdapterInstance == 'accuweather.' + weatherAdapterInstanceNumber + '.') { + if (i < 6) { + //Maximal 5 Tage bei accuweather + TempMin = (existsObject('accuweather.' + weatherAdapterInstanceNumber + '.Summary.TempMin_d' + i)) ? getState('accuweather.' + weatherAdapterInstanceNumber + '.Summary.TempMin_d' + i).val : 0; + TempMax = (existsObject('accuweather.' + weatherAdapterInstanceNumber + '.Summary.TempMax_d' + i)) ? getState('accuweather.' + weatherAdapterInstanceNumber + '.Summary.TempMax_d' + i).val : 0; + DayOfWeek = (existsObject('accuweather.' + weatherAdapterInstanceNumber + '.Summary.DayOfWeek_d' + i)) ? getState('accuweather.' + weatherAdapterInstanceNumber + '.Summary.DayOfWeek_d' + i).val : 0; + WeatherIcon = (existsObject('accuweather.' + weatherAdapterInstanceNumber + '.Summary.WeatherIcon_d' + i)) ? GetAccuWeatherIcon(getState('accuweather.' + weatherAdapterInstanceNumber + '.Summary.WeatherIcon_d' + i).val) : ''; + WheatherColor = (existsObject('accuweather.' + weatherAdapterInstanceNumber + '.Summary.WeatherIcon_d' + i)) ? GetAccuWeatherIconColor(getState('accuweather.' + weatherAdapterInstanceNumber + '.Summary.WeatherIcon_d' + i).val) : 0; + + RegisterScreensaverEntityWatcher('accuweather.' + weatherAdapterInstanceNumber + '.Summary.TempMin_d' + i); + RegisterScreensaverEntityWatcher('accuweather.' + weatherAdapterInstanceNumber + '.Summary.TempMax_d' + i); + RegisterScreensaverEntityWatcher('accuweather.' + weatherAdapterInstanceNumber + '.Summary.DayOfWeek_d' + i); + RegisterScreensaverEntityWatcher('accuweather.' + weatherAdapterInstanceNumber + '.Summary.WeatherIcon_d' + i); + } + } + + let tempMinMaxString: string = ''; + if (weatherScreensaverTempMinMax == 'Min') { + tempMinMaxString = TempMin + temperatureUnit; + } else if (weatherScreensaverTempMinMax == 'Max') { + tempMinMaxString = TempMax + temperatureUnit; + } else if (weatherScreensaverTempMinMax == 'MinMax') { + tempMinMaxString = Math.round(TempMin) + '° ' + Math.round(TempMax) + '°'; + } + + if (weatherAdapterInstance == 'accuweather.' + weatherAdapterInstanceNumber + '.' && i == 6) { + + let nextSunEvent = 0 + let valDateNow = new Date().getTime(); + let arraySunEvent: number[] = []; + + arraySunEvent[0] = getDateObject(getState('accuweather.' + weatherAdapterInstanceNumber + '.Daily.Day1.Sunrise').val).getTime(); + arraySunEvent[1] = getDateObject(getState('accuweather.' + weatherAdapterInstanceNumber + '.Daily.Day1.Sunset').val).getTime(); + arraySunEvent[2] = getDateObject(getState('accuweather.' + weatherAdapterInstanceNumber + '.Daily.Day2.Sunrise').val).getTime(); + + let j = 0; + for (j = 0; j < 3; j++) { + if (arraySunEvent[j] > valDateNow) { + nextSunEvent = j; + break; + } + } + let sun = ''; + if (j == 1) { + sun = 'weather-sunset-down'; + } else { + sun = 'weather-sunset-up'; + } + + payloadString += '~' + + '~' + + Icons.GetIcon(sun) + '~' + + rgb_dec565(MSYellow) + '~' + + 'Sonne' + '~' + + formatDate(getDateObject(arraySunEvent[nextSunEvent]), 'hh:mm') + '~'; + } else { + payloadString += '~' + + '~' + + Icons.GetIcon(WeatherIcon) + '~' + + WheatherColor + '~' + + DayOfWeek + '~' + + tempMinMaxString + '~'; + } + } + + //Alternativ Layout bekommt zusätzlichen Status + if (getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { + let val = getState(config.bottomScreensaverEntity[4].ScreensaverEntity).val; + if (parseFloat(val+"") == val) { + val = parseFloat(val); + } + let iconColor = rgb_dec565(White); + if (typeof(val) == 'number') { + val = (val * (config.bottomScreensaverEntity[4].ScreensaverEntityFactor ? config.bottomScreensaverEntity[4].ScreensaverEntityFactor : 0)).toFixed(config.bottomScreensaverEntity[4].ScreensaverEntityDecimalPlaces) + config.bottomScreensaverEntity[4].ScreensaverEntityUnitText; + iconColor = GetScreenSaverEntityColor(config.bottomScreensaverEntity[4]); + } + else if (typeof(val) == 'boolean') { + iconColor = GetScreenSaverEntityColor(config.bottomScreensaverEntity[4]); + } + else if (typeof(val) == 'string') { + iconColor = GetScreenSaverEntityColor(config.bottomScreensaverEntity[4]); + + let pformat = parseFormat(val); + if (Debug) log('moments.js --> Datum ' + val + ' valid?: ' + moment(val, pformat, true).isValid(), 'info'); + if (moment(val, pformat, true).isValid()) { + let DatumZeit = moment(val, pformat).unix(); // Conversion to Unix time stamp + if (config.bottomScreensaverEntity[4].ScreensaverEntityDateFormat !== undefined) { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val, config.bottomScreensaverEntity[4].ScreensaverEntityDateFormat); + } else { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val); + } + } + + } + const temp = config.bottomScreensaverEntity[4].ScreensaverEntityIconColor + if (temp && typeof temp == 'string' && existsObject(temp)) { + iconColor = getState(temp).val; + } + payloadString += '~' + + '~' + + Icons.GetIcon(config.bottomScreensaverEntity[4].ScreensaverEntityIconOn) + '~' + + iconColor + '~' + + config.bottomScreensaverEntity[4].ScreensaverEntityText + '~' + + val + } + + } else { + let checkpoint = true; + let i = 0; + for (i = 0; i < maxEntities - 1; i++) { + if (config.bottomScreensaverEntity[i] == null) { + checkpoint = false; + break; + } + RegisterScreensaverEntityWatcher(config.bottomScreensaverEntity[i].ScreensaverEntity) + + let val = getState(config.bottomScreensaverEntity[i].ScreensaverEntity).val; + if (parseFloat(val+"") == val) { + val = parseFloat(val); + } + let iconColor = rgb_dec565(White); + let icon; + if (config.bottomScreensaverEntity[i].ScreensaverEntityIconOn && existsObject(config.bottomScreensaverEntity[i].ScreensaverEntityIconOn!)) { + let iconName = getState(config.bottomScreensaverEntity[i].ScreensaverEntityIconOn!).val; + icon = Icons.GetIcon(iconName); + } else { + icon = Icons.GetIcon(config.bottomScreensaverEntity[i].ScreensaverEntityIconOn); + } + + if (typeof(val) == 'number') { + val = (val * (config.bottomScreensaverEntity[i].ScreensaverEntityFactor ? config.bottomScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.bottomScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.bottomScreensaverEntity[i].ScreensaverEntityUnitText; + iconColor = GetScreenSaverEntityColor(config.bottomScreensaverEntity[i]); + } + else if (typeof(val) == 'boolean') { + iconColor = GetScreenSaverEntityColor(config.bottomScreensaverEntity[i]); + if (!val && config.bottomScreensaverEntity[i].ScreensaverEntityIconOff != null) { + icon = Icons.GetIcon(config.bottomScreensaverEntity[i].ScreensaverEntityIconOff) + } + if (val && config.bottomScreensaverEntity[i].ScreensaverEntityOnText !=undefined) { + val = config.bottomScreensaverEntity[i].ScreensaverEntityOnText; + } + if (!val && config.bottomScreensaverEntity[i].ScreensaverEntityOffText !=undefined) { + val = config.bottomScreensaverEntity[i].ScreensaverEntityOffText; + } + + } + else if (typeof(val) == 'string') { + iconColor = GetScreenSaverEntityColor(config.bottomScreensaverEntity[i]); + let pformat = parseFormat(val); + if (Debug) log('moments.js --> Datum ' + val + ' valid?: ' + moment(val, pformat, true).isValid(), 'info'); + if (moment(val, pformat, true).isValid()) { + let DatumZeit = moment(val, pformat).unix(); // Conversion to Unix time stamp + if (config.bottomScreensaverEntity[i].ScreensaverEntityDateFormat !== undefined) { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val, config.bottomScreensaverEntity[i].ScreensaverEntityDateFormat); + } else { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val); + } + } + } + + const temp = config.bottomScreensaverEntity[4].ScreensaverEntityIconColor + if (temp && typeof temp == 'string' && existsObject(temp)) { + iconColor = getState(temp).val; + } + if (i < maxEntities - 1) { + val = val + '~'; + } + payloadString += '~' + + '~' + + icon + '~' + + iconColor + '~' + + config.bottomScreensaverEntity[i].ScreensaverEntityText + '~' + + val + } + if (checkpoint == false) { + for (let j = i; j < maxEntities - 1; j++) { + payloadString += '~~~~~~'; + } + } + } + + if (screensaverAdvanced) { + // 5 indicatorScreensaverEntities + for (let i = 0; i < 5; i++) { + let checkpoint = true; + if (config.indicatorScreensaverEntity[i] == null) { + checkpoint = false; + break; + } + RegisterScreensaverEntityWatcher(config.indicatorScreensaverEntity[i].ScreensaverEntity) + + let val = getState(config.indicatorScreensaverEntity[i].ScreensaverEntity).val; + if (parseFloat(val+"") == val) { + val = parseFloat(val); + } + let iconColor = rgb_dec565(White); + + let icon; + if (config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn && existsObject(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn!)) { + let iconName = getState(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn!).val; + icon = Icons.GetIcon(iconName); + } else { + icon = Icons.GetIcon(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn); + } + + if (typeof(val) == 'number') { + val = (val * (config.indicatorScreensaverEntity[i].ScreensaverEntityFactor ? config.indicatorScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.indicatorScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.indicatorScreensaverEntity[i].ScreensaverEntityUnitText; + iconColor = GetScreenSaverEntityColor(config.indicatorScreensaverEntity[i]); + } + else if (typeof(val) == 'boolean') { + iconColor = GetScreenSaverEntityColor(config.indicatorScreensaverEntity[i]); + if (!val && config.indicatorScreensaverEntity[i].ScreensaverEntityIconOff != null) { + icon = Icons.GetIcon(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOff) + } + } + const temp = config.indicatorScreensaverEntity[4].ScreensaverEntityIconColor + if (temp && typeof temp == 'string' && existsObject(temp)) { + iconColor = getState(temp).val; + } + payloadString += '~' + + '~' + + icon + '~' + + iconColor + '~' + + config.indicatorScreensaverEntity[i].ScreensaverEntityText + '~' + + val + '~'; + } + } + if (Debug) log('HandleScreensaverUpdate payload: weatherUpdate~' + payloadString, 'info'); + + SendToPanel({ payload: 'weatherUpdate~' + payloadString }); + + HandleScreensaverStatusIcons(); + + } + + } catch (err: any) { + log('error at function HandleScreensaverUpdate: ' + err.message, 'warn'); + } +} + +function RegisterScreensaverEntityWatcher(id: string): void { + try { + if (subscriptions.hasOwnProperty(id)) { + return; + } + + subscriptions[id] = (on({ id: id, change: 'any' }, () => { + HandleScreensaverUpdate(); + })); + } catch (err: any) { + log('function RegisterEntityWatcher: ' + err.message, 'warn'); + } +} + +function HandleScreensaverStatusIcons() : void { + try { + let payloadString = ''; + let hwBtn1Col: any = config.mrIcon1ScreensaverEntity.ScreensaverEntityOffColor; + if (config.mrIcon1ScreensaverEntity.ScreensaverEntity != null) { + // Prüfung ob ScreensaverEntity vom Typ String ist + if (typeof (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val) == 'string') { + if (Debug) log('Entity ist String', 'info') + let hwBtn1: string = getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val; + if (hwBtn1 == 'ON') { + hwBtn1Col = config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor; + } + if (Debug) log('Value: ' + hwBtn1 + ' Color: ' + JSON.stringify(hwBtn1Col), 'info') + + // Icon ermitteln + if (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val) { + payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn); + if (Debug) log('Icon if true '+payloadString, 'info') + } else { + if (config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff != null) { + payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff); + if (Debug) log('Icon else true '+payloadString, 'info') + } else { + payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn); + if (Debug) log('Icon else false '+payloadString, 'info') + } + } + if (config.mrIcon1ScreensaverEntity.ScreensaverEntityValue != null) { + if (isNaN(getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val) == false) { + payloadString += (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val).toFixed(config.mrIcon1ScreensaverEntity.ScreensaverEntityValueDecimalPlace); + payloadString += (config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit; + if (Debug) log('Value ist eine Zahl ' + payloadString, 'info') + } else { + payloadString += getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val + if (Debug) log('Value ist keine Zahl ' + payloadString, 'info') + } + } + payloadString += '~' + rgb_dec565(hwBtn1Col) + '~'; + } else if (typeof (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val) == 'boolean') { + let hwBtn1: boolean = getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val; + if (hwBtn1) { + hwBtn1Col = config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor; + } + if (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val) { + payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn); + } else { + if (config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff != null) { + payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff); + } else { + payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn); + } + } + if (config.mrIcon1ScreensaverEntity.ScreensaverEntityValue != null) { + if (isNaN(getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val) == false) { + payloadString += (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val).toFixed(config.mrIcon1ScreensaverEntity.ScreensaverEntityValueDecimalPlace); + payloadString += (config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit; + } else { + payloadString += getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val + } + } + payloadString += '~' + rgb_dec565(hwBtn1Col) + '~'; + } + } else if (config.mrIcon1ScreensaverEntity.ScreensaverEntity == null && config.mrIcon1ScreensaverEntity.ScreensaverEntityValue != null){ + + if(config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor != null){ + hwBtn1Col = config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor; + } + if(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn != null){ + payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn); + } + + if (config.mrIcon1ScreensaverEntity.ScreensaverEntityValue != null) { + if (isNaN(getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val) == false) { + payloadString += (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val).toFixed(config.mrIcon1ScreensaverEntity.ScreensaverEntityValueDecimalPlace); + payloadString += (config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit; + } else { + payloadString += getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val + } + } + payloadString += '~' + rgb_dec565(hwBtn1Col) + '~'; + } + else { + hwBtn1Col = Black; + payloadString += '~~'; + } + + let hwBtn2Col: any = config.mrIcon2ScreensaverEntity.ScreensaverEntityOffColor; + if (config.mrIcon2ScreensaverEntity.ScreensaverEntity != null) { + if (typeof (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val) == 'string') { + let hwBtn2: string = getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val; + if (hwBtn2 == 'ON') { + hwBtn2Col = config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor; + } + if (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val) { + payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); + } else { + if (config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff != null) { + payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff); + } else { + payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); + } + } + if (config.mrIcon2ScreensaverEntity.ScreensaverEntityValue != null) { + if (isNaN(getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val) == false) { + payloadString += (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val).toFixed(config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace); + payloadString += (config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit; + } else { + payloadString += getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val + } + } + payloadString += '~' + rgb_dec565(hwBtn2Col) + '~'; + } else if (typeof (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val) == 'boolean') { + let hwBtn2: boolean = getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val; + if (hwBtn2) { + hwBtn2Col = config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor; + } + if (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val) { + payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); + } else { + if (config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff != null) { + payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff); + } else { + payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); + } + } + if (config.mrIcon2ScreensaverEntity.ScreensaverEntityValue != null) { + if (isNaN(getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val) == false) { + payloadString += (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val).toFixed(config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace); + payloadString += (config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit; + } else { + payloadString += getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val + } + } + payloadString += '~' + rgb_dec565(hwBtn2Col) + '~'; + } + } else if (config.mrIcon2ScreensaverEntity.ScreensaverEntity == null && config.mrIcon2ScreensaverEntity.ScreensaverEntityValue != null){ + + if(config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor != null){ + hwBtn2Col = config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor; + } + + if(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn != null){ + payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); + } + + if (config.mrIcon2ScreensaverEntity.ScreensaverEntityValue != null) { + if (isNaN(getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val) == false) { + payloadString += (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val).toFixed(config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace); + payloadString += (config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit; + } else { + payloadString += getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val + } + } + payloadString += '~' + rgb_dec565(hwBtn2Col) + '~'; + } else { + hwBtn2Col = Black; + payloadString += '~~'; + } + + let alternateScreensaverMFRIcon1Size = getState(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1').val + let alternateScreensaverMFRIcon2Size = getState(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2').val + //Alternate MRIcon Size + if (alternateScreensaverMFRIcon1Size) { + payloadString += '1~'; + } else { + payloadString += '~'; + } + if (alternateScreensaverMFRIcon2Size) { + payloadString += '1~'; + } else { + payloadString += '~'; + } + + SendToPanel({ payload: 'statusUpdate~' + payloadString }); + + } catch (err: any) { + log('error at function HandleScreensaverStatusIcons: ' + err.message, 'warn'); + } +} + +function HandleColorScale(valueScaletemp: string): number { + switch (valueScaletemp) { + case '0': + return rgb_dec565(colorScale0); + case '1': + return rgb_dec565(colorScale1); + case '2': + return rgb_dec565(colorScale2); + case '3': + return rgb_dec565(colorScale3); + case '4': + return rgb_dec565(colorScale4); + case '5': + return rgb_dec565(colorScale5); + case '6': + return rgb_dec565(colorScale6); + case '7': + return rgb_dec565(colorScale7); + case '8': + return rgb_dec565(colorScale8); + case '9': + return rgb_dec565(colorScale9); + case '10': + return rgb_dec565(colorScale10); + default: + return rgb_dec565(colorScale10); + } +} + +function HandleScreensaverColors(): void { + try { + let vwIcon: number[] = []; + if (getState(NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout').val) { + vwIcon[0] = vwIconColor[0]; + vwIcon[1] = vwIconColor[1]; + vwIcon[2] = vwIconColor[2]; + vwIcon[3] = vwIconColor[3]; + vwIcon[4] = vwIconColor[4]; + } else { + if (weatherForecast) { + vwIcon[0] = rgb_dec565(sctMainIcon); + vwIcon[1] = rgb_dec565(sctF1Icon); + vwIcon[2] = rgb_dec565(sctF2Icon); + vwIcon[3] = rgb_dec565(sctF3Icon); + vwIcon[4] = rgb_dec565(sctF4Icon); + } else { + vwIcon[0] = rgb_dec565(sctMainIcon); + vwIcon[1] = vwIconColor[1]; + vwIcon[2] = vwIconColor[2]; + vwIcon[3] = vwIconColor[3]; + vwIcon[4] = vwIconColor[4]; + } + } + + let scrSvrBGCol: any; + + if (bgColorScrSaver == 0) { + scrSvrBGCol = rgb_dec565(scbackground); + } else if (bgColorScrSaver == 1) { + scrSvrBGCol = rgb_dec565(scbackgroundInd1); + } else if (bgColorScrSaver == 2) { + scrSvrBGCol = rgb_dec565(scbackgroundInd2); + } else if (bgColorScrSaver == 3) { + scrSvrBGCol = rgb_dec565(scbackgroundInd3); + } + + let payloadString = 'color' + '~' + + scrSvrBGCol + '~' + //background + rgb_dec565(sctime) + '~' + //time + rgb_dec565(sctimeAMPM) + '~' + //timeAMPM~ + rgb_dec565(scdate) + '~' + //date~ + rgb_dec565(sctMainText) + '~' + //tMainText~ + rgb_dec565(sctForecast1) + '~' + //tForecast1~ + rgb_dec565(sctForecast2) + '~' + //tForecast2~ + rgb_dec565(sctForecast3) + '~' + //tForecast3~ + rgb_dec565(sctForecast4) + '~' + //tForecast4~ + rgb_dec565(sctForecast1Val) + '~' + //tForecast1Val~ + rgb_dec565(sctForecast2Val) + '~' + //tForecast2Val~ + rgb_dec565(sctForecast3Val) + '~' + //tForecast3Val~ + rgb_dec565(sctForecast4Val) + '~' + //tForecast4Val~ + rgb_dec565(scbar) + '~' + //bar~ + rgb_dec565(sctMainTextAlt) + '~' + //tMainTextAlt + rgb_dec565(sctTimeAdd); //tTimeAdd + + SendToPanel({ payload: payloadString }); + } catch (err: any) { + log('error at function HandleScreensaverColors: '+ err.message, 'warn'); + } +} + +function GetScreenSaverEntityColor(configElement: ScreenSaverElement | null): number { + try { + let colorReturn: number; + if (configElement && configElement.ScreensaverEntityIconColor != undefined) { + const ScreensaverEntityIconColor = configElement.ScreensaverEntityIconColor as IconScaleElement; + if (typeof getState(configElement.ScreensaverEntity).val == 'boolean') { + let iconvalbest = (typeof ScreensaverEntityIconColor == 'object' && ScreensaverEntityIconColor.val_best !== undefined ) ? ScreensaverEntityIconColor.val_best : false ; + colorReturn = (getState(configElement.ScreensaverEntity).val == iconvalbest) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); + } else if (typeof ScreensaverEntityIconColor == 'object') { + const iconvalmin: number = ScreensaverEntityIconColor.val_min != undefined ? ScreensaverEntityIconColor.val_min : 0 ; + const iconvalmax: number = ScreensaverEntityIconColor.val_max != undefined ? ScreensaverEntityIconColor.val_max : 100 ; + const iconvalbest: number = ScreensaverEntityIconColor.val_best != undefined ? ScreensaverEntityIconColor.val_best : iconvalmin ; + let valueScale = getState(configElement.ScreensaverEntity).val * configElement.ScreensaverEntityFactor!; + + if (iconvalmin == 0 && iconvalmax == 1) { + colorReturn = (getState(configElement.ScreensaverEntity).val == 1) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); + } else { + if (iconvalbest == iconvalmin) { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0); + } else { + if (valueScale < iconvalbest) { + valueScale = scale(valueScale,iconvalmin, iconvalbest, 0, 10); + } else if (valueScale > iconvalbest || iconvalbest != iconvalmin) { + valueScale = scale(valueScale,iconvalbest, iconvalmax, 10, 0); + } else { + valueScale = scale(valueScale,iconvalmin, iconvalmax, 10, 0); + } + } + //limit if valueScale is smaller/larger than 0-10 + if (valueScale > 10) valueScale = 10; + if (valueScale < 0) valueScale = 0; + + let valueScaletemp = (Math.round(valueScale)).toFixed(); + colorReturn = HandleColorScale(valueScaletemp); + } + if (ScreensaverEntityIconColor.val_min == undefined) { + colorReturn = rgb_dec565(configElement.ScreensaverEntityIconColor as RGB); + } + } else { + colorReturn = rgb_dec565(White); + } + } else { + const value: number | boolean = configElement ? getState(configElement.ScreensaverEntity).val : 0; + if (configElement && typeof value == 'boolean') { + if (value) { + if (configElement.ScreensaverEntityOnColor != undefined) { + colorReturn = rgb_dec565(configElement.ScreensaverEntityOnColor); + } else { + colorReturn = rgb_dec565(White); + } + } else { + if (configElement.ScreensaverEntityOffColor != undefined) { + colorReturn = rgb_dec565(configElement.ScreensaverEntityOffColor); + } else { + colorReturn = rgb_dec565(White); + } + } + } else { + colorReturn = rgb_dec565(White); + } + } + return colorReturn; + } catch (err: any) { + log('error at function GetScreenSaverEntityColor: '+ err.message, 'warn'); + } + return rgb_dec565(White); +} + +function GetAccuWeatherIcon(icon: number): string { + try { + switch (icon) { + case 30: // Hot + return 'weather-sunny-alert'; // exceptional + + case 24: // Ice + case 31: // Cold + return 'snowflake-alert'; // exceptional + + case 7: // Cloudy + case 8: // Dreary (Overcast) + case 38: // Mostly Cloudy + return 'weather-cloudy'; // cloudy + + case 11: // fog + return 'weather-fog'; // fog + + case 25: // Sleet + return 'weather-hail'; // Hail + + case 15: // T-Storms + return 'weather-lightning'; // lightning + + case 16: // Mostly Cloudy w/ T-Storms + case 17: // Partly Sunny w/ T-Storms + case 41: // Partly Cloudy w/ T-Storms + case 42: // Mostly Cloudy w/ T-Storms + return 'weather-lightning-rainy'; // lightning-rainy + + case 33: // Clear + case 34: // Mostly Clear + case 37: // Hazy Moonlight + return 'weather-night'; + + case 3: // Partly Sunny + case 4: // Intermittent Clouds + case 6: // Mostly Cloudy + case 35: // Partly Cloudy + case 36: // Intermittent Clouds + return 'weather-partly-cloudy'; // partlycloudy + + case 18: // pouring + return 'weather-pouring'; // pouring + + case 12: // Showers + case 13: // Mostly Cloudy w/ Showers + case 14: // Partly Sunny w/ Showers + case 26: // Freezing Rain + case 39: // Partly Cloudy w/ Showers + case 40: // Mostly Cloudy w/ Showers + return 'weather-rainy'; // rainy + + case 19: // Flurries + case 20: // Mostly Cloudy w/ Flurries + case 21: // Partly Sunny w/ Flurries + case 22: // Snow + case 23: // Mostly Cloudy w/ Snow + case 43: // Mostly Cloudy w/ Flurries + case 44: // Mostly Cloudy w/ Snow + return 'weather-snowy'; // snowy + + case 29: // Rain and Snow + return 'weather-snowy-rainy'; // snowy-rainy + + case 1: // Sunny + case 2: // Mostly Sunny + case 5: // Hazy Sunshine + return 'weather-sunny'; // sunny + + case 32: // windy + return 'weather-windy'; // windy + + default: + return 'alert-circle-outline'; + } + } catch (err: any) { + log('error at function GetAccuWeatherIcon: '+ err.message, 'warn'); + } + return ''; +} + +function GetAccuWeatherIconColor(icon: number): number { + try{ + switch (icon) { + case 24: // Ice + case 30: // Hot + case 31: // Cold + return rgb_dec565(swExceptional); // exceptional + + case 7: // Cloudy + case 8: // Dreary (Overcast) + case 38: // Mostly Cloudy + return rgb_dec565(swCloudy); // cloudy + + case 11: // fog + return rgb_dec565(swFog); // fog + + case 25: // Sleet + return rgb_dec565(swHail); // Hail + + case 15: // T-Storms + return rgb_dec565(swLightning); // lightning + + case 16: // Mostly Cloudy w/ T-Storms + case 17: // Partly Sunny w/ T-Storms + case 41: // Partly Cloudy w/ T-Storms + case 42: // Mostly Cloudy w/ T-Storms + return rgb_dec565(swLightningRainy); // lightning-rainy + + case 33: // Clear + case 34: // Mostly Clear + case 37: // Hazy Moonlight + return rgb_dec565(swClearNight); + + case 3: // Partly Sunny + case 4: // Intermittent Clouds + case 6: // Mostly Cloudy + case 35: // Partly Cloudy + case 36: // Intermittent Clouds + return rgb_dec565(swPartlycloudy); // partlycloudy + + case 18: // pouring + return rgb_dec565(swPouring); // pouring + + case 12: // Showers + case 13: // Mostly Cloudy w/ Showers + case 14: // Partly Sunny w/ Showers + case 26: // Freezing Rain + case 39: // Partly Cloudy w/ Showers + case 40: // Mostly Cloudy w/ Showers + return rgb_dec565(swRainy); // rainy + + case 19: // Flurries + case 20: // Mostly Cloudy w/ Flurries + case 21: // Partly Sunny w/ Flurries + case 22: // Snow + case 23: // Mostly Cloudy w/ Snow + case 43: // Mostly Cloudy w/ Flurries + case 44: // Mostly Cloudy w/ Snow + return rgb_dec565(swSnowy); // snowy + + case 29: // Rain and Snow + return rgb_dec565(swSnowyRainy); // snowy-rainy + + case 1: // Sunny + case 2: // Mostly Sunny + case 5: // Hazy Sunshine + return rgb_dec565(swSunny); // sunny + + case 32: // windy + return rgb_dec565(swWindy); // windy + + default: + return rgb_dec565(White); + } + } catch (err: any) { + log('error at function GetAccuWeatherIconColor: '+ err.message, 'warn'); + } + return 0; +} + +function GetDasWetterIcon(icon: number): string { + try { + switch (icon) { + case 1: // Sonnig + return 'weather-sunny'; // sunny + + case 2: // Teils bewölkt + case 3: // Bewölkt + return 'weather-partly-cloudy'; // partlycloudy + + case 4: // Bedeckt + return 'weather-cloudy'; // cloudy + + case 5: // Teils bewölkt mit leichtem Regen + case 6: // Bewölkt mit leichtem Regen + case 8: // Teils bewölkt mit mäßigem Regen + case 9: // Bewölkt mit mäßigem Regen + return 'weather-partly-rainy'; // partly-rainy + + case 7: // Bedeckt mit leichtem Regen + return 'weather-rainy'; // rainy + + case 10: // Bedeckt mit mäßigem Regen + return 'weather-pouring'; // pouring + + case 11: // Teils bewölkt mit starken Regenschauern + case 12: // Bewölkt mit stürmischen Regenschauern + return 'weather-partly-lightning'; // partlylightning + + case 13: // Bedeckt mit stürmischen Regenschauern + return 'weather-lightning'; // lightning + + case 14: // Teils bewölkt mit stürmischen Regenschauern und Hagel + case 15: // Bewölkt mit stürmischen Regenschauern und Hagel + case 16: // Bedeckt mit stürmischen Regenschauern und Hagel + return 'weather-hail'; // Hail + + case 17: // Teils bewölkt mit Schnee + case 18: // Bewölkt mit Schnee + return 'weather-partly-snowy'; // partlysnowy + + case 19: // Bedeckt mit Schneeschauern + return 'weather-snowy'; // snowy + + case 20: // Teils bewölkt mit Schneeregen + case 21: // Bewölkt mit Schneeregen + return 'weather-partly-snowy-rainy'; + + case 22: // Bedeckt mit Schneeregen + return 'weather-snowy-rainy'; // snowy-rainy + + default: + return 'alert-circle-outline'; + } + } catch (err: any) { + log('error at function GetDasWetterIcon: '+ err.message, 'warn'); + } + return ''; +} + +function GetDasWetterIconColor(icon: number): number { + try{ + switch (icon) { + case 1: // Sonnig + return rgb_dec565(swSunny); + + case 2: // Teils bewölkt + case 3: // Bewölkt + return rgb_dec565(swPartlycloudy); + + case 4: // Bedeckt + return rgb_dec565(swCloudy); + + case 5: // Teils bewölkt mit leichtem Regen + case 6: // Bewölkt mit leichtem Regen + case 8: // Teils bewölkt mit mäßigem Regen + case 9: // Bewölkt mit mäßigem Regen + return rgb_dec565(swRainy); + + case 7: // Bedeckt mit leichtem Regen + return rgb_dec565(swRainy); + + case 10: // Bedeckt mit mäßigem Regen + return rgb_dec565(swPouring); + + case 11: // Teils bewölkt mit starken Regenschauern + case 12: // Bewölkt mit stürmischen Regenschauern + return rgb_dec565(swLightningRainy); + + case 13: // Bedeckt mit stürmischen Regenschauern + return rgb_dec565(swLightning); + + case 14: // Teils bewölkt mit stürmischen Regenschauern und Hagel + case 15: // Bewölkt mit stürmischen Regenschauern und Hagel + case 16: // Bedeckt mit stürmischen Regenschauern und Hagel + return rgb_dec565(swHail); + + case 17: // Teils bewölkt mit Schnee + case 18: // Bewölkt mit Schnee + return rgb_dec565(swSnowy); + + case 19: // Bedeckt mit Schneeschauern + return rgb_dec565(swSnowy); + + case 20: // Teils bewölkt mit Schneeregen + case 21: // Bewölkt mit Schneeregen + return rgb_dec565(swSnowyRainy); // snowy-rainy + + case 22: // Bedeckt mit Schneeregen + return rgb_dec565(swSnowyRainy); + + default: + return rgb_dec565(White); + } + } catch (err: any) { + log('error at function GetDasWetterIconColor: '+ err.message, 'warn'); + } + return 0; +} + +//------------------Begin Read Internal Sensor Data +on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'SENSOR' }, async (obj) => { + try { + const Tasmota_Sensor = JSON.parse(obj.state.val); + + await createStateAsync(NSPanel_Path + 'Sensor.Time', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Sensor.TempUnit', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Sensor.ANALOG.Temperature', { type: 'number', 'unit': '°C' }); + await createStateAsync(NSPanel_Path + 'Sensor.ESP32.Temperature', { type: 'number', 'unit': '°C' }); + let dateTime: string = Tasmota_Sensor.Time.split('T'); + await setStateAsync(NSPanel_Path + 'Sensor.Time', { val: dateTime[0] + '\r\n' + dateTime[1] , ack: true }); + await setStateAsync(NSPanel_Path + 'Sensor.TempUnit', { val: '°' + Tasmota_Sensor.TempUnit, ack: true }); + + /* Some messages do not include temperature values, so catch ecxeption for them separately */ + try { + await setStateAsync(NSPanel_Path + 'Sensor.ANALOG.Temperature', { val: parseFloat(Tasmota_Sensor.ANALOG.Temperature1), ack: true }); + await setStateAsync(NSPanel_Path + 'Sensor.ESP32.Temperature', { val: parseFloat(Tasmota_Sensor.ESP32.Temperature), ack: true }); + } catch (e){ + /* Nothing to do */ + } + + if (autoCreateAlias) { + setObject(AliasPath + 'Sensor.ANALOG.Temperature', {type: 'channel', common: {role: 'info', name: ''}, native: {}}); + setObject(AliasPath + 'Sensor.ESP32.Temperature', {type: 'channel', common: {role: 'info', name:''}, native: {}}); + setObject(AliasPath + 'Sensor.Time', {type: 'channel', common: {role: 'info', name:''}, native: {}}); + setObject(AliasPath + 'Sensor.TempUnit', {type: 'channel', common: {role: 'info', name:''}, native: {}}); + await createAliasAsync(AliasPath + 'Sensor.ANALOG.Temperature.ACTUAL', NSPanel_Path + 'Sensor.ANALOG.Temperature', true, { type: 'number', 'unit': '°C' }); + await createAliasAsync(AliasPath + 'Sensor.ESP32.Temperature.ACTUAL', NSPanel_Path + 'Sensor.ESP32.Temperature', true, { type: 'number', 'unit': '°C' }); + await createAliasAsync(AliasPath + 'Sensor.Time.ACTUAL', NSPanel_Path + 'Sensor.Time', true, { type: 'string' }); + await createAliasAsync(AliasPath + 'Sensor.TempUnit.ACTUAL', NSPanel_Path + 'Sensor.TempUnit', true, { type: 'string' }); + } + } catch (err: any) { + log('error Trigger reading senor-data: '+ err.message, 'warn'); + } +}); +//------------------End Read Internal Sensor Data + +function formatInSelText(Text: string ): string { + let splitText = Text.split(' '); + let lengthLineOne = 0; + let arrayLineOne: string[] = []; + for (let i = 0; i < splitText.length; i++) { + lengthLineOne = lengthLineOne + splitText[i].length + 1; + if (lengthLineOne > 12) { + break; + } else { + arrayLineOne[i] = splitText[i]; + } + } + let textLineOne = arrayLineOne.join(' '); + let arrayLineTwo: string[] = []; + for (let i = arrayLineOne.length; i < splitText.length; i++) { + arrayLineTwo[i] = splitText[i]; + } + let textLineTwo = arrayLineTwo.join(' '); + if (textLineTwo.length > 12) { + textLineTwo = textLineTwo.substring(0,9) + '...'; + } + if (textLineOne.length != 0) { + return textLineOne + '\r\n' + textLineTwo.trim(); + } else { + return textLineTwo.trim(); + } +} + +function GetBlendedColor(percentage: number): RGB { + if (percentage < 50) { + return Interpolate(config.defaultOffColor, config.defaultOnColor, percentage / 50.0); + } + + return Interpolate(Red, White, (percentage - 50) / 50.0); +} + +function Interpolate(color1: RGB, color2: RGB, fraction: number): RGB { + let r: number = InterpolateNum(color1.red, color2.red, fraction); + let g: number = InterpolateNum(color1.green, color2.green, fraction); + let b: number = InterpolateNum(color1.blue, color2.blue, fraction); + return { red: Math.round(r), green: Math.round(g), blue: Math.round(b) }; +} + +function InterpolateNum(d1: number, d2: number, fraction: number): number { + return d1 + (d2 - d1) * fraction; +} + +function rgb_dec565(rgb: RGB): number { + //return ((Math.floor(rgb.red / 255 * 31) << 11) | (Math.floor(rgb.green / 255 * 63) << 5) | (Math.floor(rgb.blue / 255 * 31))); + return ((rgb.red >> 3) << 11) | ((rgb.green >> 2)) << 5 | ((rgb.blue) >> 3); +} + +/** + * Convert radians to degrees + * @param rad radians to convert, expects rad in range +/- PI per Math.atan2 + * @returns {number} degrees equivalent of rad + */ +function rad2deg(rad): number { + return (360 + 180 * rad / Math.PI) % 360; +} + +function ColorToHex(color): string { + let hexadecimal: string = color.toString(16); + return hexadecimal.length == 1 ? '0' + hexadecimal : hexadecimal; +} + +function ConvertRGBtoHex(red: number, green: number, blue: Number): string { + return '#' + ColorToHex(red) + ColorToHex(green) + ColorToHex(blue); +} + +/** + * Convert h,s,v values to r,g,b + * @param hue in range [0, 360] + * @param saturation in range 0 to 1 + * @param value in range 0 to 1 + * @returns {[number, number, number]} [r, g,b] in range 0 to 255 + */ +function hsv2rgb(hue: number, saturation: number, value: number): [number, number, number] { + hue /= 60; + let chroma = value * saturation; + let x = chroma * (1 - Math.abs((hue % 2) - 1)); + let rgb: [number, number, number] = hue <= 1 ? [chroma, x, 0] : + hue <= 2 ? [x, chroma, 0] : + hue <= 3 ? [0, chroma, x] : + hue <= 4 ? [0, x, chroma] : + hue <= 5 ? [x, 0, chroma] : + [chroma, 0, x]; + + return rgb.map(v => (v + value - chroma) * 255) as [number, number, number]; +} + +function getHue(red: number, green: number, blue: number): number { + + let min = Math.min(Math.min(red, green), blue); + let max = Math.max(Math.max(red, green), blue); + + if (min == max) { + return 0; + } + + let 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 { + let r = 160 / 2; + x = Math.round((x - r) / r * 100) / 100; + y = Math.round((r - y) / r * 100) / 100; + + r = Math.sqrt(x * x + y * y); + let sat = 0 + if (r > 1) { + sat = 0; + } else { + sat = r; + } + + let hsv = rad2deg(Math.atan2(y, x)); + let rgb = hsv2rgb(hsv, sat, 1); + + return { red: Math.round(rgb[0]), green: Math.round(rgb[1]), blue: Math.round(rgb[2]) }; +} + +/** + * + * @param red + * @param green + * @param blue + * @returns + */ +function rgb_to_cie(red: number, green: number, blue: number): string +{ + //Apply a gamma correction to the RGB values, which makes the color more vivid and more the like the color displayed on the screen of your device + let vred = (red > 0.04045) ? Math.pow((red + 0.055) / (1.0 + 0.055), 2.4) : (red / 12.92); + let vgreen = (green > 0.04045) ? Math.pow((green + 0.055) / (1.0 + 0.055), 2.4) : (green / 12.92); + let vblue = (blue > 0.04045) ? Math.pow((blue + 0.055) / (1.0 + 0.055), 2.4) : (blue / 12.92); + + //RGB values to XYZ using the Wide RGB D65 conversion formula + let X = vred * 0.664511 + vgreen * 0.154324 + vblue * 0.162028; + let Y = vred * 0.283881 + vgreen * 0.668433 + vblue * 0.047685; + let Z = vred * 0.000088 + vgreen * 0.072310 + vblue * 0.986039; + + //Calculate the xy values from the XYZ values + let ciex = (X / (X + Y + Z)).toFixed(4); + let ciey = (Y / (X + Y + Z)).toFixed(4); + let cie = "[" + ciex + "," + ciey + "]" + + return cie; +} +/** + * + * @param vDeviceString + * @returns + */ +function spotifyGetDeviceID(vDeviceString: string): string { + const availableDeviceIDs: string = getState("spotify-premium.0.devices.availableDeviceListIds").val; + const availableDeviceNames: string = getState("spotify-premium.0.devices.availableDeviceListString").val; + let arrayDeviceListIds: string[] = availableDeviceIDs.split(";"); + let arrayDeviceListSting: string[] = availableDeviceNames.split(";"); + let indexPos: number = arrayDeviceListSting.indexOf(vDeviceString); + let strDevID = arrayDeviceListIds[indexPos]; + return strDevID; +} + +type RGB = { + red: number, + green: number, + blue: number +}; + +type Payload = { + payload: string; +}; + +type PageBaseType = { + type: PagetypeType, + heading: string, + items: PageItem[], + useColor: boolean, + subPage?: boolean, + parent?: PageType, + parentIcon?: string, + parentIconColor?: RGB, + prev?: string, + prevIcon?: string, + prevIconColor?: RGB, + next?: string, + nextIcon?: string, + nextIconColor?: RGB, + home?: string, + homeIcon?: string, + homeIconColor?: RGB +}; + +type PagetypeType = 'cardChart' | 'cardLChart' | 'cardEntities' |'cardGrid'|'cardGrid2'|'cardThermo'|'cardMedia'|'cardUnlock'|'cardQR'|'cardAlarm'|'cardPower' + +type PageType = PageChart | PageEntities | PageGrid | PageGrid2 | PageThermo | PageMedia | PageUnlock | PageQR | PageAlarm | PagePower + +// If u get a error here u forgot something in PagetypeType or PageType +function checkPageType(F: PagetypeType, A: PageType) { + A.type = F; +} + +type PageEntities = { + type: 'cardEntities', + items: PageItem[], +} & PageBaseType + +type PageGrid = { + type: 'cardGrid', + items: PageItem[], +} & PageBaseType + +type PageGrid2 = { + type: 'cardGrid2', + items: PageItem[], +} & PageBaseType + +type PageThermo = { + type: 'cardThermo', + items: PageItem[], +} & Omit + +type PageMedia = { + type: 'cardMedia', + items: PageMediaItem[], +} & Omit + +type PageAlarm = { + type: 'cardAlarm', + items: PageItem[], +} & Omit + +type PageUnlock = { + type: 'cardUnlock', + items: PageItem[], +} & Omit & Partial> + +type PageQR = { + type: 'cardQR', + items: PageItem[], +} & Omit + +type PagePower = { + type: 'cardPower', + items: PageItem[], +} & Omit + +type PageChart = { + type: 'cardChart' | 'cardLChart', + items: PageItem[], +} & Omit + +type PageItem = PageBaseItem | PageMediaItem + +function isPageMediaItem(F: PageItem | PageMediaItem):F is PageMediaItem { + return (F as PageMediaItem).adapterPlayerInstance !== undefined +} +type PageMediaItem = { + adapterPlayerInstance: adapterPlayerInstanceType, +} & PageBaseItem + +type PageBaseItem = { + id?: string | null, + icon?: string, + icon2?: string, + onColor?: RGB, + offColor?: RGB, + useColor?: boolean, + interpolateColor?: boolean, + minValueBrightness?: number, + maxValueBrightness?: number, + minValueColorTemp?: number, + maxValueColorTemp?: number, + minValueLevel?: number, + maxValueLevel?: number, + minValueTilt?: number, + maxValueTilt?: number, + minValue?: number, + maxValue?: number, + stepValue?: number, + prefixName?: string, + suffixName?: string, + name?: string, + secondRow?: string, + buttonText?: string, + unit?: string, + navigate?: boolean, + colormode?: string, + colorScale?: any, + //adapterPlayerInstance?: adapterPlayerInstanceType, + mediaDevice?: string, + targetPage?: string, + speakerList?: string[], + playList?: string[], + equalizerList?: string[], + repeatList?: string[], + globalTracklist?: string[], + modeList?: string[], + hidePassword?: boolean, + autoCreateALias?: boolean + colorMediaIcon?: RGB, + colorMediaArtist?: RGB, + colorMediaTitle?: RGB, + popupThermoMode1?: string[], + popupThermoMode2?: string[], + popupThermoMode3?: string[], + popUpThermoName?: string[], + popupMediaMode1?: string[], + popupMediaMode2?: string[], + popupMediaMode3?: string[], + popUpMediaName?: string[], + setThermoAlias?: string[], + setThermoDestTemp2?: string, + yAxis?: string, + yAxisTicks?: number[] | string, + xAxisDecorationId?: string, + popupType?: string, + popupOptions?: string[], + useValue?: boolean, + monobutton?: boolean, + inSel_ChoiceState?: boolean, + iconArray?: string[], + fontSize?: number, + actionStringArray?: string[], + popupTimerType?: string, + alwaysOnDisplay?: boolean, + crossfade?: boolean, +} + +type DimMode = { + dimmodeOn: (boolean | undefined), + brightnessDay: (number | undefined), + brightnessNight: (number | undefined), + timeDay: (string | undefined), + timeNight: (string | undefined) +} + +type ConfigButtonFunction = { + mode: 'page' | 'toggle' | 'set' | null, + page: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PageGrid2 | PagePower | PageChart | PageUnlock | null), + entity: string | null, + setValue: string | number | boolean | null +} + +type Config = { + panelRecvTopic: string, + panelSendTopic: string, + weatherEntity: string, + leftScreensaverEntity: ScreenSaverElement[], + bottomScreensaverEntity: ScreenSaverElement[], + indicatorScreensaverEntity: ScreenSaverElement[], + mrIcon1ScreensaverEntity: ScreenSaverMRElement, + mrIcon2ScreensaverEntity: ScreenSaverMRElement, + defaultColor: RGB, + defaultOnColor: RGB, + defaultOffColor: RGB, + defaultBackgroundColor: RGB, + pages: PageType[], + subPages: PageType[], + button1: ConfigButtonFunction, + button2: ConfigButtonFunction +} + +type ScreenSaverElement = { + ScreensaverEntity: string, + ScreensaverEntityFactor?: number, + ScreensaverEntityDecimalPlaces?: number, + ScreensaverEntityDateFormat?: any | null, + ScreensaverEntityIconOn?: string | null, + ScreensaverEntityIconOff?: string | null, + ScreensaverEntityText: string, + ScreensaverEntityUnitText?: string | null, + ScreensaverEntityIconColor?: RGB | IconScaleElement | string + ScreensaverEntityOnColor?: RGB + ScreensaverEntityOffColor?: RGB + ScreensaverEntityOnText?: string | null, + ScreensaverEntityOffText?: string | null, +} + +type ScreenSaverMRElement = { + ScreensaverEntity: string | null, + ScreensaverEntityIconOn: string | null, + ScreensaverEntityIconOff: string | null, + ScreensaverEntityValue: string | null, + ScreensaverEntityValueDecimalPlace: number | null, + ScreensaverEntityValueUnit: string | null, + ScreensaverEntityOnColor: RGB, + ScreensaverEntityOffColor: RGB +} + +type IconScaleElement = { + val_min:number, + val_max:number, + val_best?: number +} +/** we need this to have a nice order when using switch() */ +type adapterPlayerInstanceType = + 'alexa2.0.' | 'alexa2.1.'| 'alexa2.2.' | 'alexa2.3.' | 'alexa2.4.' | 'alexa2.5.' | 'alexa2.6.' | 'alexa2.7.' | 'alexa2.8.' | 'alexa2.9.' +| 'sonos.0.' | 'sonos.1.' | 'sonos.2.' | 'sonos.3.' | 'sonos.4.' | 'sonos.5.' | 'sonos.6.' | 'sonos.7.' | 'sonos.8.' | 'sonos.9.' +| 'spotify-premium.0.' | 'spotify-premium.1.' | 'spotify-premium.2.' | 'spotify-premium.3.' | 'spotify-premium.4.' | 'spotify-premium.5.' | 'spotify-premium.6.' | 'spotify-premium.7.' | 'spotify-premium.8.' | 'spotify-premium.9.' +| 'volumio.0.' | 'volumio.1.' | 'volumio.2.' | 'volumio.3.' |'volumio.4.' | 'volumio.5.' | 'volumio.6.' | 'volumio.7.' | 'volumio.8.' | 'volumio.9.' +| 'squeezeboxrpc.0.' | 'squeezeboxrpc.1.' | 'squeezeboxrpc.2.' | 'squeezeboxrpc.3.' | 'squeezeboxrpc.4.' | 'squeezeboxrpc.5.' | 'squeezeboxrpc.6.' | 'squeezeboxrpc.7.' | 'squeezeboxrpc.8.' | 'squeezeboxrpc.9.' +| 'bosesoundtouch.0.' | 'bosesoundtouch.1.' | 'bosesoundtouch.2.' | 'bosesoundtouch.3.' |'bosesoundtouch.4.' | 'bosesoundtouch.5.' | 'bosesoundtouch.6.' | 'bosesoundtouch.7.' | 'bosesoundtouch.8.' | 'bosesoundtouch.9.' + +type PlayerType = 'alexa2' | 'sonos' | 'spotify-premium' | 'volumio' | 'squeezeboxrpc' | 'bosesoundtouch' + +type notSortedPlayerType = `${PlayerType}.0.` | `${PlayerType}.1.` | `${PlayerType}.2.` | `${PlayerType}.3.` | `${PlayerType}.4.` | `${PlayerType}.5.` | `${PlayerType}.6.` | `${PlayerType}.7.` | `${PlayerType}.8.` | `${PlayerType}.9.` + +/** check if adapterPlayerInstanceType has all Playertypes */ +function checkSortedPlayerType(F: notSortedPlayerType) { + const test: adapterPlayerInstanceType = F; +} + +type mediaOptional = 'seek' | 'crossfade' | 'speakerlist' | 'playlist' | 'tracklist' | 'equalizer' | 'repeat' | 'favorites' + +function isMediaOptional(F: string | mediaOptional): F is mediaOptional { + switch(F as mediaOptional) { + case "seek": + case "crossfade": + case "speakerlist": + case "playlist": + case "tracklist": + case "equalizer": + case "repeat": + case "favorites": + return true; + default: + return false + } +} From 10cf15bebd17fab07e27e28e1a3615a9f4e95180 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Thu, 4 Jan 2024 22:22:01 +0100 Subject: [PATCH 39/99] v4.3.3.32 - Update NSPanelTs.ts Hotfix Spotify Player --- ioBroker/DEV/NSPanelTs.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 5a0b514e..b0eae358 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.31 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.32 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -96,6 +96,7 @@ ReleaseNotes: - 03.02.2024 - v4.3.3.31 [dev]: optional with type - cardMedia has adapterPlayerInstance all other not - 03.02.2024 - v4.3.3.31 [dev]: add PlayerType some more work to do - 03.02.2024 - v4.3.3.31 changed: adapterPlayerInstance instance 0-9 allowed. Always require a '.' at the end. + - 04.01.2024 - v4.3.3.32 Hiofix Spotify Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -958,7 +959,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.31'; +const scriptVersion: string = 'v4.3.3.32'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -4994,7 +4995,9 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } let vMediaDevice = (page.items[0].mediaDevice != undefined) ? page.items[0].mediaDevice : ''; - if (!vMediaDevice) throw new Error(`Error in cardMedia! mediaDevice is empty! Page: ${JSON.stringify(page)}`); + if (v2Adapter == 'alexa2' || v2Adapter == 'sonos' || v2Adapter == 'squeezeboxrpc') { + if (!vMediaDevice) throw new Error(`Error in cardMedia! mediaDevice is empty! Page: ${JSON.stringify(page)}`); + } createAutoMediaAlias(id, vMediaDevice, page.items[0].adapterPlayerInstance!); // Leave the display on if the alwaysOnDisplay parameter is specified (true) From b7687e006cd0349624f4ee9ca743e59d0c4f4342 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Thu, 4 Jan 2024 22:23:56 +0100 Subject: [PATCH 40/99] v4.3.3.32 - Update NsPanelTs.ts Hotfix Spotify Player --- ioBroker/NsPanelTs.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 5a0b514e..b0eae358 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.31 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.32 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -96,6 +96,7 @@ ReleaseNotes: - 03.02.2024 - v4.3.3.31 [dev]: optional with type - cardMedia has adapterPlayerInstance all other not - 03.02.2024 - v4.3.3.31 [dev]: add PlayerType some more work to do - 03.02.2024 - v4.3.3.31 changed: adapterPlayerInstance instance 0-9 allowed. Always require a '.' at the end. + - 04.01.2024 - v4.3.3.32 Hiofix Spotify Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -958,7 +959,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.31'; +const scriptVersion: string = 'v4.3.3.32'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -4994,7 +4995,9 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } let vMediaDevice = (page.items[0].mediaDevice != undefined) ? page.items[0].mediaDevice : ''; - if (!vMediaDevice) throw new Error(`Error in cardMedia! mediaDevice is empty! Page: ${JSON.stringify(page)}`); + if (v2Adapter == 'alexa2' || v2Adapter == 'sonos' || v2Adapter == 'squeezeboxrpc') { + if (!vMediaDevice) throw new Error(`Error in cardMedia! mediaDevice is empty! Page: ${JSON.stringify(page)}`); + } createAutoMediaAlias(id, vMediaDevice, page.items[0].adapterPlayerInstance!); // Leave the display on if the alwaysOnDisplay parameter is specified (true) From 089e55394461f8a35abe5ce5fd346a57661b7af2 Mon Sep 17 00:00:00 2001 From: ticaki Date: Fri, 5 Jan 2024 03:14:55 +0100 Subject: [PATCH 41/99] remove unused propertys add types leftScreensaverEntityType add types indicatorScreensaverEntityType add types PageMediaItem add types PageThermoItem add types roles (common.role) add types ButtonActionType add alot undefined checks add some type checks merge 2 on() functions --- ioBroker/DEV/NSPanelTs.ts | 503 +++++++++++++++++++------------------- 1 file changed, 258 insertions(+), 245 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index b0eae358..daa4e7a2 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -2769,12 +2769,14 @@ function check_online_display_firmware() { } } +//mqttCallback (topic: string, message: string): Promise { on({ id: config.panelRecvTopic }, async (obj) => { if (obj.state.val.startsWith('\{"CustomRecv":')) { try { + const json = JSON.parse(obj.state.val); + const split = json.CustomRecv.split(','); if (isSetOptionActive) { - let json = JSON.parse(obj.state.val); - let split = json.CustomRecv.split(','); + if (split[0] == 'event' && split[1] == 'startup') { await createStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { type: 'string' }); await createStateAsync(NSPanel_Path + 'NSPanel_Version', { type: 'string' }); @@ -2790,9 +2792,11 @@ on({ id: config.panelRecvTopic }, async (obj) => { } } } + HandleMessage(split[0], split[1], parseInt(split[2]), split); } catch (err: any) { log('error at trigger rceiving CustomRecv: ' + err.message, 'warn'); } + } }); @@ -2915,7 +2919,7 @@ function update_tasmota_firmware() { log('error request in function update_tasmota_firmware: ' + err.message, 'warn'); } } - +//mqttCallback (topic: string, message: string): Promise { on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'INFO1', change: 'ne'}, async (obj) => { try { if (getState(NSPanel_Path + 'Config.Update.activ').val == 0) { @@ -2936,23 +2940,6 @@ on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESU //------------------End Update Functions -on({ id: config.panelRecvTopic, change: 'any' }, async function (obj) { - try { - if (obj.state.val.startsWith('\{"CustomRecv":')) { - try { - let json = JSON.parse(obj.state.val); - - let split = json.CustomRecv.split(','); - HandleMessage(split[0], split[1], parseInt(split[2]), split); - } catch (err: any) { - log('error json.split in Trigger panelRecTopic: ' + err.message, 'warn'); - } - } - } catch (err: any) { - log('error at Trigger panelRecTopic: ' + err.message, 'warn'); - } -}); - async function SendToPanel(val: Payload | Payload[]) { try { if (Array.isArray(val)) { @@ -3316,17 +3303,6 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let buttonText: string = 'PRESS'; let type: string; - if (pageItem.id && existsState(pageItem.id + '.ACTUAL') == false) { - if (pageItem.popupTimerType == 'TimeCard' && pageItem.autoCreateALias == true) { - log(NSPanel_Path + 'Userdata.' + pageItem.id + '.Time') - createStateAsync(NSPanel_Path + 'Userdata.' + pageItem.id + '.Time', '0', { type: 'number' }); - createStateAsync(NSPanel_Path + 'Userdata.' + pageItem.id + '.State', 'idle', { type: 'string' }); - setObject(pageItem.id, { type: 'channel', common: { role: 'value.time', name: 'Time' }, native: {} }); - createAliasAsync(pageItem.id + '.ACTUAL', NSPanel_Path + 'Userdata.' + pageItem.id + '.Time', true, { type: 'number', role: 'state', name: 'ACTUAL' }); - createAliasAsync(pageItem.id + '.STATE', NSPanel_Path + 'Userdata.' + pageItem.id + '.State', true, { type: 'string', role: 'state', name: 'STATE' }); - } - } - // ioBroker if (pageItem.id && existsObject(pageItem.id) || pageItem.navigate === true) { @@ -3398,11 +3374,11 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } else if (pageItem.id != null && pageItem.targetPage != undefined) { type = 'button'; - - switch (o.common.role) { + const role = o.common.role as roles; + switch (role as roles) { case 'socket': case '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) : role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : iconId; buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : existsState(pageItem.id + '.BUTTONTEXT') ? getState(pageItem.id + '.BUTTONTEXT').val : 'PRESS'; @@ -3426,8 +3402,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = case 'door': case 'window': - iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); - iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : o.common.role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); + iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : existsState(pageItem.id + '.BUTTONTEXT') ? getState(pageItem.id + '.BUTTONTEXT').val : 'PRESS'; if (existsState(pageItem.id + '.COLORDEC')) { @@ -3499,7 +3475,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = case 'thermostat': - iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'temperature' || o.common.role == 'value.temperature' || o.common.role == 'thermostat' ? Icons.GetIcon('thermometer') : Icons.GetIcon('information-outline'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'temperature' || role == 'value.temperature' || role == 'thermostat' ? Icons.GetIcon('thermometer') : Icons.GetIcon('information-outline'); let unit = ''; optVal = '0'; @@ -3583,13 +3559,13 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = return '~' + type + '~' + 'navigate.' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; } } - - switch (o.common.role) { + const role = o.common.role as roles + switch (role as roles) { 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'); - iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : o.common.role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); optVal = '0'; if (val === true || val === 'true') { @@ -3804,11 +3780,11 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = if (existsState(pageItem.id + '.ACTUAL')) { if (getState(pageItem.id + '.ACTUAL').val) { - iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); iconColor = GetIconColor(pageItem, true, useColors); windowState = findLocale('window', 'opened'); } else { - iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); iconId = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : iconId; iconColor = GetIconColor(pageItem, false, useColors); windowState = findLocale('window', 'closed'); @@ -3850,7 +3826,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = case 'thermostat': type = 'text'; - iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'temperature' || o.common.role == 'value.temperature' || o.common.role == 'thermostat' ? Icons.GetIcon('thermometer') : Icons.GetIcon('information-outline'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'temperature' || role == 'value.temperature' || role == 'thermostat' ? Icons.GetIcon('thermometer') : Icons.GetIcon('information-outline'); let unit = ''; optVal = '0'; @@ -4294,7 +4270,7 @@ function GenerateThermoPage(page: PageThermo): Payload[] { if ((i_list.length - 3) != 0) { let i = 0; - switch (o.common.role) { + switch (o.common.role as roles) { case 'thermostat': { if (existsState(id + '.AUTOMATIC') && getState(id + '.AUTOMATIC').val != null) { @@ -4995,7 +4971,8 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } let vMediaDevice = (page.items[0].mediaDevice != undefined) ? page.items[0].mediaDevice : ''; - if (v2Adapter == 'alexa2' || v2Adapter == 'sonos' || v2Adapter == 'squeezeboxrpc') { + + if (isPlayerWithMediaDevice(v2Adapter)) { if (!vMediaDevice) throw new Error(`Error in cardMedia! mediaDevice is empty! Page: ${JSON.stringify(page)}`); } createAutoMediaAlias(id, vMediaDevice, page.items[0].adapterPlayerInstance!); @@ -6114,7 +6091,7 @@ function HandleButtonEvent(words: any): void { let tempid = words[2].split('?'); let id = tempid[0]; - let buttonAction = words[3]; + let buttonAction: ButtonActionType = words[3] as ButtonActionType; let pageItemID: string = ''; if (!isNaN(id)) { @@ -6293,7 +6270,8 @@ function HandleButtonEvent(words: any): void { if (Debug) { log('HandleButtonEvent -> OnOff: ' + words[4] + ' - ' + id + ' - Role - ' + o.common.role, 'info') } - switch (o.common.role) { + const role = o.common.role as roles; + switch (role as roles) { case 'level.mode.fan': case 'socket': case 'light': @@ -6329,7 +6307,7 @@ function HandleButtonEvent(words: any): void { if (words[4] == '1') action = true; let o = getObject(id); - switch (o.common.role) { + switch (o.common.role as roles) { case 'lock': case 'button': toggleState(id + '.SET') ? true : toggleState(id + '.ON_SET'); @@ -6503,8 +6481,8 @@ function HandleButtonEvent(words: any): void { if (existsObject(id)) { let o = getObject(id); let pageItem = findPageItem(id); - - switch (o.common.role) { + const role = o.common.role as roles; + switch (role as roles) { case 'dimmer': if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { let sliderPos = Math.trunc(scale(parseInt(words[4]), 0, 100, pageItem.maxValueBrightness, pageItem.minValueBrightness)); @@ -6550,7 +6528,7 @@ function HandleButtonEvent(words: any): void { log('HandleButtonEvent colorWeel -> getHue-Werte: ' + getHue(rgb.red, rgb.green, rgb.blue), 'info'); } let o = getObject(id); - switch (o.common.role) { + switch (o.common.role as roles) { case 'hue': setIfExists(id + '.HUE', getHue(rgb.red, rgb.green, rgb.blue)); break; @@ -6625,7 +6603,9 @@ function HandleButtonEvent(words: any): void { const tempPage = findPageItem(id); if (isPageMediaItem(tempPage)) { if (tempPage.adapterPlayerInstance.startsWith("volumio")) { - findPageItem(id).playList = []; break; + const item = findPageItem(id) + if (isPageMediaItem(item)) item.playList = []; + break; } //Volumio: empty playlist $uha-20230103 if ((tempPage.adapterPlayerInstance).startsWith("spotify")) { if (getState(id + '.SHUFFLE').val == 'off') { @@ -6837,6 +6817,7 @@ function HandleButtonEvent(words: any): void { break; case 'mode-equalizer': let pageItemEQ = findPageItem(id); + if (!isPageMediaItem(pageItemEQ)) break; if (Debug) log('HandleButtonEvent mode-equalizer -> id: ' + id, 'info'); let lastIndex = (id.split('.')).pop(); setState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode', pageItemEQ.equalizerList![words[4]]); @@ -7010,19 +6991,19 @@ function HandleButtonEvent(words: any): void { break; case 'mode-modus1': let pageItemT1 = findPageItem(id); - setIfExists(id + '.' + pageItemT1.setThermoAlias![0], pageItemT1.popupThermoMode1![parseInt(words[4])]); + if (isPageThermoItem(pageItemT1)) setIfExists(id + '.' + pageItemT1.setThermoAlias![0], pageItemT1.popupThermoMode1![parseInt(words[4])]); break; case 'mode-modus2': let pageItemT2 = findPageItem(id); - setIfExists(id + '.' + pageItemT2.setThermoAlias![1], pageItemT2.popupThermoMode2![parseInt(words[4])]); + if (isPageThermoItem(pageItemT2)) setIfExists(id + '.' + pageItemT2.setThermoAlias![1], pageItemT2.popupThermoMode2![parseInt(words[4])]); break; case 'mode-modus3': let pageItemT3 = findPageItem(id); - setIfExists(id + '.' + pageItemT3.setThermoAlias![2], pageItemT3.popupThermoMode3![parseInt(words[4])]); + if (isPageThermoItem(pageItemT3)) setIfExists(id + '.' + pageItemT3.setThermoAlias![2], pageItemT3.popupThermoMode3![parseInt(words[4])]); break; case 'number-set': let nobj = getObject(id); - switch (nobj.common.role) { + switch (nobj.common.role as roles) { case 'level.mode.fan': (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); timeoutSlider = setTimeout(async function () { @@ -7229,7 +7210,6 @@ function GetNavigationString(pageId: number): string { } return ''; } - function GenerateDetailPage(type: string, optional: mediaOptional | undefined, pageItem: PageItem, placeId: number | undefined): Payload[] { if (Debug) log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); try { @@ -7238,16 +7218,17 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p if (id && existsObject(id)) { - let o = getObject(id); + const o = getObject(id); let val: (boolean | number) = 0; let icon = Icons.GetIcon('lightbulb'); let iconColor = rgb_dec565(config.defaultColor); + const role = o.common.role as roles; if (type == 'popupLight') { let switchVal = '0'; let brightness = 0; - switch (o.common.role) { + switch (role) { case 'light': case 'socket': { if (existsState(id + '.GET')) { @@ -7264,7 +7245,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p } } - icon = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + icon = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); if (val) { switchVal = '1'; @@ -7636,7 +7617,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p }); } break; - } + } } if (type == 'popupShutter') { @@ -7740,12 +7721,12 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p if (type == 'popupThermo') { let vIcon = (pageItem.icon != undefined) ? pageItem.icon : 'fan'; - let mode1 = (pageItem.popupThermoMode1 != undefined) ? pageItem.popupThermoMode1.join('?') : ''; - let mode2 = (pageItem.popupThermoMode2 != undefined) ? pageItem.popupThermoMode2.join('?') : ''; - let mode3 = (pageItem.popupThermoMode3 != undefined) ? pageItem.popupThermoMode3.join('?') : ''; + let mode1 = (isPageThermoItem(pageItem) && pageItem.popupThermoMode1 != undefined) ? pageItem.popupThermoMode1.join('?') : ''; + let mode2 = (isPageThermoItem(pageItem) && pageItem.popupThermoMode2 != undefined) ? pageItem.popupThermoMode2.join('?') : ''; + let mode3 = (isPageThermoItem(pageItem) && pageItem.popupThermoMode3 != undefined) ? pageItem.popupThermoMode3.join('?') : ''; let payloadParameters1 = '~~~~' - if (pageItem.popupThermoMode1 != undefined) { + if (isPageThermoItem(pageItem) && pageItem.popupThermoMode1 != undefined) { RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias![0], pageItem, type, placeId); payloadParameters1 = pageItem.popUpThermoName![0] + '~' //{heading}~ Mode 1 + 'modus1' + '~' //{id}~ Mode 1 @@ -7754,7 +7735,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p } let payloadParameters2 = '~~~~' - if (pageItem.popupThermoMode2 != undefined) { + if (isPageThermoItem(pageItem) && pageItem.popupThermoMode2 != undefined) { RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias![1], pageItem, type, placeId); payloadParameters2 = pageItem.popUpThermoName![1] + '~' //{heading}~ Mode 2 + 'modus2' + '~' //{id}~ Mode 2 @@ -7763,7 +7744,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p } let payloadParameters3 = '~~~~' - if (pageItem.popupThermoMode3 != undefined) { + if (isPageThermoItem(pageItem) && pageItem.popupThermoMode3 != undefined) { RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias![2], pageItem, type, placeId); payloadParameters3 = pageItem.popUpThermoName![2] + '~' //{heading}~ Mode 3 + 'modus3' + '~' //{id}~ Mode 3 @@ -7789,83 +7770,82 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p if (existsState(id + '.ACTUAL')) { RegisterDetailEntityWatcher(id + '.ACTUAL', pageItem, type, placeId); timer_actual = getState(id + '.ACTUAL').val; - } + } if (existsState(id + '.STATE')) { RegisterDetailEntityWatcher(id + '.STATE', pageItem, type, placeId); - } + } let editable = 1; let action1 = ''; let action2 = ''; let action3 = ''; - let label1 = ''; - let label2 = ''; - let label3 = ''; + let label1 = ''; + let label2 = ''; + let label3 = ''; let min_remaining = 0; let sec_remaining = 0; if (existsState(id + '.STATE')) { - - if (o.common.role == 'value.time') { - if (getState(id + '.STATE').val == 'idle' || getState(id + '.STATE').val == 'paused') { - min_remaining = Math.floor(timer_actual / 60); - sec_remaining = timer_actual % 60; - editable = 1; - } else { - min_remaining = Math.floor(timer_actual / 60); - sec_remaining = timer_actual % 60; - editable = 1; - } - } else if (o.common.role == 'level.timer') { - if (getState(id + '.STATE').val == 'idle' || getState(id + '.STATE').val == 'paused') { - min_remaining = Math.floor(timer_actual / 60); - sec_remaining = timer_actual % 60; - editable = 1; - action2 = 'start'; - label2 = findLocale('timer', 'start'); - } else { - min_remaining = Math.floor(timer_actual / 60); - sec_remaining = timer_actual % 60; - editable = 0; - action1 = 'pause'; - action2 = 'cancle'; - action3 = 'finish'; - label1 = findLocale('timer', 'pause'); - label2 = findLocale('timer', 'cancel'); - label3 = findLocale('timer', 'finish'); - } - } else if (o.common.role == 'value.alarmtime') { - if (getState(id + '.STATE').val == 'paused') { - min_remaining = Math.floor(timer_actual / 60); - sec_remaining = timer_actual % 60; - editable = 1; - action2 = 'start'; - label2 = findLocale('timer', 'on'); - } else { - min_remaining = Math.floor(timer_actual / 60); - sec_remaining = timer_actual % 60; - editable = 0; - action2 = 'pause'; - label2 = findLocale('timer', 'off'); + if (role == 'value.time') { + if (getState(id + '.STATE').val == 'idle' || getState(id + '.STATE').val == 'paused') { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 1; + } else { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 1; + } + } else if (role == 'level.timer') { + if (getState(id + '.STATE').val == 'idle' || getState(id + '.STATE').val == 'paused') { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 1; + action2 = 'start'; + label2 = findLocale('timer', 'start'); + } else { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 0; + action1 = 'pause'; + action2 = 'cancle'; + action3 = 'finish'; + label1 = findLocale('timer', 'pause'); + label2 = findLocale('timer', 'cancel'); + label3 = findLocale('timer', 'finish'); + } + } else if (role == 'value.alarmtime') { + if (getState(id + '.STATE').val == 'paused') { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 1; + action2 = 'start'; + label2 = findLocale('timer', 'on'); + } else { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 0; + action2 = 'pause'; + label2 = findLocale('timer', 'off'); + } } - } - let tempId = placeId != undefined ? placeId : id; - - out_msgs.push({ - payload: 'entityUpdateDetail' + '~' //entityUpdateDetail - + tempId + '~~' //{entity_id} - + rgb_dec565(White) + '~' //{icon_color}~ - + tempId + '~' - + min_remaining + '~' - + sec_remaining + '~' - + editable + '~' - + action1 + '~' - + action2 + '~' - + action3 + '~' - + label1 + '~' - + label2 + '~' - + label3 + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + tempId + '~~' //{entity_id} + + rgb_dec565(White) + '~' //{icon_color}~ + + tempId + '~' + + min_remaining + '~' + + sec_remaining + '~' + + editable + '~' + + action1 + '~' + + action2 + '~' + + action3 + '~' + + label1 + '~' + + label2 + '~' + + label3 }); } } @@ -7873,7 +7853,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p if (type == 'popupFan') { let switchVal = '0'; - if (o.common.role == 'level.mode.fan') { + if (role == 'level.mode.fan') { if (existsState(id + '.SET')) { val = getState(id + '.SET').val; RegisterDetailEntityWatcher(id + '.SET', pageItem, type, placeId); @@ -7915,7 +7895,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p } if (type == 'popupInSel') { - if (o.common.role == 'media') { + if (role == 'media') { let actualState: any = ''; let optionalString: string = 'Kein Eintrag'; let mode: string = ''; @@ -8142,7 +8122,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p }); GeneratePage(activePage!); } - } else if (o.common.role == 'buttonSensor') { + } else if (role == 'buttonSensor') { let actualValue: string = ''; @@ -8169,12 +8149,12 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p + actualValue + '~' + valueList }); - } else if (o.common.role == 'light' || - o.common.role == 'dimmer' || - o.common.role == 'hue' || - o.common.role == 'rgb' || - o.common.role == 'rgbSingle' || - o.common.role == 'ct') { + } else if (role == 'light' || + role == 'dimmer' || + role == 'hue' || + role == 'rgb' || + role == 'rgbSingle' || + role == 'ct') { //log(pageItem.id, 'info'); if (pageItem.modeList != undefined) { @@ -8303,65 +8283,67 @@ function HandleScreensaverUpdate(): void { } // 3 leftScreensaverEntities - if (screensaverAdvanced) { + if (screensaverAdvanced) { let checkpoint = true; let i = 0; - for (i = 0; i < 3; i++) { - - if (config.leftScreensaverEntity[i] == null || config.leftScreensaverEntity[i] == undefined) { - checkpoint = false; - break; - } - RegisterScreensaverEntityWatcher(config.leftScreensaverEntity[i].ScreensaverEntity) - - let val = getState(config.leftScreensaverEntity[i].ScreensaverEntity).val; - let iconColor = rgb_dec565(White); - let icon; - if (typeof config.leftScreensaverEntity[i].ScreensaverEntityIconOn == 'string' && existsObject(config.leftScreensaverEntity[i].ScreensaverEntityIconOn as string)) { - let iconName = getState(config.leftScreensaverEntity[i].ScreensaverEntityIconOn!).val; - icon = Icons.GetIcon(iconName); - } else { - icon = Icons.GetIcon(config.leftScreensaverEntity[i].ScreensaverEntityIconOn); - } - - if (parseFloat(val+"") == val) { - val = parseFloat(val); - } - - if (typeof(val) == 'number') { - val = (val * (config.leftScreensaverEntity[i].ScreensaverEntityFactor ? config.leftScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.leftScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.leftScreensaverEntity[i].ScreensaverEntityUnitText; - iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); - } - else if (typeof(val) == 'boolean') { - iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); - if (!val && config.leftScreensaverEntity[i].ScreensaverEntityIconOff != null) { - icon = Icons.GetIcon(config.leftScreensaverEntity[i].ScreensaverEntityIconOff) + if (config.leftScreensaverEntity && Array.isArray(config.leftScreensaverEntity)) { + for (i = 0; i < 3; i++) { + const leftScreensaverEntity = config.leftScreensaverEntity[i] + if (leftScreensaverEntity === null || leftScreensaverEntity === undefined) { + checkpoint = false; + break;; } - } - else if (typeof(val) == 'string') { - iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); - let pformat = parseFormat(val); - if (Debug) log('moments.js --> Datum ' + val + ' valid?: ' + moment(val, pformat, true).isValid(), 'info'); - if (moment(val, pformat, true).isValid()) { - let DatumZeit = moment(val, pformat).unix(); // Umwandlung in Unix Time-Stamp - if (config.leftScreensaverEntity[i].ScreensaverEntityDateFormat !== undefined) { - val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val, config.leftScreensaverEntity[i].ScreensaverEntityDateFormat); - } else { - val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val); - } - } - } - const temp = config.leftScreensaverEntity[i].ScreensaverEntityIconColor; - if (temp && typeof temp == 'string' && existsObject(temp)) { - iconColor = getState(temp).val; - } + RegisterScreensaverEntityWatcher(leftScreensaverEntity.ScreensaverEntity) - payloadString += '~' + - '~' + - icon + '~' + - iconColor + '~' + - config.leftScreensaverEntity[i].ScreensaverEntityText + '~' + - val + '~'; + let val = getState(leftScreensaverEntity.ScreensaverEntity).val; + let iconColor = rgb_dec565(White); + let icon; + if (typeof leftScreensaverEntity.ScreensaverEntityIconOn == 'string' && existsObject(leftScreensaverEntity.ScreensaverEntityIconOn as string)) { + let iconName = getState(leftScreensaverEntity.ScreensaverEntityIconOn!).val; + icon = Icons.GetIcon(iconName); + } else { + icon = Icons.GetIcon(leftScreensaverEntity.ScreensaverEntityIconOn); + } + + if (parseFloat(val + "") == val) { + val = parseFloat(val); + } + + if (typeof (val) == 'number') { + val = (val * (leftScreensaverEntity.ScreensaverEntityFactor ? leftScreensaverEntity.ScreensaverEntityFactor! : 0)).toFixed(leftScreensaverEntity.ScreensaverEntityDecimalPlaces) + leftScreensaverEntity.ScreensaverEntityUnitText; + iconColor = GetScreenSaverEntityColor(leftScreensaverEntity); + } + else if (typeof (val) == 'boolean') { + iconColor = GetScreenSaverEntityColor(leftScreensaverEntity); + if (!val && leftScreensaverEntity.ScreensaverEntityIconOff != null) { + icon = Icons.GetIcon(leftScreensaverEntity.ScreensaverEntityIconOff) + } + } + else if (typeof (val) == 'string') { + iconColor = GetScreenSaverEntityColor(leftScreensaverEntity); + let pformat = parseFormat(val); + if (Debug) log('moments.js --> Datum ' + val + ' valid?: ' + moment(val, pformat, true).isValid(), 'info'); + if (moment(val, pformat, true).isValid()) { + let DatumZeit = moment(val, pformat).unix(); // Umwandlung in Unix Time-Stamp + if (leftScreensaverEntity.ScreensaverEntityDateFormat !== undefined) { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val, leftScreensaverEntity.ScreensaverEntityDateFormat); + } else { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val); + } + } + } + const temp = leftScreensaverEntity.ScreensaverEntityIconColor; + if (temp && typeof temp == 'string' && existsObject(temp)) { + iconColor = getState(temp).val; + } + + payloadString += '~' + + '~' + + icon + '~' + + iconColor + '~' + + leftScreensaverEntity.ScreensaverEntityText + '~' + + val + '~'; + } } if (checkpoint == false) { for (let j = i; j < 3; j++) { @@ -8469,7 +8451,7 @@ function HandleScreensaverUpdate(): void { } //Alternativ Layout bekommt zusätzlichen Status - if (getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { + if (config.bottomScreensaverEntity[4] && getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { let val = getState(config.bottomScreensaverEntity[4].ScreensaverEntity).val; if (parseFloat(val+"") == val) { val = parseFloat(val); @@ -8588,37 +8570,38 @@ function HandleScreensaverUpdate(): void { // 5 indicatorScreensaverEntities for (let i = 0; i < 5; i++) { let checkpoint = true; - if (config.indicatorScreensaverEntity[i] == null) { + const indicatorScreensaverEntity:ScreenSaverElementWithUndefined = config.indicatorScreensaverEntity[i]; + if (indicatorScreensaverEntity == null) { checkpoint = false; break; } - RegisterScreensaverEntityWatcher(config.indicatorScreensaverEntity[i].ScreensaverEntity) + RegisterScreensaverEntityWatcher(indicatorScreensaverEntity.ScreensaverEntity) - let val = getState(config.indicatorScreensaverEntity[i].ScreensaverEntity).val; + let val = getState(indicatorScreensaverEntity.ScreensaverEntity).val; if (parseFloat(val+"") == val) { val = parseFloat(val); } let iconColor = rgb_dec565(White); let icon; - if (config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn && existsObject(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn!)) { - let iconName = getState(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn!).val; + if (indicatorScreensaverEntity.ScreensaverEntityIconOn && existsObject(indicatorScreensaverEntity.ScreensaverEntityIconOn!)) { + let iconName = getState(indicatorScreensaverEntity.ScreensaverEntityIconOn!).val; icon = Icons.GetIcon(iconName); } else { - icon = Icons.GetIcon(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn); + icon = Icons.GetIcon(indicatorScreensaverEntity.ScreensaverEntityIconOn); } if (typeof(val) == 'number') { - val = (val * (config.indicatorScreensaverEntity[i].ScreensaverEntityFactor ? config.indicatorScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.indicatorScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.indicatorScreensaverEntity[i].ScreensaverEntityUnitText; - iconColor = GetScreenSaverEntityColor(config.indicatorScreensaverEntity[i]); + val = (val * (indicatorScreensaverEntity.ScreensaverEntityFactor ? indicatorScreensaverEntity.ScreensaverEntityFactor! : 0)).toFixed(indicatorScreensaverEntity.ScreensaverEntityDecimalPlaces) + indicatorScreensaverEntity.ScreensaverEntityUnitText; + iconColor = GetScreenSaverEntityColor(indicatorScreensaverEntity); } else if (typeof(val) == 'boolean') { - iconColor = GetScreenSaverEntityColor(config.indicatorScreensaverEntity[i]); - if (!val && config.indicatorScreensaverEntity[i].ScreensaverEntityIconOff != null) { - icon = Icons.GetIcon(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOff) + iconColor = GetScreenSaverEntityColor(indicatorScreensaverEntity); + if (!val && indicatorScreensaverEntity.ScreensaverEntityIconOff != null) { + icon = Icons.GetIcon(indicatorScreensaverEntity.ScreensaverEntityIconOff) } } - const temp = config.indicatorScreensaverEntity[4].ScreensaverEntityIconColor + const temp = indicatorScreensaverEntity.ScreensaverEntityIconColor if (temp && typeof temp == 'string' && existsObject(temp)) { iconColor = getState(temp).val; } @@ -8626,7 +8609,7 @@ function HandleScreensaverUpdate(): void { '~' + icon + '~' + iconColor + '~' + - config.indicatorScreensaverEntity[i].ScreensaverEntityText + '~' + + indicatorScreensaverEntity.ScreensaverEntityText + '~' + val + '~'; } } @@ -9278,6 +9261,7 @@ function GetDasWetterIconColor(icon: number): number { } //------------------Begin Read Internal Sensor Data +//mqttCallback (topic: string, message: string): Promise { on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'SENSOR' }, async (obj) => { try { const Tasmota_Sensor = JSON.parse(obj.state.val); @@ -9491,6 +9475,22 @@ function spotifyGetDeviceID(vDeviceString: string): string { return strDevID; } + + + +type roles = 'light' |'socket'|'dimmer'| 'hue' | 'rgb' | 'rgbSingle' | 'cd' | 'blind' | 'door' | 'window' | 'volumeGroup' | 'volume' + | 'info' | 'humidity' | 'temperature' | 'value.temperature' | 'value.humidity' | 'sensor.door' | 'sensor.window' | 'thermostat' | 'warning' | 'ct' + | 'cie' | 'gate' | 'motion' | 'buttonSensor' | 'button' | 'value.time' | 'level.timer' | 'value.alarmtime' | 'level.mode.fan' | 'lock' | 'slider' + | 'switch.mode.wlan' | 'media' | 'timeTable' | 'airCondition' + +type ButtonActionType = 'bExit' | 'bUp' | 'bNext' | 'bSubNext' | 'bPrev' | 'bSubPrev' | 'bHome' | 'notifyAction' | 'OnOff' | 'button' | 'up' | 'stop' | 'down' + | 'positionSlider' | 'tiltOpen' | 'tiltStop' | 'tiltSlider' | 'tiltClose' | 'brightnessSlider' | 'colorTempSlider' | 'colorWheel' | 'tempUpd' | 'tempUpdHighLow' | 'media-back' + | 'media-pause' | 'media-next' | 'media-shuffle' | 'volumeSlider' | 'mode-speakerlist' | 'mode-playlist' | 'mode-tracklist' | 'mode-repeat' | 'mode-equalizer' | 'mode-seek' | 'mode-crossfade' + | 'mode-favorites' | 'mode-insel' | 'media-OnOff' | 'timer-start' | 'timer-pause' | 'timer-cancle' | 'timer-finish' | 'hvac_action' | 'mode-modus1' | 'mode-modus2' | 'mode-modus3' | 'number-set' + | 'mode-preset_modes' | 'A1' | 'A2' | 'A3' | 'A4' | 'D1' | 'U1' + + + type RGB = { red: number, green: number, @@ -9547,7 +9547,8 @@ type PageGrid2 = { type PageThermo = { type: 'cardThermo', - items: PageItem[], + items: PageThermoItem[], + } & Omit type PageMedia = { @@ -9580,13 +9581,36 @@ type PageChart = { items: PageItem[], } & Omit -type PageItem = PageBaseItem | PageMediaItem +type PageItem = PageBaseItem | PageMediaItem | PageThermoItem function isPageMediaItem(F: PageItem | PageMediaItem):F is PageMediaItem { - return (F as PageMediaItem).adapterPlayerInstance !== undefined + return 'adapterPlayerInstance' in F +} + +function isPageThermoItem(F: PageItem | PageThermoItem):F is PageThermoItem { + return 'popupThermoMode1' in F; } type PageMediaItem = { adapterPlayerInstance: adapterPlayerInstanceType, + mediaDevice?: string, + colorMediaIcon?: RGB, + colorMediaArtist?: RGB, + colorMediaTitle?: RGB, + speakerList?: string[], + playList?: string[], + equalizerList?: string[], + repeatList?: string[], + globalTracklist?: string[], + crossfade?: boolean, +} & PageBaseItem + +type PageThermoItem = { + popupThermoMode1?: string[], + popupThermoMode2?: string[], + popupThermoMode3?: string[], + popUpThermoName?: string[], + setThermoAlias?: string[], + setThermoDestTemp2?: string, } & PageBaseItem type PageBaseItem = { @@ -9616,45 +9640,22 @@ type PageBaseItem = { unit?: string, navigate?: boolean, colormode?: string, - colorScale?: any, + colorScale?: IconScaleElement, //adapterPlayerInstance?: adapterPlayerInstanceType, - mediaDevice?: string, targetPage?: string, - speakerList?: string[], - playList?: string[], - equalizerList?: string[], - repeatList?: string[], - globalTracklist?: string[], modeList?: string[], hidePassword?: boolean, autoCreateALias?: boolean - colorMediaIcon?: RGB, - colorMediaArtist?: RGB, - colorMediaTitle?: RGB, - popupThermoMode1?: string[], - popupThermoMode2?: string[], - popupThermoMode3?: string[], - popUpThermoName?: string[], - popupMediaMode1?: string[], - popupMediaMode2?: string[], - popupMediaMode3?: string[], - popUpMediaName?: string[], - setThermoAlias?: string[], - setThermoDestTemp2?: string, yAxis?: string, yAxisTicks?: number[] | string, xAxisDecorationId?: string, - popupType?: string, - popupOptions?: string[], useValue?: boolean, monobutton?: boolean, inSel_ChoiceState?: boolean, iconArray?: string[], fontSize?: number, actionStringArray?: string[], - popupTimerType?: string, alwaysOnDisplay?: boolean, - crossfade?: boolean, } type DimMode = { @@ -9676,9 +9677,9 @@ type Config = { panelRecvTopic: string, panelSendTopic: string, weatherEntity: string, - leftScreensaverEntity: ScreenSaverElement[], + leftScreensaverEntity: leftScreensaverEntityType bottomScreensaverEntity: ScreenSaverElement[], - indicatorScreensaverEntity: ScreenSaverElement[], + indicatorScreensaverEntity: indicatorScreensaverEntityType mrIcon1ScreensaverEntity: ScreenSaverMRElement, mrIcon2ScreensaverEntity: ScreenSaverMRElement, defaultColor: RGB, @@ -9690,16 +9691,18 @@ type Config = { button1: ConfigButtonFunction, button2: ConfigButtonFunction } - +type leftScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; +type indicatorScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; +type ScreenSaverElementWithUndefined = null | undefined | ScreenSaverElement type ScreenSaverElement = { ScreensaverEntity: string, + ScreensaverEntityText: string, ScreensaverEntityFactor?: number, ScreensaverEntityDecimalPlaces?: number, - ScreensaverEntityDateFormat?: any | null, + ScreensaverEntityDateFormat?: Intl.DateTimeFormatOptions, ScreensaverEntityIconOn?: string | null, ScreensaverEntityIconOff?: string | null, - ScreensaverEntityText: string, - ScreensaverEntityUnitText?: string | null, + ScreensaverEntityUnitText?: string, ScreensaverEntityIconColor?: RGB | IconScaleElement | string ScreensaverEntityOnColor?: RGB ScreensaverEntityOffColor?: RGB @@ -9732,8 +9735,17 @@ type adapterPlayerInstanceType = | 'squeezeboxrpc.0.' | 'squeezeboxrpc.1.' | 'squeezeboxrpc.2.' | 'squeezeboxrpc.3.' | 'squeezeboxrpc.4.' | 'squeezeboxrpc.5.' | 'squeezeboxrpc.6.' | 'squeezeboxrpc.7.' | 'squeezeboxrpc.8.' | 'squeezeboxrpc.9.' | 'bosesoundtouch.0.' | 'bosesoundtouch.1.' | 'bosesoundtouch.2.' | 'bosesoundtouch.3.' |'bosesoundtouch.4.' | 'bosesoundtouch.5.' | 'bosesoundtouch.6.' | 'bosesoundtouch.7.' | 'bosesoundtouch.8.' | 'bosesoundtouch.9.' -type PlayerType = 'alexa2' | 'sonos' | 'spotify-premium' | 'volumio' | 'squeezeboxrpc' | 'bosesoundtouch' - +type PlayerType = _PlayerTypeWithMediaDevice | _PlayerTypeWithOutMediaDevice; + +const ArrayPlayerTypeWithMediaDevice = ['alexa2', 'sonos', 'squeezeboxrpc'] as const +const ArrayPlayerTypeWithOutMediaDevice = ['spotify-premium', 'volumio', 'bosesoundtouch'] as const +type _PlayerTypeWithOutMediaDevice = typeof ArrayPlayerTypeWithOutMediaDevice[number] +type _PlayerTypeWithMediaDevice = typeof ArrayPlayerTypeWithMediaDevice[number] + +function isPlayerWithMediaDevice (F: string | _PlayerTypeWithMediaDevice): F is _PlayerTypeWithMediaDevice { + return ArrayPlayerTypeWithMediaDevice.indexOf(F as _PlayerTypeWithMediaDevice) != -1; +} + type notSortedPlayerType = `${PlayerType}.0.` | `${PlayerType}.1.` | `${PlayerType}.2.` | `${PlayerType}.3.` | `${PlayerType}.4.` | `${PlayerType}.5.` | `${PlayerType}.6.` | `${PlayerType}.7.` | `${PlayerType}.8.` | `${PlayerType}.9.` /** check if adapterPlayerInstanceType has all Playertypes */ @@ -9743,6 +9755,7 @@ function checkSortedPlayerType(F: notSortedPlayerType) { type mediaOptional = 'seek' | 'crossfade' | 'speakerlist' | 'playlist' | 'tracklist' | 'equalizer' | 'repeat' | 'favorites' + function isMediaOptional(F: string | mediaOptional): F is mediaOptional { switch(F as mediaOptional) { case "seek": From 5102b8b9555b043655c7582f494adf061b9c125c Mon Sep 17 00:00:00 2001 From: ticaki Date: Fri, 5 Jan 2024 11:06:53 +0100 Subject: [PATCH 42/99] Add Types for ButtonActionType EventMethod SerialType --- ioBroker/DEV/NSPanelTs.ts | 48 ++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index daa4e7a2..9a30a7f9 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -96,7 +96,10 @@ ReleaseNotes: - 03.02.2024 - v4.3.3.31 [dev]: optional with type - cardMedia has adapterPlayerInstance all other not - 03.02.2024 - v4.3.3.31 [dev]: add PlayerType some more work to do - 03.02.2024 - v4.3.3.31 changed: adapterPlayerInstance instance 0-9 allowed. Always require a '.' at the end. - - 04.01.2024 - v4.3.3.32 Hiofix Spotify + - 04.01.2024 - v4.3.3.32 Hotfix Spotify + - 04.01.2024 - v4.3.3.32 [DEV] Add Types see commits + - 04.01.2024 - v4.3.3.32 Add more details to types for: leftScreensaverEntity, indicatorScreensaverEntity, PageThermo, PageMedia + - 04.01.2024 - v4.3.3.32 Remove not uses propertys from PageItem Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -2791,8 +2794,9 @@ on({ id: config.panelRecvTopic }, async (obj) => { await createAliasAsync(AliasPath + 'Display.Model.ACTUAL', NSPanel_Path + 'NSPanel_Version', true, { type: 'string', role: 'state', name: 'ACTUAL' }); } } - } - HandleMessage(split[0], split[1], parseInt(split[2]), split); + } + + if (isEventMethod(split[1])) HandleMessage(split[0], split[1], parseInt(split[2]), split); } catch (err: any) { log('error at trigger rceiving CustomRecv: ' + err.message, 'warn'); } @@ -2973,10 +2977,10 @@ on({ id: NSPanel_Alarm_Path + 'Alarm.AlarmState', change: 'ne' }, async (obj) => } }); -function HandleMessage(typ: string, method: string, page: number | undefined, words: Array | undefined): void { +function HandleMessage(typ: string, method: EventMethod, page: number | undefined, words: Array | undefined): void { try { if (typ == 'event') { - switch (method) { + switch (method as EventMethod) { case 'startup': screensaverEnabled = false; UnsubscribeWatcher(); @@ -3122,7 +3126,7 @@ function GeneratePage(page: PageType): void { } } -function HandleHardwareButton(method: string): void { +function HandleHardwareButton(method: EventMethod): void { try { let buttonConfig: ConfigButtonFunction = config[method]; if(buttonConfig.mode === null) { @@ -3301,7 +3305,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let name: string; let buttonText: string = 'PRESS'; - let type: string; + let type: SerialType; // ioBroker if (pageItem.id && existsObject(pageItem.id) || pageItem.navigate === true) { @@ -5537,7 +5541,7 @@ function GenerateAlarmPage(page: PageAlarm): Payload[] { } //let entityType = getState(nsPath + 'AlarmType').val; let arm1: string, arm2: string, arm3: string, arm4: string; - let arm1ActionName: string, arm2ActionName: string, arm3ActionName: string, arm4ActionName: string; + let arm1ActionName: ButtonActionType | '', arm2ActionName: ButtonActionType | '', arm3ActionName: ButtonActionType | '', arm4ActionName: ButtonActionType | ''; let icon = '0'; let iconcolor = 63488; let numpadStatus = 'disable'; @@ -5691,7 +5695,7 @@ function GenerateUnlockPage(page: PageUnlock): Payload[] { } let unlock1 = findLocale('lock', 'UNLOCK'); //unlock1*~* - let unlock1ActionName = 'U1'; //unlock1ActionName*~* + let unlock1ActionName: ButtonActionType | '' = 'U1'; //unlock1ActionName*~* let iconcolor = rgb_dec565({ red: 223, green: 76, blue: 30 }); //icon*~* let icon = Icons.GetIcon('lock-remove'); //iconcolor*~* @@ -6802,7 +6806,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemRP)) break; let adapterInstanceRP = pageItemRP.adapterPlayerInstance!; let adapterRP = adapterInstanceRP.split('.'); - let deviceAdapterRP = adapterRP[0]; + let deviceAdapterRP: PlayerType = adapterRP[0] as PlayerType; if (Debug) log(pageItemRP.repeatList![words[4]], 'warn'); switch (deviceAdapterRP) { @@ -6833,7 +6837,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemSeek)) break; let adapterInstanceSK = pageItemSeek.adapterPlayerInstance!; let adapterSK = adapterInstanceSK.split('.'); - let deviceAdapterSK = adapterSK[0]; + let deviceAdapterSK: PlayerType = adapterSK[0] as PlayerType; switch (deviceAdapterSK) { case 'spotify-premium': break; @@ -6854,7 +6858,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemCrossfade)) break; let adapterInstanceCF = pageItemCrossfade.adapterPlayerInstance!; let adapterCF = adapterInstanceCF.split('.'); - let deviceAdapterCF = adapterCF[0]; + let deviceAdapterCF: PlayerType = adapterCF[0] as PlayerType; switch (deviceAdapterCF) { case 'spotify-premium': break; @@ -9475,8 +9479,9 @@ function spotifyGetDeviceID(vDeviceString: string): string { return strDevID; } +type EventMethod = 'startup' | 'sleepReached' | 'pageOpenDetail' | 'buttonPress2' | 'renderCurrentPage' | 'button1' | 'button2' - +type SerialType = 'button' | 'light' | 'shutter' | 'text' | 'input_sel' | 'timer' | 'number' | 'fan' type roles = 'light' |'socket'|'dimmer'| 'hue' | 'rgb' | 'rgbSingle' | 'cd' | 'blind' | 'door' | 'window' | 'volumeGroup' | 'volume' | 'info' | 'humidity' | 'temperature' | 'value.temperature' | 'value.humidity' | 'sensor.door' | 'sensor.window' | 'thermostat' | 'warning' | 'ct' @@ -9771,3 +9776,20 @@ function isMediaOptional(F: string | mediaOptional): F is mediaOptional { return false } } + +function isEventMethod(F: string | EventMethod): F is EventMethod { + switch(F as EventMethod) { + case "startup": + case "sleepReached": + case "pageOpenDetail": + case "buttonPress2": + case "renderCurrentPage": + case "button1": + case "button2": + return true; + default: + // Have to talk about this. + log(`Please report to developer: Unknown EventMethod: ${F} `, 'warn'); + return false; + } +} From f5019b494f2fcdde739674a78a2783f11e268813 Mon Sep 17 00:00:00 2001 From: ticaki Date: Fri, 5 Jan 2024 11:10:42 +0100 Subject: [PATCH 43/99] Reset NsPanelTS.ts from ./iobroker/ --- ioBroker/NsPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 9da7554e..acd3ffa9 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -9736,4 +9736,4 @@ function isMediaOptional(F: string | mediaOptional): F is mediaOptional { default: return false } -} +} \ No newline at end of file From 4b81b1794ddfff8aec2254e99cef21f41ef0cb5c Mon Sep 17 00:00:00 2001 From: ticaki Date: Fri, 5 Jan 2024 11:16:52 +0100 Subject: [PATCH 44/99] Reset NsPanelTS.ts from ./iobroker/ --- ioBroker/NsPanelTs.ts | 201 +++++++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 90 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index acd3ffa9..34626e77 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -2769,14 +2769,12 @@ function check_online_display_firmware() { } } -//mqttCallback (topic: string, message: string): Promise { on({ id: config.panelRecvTopic }, async (obj) => { if (obj.state.val.startsWith('\{"CustomRecv":')) { try { - const json = JSON.parse(obj.state.val); - const split = json.CustomRecv.split(','); if (isSetOptionActive) { - + let json = JSON.parse(obj.state.val); + let split = json.CustomRecv.split(','); if (split[0] == 'event' && split[1] == 'startup') { await createStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { type: 'string' }); await createStateAsync(NSPanel_Path + 'NSPanel_Version', { type: 'string' }); @@ -2792,11 +2790,9 @@ on({ id: config.panelRecvTopic }, async (obj) => { } } } - HandleMessage(split[0], split[1], parseInt(split[2]), split); } catch (err: any) { log('error at trigger rceiving CustomRecv: ' + err.message, 'warn'); } - } }); @@ -2919,7 +2915,7 @@ function update_tasmota_firmware() { log('error request in function update_tasmota_firmware: ' + err.message, 'warn'); } } -//mqttCallback (topic: string, message: string): Promise { + on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'INFO1', change: 'ne'}, async (obj) => { try { if (getState(NSPanel_Path + 'Config.Update.activ').val == 0) { @@ -2940,6 +2936,23 @@ on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESU //------------------End Update Functions +on({ id: config.panelRecvTopic, change: 'any' }, async function (obj) { + try { + if (obj.state.val.startsWith('\{"CustomRecv":')) { + try { + let json = JSON.parse(obj.state.val); + + let split = json.CustomRecv.split(','); + HandleMessage(split[0], split[1], parseInt(split[2]), split); + } catch (err: any) { + log('error json.split in Trigger panelRecTopic: ' + err.message, 'warn'); + } + } + } catch (err: any) { + log('error at Trigger panelRecTopic: ' + err.message, 'warn'); + } +}); + async function SendToPanel(val: Payload | Payload[]) { try { if (Array.isArray(val)) { @@ -3303,6 +3316,17 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let buttonText: string = 'PRESS'; let type: string; + if (pageItem.id && existsState(pageItem.id + '.ACTUAL') == false) { + if (pageItem.popupTimerType == 'TimeCard' && pageItem.autoCreateALias == true) { + log(NSPanel_Path + 'Userdata.' + pageItem.id + '.Time') + createStateAsync(NSPanel_Path + 'Userdata.' + pageItem.id + '.Time', '0', { type: 'number' }); + createStateAsync(NSPanel_Path + 'Userdata.' + pageItem.id + '.State', 'idle', { type: 'string' }); + setObject(pageItem.id, { type: 'channel', common: { role: 'value.time', name: 'Time' }, native: {} }); + createAliasAsync(pageItem.id + '.ACTUAL', NSPanel_Path + 'Userdata.' + pageItem.id + '.Time', true, { type: 'number', role: 'state', name: 'ACTUAL' }); + createAliasAsync(pageItem.id + '.STATE', NSPanel_Path + 'Userdata.' + pageItem.id + '.State', true, { type: 'string', role: 'state', name: 'STATE' }); + } + } + // ioBroker if (pageItem.id && existsObject(pageItem.id) || pageItem.navigate === true) { @@ -8279,67 +8303,65 @@ function HandleScreensaverUpdate(): void { } // 3 leftScreensaverEntities - if (screensaverAdvanced) { + if (screensaverAdvanced) { let checkpoint = true; let i = 0; - if (config.leftScreensaverEntity && Array.isArray(config.leftScreensaverEntity)) { - for (i = 0; i < 3; i++) { - const leftScreensaverEntity = config.leftScreensaverEntity[i] - if (leftScreensaverEntity === null || leftScreensaverEntity === undefined) { - checkpoint = false; - break;; - } - RegisterScreensaverEntityWatcher(leftScreensaverEntity.ScreensaverEntity) - - let val = getState(leftScreensaverEntity.ScreensaverEntity).val; - let iconColor = rgb_dec565(White); - let icon; - if (typeof leftScreensaverEntity.ScreensaverEntityIconOn == 'string' && existsObject(leftScreensaverEntity.ScreensaverEntityIconOn as string)) { - let iconName = getState(leftScreensaverEntity.ScreensaverEntityIconOn!).val; - icon = Icons.GetIcon(iconName); - } else { - icon = Icons.GetIcon(leftScreensaverEntity.ScreensaverEntityIconOn); - } - - if (parseFloat(val + "") == val) { - val = parseFloat(val); - } - - if (typeof (val) == 'number') { - val = (val * (leftScreensaverEntity.ScreensaverEntityFactor ? leftScreensaverEntity.ScreensaverEntityFactor! : 0)).toFixed(leftScreensaverEntity.ScreensaverEntityDecimalPlaces) + leftScreensaverEntity.ScreensaverEntityUnitText; - iconColor = GetScreenSaverEntityColor(leftScreensaverEntity); - } - else if (typeof (val) == 'boolean') { - iconColor = GetScreenSaverEntityColor(leftScreensaverEntity); - if (!val && leftScreensaverEntity.ScreensaverEntityIconOff != null) { - icon = Icons.GetIcon(leftScreensaverEntity.ScreensaverEntityIconOff) - } - } - else if (typeof (val) == 'string') { - iconColor = GetScreenSaverEntityColor(leftScreensaverEntity); - let pformat = parseFormat(val); - if (Debug) log('moments.js --> Datum ' + val + ' valid?: ' + moment(val, pformat, true).isValid(), 'info'); - if (moment(val, pformat, true).isValid()) { - let DatumZeit = moment(val, pformat).unix(); // Umwandlung in Unix Time-Stamp - if (leftScreensaverEntity.ScreensaverEntityDateFormat !== undefined) { - val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val, leftScreensaverEntity.ScreensaverEntityDateFormat); - } else { - val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val); - } - } - } - const temp = leftScreensaverEntity.ScreensaverEntityIconColor; - if (temp && typeof temp == 'string' && existsObject(temp)) { - iconColor = getState(temp).val; - } - - payloadString += '~' + - '~' + - icon + '~' + - iconColor + '~' + - leftScreensaverEntity.ScreensaverEntityText + '~' + - val + '~'; + for (i = 0; i < 3; i++) { + + if (config.leftScreensaverEntity[i] == null || config.leftScreensaverEntity[i] == undefined) { + checkpoint = false; + break; } + RegisterScreensaverEntityWatcher(config.leftScreensaverEntity[i].ScreensaverEntity) + + let val = getState(config.leftScreensaverEntity[i].ScreensaverEntity).val; + let iconColor = rgb_dec565(White); + let icon; + if (typeof config.leftScreensaverEntity[i].ScreensaverEntityIconOn == 'string' && existsObject(config.leftScreensaverEntity[i].ScreensaverEntityIconOn as string)) { + let iconName = getState(config.leftScreensaverEntity[i].ScreensaverEntityIconOn!).val; + icon = Icons.GetIcon(iconName); + } else { + icon = Icons.GetIcon(config.leftScreensaverEntity[i].ScreensaverEntityIconOn); + } + + if (parseFloat(val+"") == val) { + val = parseFloat(val); + } + + if (typeof(val) == 'number') { + val = (val * (config.leftScreensaverEntity[i].ScreensaverEntityFactor ? config.leftScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.leftScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.leftScreensaverEntity[i].ScreensaverEntityUnitText; + iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); + } + else if (typeof(val) == 'boolean') { + iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); + if (!val && config.leftScreensaverEntity[i].ScreensaverEntityIconOff != null) { + icon = Icons.GetIcon(config.leftScreensaverEntity[i].ScreensaverEntityIconOff) + } + } + else if (typeof(val) == 'string') { + iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); + let pformat = parseFormat(val); + if (Debug) log('moments.js --> Datum ' + val + ' valid?: ' + moment(val, pformat, true).isValid(), 'info'); + if (moment(val, pformat, true).isValid()) { + let DatumZeit = moment(val, pformat).unix(); // Umwandlung in Unix Time-Stamp + if (config.leftScreensaverEntity[i].ScreensaverEntityDateFormat !== undefined) { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val, config.leftScreensaverEntity[i].ScreensaverEntityDateFormat); + } else { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val); + } + } + } + const temp = config.leftScreensaverEntity[i].ScreensaverEntityIconColor; + if (temp && typeof temp == 'string' && existsObject(temp)) { + iconColor = getState(temp).val; + } + + payloadString += '~' + + '~' + + icon + '~' + + iconColor + '~' + + config.leftScreensaverEntity[i].ScreensaverEntityText + '~' + + val + '~'; } if (checkpoint == false) { for (let j = i; j < 3; j++) { @@ -8447,7 +8469,7 @@ function HandleScreensaverUpdate(): void { } //Alternativ Layout bekommt zusätzlichen Status - if (config.bottomScreensaverEntity[4] && getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { + if (getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { let val = getState(config.bottomScreensaverEntity[4].ScreensaverEntity).val; if (parseFloat(val+"") == val) { val = parseFloat(val); @@ -8566,38 +8588,37 @@ function HandleScreensaverUpdate(): void { // 5 indicatorScreensaverEntities for (let i = 0; i < 5; i++) { let checkpoint = true; - const indicatorScreensaverEntity:ScreenSaverElementWithUndefined = config.indicatorScreensaverEntity[i]; - if (indicatorScreensaverEntity == null) { + if (config.indicatorScreensaverEntity[i] == null) { checkpoint = false; break; } - RegisterScreensaverEntityWatcher(indicatorScreensaverEntity.ScreensaverEntity) + RegisterScreensaverEntityWatcher(config.indicatorScreensaverEntity[i].ScreensaverEntity) - let val = getState(indicatorScreensaverEntity.ScreensaverEntity).val; + let val = getState(config.indicatorScreensaverEntity[i].ScreensaverEntity).val; if (parseFloat(val+"") == val) { val = parseFloat(val); } let iconColor = rgb_dec565(White); let icon; - if (indicatorScreensaverEntity.ScreensaverEntityIconOn && existsObject(indicatorScreensaverEntity.ScreensaverEntityIconOn!)) { - let iconName = getState(indicatorScreensaverEntity.ScreensaverEntityIconOn!).val; + if (config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn && existsObject(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn!)) { + let iconName = getState(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn!).val; icon = Icons.GetIcon(iconName); } else { - icon = Icons.GetIcon(indicatorScreensaverEntity.ScreensaverEntityIconOn); + icon = Icons.GetIcon(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn); } if (typeof(val) == 'number') { - val = (val * (indicatorScreensaverEntity.ScreensaverEntityFactor ? indicatorScreensaverEntity.ScreensaverEntityFactor! : 0)).toFixed(indicatorScreensaverEntity.ScreensaverEntityDecimalPlaces) + indicatorScreensaverEntity.ScreensaverEntityUnitText; - iconColor = GetScreenSaverEntityColor(indicatorScreensaverEntity); + val = (val * (config.indicatorScreensaverEntity[i].ScreensaverEntityFactor ? config.indicatorScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.indicatorScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.indicatorScreensaverEntity[i].ScreensaverEntityUnitText; + iconColor = GetScreenSaverEntityColor(config.indicatorScreensaverEntity[i]); } else if (typeof(val) == 'boolean') { - iconColor = GetScreenSaverEntityColor(indicatorScreensaverEntity); - if (!val && indicatorScreensaverEntity.ScreensaverEntityIconOff != null) { - icon = Icons.GetIcon(indicatorScreensaverEntity.ScreensaverEntityIconOff) + iconColor = GetScreenSaverEntityColor(config.indicatorScreensaverEntity[i]); + if (!val && config.indicatorScreensaverEntity[i].ScreensaverEntityIconOff != null) { + icon = Icons.GetIcon(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOff) } } - const temp = indicatorScreensaverEntity.ScreensaverEntityIconColor + const temp = config.indicatorScreensaverEntity[4].ScreensaverEntityIconColor if (temp && typeof temp == 'string' && existsObject(temp)) { iconColor = getState(temp).val; } @@ -8605,7 +8626,7 @@ function HandleScreensaverUpdate(): void { '~' + icon + '~' + iconColor + '~' + - indicatorScreensaverEntity.ScreensaverEntityText + '~' + + config.indicatorScreensaverEntity[i].ScreensaverEntityText + '~' + val + '~'; } } @@ -9257,7 +9278,6 @@ function GetDasWetterIconColor(icon: number): number { } //------------------Begin Read Internal Sensor Data -//mqttCallback (topic: string, message: string): Promise { on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'SENSOR' }, async (obj) => { try { const Tasmota_Sensor = JSON.parse(obj.state.val); @@ -9596,7 +9616,7 @@ type PageBaseItem = { unit?: string, navigate?: boolean, colormode?: string, - colorScale?: IconScaleElement, + colorScale?: any, //adapterPlayerInstance?: adapterPlayerInstanceType, mediaDevice?: string, targetPage?: string, @@ -9624,12 +9644,15 @@ type PageBaseItem = { yAxis?: string, yAxisTicks?: number[] | string, xAxisDecorationId?: string, + popupType?: string, + popupOptions?: string[], useValue?: boolean, monobutton?: boolean, inSel_ChoiceState?: boolean, iconArray?: string[], fontSize?: number, actionStringArray?: string[], + popupTimerType?: string, alwaysOnDisplay?: boolean, crossfade?: boolean, } @@ -9653,9 +9676,9 @@ type Config = { panelRecvTopic: string, panelSendTopic: string, weatherEntity: string, - leftScreensaverEntity: leftScreensaverEntityType + leftScreensaverEntity: ScreenSaverElement[], bottomScreensaverEntity: ScreenSaverElement[], - indicatorScreensaverEntity: indicatorScreensaverEntityType + indicatorScreensaverEntity: ScreenSaverElement[], mrIcon1ScreensaverEntity: ScreenSaverMRElement, mrIcon2ScreensaverEntity: ScreenSaverMRElement, defaultColor: RGB, @@ -9667,18 +9690,16 @@ type Config = { button1: ConfigButtonFunction, button2: ConfigButtonFunction } -type leftScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; -type indicatorScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; -type ScreenSaverElementWithUndefined = null | undefined | ScreenSaverElement + type ScreenSaverElement = { ScreensaverEntity: string, - ScreensaverEntityText: string, ScreensaverEntityFactor?: number, ScreensaverEntityDecimalPlaces?: number, - ScreensaverEntityDateFormat?: Intl.DateTimeFormatOptions, + ScreensaverEntityDateFormat?: any | null, ScreensaverEntityIconOn?: string | null, ScreensaverEntityIconOff?: string | null, - ScreensaverEntityUnitText?: string, + ScreensaverEntityText: string, + ScreensaverEntityUnitText?: string | null, ScreensaverEntityIconColor?: RGB | IconScaleElement | string ScreensaverEntityOnColor?: RGB ScreensaverEntityOffColor?: RGB From bfb2c2eaabec99895a9028722e7bfb74d887d956 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Fri, 5 Jan 2024 12:53:46 +0100 Subject: [PATCH 45/99] v4.3.3.32 - Update NSPanelTs.ts * Hotfix Spotify * Add Types see commits * v4.3.3.32 Add more details to types for: leftScreensaverEntity, indicatorScreensaverEntity, PageThermo, PageMedia * Remove not uses propertys from PageItem * Add Body for BoseSoundtouch-Player --- ioBroker/DEV/NSPanelTs.ts | 97 ++++++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 11 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 9a30a7f9..cf71aded 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -95,11 +95,12 @@ ReleaseNotes: - 03.02.2024 - v4.3.3.31 Remove: adapterPlayerInstance from every card except cardMedia - 03.02.2024 - v4.3.3.31 [dev]: optional with type - cardMedia has adapterPlayerInstance all other not - 03.02.2024 - v4.3.3.31 [dev]: add PlayerType some more work to do - - 03.02.2024 - v4.3.3.31 changed: adapterPlayerInstance instance 0-9 allowed. Always require a '.' at the end. - - 04.01.2024 - v4.3.3.32 Hotfix Spotify + - 03.02.2024 - v4.3.3.31 changed: adapterPlayerInstance instance 0-9 allowed. Always require a '.' at the end. + - 04.01.2024 - v4.3.3.32 Hotfix Spotify - 04.01.2024 - v4.3.3.32 [DEV] Add Types see commits - 04.01.2024 - v4.3.3.32 Add more details to types for: leftScreensaverEntity, indicatorScreensaverEntity, PageThermo, PageMedia - 04.01.2024 - v4.3.3.32 Remove not uses propertys from PageItem + - 05.01.2024 - v4.3.3.32 Add Body for BoseSoundtouch-Player Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -4693,6 +4694,21 @@ function subscribeMediaSubscriptionsAlexaAdd(id: string): void { }); } +function subscribeMediaSubscriptionsBoseAdd(id: string): void { + on({id: [id + '.DURATION', + id + '.ELAPSED'], change: "any"}, async function () { + (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); + timeoutMedia = setTimeout(async function () { + if (useMediaEvents) { + GeneratePage(activePage!); + setTimeout(async function () { + GeneratePage(activePage!); + }, 50); + } + },50) + }); +} + async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPlayerInstance: adapterPlayerInstanceType) { if (autoCreateAlias) { if (isSetOptionActive) { @@ -4908,10 +4924,11 @@ async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPla log('bosesoundtouch Alias ' + id + ' does not exist - will be created now', 'info'); try { - let dpPath: string = adapterPlayerInstance + 'keys'; + let dpPath: string = adapterPlayerInstance; await extendObjectAsync(id, {_id: id, type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); - await createAliasAsync(id + '.ACTUAL', dpPath + '.volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); - await createAliasAsync(id + '.VOLUME', dpPath + '.volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.ACTUAL', dpPath + 'volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); + await createAliasAsync(id + '.VOLUME', dpPath + 'volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.STATE', dpPath + 'on', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); dpPath = adapterPlayerInstance + 'nowPlaying'; await createAliasAsync(id + '.ALBUM', dpPath + '.album', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); @@ -4923,7 +4940,6 @@ async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPla await createAliasAsync(id + '.SHUFFLE', dpPath + '.shuffle', true, {type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE'}); dpPath = adapterPlayerInstance + 'keys'; - await createAliasAsync(id + '.STATE', dpPath + '.POWER', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); await createAliasAsync(id + '.NEXT', dpPath + '.NEXT_TRACK', true, {type: 'boolean', role: 'button.next', name: 'NEXT'}); await createAliasAsync(id + '.PREV', dpPath + '.PREV_TRACK', true, {type: 'boolean', role: 'button.prev', name: 'PREV'}); await createAliasAsync(id + '.PLAY', dpPath + '.PLAY', true, {type: 'boolean', role: 'button.play', name: 'PLAY'}); @@ -4975,7 +4991,7 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } let vMediaDevice = (page.items[0].mediaDevice != undefined) ? page.items[0].mediaDevice : ''; - + if (isPlayerWithMediaDevice(v2Adapter)) { if (!vMediaDevice) throw new Error(`Error in cardMedia! mediaDevice is empty! Page: ${JSON.stringify(page)}`); } @@ -4995,6 +5011,8 @@ function GenerateMediaPage(page: PageMedia): Payload[] { subscribeMediaSubscriptionsSonosAdd(page.items[0].id); } else if (v2Adapter == 'alexa2') { subscribeMediaSubscriptionsAlexaAdd(page.items[0].id); + } else if (v2Adapter == 'bosesoundtouch') { + subscribeMediaSubscriptionsBoseAdd(page.items[0].id); } } } @@ -5005,7 +5023,9 @@ function GenerateMediaPage(page: PageMedia): Payload[] { if (v2Adapter == 'sonos') { subscribeMediaSubscriptionsSonosAdd(page.items[0].id); } else if (v2Adapter == 'alexa2') { - subscribeMediaSubscriptionsAlexaAdd(page.items[0].id); + subscribeMediaSubscriptionsAlexaAdd(page.items[0].id); + } else if (v2Adapter == 'bosesoundtouch') { + subscribeMediaSubscriptionsBoseAdd(page.items[0].id); } } else if (page.type == 'cardMedia' && pageCounter == -1) { //Do Nothing @@ -5055,7 +5075,15 @@ function GenerateMediaPage(page: PageMedia): Payload[] { vDuration = vDuration.slice(4); } title = title + ' (' + vElapsed + '|' + vDuration + ')'; - } + } else if (v2Adapter == 'bosesoundtouch') { + if (Debug) log(getState(id + '.ELAPSED').val, 'info'); + let elapsedSeconds = parseInt(getState(id + '.ELAPSED').val)%60 < 10 ? '0' : '' + let vElapsed = Math.floor(getState(id + '.ELAPSED').val/60) + ":" + elapsedSeconds + getState(id + '.ELAPSED').val%60 + if (Debug) log(getState(id + '.DURATION').val, 'info'); + let durationSeconds = parseInt(getState(id + '.DURATION').val)%60 < 10 ? '0' : '' + let vDuration = Math.floor(getState(id + '.DURATION').val/60) + ":" + durationSeconds + getState(id + '.DURATION').val%60 + title = title + ' (' + vElapsed + '|' + vDuration + ')'; + } } let author = getState(id + '.ARTIST').val; let shuffle = getState(id + '.SHUFFLE').val; @@ -5110,6 +5138,24 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } } + //Bose Soundtouch + if (v2Adapter == 'bosesoundtouch') { + media_icon = Icons.GetIcon('alpha-b-circle'); + name = page.heading; + + if ((getState(id + '.ALBUM').val).length > 0) { + author = getState(id + '.ARTIST').val + ' | ' + getState(id + '.ALBUM').val; + if (author.length > 37) { + author = author.slice(0,37) + '...'; + } + } else { + author = getState(id + '.ARTIST').val; + } + if ((getState(id + '.ARTIST').val).length == 0) { + author = findLocale('media','no_music_to_control'); + } + } + //Logitech Squeezebox RPC if (v2Adapter == 'squeezeboxrpc') { media_icon = Icons.GetIcon('dlna'); @@ -5198,7 +5244,9 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } else if (v2Adapter == 'sonos') { currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'root.', page.items[0].mediaDevice, '.members'].join(''))).val; } else if (v2Adapter == 'squeezeboxrpc') { - currentSpeaker = getState(([page.items[0].adapterPlayerInstance, '.Players.', page.items[0].mediaDevice, '.Playername'].join(''))).val; + currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'Players.', page.items[0].mediaDevice, '.Playername'].join(''))).val; + } else if (v2Adapter == 'bosesoundtouch') { + currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'deviceInfo.name'].join(''))).val; } //------------------------------------------------------------------------------------------------------------- // All Alexa devices (the online / player and commands directory is available) are listed and linked below @@ -5400,6 +5448,14 @@ function GenerateMediaPage(page: PageMedia): Payload[] { repeatIcon = Icons.GetIcon('repeat-once'); repeatIconCol = rgb_dec565(HMIOn); } + } else if (v2Adapter == 'bosesoundtouch') { + if (getState(id + '.REPEAT').val == 'REPEAT_ALL') { + repeatIcon = Icons.GetIcon('repeat-variant'); + repeatIconCol = rgb_dec565(HMIOn); + } else if (getState(id + '.REPEAT').val == 'REPEAT_ONE') { + repeatIcon = Icons.GetIcon('repeat-once'); + repeatIconCol = rgb_dec565(HMIOn); + } } else if (v2Adapter == 'squeezeboxrpc') { if (getState(id + '.REPEAT').val == 1) { repeatIcon = Icons.GetIcon('repeat-once'); @@ -5418,7 +5474,12 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } } - if (v2Adapter == 'spotify-premium' || v2Adapter == 'alexa2' || v2Adapter == 'sonos' || v2Adapter == 'volumio' || v2Adapter == 'squeezeboxrpc') { + if (v2Adapter == 'spotify-premium' || + v2Adapter == 'alexa2' || + v2Adapter == 'sonos' || + v2Adapter == 'bosesoundtouch' || + v2Adapter == 'volumio' || + v2Adapter == 'squeezeboxrpc') { repeatButtonString = 'button' + '~' + id + '?repeat' + '~' + repeatIcon + '~' + @@ -7958,6 +8019,10 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p //Todo Richtiges Device finden actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Info.name').val); } + } else if (vAdapter == 'bosesoundtouch') { + if (existsObject(pageItem.adapterPlayerInstance + 'deviceInfo.name')) { + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'deviceInfo.name').val); + } } else if (vAdapter == 'squeezeboxrpc') { actualState = pageItem.mediaDevice; } @@ -7993,6 +8058,16 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p tempPlayList[i] = formatInSelText(tPlayList[i]); } optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' + } else if (vAdapter == 'bosesoundtouch') { + if (existsObject(pageItem.adapterPlayerInstance + 'deviceInfo.name')) { + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'deviceInfo.name').val); + log(actualState); + } + let tempPlayList: string[] = []; + for (let i = 0; i < pageItem.playList!.length; i++) { + tempPlayList[i] = formatInSelText(pageItem.playList![i]); + } + optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' } else if (vAdapter == 'sonos') { if (Debug) log(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set', 'info'); if (existsObject(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set')) { From 56c104a5bc687312fd865b2374cecad9223d3b77 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Fri, 5 Jan 2024 12:55:36 +0100 Subject: [PATCH 46/99] v4.3.3.32 - Update NsPanelTs.ts * Hotfix Spotify * Add Types see commits * v4.3.3.32 Add more details to types for: leftScreensaverEntity, indicatorScreensaverEntity, PageThermo, PageMedia * Remove not uses propertys from PageItem * Add Body for BoseSoundtouch-Player --- ioBroker/NsPanelTs.ts | 642 +++++++++++++++++++++++++----------------- 1 file changed, 376 insertions(+), 266 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 34626e77..cf71aded 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -95,8 +95,12 @@ ReleaseNotes: - 03.02.2024 - v4.3.3.31 Remove: adapterPlayerInstance from every card except cardMedia - 03.02.2024 - v4.3.3.31 [dev]: optional with type - cardMedia has adapterPlayerInstance all other not - 03.02.2024 - v4.3.3.31 [dev]: add PlayerType some more work to do - - 03.02.2024 - v4.3.3.31 changed: adapterPlayerInstance instance 0-9 allowed. Always require a '.' at the end. - - 04.01.2024 - v4.3.3.32 Hiofix Spotify + - 03.02.2024 - v4.3.3.31 changed: adapterPlayerInstance instance 0-9 allowed. Always require a '.' at the end. + - 04.01.2024 - v4.3.3.32 Hotfix Spotify + - 04.01.2024 - v4.3.3.32 [DEV] Add Types see commits + - 04.01.2024 - v4.3.3.32 Add more details to types for: leftScreensaverEntity, indicatorScreensaverEntity, PageThermo, PageMedia + - 04.01.2024 - v4.3.3.32 Remove not uses propertys from PageItem + - 05.01.2024 - v4.3.3.32 Add Body for BoseSoundtouch-Player Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -2769,12 +2773,14 @@ function check_online_display_firmware() { } } +//mqttCallback (topic: string, message: string): Promise { on({ id: config.panelRecvTopic }, async (obj) => { if (obj.state.val.startsWith('\{"CustomRecv":')) { try { + const json = JSON.parse(obj.state.val); + const split = json.CustomRecv.split(','); if (isSetOptionActive) { - let json = JSON.parse(obj.state.val); - let split = json.CustomRecv.split(','); + if (split[0] == 'event' && split[1] == 'startup') { await createStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { type: 'string' }); await createStateAsync(NSPanel_Path + 'NSPanel_Version', { type: 'string' }); @@ -2789,10 +2795,13 @@ on({ id: config.panelRecvTopic }, async (obj) => { await createAliasAsync(AliasPath + 'Display.Model.ACTUAL', NSPanel_Path + 'NSPanel_Version', true, { type: 'string', role: 'state', name: 'ACTUAL' }); } } - } + } + + if (isEventMethod(split[1])) HandleMessage(split[0], split[1], parseInt(split[2]), split); } catch (err: any) { log('error at trigger rceiving CustomRecv: ' + err.message, 'warn'); } + } }); @@ -2915,7 +2924,7 @@ function update_tasmota_firmware() { log('error request in function update_tasmota_firmware: ' + err.message, 'warn'); } } - +//mqttCallback (topic: string, message: string): Promise { on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'INFO1', change: 'ne'}, async (obj) => { try { if (getState(NSPanel_Path + 'Config.Update.activ').val == 0) { @@ -2936,23 +2945,6 @@ on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESU //------------------End Update Functions -on({ id: config.panelRecvTopic, change: 'any' }, async function (obj) { - try { - if (obj.state.val.startsWith('\{"CustomRecv":')) { - try { - let json = JSON.parse(obj.state.val); - - let split = json.CustomRecv.split(','); - HandleMessage(split[0], split[1], parseInt(split[2]), split); - } catch (err: any) { - log('error json.split in Trigger panelRecTopic: ' + err.message, 'warn'); - } - } - } catch (err: any) { - log('error at Trigger panelRecTopic: ' + err.message, 'warn'); - } -}); - async function SendToPanel(val: Payload | Payload[]) { try { if (Array.isArray(val)) { @@ -2986,10 +2978,10 @@ on({ id: NSPanel_Alarm_Path + 'Alarm.AlarmState', change: 'ne' }, async (obj) => } }); -function HandleMessage(typ: string, method: string, page: number | undefined, words: Array | undefined): void { +function HandleMessage(typ: string, method: EventMethod, page: number | undefined, words: Array | undefined): void { try { if (typ == 'event') { - switch (method) { + switch (method as EventMethod) { case 'startup': screensaverEnabled = false; UnsubscribeWatcher(); @@ -3135,7 +3127,7 @@ function GeneratePage(page: PageType): void { } } -function HandleHardwareButton(method: string): void { +function HandleHardwareButton(method: EventMethod): void { try { let buttonConfig: ConfigButtonFunction = config[method]; if(buttonConfig.mode === null) { @@ -3314,18 +3306,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let name: string; let buttonText: string = 'PRESS'; - let type: string; - - if (pageItem.id && existsState(pageItem.id + '.ACTUAL') == false) { - if (pageItem.popupTimerType == 'TimeCard' && pageItem.autoCreateALias == true) { - log(NSPanel_Path + 'Userdata.' + pageItem.id + '.Time') - createStateAsync(NSPanel_Path + 'Userdata.' + pageItem.id + '.Time', '0', { type: 'number' }); - createStateAsync(NSPanel_Path + 'Userdata.' + pageItem.id + '.State', 'idle', { type: 'string' }); - setObject(pageItem.id, { type: 'channel', common: { role: 'value.time', name: 'Time' }, native: {} }); - createAliasAsync(pageItem.id + '.ACTUAL', NSPanel_Path + 'Userdata.' + pageItem.id + '.Time', true, { type: 'number', role: 'state', name: 'ACTUAL' }); - createAliasAsync(pageItem.id + '.STATE', NSPanel_Path + 'Userdata.' + pageItem.id + '.State', true, { type: 'string', role: 'state', name: 'STATE' }); - } - } + let type: SerialType; // ioBroker if (pageItem.id && existsObject(pageItem.id) || pageItem.navigate === true) { @@ -3398,11 +3379,11 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } else if (pageItem.id != null && pageItem.targetPage != undefined) { type = 'button'; - - switch (o.common.role) { + const role = o.common.role as roles; + switch (role as roles) { case 'socket': case '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) : role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : iconId; buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : existsState(pageItem.id + '.BUTTONTEXT') ? getState(pageItem.id + '.BUTTONTEXT').val : 'PRESS'; @@ -3426,8 +3407,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = case 'door': case 'window': - iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); - iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : o.common.role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); + iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); buttonText = pageItem.buttonText !== undefined ? pageItem.buttonText : existsState(pageItem.id + '.BUTTONTEXT') ? getState(pageItem.id + '.BUTTONTEXT').val : 'PRESS'; if (existsState(pageItem.id + '.COLORDEC')) { @@ -3499,7 +3480,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = case 'thermostat': - iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'temperature' || o.common.role == 'value.temperature' || o.common.role == 'thermostat' ? Icons.GetIcon('thermometer') : Icons.GetIcon('information-outline'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'temperature' || role == 'value.temperature' || role == 'thermostat' ? Icons.GetIcon('thermometer') : Icons.GetIcon('information-outline'); let unit = ''; optVal = '0'; @@ -3583,13 +3564,13 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = return '~' + type + '~' + 'navigate.' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; } } - - switch (o.common.role) { + const role = o.common.role as roles + switch (role as roles) { 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'); - iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : o.common.role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + iconId2 = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); optVal = '0'; if (val === true || val === 'true') { @@ -3804,11 +3785,11 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = if (existsState(pageItem.id + '.ACTUAL')) { if (getState(pageItem.id + '.ACTUAL').val) { - iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'door' ? Icons.GetIcon('door-open') : Icons.GetIcon('window-open-variant'); iconColor = GetIconColor(pageItem, true, useColors); windowState = findLocale('window', 'opened'); } else { - iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'door' ? Icons.GetIcon('door-closed') : Icons.GetIcon('window-closed-variant'); iconId = pageItem.icon2 !== undefined ? Icons.GetIcon(pageItem.icon2) : iconId; iconColor = GetIconColor(pageItem, false, useColors); windowState = findLocale('window', 'closed'); @@ -3850,7 +3831,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = case 'thermostat': type = 'text'; - iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'temperature' || o.common.role == 'value.temperature' || o.common.role == 'thermostat' ? Icons.GetIcon('thermometer') : Icons.GetIcon('information-outline'); + iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'temperature' || role == 'value.temperature' || role == 'thermostat' ? Icons.GetIcon('thermometer') : Icons.GetIcon('information-outline'); let unit = ''; optVal = '0'; @@ -4294,7 +4275,7 @@ function GenerateThermoPage(page: PageThermo): Payload[] { if ((i_list.length - 3) != 0) { let i = 0; - switch (o.common.role) { + switch (o.common.role as roles) { case 'thermostat': { if (existsState(id + '.AUTOMATIC') && getState(id + '.AUTOMATIC').val != null) { @@ -4713,6 +4694,21 @@ function subscribeMediaSubscriptionsAlexaAdd(id: string): void { }); } +function subscribeMediaSubscriptionsBoseAdd(id: string): void { + on({id: [id + '.DURATION', + id + '.ELAPSED'], change: "any"}, async function () { + (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); + timeoutMedia = setTimeout(async function () { + if (useMediaEvents) { + GeneratePage(activePage!); + setTimeout(async function () { + GeneratePage(activePage!); + }, 50); + } + },50) + }); +} + async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPlayerInstance: adapterPlayerInstanceType) { if (autoCreateAlias) { if (isSetOptionActive) { @@ -4928,10 +4924,11 @@ async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPla log('bosesoundtouch Alias ' + id + ' does not exist - will be created now', 'info'); try { - let dpPath: string = adapterPlayerInstance + 'keys'; + let dpPath: string = adapterPlayerInstance; await extendObjectAsync(id, {_id: id, type: 'channel', common: {role: 'media', name: 'media'}, native: {}}); - await createAliasAsync(id + '.ACTUAL', dpPath + '.volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); - await createAliasAsync(id + '.VOLUME', dpPath + '.volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.ACTUAL', dpPath + 'volume', true, {type: 'number', role: 'value.volume', name: 'ACTUAL'}); + await createAliasAsync(id + '.VOLUME', dpPath + 'volume', true, {type: 'number', role: 'level.volume', name: 'VOLUME'}); + await createAliasAsync(id + '.STATE', dpPath + 'on', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); dpPath = adapterPlayerInstance + 'nowPlaying'; await createAliasAsync(id + '.ALBUM', dpPath + '.album', true, {type: 'string', role: 'media.album', name: 'ALBUM'}); @@ -4943,7 +4940,6 @@ async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPla await createAliasAsync(id + '.SHUFFLE', dpPath + '.shuffle', true, {type: 'boolean', role: 'media.mode.shuffle', name: 'SHUFFLE'}); dpPath = adapterPlayerInstance + 'keys'; - await createAliasAsync(id + '.STATE', dpPath + '.POWER', true, {type: 'boolean', role: 'media.state', name: 'STATE'}); await createAliasAsync(id + '.NEXT', dpPath + '.NEXT_TRACK', true, {type: 'boolean', role: 'button.next', name: 'NEXT'}); await createAliasAsync(id + '.PREV', dpPath + '.PREV_TRACK', true, {type: 'boolean', role: 'button.prev', name: 'PREV'}); await createAliasAsync(id + '.PLAY', dpPath + '.PLAY', true, {type: 'boolean', role: 'button.play', name: 'PLAY'}); @@ -4995,7 +4991,8 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } let vMediaDevice = (page.items[0].mediaDevice != undefined) ? page.items[0].mediaDevice : ''; - if (v2Adapter == 'alexa2' || v2Adapter == 'sonos' || v2Adapter == 'squeezeboxrpc') { + + if (isPlayerWithMediaDevice(v2Adapter)) { if (!vMediaDevice) throw new Error(`Error in cardMedia! mediaDevice is empty! Page: ${JSON.stringify(page)}`); } createAutoMediaAlias(id, vMediaDevice, page.items[0].adapterPlayerInstance!); @@ -5014,6 +5011,8 @@ function GenerateMediaPage(page: PageMedia): Payload[] { subscribeMediaSubscriptionsSonosAdd(page.items[0].id); } else if (v2Adapter == 'alexa2') { subscribeMediaSubscriptionsAlexaAdd(page.items[0].id); + } else if (v2Adapter == 'bosesoundtouch') { + subscribeMediaSubscriptionsBoseAdd(page.items[0].id); } } } @@ -5024,7 +5023,9 @@ function GenerateMediaPage(page: PageMedia): Payload[] { if (v2Adapter == 'sonos') { subscribeMediaSubscriptionsSonosAdd(page.items[0].id); } else if (v2Adapter == 'alexa2') { - subscribeMediaSubscriptionsAlexaAdd(page.items[0].id); + subscribeMediaSubscriptionsAlexaAdd(page.items[0].id); + } else if (v2Adapter == 'bosesoundtouch') { + subscribeMediaSubscriptionsBoseAdd(page.items[0].id); } } else if (page.type == 'cardMedia' && pageCounter == -1) { //Do Nothing @@ -5074,7 +5075,15 @@ function GenerateMediaPage(page: PageMedia): Payload[] { vDuration = vDuration.slice(4); } title = title + ' (' + vElapsed + '|' + vDuration + ')'; - } + } else if (v2Adapter == 'bosesoundtouch') { + if (Debug) log(getState(id + '.ELAPSED').val, 'info'); + let elapsedSeconds = parseInt(getState(id + '.ELAPSED').val)%60 < 10 ? '0' : '' + let vElapsed = Math.floor(getState(id + '.ELAPSED').val/60) + ":" + elapsedSeconds + getState(id + '.ELAPSED').val%60 + if (Debug) log(getState(id + '.DURATION').val, 'info'); + let durationSeconds = parseInt(getState(id + '.DURATION').val)%60 < 10 ? '0' : '' + let vDuration = Math.floor(getState(id + '.DURATION').val/60) + ":" + durationSeconds + getState(id + '.DURATION').val%60 + title = title + ' (' + vElapsed + '|' + vDuration + ')'; + } } let author = getState(id + '.ARTIST').val; let shuffle = getState(id + '.SHUFFLE').val; @@ -5129,6 +5138,24 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } } + //Bose Soundtouch + if (v2Adapter == 'bosesoundtouch') { + media_icon = Icons.GetIcon('alpha-b-circle'); + name = page.heading; + + if ((getState(id + '.ALBUM').val).length > 0) { + author = getState(id + '.ARTIST').val + ' | ' + getState(id + '.ALBUM').val; + if (author.length > 37) { + author = author.slice(0,37) + '...'; + } + } else { + author = getState(id + '.ARTIST').val; + } + if ((getState(id + '.ARTIST').val).length == 0) { + author = findLocale('media','no_music_to_control'); + } + } + //Logitech Squeezebox RPC if (v2Adapter == 'squeezeboxrpc') { media_icon = Icons.GetIcon('dlna'); @@ -5217,7 +5244,9 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } else if (v2Adapter == 'sonos') { currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'root.', page.items[0].mediaDevice, '.members'].join(''))).val; } else if (v2Adapter == 'squeezeboxrpc') { - currentSpeaker = getState(([page.items[0].adapterPlayerInstance, '.Players.', page.items[0].mediaDevice, '.Playername'].join(''))).val; + currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'Players.', page.items[0].mediaDevice, '.Playername'].join(''))).val; + } else if (v2Adapter == 'bosesoundtouch') { + currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'deviceInfo.name'].join(''))).val; } //------------------------------------------------------------------------------------------------------------- // All Alexa devices (the online / player and commands directory is available) are listed and linked below @@ -5419,6 +5448,14 @@ function GenerateMediaPage(page: PageMedia): Payload[] { repeatIcon = Icons.GetIcon('repeat-once'); repeatIconCol = rgb_dec565(HMIOn); } + } else if (v2Adapter == 'bosesoundtouch') { + if (getState(id + '.REPEAT').val == 'REPEAT_ALL') { + repeatIcon = Icons.GetIcon('repeat-variant'); + repeatIconCol = rgb_dec565(HMIOn); + } else if (getState(id + '.REPEAT').val == 'REPEAT_ONE') { + repeatIcon = Icons.GetIcon('repeat-once'); + repeatIconCol = rgb_dec565(HMIOn); + } } else if (v2Adapter == 'squeezeboxrpc') { if (getState(id + '.REPEAT').val == 1) { repeatIcon = Icons.GetIcon('repeat-once'); @@ -5437,7 +5474,12 @@ function GenerateMediaPage(page: PageMedia): Payload[] { } } - if (v2Adapter == 'spotify-premium' || v2Adapter == 'alexa2' || v2Adapter == 'sonos' || v2Adapter == 'volumio' || v2Adapter == 'squeezeboxrpc') { + if (v2Adapter == 'spotify-premium' || + v2Adapter == 'alexa2' || + v2Adapter == 'sonos' || + v2Adapter == 'bosesoundtouch' || + v2Adapter == 'volumio' || + v2Adapter == 'squeezeboxrpc') { repeatButtonString = 'button' + '~' + id + '?repeat' + '~' + repeatIcon + '~' + @@ -5560,7 +5602,7 @@ function GenerateAlarmPage(page: PageAlarm): Payload[] { } //let entityType = getState(nsPath + 'AlarmType').val; let arm1: string, arm2: string, arm3: string, arm4: string; - let arm1ActionName: string, arm2ActionName: string, arm3ActionName: string, arm4ActionName: string; + let arm1ActionName: ButtonActionType | '', arm2ActionName: ButtonActionType | '', arm3ActionName: ButtonActionType | '', arm4ActionName: ButtonActionType | ''; let icon = '0'; let iconcolor = 63488; let numpadStatus = 'disable'; @@ -5714,7 +5756,7 @@ function GenerateUnlockPage(page: PageUnlock): Payload[] { } let unlock1 = findLocale('lock', 'UNLOCK'); //unlock1*~* - let unlock1ActionName = 'U1'; //unlock1ActionName*~* + let unlock1ActionName: ButtonActionType | '' = 'U1'; //unlock1ActionName*~* let iconcolor = rgb_dec565({ red: 223, green: 76, blue: 30 }); //icon*~* let icon = Icons.GetIcon('lock-remove'); //iconcolor*~* @@ -6114,7 +6156,7 @@ function HandleButtonEvent(words: any): void { let tempid = words[2].split('?'); let id = tempid[0]; - let buttonAction = words[3]; + let buttonAction: ButtonActionType = words[3] as ButtonActionType; let pageItemID: string = ''; if (!isNaN(id)) { @@ -6293,7 +6335,8 @@ function HandleButtonEvent(words: any): void { if (Debug) { log('HandleButtonEvent -> OnOff: ' + words[4] + ' - ' + id + ' - Role - ' + o.common.role, 'info') } - switch (o.common.role) { + const role = o.common.role as roles; + switch (role as roles) { case 'level.mode.fan': case 'socket': case 'light': @@ -6329,7 +6372,7 @@ function HandleButtonEvent(words: any): void { if (words[4] == '1') action = true; let o = getObject(id); - switch (o.common.role) { + switch (o.common.role as roles) { case 'lock': case 'button': toggleState(id + '.SET') ? true : toggleState(id + '.ON_SET'); @@ -6503,8 +6546,8 @@ function HandleButtonEvent(words: any): void { if (existsObject(id)) { let o = getObject(id); let pageItem = findPageItem(id); - - switch (o.common.role) { + const role = o.common.role as roles; + switch (role as roles) { case 'dimmer': if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { let sliderPos = Math.trunc(scale(parseInt(words[4]), 0, 100, pageItem.maxValueBrightness, pageItem.minValueBrightness)); @@ -6550,7 +6593,7 @@ function HandleButtonEvent(words: any): void { log('HandleButtonEvent colorWeel -> getHue-Werte: ' + getHue(rgb.red, rgb.green, rgb.blue), 'info'); } let o = getObject(id); - switch (o.common.role) { + switch (o.common.role as roles) { case 'hue': setIfExists(id + '.HUE', getHue(rgb.red, rgb.green, rgb.blue)); break; @@ -6625,7 +6668,9 @@ function HandleButtonEvent(words: any): void { const tempPage = findPageItem(id); if (isPageMediaItem(tempPage)) { if (tempPage.adapterPlayerInstance.startsWith("volumio")) { - findPageItem(id).playList = []; break; + const item = findPageItem(id) + if (isPageMediaItem(item)) item.playList = []; + break; } //Volumio: empty playlist $uha-20230103 if ((tempPage.adapterPlayerInstance).startsWith("spotify")) { if (getState(id + '.SHUFFLE').val == 'off') { @@ -6822,7 +6867,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemRP)) break; let adapterInstanceRP = pageItemRP.adapterPlayerInstance!; let adapterRP = adapterInstanceRP.split('.'); - let deviceAdapterRP = adapterRP[0]; + let deviceAdapterRP: PlayerType = adapterRP[0] as PlayerType; if (Debug) log(pageItemRP.repeatList![words[4]], 'warn'); switch (deviceAdapterRP) { @@ -6837,6 +6882,7 @@ function HandleButtonEvent(words: any): void { break; case 'mode-equalizer': let pageItemEQ = findPageItem(id); + if (!isPageMediaItem(pageItemEQ)) break; if (Debug) log('HandleButtonEvent mode-equalizer -> id: ' + id, 'info'); let lastIndex = (id.split('.')).pop(); setState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode', pageItemEQ.equalizerList![words[4]]); @@ -6852,7 +6898,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemSeek)) break; let adapterInstanceSK = pageItemSeek.adapterPlayerInstance!; let adapterSK = adapterInstanceSK.split('.'); - let deviceAdapterSK = adapterSK[0]; + let deviceAdapterSK: PlayerType = adapterSK[0] as PlayerType; switch (deviceAdapterSK) { case 'spotify-premium': break; @@ -6873,7 +6919,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemCrossfade)) break; let adapterInstanceCF = pageItemCrossfade.adapterPlayerInstance!; let adapterCF = adapterInstanceCF.split('.'); - let deviceAdapterCF = adapterCF[0]; + let deviceAdapterCF: PlayerType = adapterCF[0] as PlayerType; switch (deviceAdapterCF) { case 'spotify-premium': break; @@ -7010,19 +7056,19 @@ function HandleButtonEvent(words: any): void { break; case 'mode-modus1': let pageItemT1 = findPageItem(id); - setIfExists(id + '.' + pageItemT1.setThermoAlias![0], pageItemT1.popupThermoMode1![parseInt(words[4])]); + if (isPageThermoItem(pageItemT1)) setIfExists(id + '.' + pageItemT1.setThermoAlias![0], pageItemT1.popupThermoMode1![parseInt(words[4])]); break; case 'mode-modus2': let pageItemT2 = findPageItem(id); - setIfExists(id + '.' + pageItemT2.setThermoAlias![1], pageItemT2.popupThermoMode2![parseInt(words[4])]); + if (isPageThermoItem(pageItemT2)) setIfExists(id + '.' + pageItemT2.setThermoAlias![1], pageItemT2.popupThermoMode2![parseInt(words[4])]); break; case 'mode-modus3': let pageItemT3 = findPageItem(id); - setIfExists(id + '.' + pageItemT3.setThermoAlias![2], pageItemT3.popupThermoMode3![parseInt(words[4])]); + if (isPageThermoItem(pageItemT3)) setIfExists(id + '.' + pageItemT3.setThermoAlias![2], pageItemT3.popupThermoMode3![parseInt(words[4])]); break; case 'number-set': let nobj = getObject(id); - switch (nobj.common.role) { + switch (nobj.common.role as roles) { case 'level.mode.fan': (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); timeoutSlider = setTimeout(async function () { @@ -7229,7 +7275,6 @@ function GetNavigationString(pageId: number): string { } return ''; } - function GenerateDetailPage(type: string, optional: mediaOptional | undefined, pageItem: PageItem, placeId: number | undefined): Payload[] { if (Debug) log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); try { @@ -7238,16 +7283,17 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p if (id && existsObject(id)) { - let o = getObject(id); + const o = getObject(id); let val: (boolean | number) = 0; let icon = Icons.GetIcon('lightbulb'); let iconColor = rgb_dec565(config.defaultColor); + const role = o.common.role as roles; if (type == 'popupLight') { let switchVal = '0'; let brightness = 0; - switch (o.common.role) { + switch (role) { case 'light': case 'socket': { if (existsState(id + '.GET')) { @@ -7264,7 +7310,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p } } - icon = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : o.common.role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); + icon = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); if (val) { switchVal = '1'; @@ -7636,7 +7682,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p }); } break; - } + } } if (type == 'popupShutter') { @@ -7740,12 +7786,12 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p if (type == 'popupThermo') { let vIcon = (pageItem.icon != undefined) ? pageItem.icon : 'fan'; - let mode1 = (pageItem.popupThermoMode1 != undefined) ? pageItem.popupThermoMode1.join('?') : ''; - let mode2 = (pageItem.popupThermoMode2 != undefined) ? pageItem.popupThermoMode2.join('?') : ''; - let mode3 = (pageItem.popupThermoMode3 != undefined) ? pageItem.popupThermoMode3.join('?') : ''; + let mode1 = (isPageThermoItem(pageItem) && pageItem.popupThermoMode1 != undefined) ? pageItem.popupThermoMode1.join('?') : ''; + let mode2 = (isPageThermoItem(pageItem) && pageItem.popupThermoMode2 != undefined) ? pageItem.popupThermoMode2.join('?') : ''; + let mode3 = (isPageThermoItem(pageItem) && pageItem.popupThermoMode3 != undefined) ? pageItem.popupThermoMode3.join('?') : ''; let payloadParameters1 = '~~~~' - if (pageItem.popupThermoMode1 != undefined) { + if (isPageThermoItem(pageItem) && pageItem.popupThermoMode1 != undefined) { RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias![0], pageItem, type, placeId); payloadParameters1 = pageItem.popUpThermoName![0] + '~' //{heading}~ Mode 1 + 'modus1' + '~' //{id}~ Mode 1 @@ -7754,7 +7800,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p } let payloadParameters2 = '~~~~' - if (pageItem.popupThermoMode2 != undefined) { + if (isPageThermoItem(pageItem) && pageItem.popupThermoMode2 != undefined) { RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias![1], pageItem, type, placeId); payloadParameters2 = pageItem.popUpThermoName![1] + '~' //{heading}~ Mode 2 + 'modus2' + '~' //{id}~ Mode 2 @@ -7763,7 +7809,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p } let payloadParameters3 = '~~~~' - if (pageItem.popupThermoMode3 != undefined) { + if (isPageThermoItem(pageItem) && pageItem.popupThermoMode3 != undefined) { RegisterDetailEntityWatcher(pageItem.id + "." + pageItem.setThermoAlias![2], pageItem, type, placeId); payloadParameters3 = pageItem.popUpThermoName![2] + '~' //{heading}~ Mode 3 + 'modus3' + '~' //{id}~ Mode 3 @@ -7789,83 +7835,82 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p if (existsState(id + '.ACTUAL')) { RegisterDetailEntityWatcher(id + '.ACTUAL', pageItem, type, placeId); timer_actual = getState(id + '.ACTUAL').val; - } + } if (existsState(id + '.STATE')) { RegisterDetailEntityWatcher(id + '.STATE', pageItem, type, placeId); - } + } let editable = 1; let action1 = ''; let action2 = ''; let action3 = ''; - let label1 = ''; - let label2 = ''; - let label3 = ''; + let label1 = ''; + let label2 = ''; + let label3 = ''; let min_remaining = 0; let sec_remaining = 0; if (existsState(id + '.STATE')) { - - if (o.common.role == 'value.time') { - if (getState(id + '.STATE').val == 'idle' || getState(id + '.STATE').val == 'paused') { - min_remaining = Math.floor(timer_actual / 60); - sec_remaining = timer_actual % 60; - editable = 1; - } else { - min_remaining = Math.floor(timer_actual / 60); - sec_remaining = timer_actual % 60; - editable = 1; - } - } else if (o.common.role == 'level.timer') { - if (getState(id + '.STATE').val == 'idle' || getState(id + '.STATE').val == 'paused') { - min_remaining = Math.floor(timer_actual / 60); - sec_remaining = timer_actual % 60; - editable = 1; - action2 = 'start'; - label2 = findLocale('timer', 'start'); - } else { - min_remaining = Math.floor(timer_actual / 60); - sec_remaining = timer_actual % 60; - editable = 0; - action1 = 'pause'; - action2 = 'cancle'; - action3 = 'finish'; - label1 = findLocale('timer', 'pause'); - label2 = findLocale('timer', 'cancel'); - label3 = findLocale('timer', 'finish'); - } - } else if (o.common.role == 'value.alarmtime') { - if (getState(id + '.STATE').val == 'paused') { - min_remaining = Math.floor(timer_actual / 60); - sec_remaining = timer_actual % 60; - editable = 1; - action2 = 'start'; - label2 = findLocale('timer', 'on'); - } else { - min_remaining = Math.floor(timer_actual / 60); - sec_remaining = timer_actual % 60; - editable = 0; - action2 = 'pause'; - label2 = findLocale('timer', 'off'); + if (role == 'value.time') { + if (getState(id + '.STATE').val == 'idle' || getState(id + '.STATE').val == 'paused') { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 1; + } else { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 1; + } + } else if (role == 'level.timer') { + if (getState(id + '.STATE').val == 'idle' || getState(id + '.STATE').val == 'paused') { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 1; + action2 = 'start'; + label2 = findLocale('timer', 'start'); + } else { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 0; + action1 = 'pause'; + action2 = 'cancle'; + action3 = 'finish'; + label1 = findLocale('timer', 'pause'); + label2 = findLocale('timer', 'cancel'); + label3 = findLocale('timer', 'finish'); + } + } else if (role == 'value.alarmtime') { + if (getState(id + '.STATE').val == 'paused') { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 1; + action2 = 'start'; + label2 = findLocale('timer', 'on'); + } else { + min_remaining = Math.floor(timer_actual / 60); + sec_remaining = timer_actual % 60; + editable = 0; + action2 = 'pause'; + label2 = findLocale('timer', 'off'); + } } - } - let tempId = placeId != undefined ? placeId : id; - - out_msgs.push({ - payload: 'entityUpdateDetail' + '~' //entityUpdateDetail - + tempId + '~~' //{entity_id} - + rgb_dec565(White) + '~' //{icon_color}~ - + tempId + '~' - + min_remaining + '~' - + sec_remaining + '~' - + editable + '~' - + action1 + '~' - + action2 + '~' - + action3 + '~' - + label1 + '~' - + label2 + '~' - + label3 + let tempId = placeId != undefined ? placeId : id; + + out_msgs.push({ + payload: 'entityUpdateDetail' + '~' //entityUpdateDetail + + tempId + '~~' //{entity_id} + + rgb_dec565(White) + '~' //{icon_color}~ + + tempId + '~' + + min_remaining + '~' + + sec_remaining + '~' + + editable + '~' + + action1 + '~' + + action2 + '~' + + action3 + '~' + + label1 + '~' + + label2 + '~' + + label3 }); } } @@ -7873,7 +7918,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p if (type == 'popupFan') { let switchVal = '0'; - if (o.common.role == 'level.mode.fan') { + if (role == 'level.mode.fan') { if (existsState(id + '.SET')) { val = getState(id + '.SET').val; RegisterDetailEntityWatcher(id + '.SET', pageItem, type, placeId); @@ -7915,7 +7960,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p } if (type == 'popupInSel') { - if (o.common.role == 'media') { + if (role == 'media') { let actualState: any = ''; let optionalString: string = 'Kein Eintrag'; let mode: string = ''; @@ -7974,6 +8019,10 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p //Todo Richtiges Device finden actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'Echo-Devices.' + pageItem.mediaDevice + '.Info.name').val); } + } else if (vAdapter == 'bosesoundtouch') { + if (existsObject(pageItem.adapterPlayerInstance + 'deviceInfo.name')) { + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'deviceInfo.name').val); + } } else if (vAdapter == 'squeezeboxrpc') { actualState = pageItem.mediaDevice; } @@ -8009,6 +8058,16 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p tempPlayList[i] = formatInSelText(tPlayList[i]); } optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' + } else if (vAdapter == 'bosesoundtouch') { + if (existsObject(pageItem.adapterPlayerInstance + 'deviceInfo.name')) { + actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'deviceInfo.name').val); + log(actualState); + } + let tempPlayList: string[] = []; + for (let i = 0; i < pageItem.playList!.length; i++) { + tempPlayList[i] = formatInSelText(pageItem.playList![i]); + } + optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' } else if (vAdapter == 'sonos') { if (Debug) log(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set', 'info'); if (existsObject(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set')) { @@ -8142,7 +8201,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p }); GeneratePage(activePage!); } - } else if (o.common.role == 'buttonSensor') { + } else if (role == 'buttonSensor') { let actualValue: string = ''; @@ -8169,12 +8228,12 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p + actualValue + '~' + valueList }); - } else if (o.common.role == 'light' || - o.common.role == 'dimmer' || - o.common.role == 'hue' || - o.common.role == 'rgb' || - o.common.role == 'rgbSingle' || - o.common.role == 'ct') { + } else if (role == 'light' || + role == 'dimmer' || + role == 'hue' || + role == 'rgb' || + role == 'rgbSingle' || + role == 'ct') { //log(pageItem.id, 'info'); if (pageItem.modeList != undefined) { @@ -8303,65 +8362,67 @@ function HandleScreensaverUpdate(): void { } // 3 leftScreensaverEntities - if (screensaverAdvanced) { + if (screensaverAdvanced) { let checkpoint = true; let i = 0; - for (i = 0; i < 3; i++) { - - if (config.leftScreensaverEntity[i] == null || config.leftScreensaverEntity[i] == undefined) { - checkpoint = false; - break; - } - RegisterScreensaverEntityWatcher(config.leftScreensaverEntity[i].ScreensaverEntity) - - let val = getState(config.leftScreensaverEntity[i].ScreensaverEntity).val; - let iconColor = rgb_dec565(White); - let icon; - if (typeof config.leftScreensaverEntity[i].ScreensaverEntityIconOn == 'string' && existsObject(config.leftScreensaverEntity[i].ScreensaverEntityIconOn as string)) { - let iconName = getState(config.leftScreensaverEntity[i].ScreensaverEntityIconOn!).val; - icon = Icons.GetIcon(iconName); - } else { - icon = Icons.GetIcon(config.leftScreensaverEntity[i].ScreensaverEntityIconOn); - } - - if (parseFloat(val+"") == val) { - val = parseFloat(val); - } - - if (typeof(val) == 'number') { - val = (val * (config.leftScreensaverEntity[i].ScreensaverEntityFactor ? config.leftScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.leftScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.leftScreensaverEntity[i].ScreensaverEntityUnitText; - iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); - } - else if (typeof(val) == 'boolean') { - iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); - if (!val && config.leftScreensaverEntity[i].ScreensaverEntityIconOff != null) { - icon = Icons.GetIcon(config.leftScreensaverEntity[i].ScreensaverEntityIconOff) + if (config.leftScreensaverEntity && Array.isArray(config.leftScreensaverEntity)) { + for (i = 0; i < 3; i++) { + const leftScreensaverEntity = config.leftScreensaverEntity[i] + if (leftScreensaverEntity === null || leftScreensaverEntity === undefined) { + checkpoint = false; + break;; } - } - else if (typeof(val) == 'string') { - iconColor = GetScreenSaverEntityColor(config.leftScreensaverEntity[i]); - let pformat = parseFormat(val); - if (Debug) log('moments.js --> Datum ' + val + ' valid?: ' + moment(val, pformat, true).isValid(), 'info'); - if (moment(val, pformat, true).isValid()) { - let DatumZeit = moment(val, pformat).unix(); // Umwandlung in Unix Time-Stamp - if (config.leftScreensaverEntity[i].ScreensaverEntityDateFormat !== undefined) { - val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val, config.leftScreensaverEntity[i].ScreensaverEntityDateFormat); - } else { - val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val); - } - } - } - const temp = config.leftScreensaverEntity[i].ScreensaverEntityIconColor; - if (temp && typeof temp == 'string' && existsObject(temp)) { - iconColor = getState(temp).val; - } + RegisterScreensaverEntityWatcher(leftScreensaverEntity.ScreensaverEntity) - payloadString += '~' + - '~' + - icon + '~' + - iconColor + '~' + - config.leftScreensaverEntity[i].ScreensaverEntityText + '~' + - val + '~'; + let val = getState(leftScreensaverEntity.ScreensaverEntity).val; + let iconColor = rgb_dec565(White); + let icon; + if (typeof leftScreensaverEntity.ScreensaverEntityIconOn == 'string' && existsObject(leftScreensaverEntity.ScreensaverEntityIconOn as string)) { + let iconName = getState(leftScreensaverEntity.ScreensaverEntityIconOn!).val; + icon = Icons.GetIcon(iconName); + } else { + icon = Icons.GetIcon(leftScreensaverEntity.ScreensaverEntityIconOn); + } + + if (parseFloat(val + "") == val) { + val = parseFloat(val); + } + + if (typeof (val) == 'number') { + val = (val * (leftScreensaverEntity.ScreensaverEntityFactor ? leftScreensaverEntity.ScreensaverEntityFactor! : 0)).toFixed(leftScreensaverEntity.ScreensaverEntityDecimalPlaces) + leftScreensaverEntity.ScreensaverEntityUnitText; + iconColor = GetScreenSaverEntityColor(leftScreensaverEntity); + } + else if (typeof (val) == 'boolean') { + iconColor = GetScreenSaverEntityColor(leftScreensaverEntity); + if (!val && leftScreensaverEntity.ScreensaverEntityIconOff != null) { + icon = Icons.GetIcon(leftScreensaverEntity.ScreensaverEntityIconOff) + } + } + else if (typeof (val) == 'string') { + iconColor = GetScreenSaverEntityColor(leftScreensaverEntity); + let pformat = parseFormat(val); + if (Debug) log('moments.js --> Datum ' + val + ' valid?: ' + moment(val, pformat, true).isValid(), 'info'); + if (moment(val, pformat, true).isValid()) { + let DatumZeit = moment(val, pformat).unix(); // Umwandlung in Unix Time-Stamp + if (leftScreensaverEntity.ScreensaverEntityDateFormat !== undefined) { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val, leftScreensaverEntity.ScreensaverEntityDateFormat); + } else { + val = new Date(DatumZeit * 1000).toLocaleString(getState(NSPanel_Path + 'Config.locale').val); + } + } + } + const temp = leftScreensaverEntity.ScreensaverEntityIconColor; + if (temp && typeof temp == 'string' && existsObject(temp)) { + iconColor = getState(temp).val; + } + + payloadString += '~' + + '~' + + icon + '~' + + iconColor + '~' + + leftScreensaverEntity.ScreensaverEntityText + '~' + + val + '~'; + } } if (checkpoint == false) { for (let j = i; j < 3; j++) { @@ -8469,7 +8530,7 @@ function HandleScreensaverUpdate(): void { } //Alternativ Layout bekommt zusätzlichen Status - if (getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { + if (config.bottomScreensaverEntity[4] && getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { let val = getState(config.bottomScreensaverEntity[4].ScreensaverEntity).val; if (parseFloat(val+"") == val) { val = parseFloat(val); @@ -8588,37 +8649,38 @@ function HandleScreensaverUpdate(): void { // 5 indicatorScreensaverEntities for (let i = 0; i < 5; i++) { let checkpoint = true; - if (config.indicatorScreensaverEntity[i] == null) { + const indicatorScreensaverEntity:ScreenSaverElementWithUndefined = config.indicatorScreensaverEntity[i]; + if (indicatorScreensaverEntity == null) { checkpoint = false; break; } - RegisterScreensaverEntityWatcher(config.indicatorScreensaverEntity[i].ScreensaverEntity) + RegisterScreensaverEntityWatcher(indicatorScreensaverEntity.ScreensaverEntity) - let val = getState(config.indicatorScreensaverEntity[i].ScreensaverEntity).val; + let val = getState(indicatorScreensaverEntity.ScreensaverEntity).val; if (parseFloat(val+"") == val) { val = parseFloat(val); } let iconColor = rgb_dec565(White); let icon; - if (config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn && existsObject(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn!)) { - let iconName = getState(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn!).val; + if (indicatorScreensaverEntity.ScreensaverEntityIconOn && existsObject(indicatorScreensaverEntity.ScreensaverEntityIconOn!)) { + let iconName = getState(indicatorScreensaverEntity.ScreensaverEntityIconOn!).val; icon = Icons.GetIcon(iconName); } else { - icon = Icons.GetIcon(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOn); + icon = Icons.GetIcon(indicatorScreensaverEntity.ScreensaverEntityIconOn); } if (typeof(val) == 'number') { - val = (val * (config.indicatorScreensaverEntity[i].ScreensaverEntityFactor ? config.indicatorScreensaverEntity[i].ScreensaverEntityFactor! : 0)).toFixed(config.indicatorScreensaverEntity[i].ScreensaverEntityDecimalPlaces) + config.indicatorScreensaverEntity[i].ScreensaverEntityUnitText; - iconColor = GetScreenSaverEntityColor(config.indicatorScreensaverEntity[i]); + val = (val * (indicatorScreensaverEntity.ScreensaverEntityFactor ? indicatorScreensaverEntity.ScreensaverEntityFactor! : 0)).toFixed(indicatorScreensaverEntity.ScreensaverEntityDecimalPlaces) + indicatorScreensaverEntity.ScreensaverEntityUnitText; + iconColor = GetScreenSaverEntityColor(indicatorScreensaverEntity); } else if (typeof(val) == 'boolean') { - iconColor = GetScreenSaverEntityColor(config.indicatorScreensaverEntity[i]); - if (!val && config.indicatorScreensaverEntity[i].ScreensaverEntityIconOff != null) { - icon = Icons.GetIcon(config.indicatorScreensaverEntity[i].ScreensaverEntityIconOff) + iconColor = GetScreenSaverEntityColor(indicatorScreensaverEntity); + if (!val && indicatorScreensaverEntity.ScreensaverEntityIconOff != null) { + icon = Icons.GetIcon(indicatorScreensaverEntity.ScreensaverEntityIconOff) } } - const temp = config.indicatorScreensaverEntity[4].ScreensaverEntityIconColor + const temp = indicatorScreensaverEntity.ScreensaverEntityIconColor if (temp && typeof temp == 'string' && existsObject(temp)) { iconColor = getState(temp).val; } @@ -8626,7 +8688,7 @@ function HandleScreensaverUpdate(): void { '~' + icon + '~' + iconColor + '~' + - config.indicatorScreensaverEntity[i].ScreensaverEntityText + '~' + + indicatorScreensaverEntity.ScreensaverEntityText + '~' + val + '~'; } } @@ -9278,6 +9340,7 @@ function GetDasWetterIconColor(icon: number): number { } //------------------Begin Read Internal Sensor Data +//mqttCallback (topic: string, message: string): Promise { on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESULT'.length) + 'SENSOR' }, async (obj) => { try { const Tasmota_Sensor = JSON.parse(obj.state.val); @@ -9491,6 +9554,23 @@ function spotifyGetDeviceID(vDeviceString: string): string { return strDevID; } +type EventMethod = 'startup' | 'sleepReached' | 'pageOpenDetail' | 'buttonPress2' | 'renderCurrentPage' | 'button1' | 'button2' + +type SerialType = 'button' | 'light' | 'shutter' | 'text' | 'input_sel' | 'timer' | 'number' | 'fan' + +type roles = 'light' |'socket'|'dimmer'| 'hue' | 'rgb' | 'rgbSingle' | 'cd' | 'blind' | 'door' | 'window' | 'volumeGroup' | 'volume' + | 'info' | 'humidity' | 'temperature' | 'value.temperature' | 'value.humidity' | 'sensor.door' | 'sensor.window' | 'thermostat' | 'warning' | 'ct' + | 'cie' | 'gate' | 'motion' | 'buttonSensor' | 'button' | 'value.time' | 'level.timer' | 'value.alarmtime' | 'level.mode.fan' | 'lock' | 'slider' + | 'switch.mode.wlan' | 'media' | 'timeTable' | 'airCondition' + +type ButtonActionType = 'bExit' | 'bUp' | 'bNext' | 'bSubNext' | 'bPrev' | 'bSubPrev' | 'bHome' | 'notifyAction' | 'OnOff' | 'button' | 'up' | 'stop' | 'down' + | 'positionSlider' | 'tiltOpen' | 'tiltStop' | 'tiltSlider' | 'tiltClose' | 'brightnessSlider' | 'colorTempSlider' | 'colorWheel' | 'tempUpd' | 'tempUpdHighLow' | 'media-back' + | 'media-pause' | 'media-next' | 'media-shuffle' | 'volumeSlider' | 'mode-speakerlist' | 'mode-playlist' | 'mode-tracklist' | 'mode-repeat' | 'mode-equalizer' | 'mode-seek' | 'mode-crossfade' + | 'mode-favorites' | 'mode-insel' | 'media-OnOff' | 'timer-start' | 'timer-pause' | 'timer-cancle' | 'timer-finish' | 'hvac_action' | 'mode-modus1' | 'mode-modus2' | 'mode-modus3' | 'number-set' + | 'mode-preset_modes' | 'A1' | 'A2' | 'A3' | 'A4' | 'D1' | 'U1' + + + type RGB = { red: number, green: number, @@ -9547,7 +9627,8 @@ type PageGrid2 = { type PageThermo = { type: 'cardThermo', - items: PageItem[], + items: PageThermoItem[], + } & Omit type PageMedia = { @@ -9580,13 +9661,36 @@ type PageChart = { items: PageItem[], } & Omit -type PageItem = PageBaseItem | PageMediaItem +type PageItem = PageBaseItem | PageMediaItem | PageThermoItem function isPageMediaItem(F: PageItem | PageMediaItem):F is PageMediaItem { - return (F as PageMediaItem).adapterPlayerInstance !== undefined + return 'adapterPlayerInstance' in F +} + +function isPageThermoItem(F: PageItem | PageThermoItem):F is PageThermoItem { + return 'popupThermoMode1' in F; } type PageMediaItem = { adapterPlayerInstance: adapterPlayerInstanceType, + mediaDevice?: string, + colorMediaIcon?: RGB, + colorMediaArtist?: RGB, + colorMediaTitle?: RGB, + speakerList?: string[], + playList?: string[], + equalizerList?: string[], + repeatList?: string[], + globalTracklist?: string[], + crossfade?: boolean, +} & PageBaseItem + +type PageThermoItem = { + popupThermoMode1?: string[], + popupThermoMode2?: string[], + popupThermoMode3?: string[], + popUpThermoName?: string[], + setThermoAlias?: string[], + setThermoDestTemp2?: string, } & PageBaseItem type PageBaseItem = { @@ -9616,45 +9720,22 @@ type PageBaseItem = { unit?: string, navigate?: boolean, colormode?: string, - colorScale?: any, + colorScale?: IconScaleElement, //adapterPlayerInstance?: adapterPlayerInstanceType, - mediaDevice?: string, targetPage?: string, - speakerList?: string[], - playList?: string[], - equalizerList?: string[], - repeatList?: string[], - globalTracklist?: string[], modeList?: string[], hidePassword?: boolean, autoCreateALias?: boolean - colorMediaIcon?: RGB, - colorMediaArtist?: RGB, - colorMediaTitle?: RGB, - popupThermoMode1?: string[], - popupThermoMode2?: string[], - popupThermoMode3?: string[], - popUpThermoName?: string[], - popupMediaMode1?: string[], - popupMediaMode2?: string[], - popupMediaMode3?: string[], - popUpMediaName?: string[], - setThermoAlias?: string[], - setThermoDestTemp2?: string, yAxis?: string, yAxisTicks?: number[] | string, xAxisDecorationId?: string, - popupType?: string, - popupOptions?: string[], useValue?: boolean, monobutton?: boolean, inSel_ChoiceState?: boolean, iconArray?: string[], fontSize?: number, actionStringArray?: string[], - popupTimerType?: string, alwaysOnDisplay?: boolean, - crossfade?: boolean, } type DimMode = { @@ -9676,9 +9757,9 @@ type Config = { panelRecvTopic: string, panelSendTopic: string, weatherEntity: string, - leftScreensaverEntity: ScreenSaverElement[], + leftScreensaverEntity: leftScreensaverEntityType bottomScreensaverEntity: ScreenSaverElement[], - indicatorScreensaverEntity: ScreenSaverElement[], + indicatorScreensaverEntity: indicatorScreensaverEntityType mrIcon1ScreensaverEntity: ScreenSaverMRElement, mrIcon2ScreensaverEntity: ScreenSaverMRElement, defaultColor: RGB, @@ -9690,16 +9771,18 @@ type Config = { button1: ConfigButtonFunction, button2: ConfigButtonFunction } - +type leftScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; +type indicatorScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; +type ScreenSaverElementWithUndefined = null | undefined | ScreenSaverElement type ScreenSaverElement = { ScreensaverEntity: string, + ScreensaverEntityText: string, ScreensaverEntityFactor?: number, ScreensaverEntityDecimalPlaces?: number, - ScreensaverEntityDateFormat?: any | null, + ScreensaverEntityDateFormat?: Intl.DateTimeFormatOptions, ScreensaverEntityIconOn?: string | null, ScreensaverEntityIconOff?: string | null, - ScreensaverEntityText: string, - ScreensaverEntityUnitText?: string | null, + ScreensaverEntityUnitText?: string, ScreensaverEntityIconColor?: RGB | IconScaleElement | string ScreensaverEntityOnColor?: RGB ScreensaverEntityOffColor?: RGB @@ -9732,8 +9815,17 @@ type adapterPlayerInstanceType = | 'squeezeboxrpc.0.' | 'squeezeboxrpc.1.' | 'squeezeboxrpc.2.' | 'squeezeboxrpc.3.' | 'squeezeboxrpc.4.' | 'squeezeboxrpc.5.' | 'squeezeboxrpc.6.' | 'squeezeboxrpc.7.' | 'squeezeboxrpc.8.' | 'squeezeboxrpc.9.' | 'bosesoundtouch.0.' | 'bosesoundtouch.1.' | 'bosesoundtouch.2.' | 'bosesoundtouch.3.' |'bosesoundtouch.4.' | 'bosesoundtouch.5.' | 'bosesoundtouch.6.' | 'bosesoundtouch.7.' | 'bosesoundtouch.8.' | 'bosesoundtouch.9.' -type PlayerType = 'alexa2' | 'sonos' | 'spotify-premium' | 'volumio' | 'squeezeboxrpc' | 'bosesoundtouch' - +type PlayerType = _PlayerTypeWithMediaDevice | _PlayerTypeWithOutMediaDevice; + +const ArrayPlayerTypeWithMediaDevice = ['alexa2', 'sonos', 'squeezeboxrpc'] as const +const ArrayPlayerTypeWithOutMediaDevice = ['spotify-premium', 'volumio', 'bosesoundtouch'] as const +type _PlayerTypeWithOutMediaDevice = typeof ArrayPlayerTypeWithOutMediaDevice[number] +type _PlayerTypeWithMediaDevice = typeof ArrayPlayerTypeWithMediaDevice[number] + +function isPlayerWithMediaDevice (F: string | _PlayerTypeWithMediaDevice): F is _PlayerTypeWithMediaDevice { + return ArrayPlayerTypeWithMediaDevice.indexOf(F as _PlayerTypeWithMediaDevice) != -1; +} + type notSortedPlayerType = `${PlayerType}.0.` | `${PlayerType}.1.` | `${PlayerType}.2.` | `${PlayerType}.3.` | `${PlayerType}.4.` | `${PlayerType}.5.` | `${PlayerType}.6.` | `${PlayerType}.7.` | `${PlayerType}.8.` | `${PlayerType}.9.` /** check if adapterPlayerInstanceType has all Playertypes */ @@ -9743,6 +9835,7 @@ function checkSortedPlayerType(F: notSortedPlayerType) { type mediaOptional = 'seek' | 'crossfade' | 'speakerlist' | 'playlist' | 'tracklist' | 'equalizer' | 'repeat' | 'favorites' + function isMediaOptional(F: string | mediaOptional): F is mediaOptional { switch(F as mediaOptional) { case "seek": @@ -9757,4 +9850,21 @@ function isMediaOptional(F: string | mediaOptional): F is mediaOptional { default: return false } -} \ No newline at end of file +} + +function isEventMethod(F: string | EventMethod): F is EventMethod { + switch(F as EventMethod) { + case "startup": + case "sleepReached": + case "pageOpenDetail": + case "buttonPress2": + case "renderCurrentPage": + case "button1": + case "button2": + return true; + default: + // Have to talk about this. + log(`Please report to developer: Unknown EventMethod: ${F} `, 'warn'); + return false; + } +} From e823c0f1ec9297f345a1fb1e19894019a53ff7aa Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Fri, 5 Jan 2024 14:28:12 +0100 Subject: [PATCH 47/99] Update NSPanelTs.ts Add Bose Soundtouch Functions --- ioBroker/DEV/NSPanelTs.ts | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index cf71aded..9380e0ac 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -101,6 +101,7 @@ ReleaseNotes: - 04.01.2024 - v4.3.3.32 Add more details to types for: leftScreensaverEntity, indicatorScreensaverEntity, PageThermo, PageMedia - 04.01.2024 - v4.3.3.32 Remove not uses propertys from PageItem - 05.01.2024 - v4.3.3.32 Add Body for BoseSoundtouch-Player + - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -963,7 +964,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.32'; +const scriptVersion: string = 'v4.3.3.33'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -6431,6 +6432,18 @@ function HandleButtonEvent(words: any): void { } GeneratePage(activePage!); break; + case 'bosesoundtouch': + log(adapterInstanceRepeat); + let stateBoseRepeat = getState(id + '.REPEAT').val + if (stateBoseRepeat == 'REPEAT_OFF') { + setIfExists(adapterInstanceRepeat + 'key', 'REPEAT_ALL'); + } else if (stateBoseRepeat == 'REPEAT_ALL') { + setIfExists(adapterInstanceRepeat + 'key', 'REPEAT_ONE'); + } else if (stateBoseRepeat == 'REPEAT_ONE') { + setIfExists(adapterInstanceRepeat + 'key', 'REPEAT_OFF'); + } + GeneratePage(activePage!); + break; case 'sonos': let stateSonosRepeat = getState(id + '.REPEAT').val if (stateSonosRepeat == 0) { @@ -6693,6 +6706,14 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.SHUFFLE', false); } } + if ((tempPage.adapterPlayerInstance).startsWith("bosesoundtouch")) { + log(tempPage.adapterPlayerInstance); + if (getState(tempPage.adapterPlayerInstance + '.SHUFFLE').val == false) { + setIfExists(tempPage.adapterPlayerInstance + 'key', 'SHUFFLE_ON'); + } else { + setIfExists(tempPage.adapterPlayerInstance + 'key', 'SHUFFLE_OFF'); + } + } GeneratePage(activePage!); } break; @@ -6802,9 +6823,12 @@ function HandleButtonEvent(words: any): void { setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'cmdPlayFavorite'].join('.'), words[4]); break; case "bosesoundtouch": + log('bosesoundtouch - playlist ' + pageItemPL.adapterPlayerInstance + ' - ' + words[4]); + log(adapterInstancePL + 'key'); + setState(adapterInstancePL + 'key', 'PRESET_' + (parseInt(words[4]) + 1)); break; default: - log('Hello Mr. Developer u miss in mode-playlist something!', 'warn') + log('Hello Mr. Developer u miss in mode-playlist something!', 'warn'); } pageCounter = 0; GeneratePage(activePage!); @@ -6853,7 +6877,7 @@ function HandleButtonEvent(words: any): void { case "bosesoundtouch": break; default: - log('Hello Mr. Developer u miss in mode-tracklist something!', 'warn') + log('Hello Mr. Developer u miss in mode-tracklist something!', 'warn'); } pageCounter = 0; GeneratePage(activePage!); From dd84fa16e5cbd56fadd8ba6d2cd9c14b79fbdaae Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Fri, 5 Jan 2024 14:30:34 +0100 Subject: [PATCH 48/99] v4.3.3.33 - Update NSPanelTs.ts Add Bose Soundtouch Functions --- ioBroker/DEV/NSPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 9380e0ac..223528d8 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.32 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.33 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 From 11add2bfcca8efd42e2ecedd9dc0e9c3f8688de9 Mon Sep 17 00:00:00 2001 From: ticaki Date: Fri, 5 Jan 2024 17:22:21 +0100 Subject: [PATCH 49/99] Fix screensaver bla of undefined --- ioBroker/DEV/NSPanelTs.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 9a30a7f9..28cacb52 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -8291,7 +8291,7 @@ function HandleScreensaverUpdate(): void { let checkpoint = true; let i = 0; if (config.leftScreensaverEntity && Array.isArray(config.leftScreensaverEntity)) { - for (i = 0; i < 3; i++) { + for (i = 0; i < 3 && i < config.leftScreensaverEntity.length; i++) { const leftScreensaverEntity = config.leftScreensaverEntity[i] if (leftScreensaverEntity === null || leftScreensaverEntity === undefined) { checkpoint = false; @@ -8498,8 +8498,8 @@ function HandleScreensaverUpdate(): void { } else { let checkpoint = true; let i = 0; - for (i = 0; i < maxEntities - 1; i++) { - if (config.bottomScreensaverEntity[i] == null) { + for (i = 0; i < maxEntities - 1 && i < config.bottomScreensaverEntity.length; i++) { + if (config.bottomScreensaverEntity[i] == null || config.bottomScreensaverEntity[i] === undefined) { checkpoint = false; break; } @@ -8572,10 +8572,10 @@ function HandleScreensaverUpdate(): void { if (screensaverAdvanced) { // 5 indicatorScreensaverEntities - for (let i = 0; i < 5; i++) { + for (let i = 0; i < 5 && i < config.indicatorScreensaverEntity.length; i++) { let checkpoint = true; const indicatorScreensaverEntity:ScreenSaverElementWithUndefined = config.indicatorScreensaverEntity[i]; - if (indicatorScreensaverEntity == null) { + if (indicatorScreensaverEntity === null || indicatorScreensaverEntity === undefined) { checkpoint = false; break; } @@ -8622,7 +8622,6 @@ function HandleScreensaverUpdate(): void { SendToPanel({ payload: 'weatherUpdate~' + payloadString }); HandleScreensaverStatusIcons(); - } } catch (err: any) { From f4c7287dfde724fe6e2e08c288da882d73cd7710 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Fri, 5 Jan 2024 17:51:15 +0100 Subject: [PATCH 50/99] v4.3.3.33 - Update NSPanelTs.ts Hotfix max Number of indicatorScreensaverEntity --- ioBroker/DEV/NSPanelTs.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 0c1e53ef..e80df03f 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -102,6 +102,7 @@ ReleaseNotes: - 04.01.2024 - v4.3.3.32 Remove not uses propertys from PageItem - 05.01.2024 - v4.3.3.32 Add Body for BoseSoundtouch-Player - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions + - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined From d0e463de98bd4efefb78089c355ff9e360675057 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Fri, 5 Jan 2024 17:54:07 +0100 Subject: [PATCH 51/99] v4.3.3.33 - Hotfix * Hotfix max Number of indicatorScreensaverEntity * Beta Player Bose Soundtouch --- ioBroker/NsPanelTs.ts | 44 +++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index cf71aded..e80df03f 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.32 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.33 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -101,6 +101,8 @@ ReleaseNotes: - 04.01.2024 - v4.3.3.32 Add more details to types for: leftScreensaverEntity, indicatorScreensaverEntity, PageThermo, PageMedia - 04.01.2024 - v4.3.3.32 Remove not uses propertys from PageItem - 05.01.2024 - v4.3.3.32 Add Body for BoseSoundtouch-Player + - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions + - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -963,7 +965,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.32'; +const scriptVersion: string = 'v4.3.3.33'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -6431,6 +6433,18 @@ function HandleButtonEvent(words: any): void { } GeneratePage(activePage!); break; + case 'bosesoundtouch': + log(adapterInstanceRepeat); + let stateBoseRepeat = getState(id + '.REPEAT').val + if (stateBoseRepeat == 'REPEAT_OFF') { + setIfExists(adapterInstanceRepeat + 'key', 'REPEAT_ALL'); + } else if (stateBoseRepeat == 'REPEAT_ALL') { + setIfExists(adapterInstanceRepeat + 'key', 'REPEAT_ONE'); + } else if (stateBoseRepeat == 'REPEAT_ONE') { + setIfExists(adapterInstanceRepeat + 'key', 'REPEAT_OFF'); + } + GeneratePage(activePage!); + break; case 'sonos': let stateSonosRepeat = getState(id + '.REPEAT').val if (stateSonosRepeat == 0) { @@ -6693,6 +6707,14 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.SHUFFLE', false); } } + if ((tempPage.adapterPlayerInstance).startsWith("bosesoundtouch")) { + log(tempPage.adapterPlayerInstance); + if (getState(tempPage.adapterPlayerInstance + '.SHUFFLE').val == false) { + setIfExists(tempPage.adapterPlayerInstance + 'key', 'SHUFFLE_ON'); + } else { + setIfExists(tempPage.adapterPlayerInstance + 'key', 'SHUFFLE_OFF'); + } + } GeneratePage(activePage!); } break; @@ -6802,9 +6824,12 @@ function HandleButtonEvent(words: any): void { setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'cmdPlayFavorite'].join('.'), words[4]); break; case "bosesoundtouch": + log('bosesoundtouch - playlist ' + pageItemPL.adapterPlayerInstance + ' - ' + words[4]); + log(adapterInstancePL + 'key'); + setState(adapterInstancePL + 'key', 'PRESET_' + (parseInt(words[4]) + 1)); break; default: - log('Hello Mr. Developer u miss in mode-playlist something!', 'warn') + log('Hello Mr. Developer u miss in mode-playlist something!', 'warn'); } pageCounter = 0; GeneratePage(activePage!); @@ -6853,7 +6878,7 @@ function HandleButtonEvent(words: any): void { case "bosesoundtouch": break; default: - log('Hello Mr. Developer u miss in mode-tracklist something!', 'warn') + log('Hello Mr. Developer u miss in mode-tracklist something!', 'warn'); } pageCounter = 0; GeneratePage(activePage!); @@ -8366,7 +8391,7 @@ function HandleScreensaverUpdate(): void { let checkpoint = true; let i = 0; if (config.leftScreensaverEntity && Array.isArray(config.leftScreensaverEntity)) { - for (i = 0; i < 3; i++) { + for (i = 0; i < 3 && i < config.leftScreensaverEntity.length; i++) { const leftScreensaverEntity = config.leftScreensaverEntity[i] if (leftScreensaverEntity === null || leftScreensaverEntity === undefined) { checkpoint = false; @@ -8573,8 +8598,8 @@ function HandleScreensaverUpdate(): void { } else { let checkpoint = true; let i = 0; - for (i = 0; i < maxEntities - 1; i++) { - if (config.bottomScreensaverEntity[i] == null) { + for (i = 0; i < maxEntities - 1 && i < config.bottomScreensaverEntity.length; i++) { + if (config.bottomScreensaverEntity[i] == null || config.bottomScreensaverEntity[i] === undefined) { checkpoint = false; break; } @@ -8647,10 +8672,10 @@ function HandleScreensaverUpdate(): void { if (screensaverAdvanced) { // 5 indicatorScreensaverEntities - for (let i = 0; i < 5; i++) { + for (let i = 0; i < 5 && i < config.indicatorScreensaverEntity.length; i++) { let checkpoint = true; const indicatorScreensaverEntity:ScreenSaverElementWithUndefined = config.indicatorScreensaverEntity[i]; - if (indicatorScreensaverEntity == null) { + if (indicatorScreensaverEntity === null || indicatorScreensaverEntity === undefined) { checkpoint = false; break; } @@ -8697,7 +8722,6 @@ function HandleScreensaverUpdate(): void { SendToPanel({ payload: 'weatherUpdate~' + payloadString }); HandleScreensaverStatusIcons(); - } } catch (err: any) { From 6908744669dd238f4fefced5f205a8f6a378dcf2 Mon Sep 17 00:00:00 2001 From: ticaki Date: Sat, 6 Jan 2024 19:32:26 +0100 Subject: [PATCH 52/99] some types and scriptname for menu --- ioBroker/DEV/NSPanelTs.ts | 95 ++++++++++++++++++++++++++++----------- 1 file changed, 70 insertions(+), 25 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 0c1e53ef..8c664745 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -541,6 +541,7 @@ let NSPanel_Service_SubPage: PageType = /*PageItem*/{ id: AliasPath + 'IoBroker.ScriptVersion', name: findLocaleServMenu('script_version_nspanelts'), offColor: Menu, onColor: Menu }, /*PageItem*/{ id: AliasPath + 'IoBroker.NodeJSVersion', name: findLocaleServMenu('nodejs_version'), offColor: Menu, onColor: Menu }, /*PageItem*/{ id: AliasPath + 'IoBroker.JavaScriptVersion', name: findLocaleServMenu('instance_javascript'), offColor: Menu, onColor: Menu }, + /*PageItem*/{ id: AliasPath + 'IoBroker.ScriptName', name: findLocaleServMenu('scriptname'), offColor: Menu, onColor: Menu }, ] }; @@ -1038,7 +1039,18 @@ async function CheckConfigParameters() { log('Config-Parameter: << config.panelRecvTopic - ' + config.panelRecvTopic + ' >> is not reachable. Please Check Parameters!','error'); } if (existsObject(config.panelSendTopic) == false) { - log('Config-Parameter: << config.panelSendTopic - ' + config.panelSendTopic + ' >> is not reachable. Please Check Parameters!','error'); + const n = config.panelSendTopic.split('.'); + const a = n.shift(); + const i = n.shift(); + + if (a === 'mqtt' && !isNaN(Number(i))) { + sendTo(`${a}.${i}`, 'sendMessage2Client', {topic: n.join('/'), message: 'time~12:00'}); + await sleep(500); + } + if (await existsObjectAsync(config.panelSendTopic) == false) { + log('Config-Parameter: << config.panelSendTopic - ' + config.panelSendTopic + ' >> is not reachable. Please Check Parameters!','error'); + stopScript(scriptName); + } } if (weatherAdapterInstance.substring(0, weatherAdapterInstance.length - 3) == 'daswetter') { if (existsObject(weatherAdapterInstance + 'NextHours.Location_1.Day_1.current.symbol_value') == false) { @@ -1063,6 +1075,7 @@ async function CheckConfigParameters() { if (common.name == 'javascript') { javaScriptVersion = common.version; setIfExists(NSPanel_Path + 'IoBroker.JavaScriptVersion', 'v' + javaScriptVersion); + setIfExists(NSPanel_Path + 'IoBroker.ScriptName', (name as unknown as string).split('.').slice(2).join('.')); let jsVersion = common.version.split('.'); let jsV = 10*parseInt(jsVersion[0]) + parseInt(jsVersion[1]); if (jsV<61) log('JS-Adapter: ' + common.name + ' must be at least v6.1.3. Currently: v' + common.version, 'error'); @@ -1115,6 +1128,10 @@ async function InitIoBrokerInfo() { await createStateAsync(NSPanel_Path + 'IoBroker.JavaScriptVersion', 'v' + javaScriptVersion, { type: 'string' }); setObject(AliasPath + 'IoBroker.JavaScriptVersion', {type: 'channel', common: {role: 'info', name:'Version JavaScript Instanz'}, native: {}}); await createAliasAsync(AliasPath + 'IoBroker.JavaScriptVersion.ACTUAL', NSPanel_Path + 'IoBroker.JavaScriptVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + // ScriptName + await createStateAsync(NSPanel_Path + 'IoBroker.ScriptName', 'v' + javaScriptVersion, { type: 'string' }); + setObject(AliasPath + 'IoBroker.ScriptName', {type: 'channel', common: {role: 'info', name:'Scriptname'}, native: {}}); + await createAliasAsync(AliasPath + 'IoBroker.ScriptName.ACTUAL', NSPanel_Path + 'IoBroker.ScriptName', true, { type: 'string', role: 'state', name: 'ACTUAL' }); } setIfExists(NSPanel_Path + 'IoBroker.ScriptVersion', scriptVersion); } catch (err: any) { @@ -2203,7 +2220,7 @@ let scheduleSendDate = schedule('0 * * * *', () => { // 3:30 a.m. Perform startup and receive current TFT version let scheduleStartup = schedule({ hour: 3, minute: 30 }, async () => { - await setStateAsync(config.panelSendTopic, 'pageType~pageStartup'); + setIfExists(config.panelSendTopic, 'pageType~pageStartup'); }); // Updates currently compare every 12 hours @@ -2216,7 +2233,7 @@ let scheduleCheckUpdates = schedule('{"time":{"start":"00:00","end":"23:59","mod // Check for updates with Start get_locales(); get_locales_servicemenu(); -setState(config.panelSendTopic, 'pageType~pageStartup'); +setIfExists(config.panelSendTopic, 'pageType~pageStartup'); get_tasmota_status0(); get_panel_update_data(); check_updates(); @@ -2325,7 +2342,7 @@ async function check_updates() { if (existsState(NSPanel_Path + 'NSPanel_autoUpdate')) { if (getState(NSPanel_Path + 'NSPanel_autoUpdate').val) { - if (Debug) log('Auto-Updates eingeschaltet - Update Tasmota wird durchgeführt', 'info'); + log('Auto-Updates eingeschaltet - Update Tasmota wird durchgeführt', 'info'); // Perform Tasmota upgrade update_tasmota_firmware(); @@ -2353,7 +2370,7 @@ async function check_updates() { if (existsState(NSPanel_Path + 'NSPanel_autoUpdate')) { if (getState(NSPanel_Path + 'NSPanel_autoUpdate').val) { - if (Debug) log('Auto-updates switched on - Berry driver update is carried out', 'info'); + log('Auto-updates switched on - Berry driver update is carried out', 'info'); // Tasmota Berry-Driver Update durchführen update_berry_driver_version(); @@ -2383,7 +2400,7 @@ async function check_updates() { if (existsState(NSPanel_Path + 'NSPanel_autoUpdate')) { if (getState(NSPanel_Path + 'NSPanel_autoUpdate').val) { - if (Debug) log('Auto-updates switched on - update TFT firmware is carried out', 'info'); + log('Auto-updates switched on - update TFT firmware is carried out', 'info'); // TFT-Firmware Update durchführen update_tft_firmware(); @@ -2950,13 +2967,13 @@ async function SendToPanel(val: Payload | Payload[]) { try { if (Array.isArray(val)) { val.forEach(function (id) { - setStateAsync(config.panelSendTopic, id.payload); + setIfExists(config.panelSendTopic, id.payload); if (Debug) { log('function SendToPanel payload: ' + id.payload, 'info'); } }); } else { - setState(config.panelSendTopic, val.payload); + setIfExists(config.panelSendTopic, val.payload); } } catch (err: any) { @@ -3020,7 +3037,7 @@ function HandleMessage(typ: string, method: EventMethod, page: number | undefine tempId = tempPageItem[0]; } let pageItem: PageItem = findPageItem(tempId); - if (pageItem !== undefined) { + if (pageItem !== undefined && isPopupType(words[2])) { let temp: string | mediaOptional | undefined = tempPageItem[1] if (isMediaOptional(temp)) SendToPanel(GenerateDetailPage(words[2], temp, pageItem, placeId)); else SendToPanel(GenerateDetailPage(words[2], undefined, pageItem, placeId)); @@ -4190,7 +4207,7 @@ function RegisterEntityWatcher(id: string): void { } } -function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: string, placeId: number | undefined): void { +function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: PopupType, placeId: number | undefined): void { try { if (subscriptions.hasOwnProperty(id)) { return; @@ -4712,7 +4729,7 @@ function subscribeMediaSubscriptionsBoseAdd(id: string): void { async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPlayerInstance: adapterPlayerInstanceType) { if (autoCreateAlias) { - if (isSetOptionActive) { + if (isSetOptionActive) { switch (adapterPlayerInstance) { case "alexa2.0.": case "alexa2.1.": @@ -7299,7 +7316,7 @@ function GetNavigationString(pageId: number): string { } return ''; } -function GenerateDetailPage(type: string, optional: mediaOptional | undefined, pageItem: PageItem, placeId: number | undefined): Payload[] { +function GenerateDetailPage(type: PopupType, optional: mediaOptional | undefined, pageItem: PageItem, placeId: number | undefined): Payload[] { if (Debug) log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); try { let out_msgs: Array = []; @@ -7967,7 +7984,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p let actualMode = pageItem.modeList![getState(id + '.MODE').val]; let tempId = placeId != undefined ? placeId : id; - + // {tempid | icon | iconColor | switchVal | actualSpeed | maxSpeed: | findLocale | actualMode | modeList} out_msgs.push({ payload: 'entityUpdateDetail' + '~' // entityUpdateDetail + tempId + '~' @@ -7987,13 +8004,14 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p if (role == 'media') { let actualState: any = ''; let optionalString: string = 'Kein Eintrag'; - let mode: string = ''; + let mode: mediaOptional | '' = ''; if (isPageMediaItem(pageItem)) { const vTempAdapter = (pageItem.adapterPlayerInstance!).split('.'); const vAdapter: PlayerType = vTempAdapter[0] as PlayerType; if (optional == 'seek') { - let actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; - if (actualStateTemp >= 95) { + const actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; + actualState = Math.round(actualStateTemp / 10) * 10 + '%'; + /*if (actualStateTemp >= 95) { actualState = '100%'; } else if (actualStateTemp >= 85) { actualState = '90%'; @@ -8015,7 +8033,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p actualState = '10%'; } else if (actualStateTemp >= 0) { actualState = '0%'; - } + }*/ if (vAdapter == 'sonos') { optionalString = '0%?10%?20%?30%?40%?50%?60%?70%?80%?90%?100%'; } @@ -8214,7 +8232,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p } let tempId = placeId != undefined ? placeId : id; - + // {tempid | color | mediaOptional | actualState | optionalString} out_msgs.push({ payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail + tempId + '?' + optional + '~~' //{entity_id} @@ -8243,7 +8261,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p let valueList = pageItem.modeList != undefined ? tempModeList.join('?') : ''; let tempId = placeId != undefined ? placeId : id; - + // {tempid | color | mediaOptional | actualValue | valueList} out_msgs.push({ payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail2 + tempId + '~~' //{entity_id} @@ -8279,7 +8297,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p //log(valueList); let tempId = placeId != undefined ? placeId : id; - + // {tempid | color | 'insel' | actualValue | valueList} out_msgs.push({ payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail2 + tempId + '~~' //{entity_id} @@ -8672,10 +8690,8 @@ function HandleScreensaverUpdate(): void { if (screensaverAdvanced) { // 5 indicatorScreensaverEntities for (let i = 0; i < 5 && i < config.indicatorScreensaverEntity.length; i++) { - let checkpoint = true; const indicatorScreensaverEntity:ScreenSaverElementWithUndefined = config.indicatorScreensaverEntity[i]; if (indicatorScreensaverEntity === null || indicatorScreensaverEntity === undefined) { - checkpoint = false; break; } RegisterScreensaverEntityWatcher(indicatorScreensaverEntity.ScreensaverEntity) @@ -9562,8 +9578,9 @@ function rgb_to_cie(red: number, green: number, blue: number): string return cie; } + /** - * + * * @param vDeviceString * @returns */ @@ -9576,6 +9593,9 @@ function spotifyGetDeviceID(vDeviceString: string): string { let strDevID = arrayDeviceListIds[indexPos]; return strDevID; } +type PopupType = 'popupFan' | 'popupInSel' | 'popupLight' | 'popupLightNew' | 'popupNotify' | 'popupShutter' | 'popupThermo' | 'popupTimer' + + type EventMethod = 'startup' | 'sleepReached' | 'pageOpenDetail' | 'buttonPress2' | 'renderCurrentPage' | 'button1' | 'button2' @@ -9624,7 +9644,7 @@ type PageBaseType = { homeIconColor?: RGB }; -type PagetypeType = 'cardChart' | 'cardLChart' | 'cardEntities' |'cardGrid'|'cardGrid2'|'cardThermo'|'cardMedia'|'cardUnlock'|'cardQR'|'cardAlarm'|'cardPower' +type PagetypeType = 'cardChart' | 'cardLChart' | 'cardEntities' |'cardGrid'|'cardGrid2'|'cardThermo'|'cardMedia'|'cardUnlock'|'cardQR'|'cardAlarm'|'cardPower' //| 'cardBurnRec' type PageType = PageChart | PageEntities | PageGrid | PageGrid2 | PageThermo | PageMedia | PageUnlock | PageQR | PageAlarm | PagePower @@ -9714,6 +9734,14 @@ type PageThermoItem = { popUpThermoName?: string[], setThermoAlias?: string[], setThermoDestTemp2?: string, +} & PageBaseItem | +{ + popupThermoMode1?: string[], + popupThermoMode2?: string[], + popupThermoMode3?: string[], + popUpThermoName?: string[], + setThermoAlias?: string[], + setThermoDestTemp2?: string, } & PageBaseItem type PageBaseItem = { @@ -9795,7 +9823,7 @@ type Config = { button2: ConfigButtonFunction } type leftScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; -type indicatorScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; +type indicatorScreensaverEntityType = [ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?] | []; type ScreenSaverElementWithUndefined = null | undefined | ScreenSaverElement type ScreenSaverElement = { ScreensaverEntity: string, @@ -9891,3 +9919,20 @@ function isEventMethod(F: string | EventMethod): F is EventMethod { return false; } } + +function isPopupType(F: PopupType | string): F is PopupType { + switch(F as PopupType) { + case "popupFan": + case "popupInSel": + case "popupLight": + case "popupLightNew": + case "popupNotify": + case "popupShutter": + case "popupThermo": + case "popupTimer": + return true; + default: + log(`Please report to developer: Unknown PopupType: ${F} `, 'warn'); + return false; + } +} From 3904ca23430ab71ee3b1d2205bbab49085addffe Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Sat, 6 Jan 2024 23:44:10 +0100 Subject: [PATCH 53/99] Fix BoseSoundtouch Proto --- ioBroker/DEV/NSPanelTs.ts | 80 ++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index c058f35f..51f1f2c3 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -5220,7 +5220,7 @@ function GenerateMediaPage(page: PageMedia): Payload[] { let shuffle_icon = Icons.GetIcon('shuffle-variant'); //shuffle let onoffbutton = 1374; - if (shuffle == 'off' || shuffle == false || shuffle == 0) { + if (shuffle == 'off' || shuffle == false || shuffle == 0 || shuffle == 'false') { shuffle_icon = Icons.GetIcon('shuffle-disabled'); //shuffle } if (v2Adapter == 'volumio') { shuffle_icon = Icons.GetIcon('refresh'); } //Volumio: refresh playlist @@ -6451,7 +6451,7 @@ function HandleButtonEvent(words: any): void { GeneratePage(activePage!); break; case 'bosesoundtouch': - log(adapterInstanceRepeat); + if (Debug) log(adapterInstanceRepeat); let stateBoseRepeat = getState(id + '.REPEAT').val if (stateBoseRepeat == 'REPEAT_OFF') { setIfExists(adapterInstanceRepeat + 'key', 'REPEAT_ALL'); @@ -6661,10 +6661,18 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.SET', parseInt(temps[0]) / 10); } break; - case 'media-back': - setIfExists(id + '.PREV', true); - GeneratePage(activePage!); + case 'media-back': { + const tempPage = findPageItem(id); + if (isPageMediaItem(tempPage)) { + if (tempPage.adapterPlayerInstance.startsWith('bosesoundtouch')) { + setIfExists(tempPage.adapterPlayerInstance + 'key', 'PREV_TRACK'); + } else { + setIfExists(id + '.PREV', true); + } + GeneratePage(activePage!); + } break; + } case 'media-pause': let pageItemTemp = findPageItem(id); if (isPageMediaItem(pageItemTemp)) { @@ -6680,6 +6688,8 @@ function HandleButtonEvent(words: any): void { } else if (stateVal == null) { setState(adapterPlayerInstanceStateSeceltor, 1); } + } else if (pageItemTemp.adapterPlayerInstance.startsWith('bosesoundtouch')) { + setIfExists(pageItemTemp.adapterPlayerInstance + 'key', 'PLAY_PAUSE'); } else { if (Debug) log('HandleButtonEvent media-pause -> .STATE Value: ' + getState(id + '.STATE').val, 'info'); if (getState(id + '.STATE').val === true) { @@ -6691,11 +6701,19 @@ function HandleButtonEvent(words: any): void { GeneratePage(activePage!); } break; - case 'media-next': - setIfExists(id + '.NEXT', true); - GeneratePage(activePage!); + case 'media-next': { + const tempPage = findPageItem(id); + if (isPageMediaItem(tempPage)) { + if (tempPage.adapterPlayerInstance.startsWith('bosesoundtouch')) { + setIfExists(tempPage.adapterPlayerInstance + 'key', 'NEXT_TRACK'); + } else { + setIfExists(id + '.NEXT', true); + } + GeneratePage(activePage!); + } break; - case 'media-shuffle': + } + case 'media-shuffle': { const tempPage = findPageItem(id); if (isPageMediaItem(tempPage)) { if (tempPage.adapterPlayerInstance.startsWith("volumio")) { @@ -6725,8 +6743,8 @@ function HandleButtonEvent(words: any): void { } } if ((tempPage.adapterPlayerInstance).startsWith("bosesoundtouch")) { - log(tempPage.adapterPlayerInstance); - if (getState(tempPage.adapterPlayerInstance + '.SHUFFLE').val == false) { + if (Debug) log(tempPage.adapterPlayerInstance + 'nowPlaying.shuffle'); + if (getState(tempPage.adapterPlayerInstance + 'nowPlaying.shuffle').val == 'false') { setIfExists(tempPage.adapterPlayerInstance + 'key', 'SHUFFLE_ON'); } else { setIfExists(tempPage.adapterPlayerInstance + 'key', 'SHUFFLE_OFF'); @@ -6735,6 +6753,7 @@ function HandleButtonEvent(words: any): void { GeneratePage(activePage!); } break; + } case 'volumeSlider': pageCounter = -1; (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); @@ -6841,8 +6860,8 @@ function HandleButtonEvent(words: any): void { setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'cmdPlayFavorite'].join('.'), words[4]); break; case "bosesoundtouch": - log('bosesoundtouch - playlist ' + pageItemPL.adapterPlayerInstance + ' - ' + words[4]); - log(adapterInstancePL + 'key'); + if (Debug) log('bosesoundtouch - playlist ' + pageItemPL.adapterPlayerInstance + ' - ' + words[4]); + if (Debug) log(adapterInstancePL + 'key'); setState(adapterInstancePL + 'key', 'PRESET_' + (parseInt(words[4]) + 1)); break; default: @@ -8012,29 +8031,6 @@ function GenerateDetailPage(type: PopupType, optional: mediaOptional | undefined if (optional == 'seek') { const actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; actualState = Math.round(actualStateTemp / 10) * 10 + '%'; - /*if (actualStateTemp >= 95) { - actualState = '100%'; - } else if (actualStateTemp >= 85) { - actualState = '90%'; - } else if (actualStateTemp >= 75) { - actualState = '80%'; - } else if (actualStateTemp >= 65) { - actualState = '70%'; - } else if (actualStateTemp >= 55) { - actualState = '60%'; - } else if (actualStateTemp >= 45) { - actualState = '50%'; - } else if (actualStateTemp >= 35) { - actualState = '40%'; - } else if (actualStateTemp >= 25) { - actualState = '30%'; - } else if (actualStateTemp >= 15) { - actualState = '20%'; - } else if (actualStateTemp >= 5) { - actualState = '10%'; - } else if (actualStateTemp >= 0) { - actualState = '0%'; - }*/ if (vAdapter == 'sonos') { optionalString = '0%?10%?20%?30%?40%?50%?60%?70%?80%?90%?100%'; } @@ -8104,11 +8100,17 @@ function GenerateDetailPage(type: PopupType, optional: mediaOptional | undefined } else if (vAdapter == 'bosesoundtouch') { if (existsObject(pageItem.adapterPlayerInstance + 'deviceInfo.name')) { actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'deviceInfo.name').val); - log(actualState); } let tempPlayList: string[] = []; - for (let i = 0; i < pageItem.playList!.length; i++) { - tempPlayList[i] = formatInSelText(pageItem.playList![i]); + let vPreset: string = 'No Entry'; + for (let i = 1; i < 7; i++) { + if (getState(pageItem.adapterPlayerInstance + 'presets.'+ i +'.source').val !== null) { + vPreset = getState(pageItem.adapterPlayerInstance + 'presets.'+ i + '.source').val; + } else { + vPreset = 'Preset ' + i.toFixed; + } + tempPlayList[i - 1] = formatInSelText(vPreset.replace('_',' ')); + if (Debug) log(formatInSelText(vPreset.replace('_',' '))) } optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' } else if (vAdapter == 'sonos') { From 1fd5784a5454674ba3f1f403efd819314ad02794 Mon Sep 17 00:00:00 2001 From: ticaki Date: Sun, 7 Jan 2024 00:05:50 +0100 Subject: [PATCH 54/99] 1 Line warning for EHOSTUNREACH --- ioBroker/DEV/NSPanelTs.ts | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index c058f35f..98c6a8c5 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1557,7 +1557,9 @@ on({id: AliasPath + 'Config.rebootNSPanel.SET', change: "any"}, async function ( } }) .catch(function (error) { - log(error, 'warn'); + if (error.code === 'EHOSTUNREACH') { + log(`Can't connect to display!`, 'warn') + } else log(error, 'warn'); }) .finally(function () { if (Debug) { @@ -1727,7 +1729,9 @@ on({id: [String(NSPanel_Path) + 'Relay.1',String(NSPanel_Path) + 'Relay.2'], cha } }) .catch(function (error) { - log(error, 'warn'); + if (error.code === 'EHOSTUNREACH') { + log(`Can't connect to display!`, 'warn') + } else log(error, 'warn'); }) } catch (err: any) { @@ -2124,7 +2128,9 @@ async function InitPopupNotify() { } }) .catch(function (error) { - log(error, 'warn'); + if (error.code === 'EHOSTUNREACH') { + log(`Can't connect to display!`, 'warn') + } else log(error, 'warn'); }); } else { if (Debug){ @@ -2591,7 +2597,9 @@ function get_current_berry_driver_version() { } }) .catch(function (error) { - log(error, 'warn'); + if (error.code === 'EHOSTUNREACH') { + log(`Can't connect to display!`, 'warn') + } else log(error, 'warn'); }); } catch (err: any) { @@ -2681,7 +2689,9 @@ function get_tasmota_status0() { } }) .catch(function (error) { - log(error, 'warn'); + if (error.code === 'EHOSTUNREACH') { + log(`Can't connect to display!`, 'warn') + } else log(error, 'error'); }); } catch (err: any) { From 71f3b75ab2bae29b73b8867941c50fff512383cc Mon Sep 17 00:00:00 2001 From: ticaki Date: Sun, 7 Jan 2024 13:33:30 +0100 Subject: [PATCH 55/99] add namespace --- ioBroker/DEV/NSPanelTs.ts | 743 +++++++++++++++++++------------------- 1 file changed, 375 insertions(+), 368 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index ab4142a1..05f618e4 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -514,7 +514,7 @@ let NSPanel_Service_SubPage: PageType = ] }; - let NSPanel_Hardware: PageEntities = + let NSPanel_Hardware: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('hardware2'), @@ -1847,7 +1847,7 @@ on({id: [NSPanel_Path + 'PageNavi'], change: "any"}, async function (obj) { }); //----------------------Begin Dimmode -function ScreensaverDimmode(timeDimMode: DimMode) { +function ScreensaverDimmode(timeDimMode:NSPanel.DimMode) { try { let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val let dimmode = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val @@ -1861,12 +1861,12 @@ function ScreensaverDimmode(timeDimMode: DimMode) { if (compareTime(timeDimMode.timeNight != undefined ? timeDimMode.timeNight : '22:00', timeDimMode.timeDay != undefined ? timeDimMode.timeDay : '07:00', 'not between', undefined)) { SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessDay + '~' + active + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); if (Debug) { - log('function ScreensaverDimmode -> Day Payload: ' + 'dimmode~' + timeDimMode.brightnessDay + '~' + active, 'info'); + log('function ScreensaverDimmode -> Day NSPanel.Payload: ' + 'dimmode~' + timeDimMode.brightnessDay + '~' + active, 'info'); } } else { SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessNight + '~' + active + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); if (Debug) { - log('function ScreensaverDimmode -> Night Payload: ' + 'dimmode~' + timeDimMode.brightnessNight + '~' + active, 'info'); + log('function ScreensaverDimmode -> Night NSPanel.Payload: ' + 'dimmode~' + timeDimMode.brightnessNight + '~' + active, 'info'); } } } else { @@ -1941,7 +1941,7 @@ async function InitDimmode() { } const vTimeDay = getState(NSPanel_Path + 'NSPanel_Dimmode_hourDay').val; const vTimeNight = getState(NSPanel_Path + 'NSPanel_Dimmode_hourNight').val; - const timeDimMode: DimMode = { + const timeDimMode: NSPanel.DimMode = { dimmodeOn: true, brightnessDay: getState(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay').val, brightnessNight: getState(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight').val, @@ -2974,7 +2974,7 @@ on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESU //------------------End Update Functions -async function SendToPanel(val: Payload | Payload[]) { +async function SendToPanel(val: NSPanel.Payload | NSPanel.Payload[]) { try { if (Array.isArray(val)) { val.forEach(function (id) { @@ -3007,10 +3007,10 @@ on({ id: NSPanel_Alarm_Path + 'Alarm.AlarmState', change: 'ne' }, async (obj) => } }); -function HandleMessage(typ: string, method: EventMethod, page: number | undefined, words: Array | undefined): void { +function HandleMessage(typ: string, method: NSPanel.EventMethod, page: number | undefined, words: Array | undefined): void { try { if (typ == 'event') { - switch (method as EventMethod) { + switch (method as NSPanel.EventMethod) { case 'startup': screensaverEnabled = false; UnsubscribeWatcher(); @@ -3049,7 +3049,7 @@ function HandleMessage(typ: string, method: EventMethod, page: number | undefine } let pageItem: PageItem = findPageItem(tempId); if (pageItem !== undefined && isPopupType(words[2])) { - let temp: string | mediaOptional | undefined = tempPageItem[1] + let temp: string | NSPanel.mediaOptional | undefined = tempPageItem[1] if (isMediaOptional(temp)) SendToPanel(GenerateDetailPage(words[2], temp, pageItem, placeId)); else SendToPanel(GenerateDetailPage(words[2], undefined, pageItem, placeId)); } @@ -3156,9 +3156,9 @@ function GeneratePage(page: PageType): void { } } -function HandleHardwareButton(method: EventMethod): void { +function HandleHardwareButton(method: NSPanel.EventMethod): void { try { - let buttonConfig: ConfigButtonFunction = config[method]; + let buttonConfig: NSPanel.ConfigButtonFunction = config[method]; if(buttonConfig.mode === null) { return; } @@ -3212,7 +3212,7 @@ function SendDate(): void { const options: any = { weekday: dpWeekday, year: 'numeric', month: dpMonth, day: 'numeric' }; const _SendDate = dpCustomFormat != '' ? dayjs().format(dpCustomFormat) : date.toLocaleDateString(getState(NSPanel_Path + 'Config.locale').val, options); - SendToPanel({ payload: 'date~' + _SendDate }); + SendToPanel({ payload: 'date~' + _SendDate }); } } catch (err: any) { if (err.message = 'Cannot convert undefined or null to object') { @@ -3229,15 +3229,15 @@ function SendTime(): void { const hr = (d.getHours() < 10 ? '0' : '') + d.getHours(); const min = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); - SendToPanel({ payload: 'time~' + hr + ':' + min }); + SendToPanel({ payload: 'time~' + hr + ':' + min }); } catch (err: any) { log('error at function SendTime: ' + err.message, 'warn'); } } -function GenerateEntitiesPage(page: PageEntities): Payload[] { +function GenerateEntitiesPage(page: NSPanel.PageEntities): NSPanel.Payload[] { try { - let out_msgs: Array; + let out_msgs: Array; out_msgs = [{ payload: 'pageType~cardEntities' }] out_msgs.push({ payload: GeneratePageElements(page) }); return out_msgs @@ -3247,9 +3247,9 @@ function GenerateEntitiesPage(page: PageEntities): Payload[] { } } -function GenerateGridPage(page: PageGrid): Payload[] { +function GenerateGridPage(page: NSPanel.PageGrid): NSPanel.Payload[] { try { - let out_msgs: Array = [{ payload: 'pageType~cardGrid' }]; + let out_msgs: Array = [{ payload: 'pageType~cardGrid' }]; out_msgs.push({ payload: GeneratePageElements(page) }); return out_msgs; } catch (err: any) { @@ -3258,9 +3258,9 @@ function GenerateGridPage(page: PageGrid): Payload[] { } } -function GenerateGridPage2(page: PageGrid2): Payload[] { +function GenerateGridPage2(page: NSPanel.PageGrid2): NSPanel.Payload[] { try { - let out_msgs: Array = [{ payload: 'pageType~cardGrid2' }]; + let out_msgs: Array = [{ payload: 'pageType~cardGrid2' }]; out_msgs.push({ payload: GeneratePageElements(page) }); return out_msgs; } catch (err: any) { @@ -3335,7 +3335,7 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let name: string; let buttonText: string = 'PRESS'; - let type: SerialType; + let type: NSPanel.SerialType; // ioBroker if (pageItem.id && existsObject(pageItem.id) || pageItem.navigate === true) { @@ -3408,8 +3408,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } else if (pageItem.id != null && pageItem.targetPage != undefined) { type = 'button'; - const role = o.common.role as roles; - switch (role as roles) { + const role = o.common.role as NSPanel.roles; + switch (role) { case 'socket': case 'light': iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); @@ -3593,8 +3593,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = return '~' + type + '~' + 'navigate.' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; } } - const role = o.common.role as roles - switch (role as roles) { + const role = o.common.role as NSPanel.roles + switch (role) { case 'socket': case 'light': type = 'light'; @@ -4218,7 +4218,7 @@ function RegisterEntityWatcher(id: string): void { } } -function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: PopupType, placeId: number | undefined): void { +function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: NSPanel.PopupType, placeId: number | undefined): void { try { if (subscriptions.hasOwnProperty(id)) { return; @@ -4255,11 +4255,11 @@ function GetUnitOfMeasurement(id: string): string { } } -function GenerateThermoPage(page: PageThermo): Payload[] { +function GenerateThermoPage(page: NSPanel.PageThermo): NSPanel.Payload[] { try { UnsubscribeWatcher(); let id = page.items[0].id - let out_msgs: Array = []; + let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~cardThermo' }); // ioBroker @@ -4304,7 +4304,7 @@ function GenerateThermoPage(page: PageThermo): Payload[] { if ((i_list.length - 3) != 0) { let i = 0; - switch (o.common.role as roles) { + switch (o.common.role as NSPanel.roles) { case 'thermostat': { if (existsState(id + '.AUTOMATIC') && getState(id + '.AUTOMATIC').val != null) { @@ -4738,7 +4738,7 @@ function subscribeMediaSubscriptionsBoseAdd(id: string): void { }); } -async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPlayerInstance: adapterPlayerInstanceType) { +async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPlayerInstance: NSPanel.adapterPlayerInstanceType) { if (autoCreateAlias) { if (isSetOptionActive) { switch (adapterPlayerInstance) { @@ -4988,19 +4988,19 @@ async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPla } } -function GenerateMediaPage(page: PageMedia): Payload[] { +function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { try { unsubscribeMediaSubscriptions(); if (!page.items[0].id) throw new Error ('Missing page id for cardMedia!'); let id = page.items[0].id; - let out_msgs: Array = []; + let out_msgs: Array = []; if (!page.items[0].adapterPlayerInstance!) throw new Error('page.items[0].adapterPlayerInstance is undefined!') let vInstance = page.items[0].adapterPlayerInstance!; let v1Adapter = vInstance.split('.'); - let v2Adapter:PlayerType = v1Adapter[0] as PlayerType; + let v2Adapter:NSPanel.PlayerType = v1Adapter[0] as NSPanel.PlayerType; // Some magic to change the ID of the alias, since speakers are not a property but separate objects if(v2Adapter == 'squeezeboxrpc') { @@ -5604,14 +5604,14 @@ async function createAutoAlarmAlias (id: string, nsPath: string){ } } -function GenerateAlarmPage(page: PageAlarm): Payload[] { +function GenerateAlarmPage(page: NSPanel.PageAlarm): NSPanel.Payload[] { try { activePage = page; let id = page.items[0].id let name = page.heading; - let out_msgs: Array = []; + let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~cardAlarm' }); let nsPath = NSPanel_Alarm_Path + 'Alarm'; @@ -5631,7 +5631,7 @@ function GenerateAlarmPage(page: PageAlarm): Payload[] { } //let entityType = getState(nsPath + 'AlarmType').val; let arm1: string, arm2: string, arm3: string, arm4: string; - let arm1ActionName: ButtonActionType | '', arm2ActionName: ButtonActionType | '', arm3ActionName: ButtonActionType | '', arm4ActionName: ButtonActionType | ''; + let arm1ActionName: NSPanel.ButtonActionType | '', arm2ActionName: NSPanel.ButtonActionType | '', arm3ActionName: NSPanel.ButtonActionType | '', arm4ActionName: NSPanel.ButtonActionType | ''; let icon = '0'; let iconcolor = 63488; let numpadStatus = 'disable'; @@ -5763,13 +5763,13 @@ async function createAutoUnlockAlias(id: string, dpPath: string) { } -function GenerateUnlockPage(page: PageUnlock): Payload[] { +function GenerateUnlockPage(page: NSPanel.PageUnlock): NSPanel.Payload[] { try { activePage = page; let id = page.items[0].id let name = page.heading; - let out_msgs: Array = []; + let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~cardAlarm' }); let dpPath : string = '' @@ -5785,7 +5785,7 @@ function GenerateUnlockPage(page: PageUnlock): Payload[] { } let unlock1 = findLocale('lock', 'UNLOCK'); //unlock1*~* - let unlock1ActionName: ButtonActionType | '' = 'U1'; //unlock1ActionName*~* + let unlock1ActionName: NSPanel.ButtonActionType | '' = 'U1'; //unlock1ActionName*~* let iconcolor = rgb_dec565({ red: 223, green: 76, blue: 30 }); //icon*~* let icon = Icons.GetIcon('lock-remove'); //iconcolor*~* @@ -5845,12 +5845,12 @@ async function createAutoQRAlias(id:string, dpPath:string) { } } -function GenerateQRPage(page: PageQR): Payload[] { +function GenerateQRPage(page: NSPanel.PageQR): NSPanel.Payload[] { try { activePage = page; if (!page.items[0].id) throw new Error ('Missing pageItem.id for cardQRPage!'); let id = page.items[0].id; - let out_msgs: Array = []; + let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~cardQR' }); let dpPath : string = '' @@ -5963,7 +5963,7 @@ function subscribePowerSubscriptions(id: string): void { }); } -function GeneratePowerPage(page: PagePower): Payload[] { +function GeneratePowerPage(page: NSPanel.PagePower): NSPanel.Payload[] { try { if (!page.items[0].id) throw new Error ('Missing pageItem.id for PowerPage!'); @@ -5991,7 +5991,7 @@ function GeneratePowerPage(page: PagePower): Payload[] { obj = JSON.parse((getState(page.items[0].id + '.ACTUAL').val)); } - let out_msgs: Array = []; + let out_msgs: Array = []; // Leave the display on if the alwaysOnDisplay parameter is specified (true) if (page.type == 'cardPower' && pageCounter == 0 && page.items[0].alwaysOnDisplay != undefined) { @@ -6085,12 +6085,12 @@ function GeneratePowerPage(page: PagePower): Payload[] { } } -function GenerateChartPage(page: PageChart): Payload[] { +function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { try { activePage = page; let id = page.items[0].id; - let out_msgs: Array = []; + let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~' + page.type }); let heading = page.heading !== undefined ? page.heading : "Chart..."; @@ -6185,7 +6185,7 @@ function HandleButtonEvent(words: any): void { let tempid = words[2].split('?'); let id = tempid[0]; - let buttonAction: ButtonActionType = words[3] as ButtonActionType; + let buttonAction: NSPanel.ButtonActionType = words[3] as NSPanel.ButtonActionType; let pageItemID: string = ''; if (!isNaN(id)) { @@ -6364,8 +6364,8 @@ function HandleButtonEvent(words: any): void { if (Debug) { log('HandleButtonEvent -> OnOff: ' + words[4] + ' - ' + id + ' - Role - ' + o.common.role, 'info') } - const role = o.common.role as roles; - switch (role as roles) { + const role = o.common.role as NSPanel.roles; + switch (role) { case 'level.mode.fan': case 'socket': case 'light': @@ -6401,7 +6401,7 @@ function HandleButtonEvent(words: any): void { if (words[4] == '1') action = true; let o = getObject(id); - switch (o.common.role as roles) { + switch (o.common.role as NSPanel.roles) { case 'lock': case 'button': toggleState(id + '.SET') ? true : toggleState(id + '.ON_SET'); @@ -6446,7 +6446,7 @@ function HandleButtonEvent(words: any): void { if (isPageMediaItem(pageItemRepeat)) { let adapterInstanceRepeat = pageItemRepeat.adapterPlayerInstance; let adapterRepeat = adapterInstanceRepeat.split('.'); - const deviceAdapterRP: PlayerType = adapterRepeat[0] as PlayerType; + const deviceAdapterRP: NSPanel.PlayerType = adapterRepeat[0] as NSPanel.PlayerType; switch (deviceAdapterRP) { case 'spotify-premium': @@ -6587,8 +6587,8 @@ function HandleButtonEvent(words: any): void { if (existsObject(id)) { let o = getObject(id); let pageItem = findPageItem(id); - const role = o.common.role as roles; - switch (role as roles) { + const role = o.common.role as NSPanel.roles; + switch (role) { case 'dimmer': if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { let sliderPos = Math.trunc(scale(parseInt(words[4]), 0, 100, pageItem.maxValueBrightness, pageItem.minValueBrightness)); @@ -6634,7 +6634,7 @@ function HandleButtonEvent(words: any): void { log('HandleButtonEvent colorWeel -> getHue-Werte: ' + getHue(rgb.red, rgb.green, rgb.blue), 'info'); } let o = getObject(id); - switch (o.common.role as roles) { + switch (o.common.role as NSPanel.roles) { case 'hue': setIfExists(id + '.HUE', getHue(rgb.red, rgb.green, rgb.blue)); break; @@ -6780,7 +6780,7 @@ function HandleButtonEvent(words: any): void { if (isPageMediaItem(pageItem)) { let adapterInstance = pageItem.adapterPlayerInstance!; let adapter = adapterInstance!.split('.'); - const deviceAdapter: PlayerType = adapter[0] as PlayerType; + const deviceAdapter: NSPanel.PlayerType = adapter[0] as NSPanel.PlayerType; switch (deviceAdapter) { case 'spotify-premium': @@ -6826,7 +6826,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemPL)) break; let adapterInstancePL = pageItemPL.adapterPlayerInstance!; let adapterPL = adapterInstancePL.split('.'); - const deviceAdapterPL: PlayerType = adapterPL[0] as PlayerType; + const deviceAdapterPL: NSPanel.PlayerType = adapterPL[0] as NSPanel.PlayerType; switch (deviceAdapterPL) { case 'spotify-premium': @@ -6889,7 +6889,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemTL)) break; let adapterInstanceTL = pageItemTL.adapterPlayerInstance!; let adapterTL = adapterInstanceTL.split('.'); - const deviceAdapterTL: PlayerType = adapterTL[0] as PlayerType; + const deviceAdapterTL: NSPanel.PlayerType = adapterTL[0] as NSPanel.PlayerType; switch (deviceAdapterTL) { case 'spotify-premium': @@ -6938,7 +6938,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemRP)) break; let adapterInstanceRP = pageItemRP.adapterPlayerInstance!; let adapterRP = adapterInstanceRP.split('.'); - let deviceAdapterRP: PlayerType = adapterRP[0] as PlayerType; + let deviceAdapterRP: NSPanel.PlayerType = adapterRP[0] as NSPanel.PlayerType; if (Debug) log(pageItemRP.repeatList![words[4]], 'warn'); switch (deviceAdapterRP) { @@ -6969,7 +6969,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemSeek)) break; let adapterInstanceSK = pageItemSeek.adapterPlayerInstance!; let adapterSK = adapterInstanceSK.split('.'); - let deviceAdapterSK: PlayerType = adapterSK[0] as PlayerType; + let deviceAdapterSK: NSPanel.PlayerType = adapterSK[0] as NSPanel.PlayerType; switch (deviceAdapterSK) { case 'spotify-premium': break; @@ -6990,7 +6990,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemCrossfade)) break; let adapterInstanceCF = pageItemCrossfade.adapterPlayerInstance!; let adapterCF = adapterInstanceCF.split('.'); - let deviceAdapterCF: PlayerType = adapterCF[0] as PlayerType; + let deviceAdapterCF: NSPanel.PlayerType = adapterCF[0] as NSPanel.PlayerType; switch (deviceAdapterCF) { case 'spotify-premium': break; @@ -7139,7 +7139,7 @@ function HandleButtonEvent(words: any): void { break; case 'number-set': let nobj = getObject(id); - switch (nobj.common.role as roles) { + switch (nobj.common.role as NSPanel.roles) { case 'level.mode.fan': (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); timeoutSlider = setTimeout(async function () { @@ -7346,10 +7346,10 @@ function GetNavigationString(pageId: number): string { } return ''; } -function GenerateDetailPage(type: PopupType, optional: mediaOptional | undefined, pageItem: PageItem, placeId: number | undefined): Payload[] { +function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOptional | undefined, pageItem: PageItem, placeId: number | undefined): NSPanel.Payload[] { if (Debug) log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); try { - let out_msgs: Array = []; + let out_msgs: Array = []; let id = pageItem.id; if (id && existsObject(id)) { @@ -7358,7 +7358,7 @@ function GenerateDetailPage(type: PopupType, optional: mediaOptional | undefined let val: (boolean | number) = 0; let icon = Icons.GetIcon('lightbulb'); let iconColor = rgb_dec565(config.defaultColor); - const role = o.common.role as roles; + const role = o.common.role as NSPanel.roles; if (type == 'popupLight') { @@ -8034,10 +8034,10 @@ function GenerateDetailPage(type: PopupType, optional: mediaOptional | undefined if (role == 'media') { let actualState: any = ''; let optionalString: string = 'Kein Eintrag'; - let mode: mediaOptional | '' = ''; + let mode: NSPanel.mediaOptional | '' = ''; if (isPageMediaItem(pageItem)) { const vTempAdapter = (pageItem.adapterPlayerInstance!).split('.'); - const vAdapter: PlayerType = vTempAdapter[0] as PlayerType; + const vAdapter: NSPanel.PlayerType = vTempAdapter[0] as NSPanel.PlayerType; if (optional == 'seek') { const actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; actualState = Math.round(actualStateTemp / 10) * 10 + '%'; @@ -8245,7 +8245,7 @@ function GenerateDetailPage(type: PopupType, optional: mediaOptional | undefined } let tempId = placeId != undefined ? placeId : id; - // {tempid | color | mediaOptional | actualState | optionalString} + // {tempid | color | NSPanel.mediaOptional | actualState | optionalString} out_msgs.push({ payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail + tempId + '?' + optional + '~~' //{entity_id} @@ -8274,7 +8274,7 @@ function GenerateDetailPage(type: PopupType, optional: mediaOptional | undefined let valueList = pageItem.modeList != undefined ? tempModeList.join('?') : ''; let tempId = placeId != undefined ? placeId : id; - // {tempid | color | mediaOptional | actualValue | valueList} + // {tempid | color | NSPanel.mediaOptional | actualValue | valueList} out_msgs.push({ payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail2 + tempId + '~~' //{entity_id} @@ -8703,7 +8703,7 @@ function HandleScreensaverUpdate(): void { if (screensaverAdvanced) { // 5 indicatorScreensaverEntities for (let i = 0; i < 5 && i < config.indicatorScreensaverEntity.length; i++) { - const indicatorScreensaverEntity:ScreenSaverElementWithUndefined = config.indicatorScreensaverEntity[i]; + const indicatorScreensaverEntity:NSPanel.ScreenSaverElementWithUndefined = config.indicatorScreensaverEntity[i]; if (indicatorScreensaverEntity === null || indicatorScreensaverEntity === undefined) { break; } @@ -8747,7 +8747,7 @@ function HandleScreensaverUpdate(): void { } if (Debug) log('HandleScreensaverUpdate payload: weatherUpdate~' + payloadString, 'info'); - SendToPanel({ payload: 'weatherUpdate~' + payloadString }); + SendToPanel({ payload: 'weatherUpdate~' + payloadString }); HandleScreensaverStatusIcons(); } @@ -8944,7 +8944,7 @@ function HandleScreensaverStatusIcons() : void { payloadString += '~'; } - SendToPanel({ payload: 'statusUpdate~' + payloadString }); + SendToPanel({ payload: 'statusUpdate~' + payloadString }); } catch (err: any) { log('error at function HandleScreensaverStatusIcons: ' + err.message, 'warn'); @@ -9035,17 +9035,17 @@ function HandleScreensaverColors(): void { rgb_dec565(sctMainTextAlt) + '~' + //tMainTextAlt rgb_dec565(sctTimeAdd); //tTimeAdd - SendToPanel({ payload: payloadString }); + SendToPanel({ payload: payloadString }); } catch (err: any) { log('error at function HandleScreensaverColors: '+ err.message, 'warn'); } } -function GetScreenSaverEntityColor(configElement: ScreenSaverElement | null): number { +function GetScreenSaverEntityColor(configElement: NSPanel.ScreenSaverElement | null): number { try { let colorReturn: number; if (configElement && configElement.ScreensaverEntityIconColor != undefined) { - const ScreensaverEntityIconColor = configElement.ScreensaverEntityIconColor as IconScaleElement; + const ScreensaverEntityIconColor = configElement.ScreensaverEntityIconColor as NSPanel.IconScaleElement; if (typeof getState(configElement.ScreensaverEntity).val == 'boolean') { let iconvalbest = (typeof ScreensaverEntityIconColor == 'object' && ScreensaverEntityIconColor.val_best !== undefined ) ? ScreensaverEntityIconColor.val_best : false ; colorReturn = (getState(configElement.ScreensaverEntity).val == iconvalbest) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); @@ -9606,302 +9606,24 @@ function spotifyGetDeviceID(vDeviceString: string): string { let strDevID = arrayDeviceListIds[indexPos]; return strDevID; } -type PopupType = 'popupFan' | 'popupInSel' | 'popupLight' | 'popupLightNew' | 'popupNotify' | 'popupShutter' | 'popupThermo' | 'popupTimer' - - - -type EventMethod = 'startup' | 'sleepReached' | 'pageOpenDetail' | 'buttonPress2' | 'renderCurrentPage' | 'button1' | 'button2' - -type SerialType = 'button' | 'light' | 'shutter' | 'text' | 'input_sel' | 'timer' | 'number' | 'fan' - -type roles = 'light' |'socket'|'dimmer'| 'hue' | 'rgb' | 'rgbSingle' | 'cd' | 'blind' | 'door' | 'window' | 'volumeGroup' | 'volume' - | 'info' | 'humidity' | 'temperature' | 'value.temperature' | 'value.humidity' | 'sensor.door' | 'sensor.window' | 'thermostat' | 'warning' | 'ct' - | 'cie' | 'gate' | 'motion' | 'buttonSensor' | 'button' | 'value.time' | 'level.timer' | 'value.alarmtime' | 'level.mode.fan' | 'lock' | 'slider' - | 'switch.mode.wlan' | 'media' | 'timeTable' | 'airCondition' - -type ButtonActionType = 'bExit' | 'bUp' | 'bNext' | 'bSubNext' | 'bPrev' | 'bSubPrev' | 'bHome' | 'notifyAction' | 'OnOff' | 'button' | 'up' | 'stop' | 'down' - | 'positionSlider' | 'tiltOpen' | 'tiltStop' | 'tiltSlider' | 'tiltClose' | 'brightnessSlider' | 'colorTempSlider' | 'colorWheel' | 'tempUpd' | 'tempUpdHighLow' | 'media-back' - | 'media-pause' | 'media-next' | 'media-shuffle' | 'volumeSlider' | 'mode-speakerlist' | 'mode-playlist' | 'mode-tracklist' | 'mode-repeat' | 'mode-equalizer' | 'mode-seek' | 'mode-crossfade' - | 'mode-favorites' | 'mode-insel' | 'media-OnOff' | 'timer-start' | 'timer-pause' | 'timer-cancle' | 'timer-finish' | 'hvac_action' | 'mode-modus1' | 'mode-modus2' | 'mode-modus3' | 'number-set' - | 'mode-preset_modes' | 'A1' | 'A2' | 'A3' | 'A4' | 'D1' | 'U1' - - - -type RGB = { - red: number, - green: number, - blue: number -}; - -type Payload = { - payload: string; -}; - -type PageBaseType = { - type: PagetypeType, - heading: string, - items: PageItem[], - useColor: boolean, - subPage?: boolean, - parent?: PageType, - parentIcon?: string, - parentIconColor?: RGB, - prev?: string, - prevIcon?: string, - prevIconColor?: RGB, - next?: string, - nextIcon?: string, - nextIconColor?: RGB, - home?: string, - homeIcon?: string, - homeIconColor?: RGB -}; - -type PagetypeType = 'cardChart' | 'cardLChart' | 'cardEntities' |'cardGrid'|'cardGrid2'|'cardThermo'|'cardMedia'|'cardUnlock'|'cardQR'|'cardAlarm'|'cardPower' //| 'cardBurnRec' - -type PageType = PageChart | PageEntities | PageGrid | PageGrid2 | PageThermo | PageMedia | PageUnlock | PageQR | PageAlarm | PagePower - -// If u get a error here u forgot something in PagetypeType or PageType -function checkPageType(F: PagetypeType, A: PageType) { - A.type = F; -} - -type PageEntities = { - type: 'cardEntities', - items: PageItem[], -} & PageBaseType - -type PageGrid = { - type: 'cardGrid', - items: PageItem[], -} & PageBaseType - -type PageGrid2 = { - type: 'cardGrid2', - items: PageItem[], -} & PageBaseType - -type PageThermo = { - type: 'cardThermo', - items: PageThermoItem[], - -} & Omit - -type PageMedia = { - type: 'cardMedia', - items: PageMediaItem[], -} & Omit - -type PageAlarm = { - type: 'cardAlarm', - items: PageItem[], -} & Omit - -type PageUnlock = { - type: 'cardUnlock', - items: PageItem[], -} & Omit & Partial> - -type PageQR = { - type: 'cardQR', - items: PageItem[], -} & Omit - -type PagePower = { - type: 'cardPower', - items: PageItem[], -} & Omit - -type PageChart = { - type: 'cardChart' | 'cardLChart', - items: PageItem[], -} & Omit - -type PageItem = PageBaseItem | PageMediaItem | PageThermoItem - -function isPageMediaItem(F: PageItem | PageMediaItem):F is PageMediaItem { - return 'adapterPlayerInstance' in F -} - -function isPageThermoItem(F: PageItem | PageThermoItem):F is PageThermoItem { - return 'popupThermoMode1' in F; -} -type PageMediaItem = { - adapterPlayerInstance: adapterPlayerInstanceType, - mediaDevice?: string, - colorMediaIcon?: RGB, - colorMediaArtist?: RGB, - colorMediaTitle?: RGB, - speakerList?: string[], - playList?: string[], - equalizerList?: string[], - repeatList?: string[], - globalTracklist?: string[], - crossfade?: boolean, -} & PageBaseItem - -type PageThermoItem = { - popupThermoMode1?: string[], - popupThermoMode2?: string[], - popupThermoMode3?: string[], - popUpThermoName?: string[], - setThermoAlias?: string[], - setThermoDestTemp2?: string, -} & PageBaseItem | -{ - popupThermoMode1?: string[], - popupThermoMode2?: string[], - popupThermoMode3?: string[], - popUpThermoName?: string[], - setThermoAlias?: string[], - setThermoDestTemp2?: string, -} & PageBaseItem - -type PageBaseItem = { - id?: string | null, - icon?: string, - icon2?: string, - onColor?: RGB, - offColor?: RGB, - useColor?: boolean, - interpolateColor?: boolean, - minValueBrightness?: number, - maxValueBrightness?: number, - minValueColorTemp?: number, - maxValueColorTemp?: number, - minValueLevel?: number, - maxValueLevel?: number, - minValueTilt?: number, - maxValueTilt?: number, - minValue?: number, - maxValue?: number, - stepValue?: number, - prefixName?: string, - suffixName?: string, - name?: string, - secondRow?: string, - buttonText?: string, - unit?: string, - navigate?: boolean, - colormode?: string, - colorScale?: IconScaleElement, - //adapterPlayerInstance?: adapterPlayerInstanceType, - targetPage?: string, - modeList?: string[], - hidePassword?: boolean, - autoCreateALias?: boolean - yAxis?: string, - yAxisTicks?: number[] | string, - xAxisDecorationId?: string, - useValue?: boolean, - monobutton?: boolean, - inSel_ChoiceState?: boolean, - iconArray?: string[], - fontSize?: number, - actionStringArray?: string[], - alwaysOnDisplay?: boolean, -} - -type DimMode = { - dimmodeOn: (boolean | undefined), - brightnessDay: (number | undefined), - brightnessNight: (number | undefined), - timeDay: (string | undefined), - timeNight: (string | undefined) -} - -type ConfigButtonFunction = { - mode: 'page' | 'toggle' | 'set' | null, - page: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PageGrid2 | PagePower | PageChart | PageUnlock | null), - entity: string | null, - setValue: string | number | boolean | null -} - -type Config = { - panelRecvTopic: string, - panelSendTopic: string, - weatherEntity: string, - leftScreensaverEntity: leftScreensaverEntityType - bottomScreensaverEntity: ScreenSaverElement[], - indicatorScreensaverEntity: indicatorScreensaverEntityType - mrIcon1ScreensaverEntity: ScreenSaverMRElement, - mrIcon2ScreensaverEntity: ScreenSaverMRElement, - defaultColor: RGB, - defaultOnColor: RGB, - defaultOffColor: RGB, - defaultBackgroundColor: RGB, - pages: PageType[], - subPages: PageType[], - button1: ConfigButtonFunction, - button2: ConfigButtonFunction -} -type leftScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; -type indicatorScreensaverEntityType = [ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?] | []; -type ScreenSaverElementWithUndefined = null | undefined | ScreenSaverElement -type ScreenSaverElement = { - ScreensaverEntity: string, - ScreensaverEntityText: string, - ScreensaverEntityFactor?: number, - ScreensaverEntityDecimalPlaces?: number, - ScreensaverEntityDateFormat?: Intl.DateTimeFormatOptions, - ScreensaverEntityIconOn?: string | null, - ScreensaverEntityIconOff?: string | null, - ScreensaverEntityUnitText?: string, - ScreensaverEntityIconColor?: RGB | IconScaleElement | string - ScreensaverEntityOnColor?: RGB - ScreensaverEntityOffColor?: RGB - ScreensaverEntityOnText?: string | null, - ScreensaverEntityOffText?: string | null, -} - -type ScreenSaverMRElement = { - ScreensaverEntity: string | null, - ScreensaverEntityIconOn: string | null, - ScreensaverEntityIconOff: string | null, - ScreensaverEntityValue: string | null, - ScreensaverEntityValueDecimalPlace: number | null, - ScreensaverEntityValueUnit: string | null, - ScreensaverEntityOnColor: RGB, - ScreensaverEntityOffColor: RGB -} - -type IconScaleElement = { - val_min:number, - val_max:number, - val_best?: number -} -/** we need this to have a nice order when using switch() */ -type adapterPlayerInstanceType = - 'alexa2.0.' | 'alexa2.1.'| 'alexa2.2.' | 'alexa2.3.' | 'alexa2.4.' | 'alexa2.5.' | 'alexa2.6.' | 'alexa2.7.' | 'alexa2.8.' | 'alexa2.9.' -| 'sonos.0.' | 'sonos.1.' | 'sonos.2.' | 'sonos.3.' | 'sonos.4.' | 'sonos.5.' | 'sonos.6.' | 'sonos.7.' | 'sonos.8.' | 'sonos.9.' -| 'spotify-premium.0.' | 'spotify-premium.1.' | 'spotify-premium.2.' | 'spotify-premium.3.' | 'spotify-premium.4.' | 'spotify-premium.5.' | 'spotify-premium.6.' | 'spotify-premium.7.' | 'spotify-premium.8.' | 'spotify-premium.9.' -| 'volumio.0.' | 'volumio.1.' | 'volumio.2.' | 'volumio.3.' |'volumio.4.' | 'volumio.5.' | 'volumio.6.' | 'volumio.7.' | 'volumio.8.' | 'volumio.9.' -| 'squeezeboxrpc.0.' | 'squeezeboxrpc.1.' | 'squeezeboxrpc.2.' | 'squeezeboxrpc.3.' | 'squeezeboxrpc.4.' | 'squeezeboxrpc.5.' | 'squeezeboxrpc.6.' | 'squeezeboxrpc.7.' | 'squeezeboxrpc.8.' | 'squeezeboxrpc.9.' -| 'bosesoundtouch.0.' | 'bosesoundtouch.1.' | 'bosesoundtouch.2.' | 'bosesoundtouch.3.' |'bosesoundtouch.4.' | 'bosesoundtouch.5.' | 'bosesoundtouch.6.' | 'bosesoundtouch.7.' | 'bosesoundtouch.8.' | 'bosesoundtouch.9.' - -type PlayerType = _PlayerTypeWithMediaDevice | _PlayerTypeWithOutMediaDevice; +type RGB = NSPanel.RGB; +type PageItem = NSPanel.PageItem; +type PageType = NSPanel.PageType; +type Config = NSPanel.Config; const ArrayPlayerTypeWithMediaDevice = ['alexa2', 'sonos', 'squeezeboxrpc'] as const const ArrayPlayerTypeWithOutMediaDevice = ['spotify-premium', 'volumio', 'bosesoundtouch'] as const -type _PlayerTypeWithOutMediaDevice = typeof ArrayPlayerTypeWithOutMediaDevice[number] -type _PlayerTypeWithMediaDevice = typeof ArrayPlayerTypeWithMediaDevice[number] -function isPlayerWithMediaDevice (F: string | _PlayerTypeWithMediaDevice): F is _PlayerTypeWithMediaDevice { - return ArrayPlayerTypeWithMediaDevice.indexOf(F as _PlayerTypeWithMediaDevice) != -1; +function isPlayerWithMediaDevice (F: string | NSPanel._PlayerTypeWithMediaDevice): F is NSPanel._PlayerTypeWithMediaDevice { + return ArrayPlayerTypeWithMediaDevice.indexOf(F as NSPanel._PlayerTypeWithMediaDevice) != -1; +} +/** check if NSPanel.adapterPlayerInstanceType has all Playertypes */ +function checkSortedPlayerType(F: NSPanel.notSortedPlayerType) { + const test: NSPanel.adapterPlayerInstanceType = F; } -type notSortedPlayerType = `${PlayerType}.0.` | `${PlayerType}.1.` | `${PlayerType}.2.` | `${PlayerType}.3.` | `${PlayerType}.4.` | `${PlayerType}.5.` | `${PlayerType}.6.` | `${PlayerType}.7.` | `${PlayerType}.8.` | `${PlayerType}.9.` - -/** check if adapterPlayerInstanceType has all Playertypes */ -function checkSortedPlayerType(F: notSortedPlayerType) { - const test: adapterPlayerInstanceType = F; -} - -type mediaOptional = 'seek' | 'crossfade' | 'speakerlist' | 'playlist' | 'tracklist' | 'equalizer' | 'repeat' | 'favorites' - - -function isMediaOptional(F: string | mediaOptional): F is mediaOptional { - switch(F as mediaOptional) { +function isMediaOptional(F: string | NSPanel.mediaOptional): F is NSPanel.mediaOptional { + switch(F as NSPanel.mediaOptional) { case "seek": case "crossfade": case "speakerlist": @@ -9916,8 +9638,8 @@ function isMediaOptional(F: string | mediaOptional): F is mediaOptional { } } -function isEventMethod(F: string | EventMethod): F is EventMethod { - switch(F as EventMethod) { +function isEventMethod(F: string | NSPanel.EventMethod): F is NSPanel.EventMethod { + switch(F as NSPanel.EventMethod) { case "startup": case "sleepReached": case "pageOpenDetail": @@ -9928,13 +9650,13 @@ function isEventMethod(F: string | EventMethod): F is EventMethod { return true; default: // Have to talk about this. - log(`Please report to developer: Unknown EventMethod: ${F} `, 'warn'); + log(`Please report to developer: Unknown NSPanel.EventMethod: ${F} `, 'warn'); return false; } } -function isPopupType(F: PopupType | string): F is PopupType { - switch(F as PopupType) { +function isPopupType(F: NSPanel.PopupType | string): F is NSPanel.PopupType { + switch(F as NSPanel.PopupType) { case "popupFan": case "popupInSel": case "popupLight": @@ -9945,7 +9667,292 @@ function isPopupType(F: PopupType | string): F is PopupType { case "popupTimer": return true; default: - log(`Please report to developer: Unknown PopupType: ${F} `, 'warn'); + log(`Please report to developer: Unknown NSPanel.PopupType: ${F} `, 'warn'); return false; } } +// If u get a error here u forgot something in PagetypeType or PageType +function checkPageType(F: NSPanel.PagetypeType, A: NSPanel.PageType) { + A.type = F; +} +function isPageMediaItem(F: NSPanel.PageItem | NSPanel.PageMediaItem):F is NSPanel.PageMediaItem { + return 'adapterPlayerInstance' in F +} + +function isPageThermoItem(F: PageItem | NSPanel.PageThermoItem):F is NSPanel.PageThermoItem { + return 'popupThermoMode1' in F; +} + +namespace NSPanel { + export type PopupType = 'popupFan' | 'popupInSel' | 'popupLight' | 'popupLightNew' | 'popupNotify' | 'popupShutter' | 'popupThermo' | 'popupTimer' + + + + export type EventMethod = 'startup' | 'sleepReached' | 'pageOpenDetail' | 'buttonPress2' | 'renderCurrentPage' | 'button1' | 'button2' + + export type SerialType = 'button' | 'light' | 'shutter' | 'text' | 'input_sel' | 'timer' | 'number' | 'fan' + + export type roles = 'light' |'socket'|'dimmer'| 'hue' | 'rgb' | 'rgbSingle' | 'cd' | 'blind' | 'door' | 'window' | 'volumeGroup' | 'volume' + | 'info' | 'humidity' | 'temperature' | 'value.temperature' | 'value.humidity' | 'sensor.door' | 'sensor.window' | 'thermostat' | 'warning' | 'ct' + | 'cie' | 'gate' | 'motion' | 'buttonSensor' | 'button' | 'value.time' | 'level.timer' | 'value.alarmtime' | 'level.mode.fan' | 'lock' | 'slider' + | 'switch.mode.wlan' | 'media' | 'timeTable' | 'airCondition' + + export type ButtonActionType = 'bExit' | 'bUp' | 'bNext' | 'bSubNext' | 'bPrev' | 'bSubPrev' | 'bHome' | 'notifyAction' | 'OnOff' | 'button' | 'up' | 'stop' | 'down' + | 'positionSlider' | 'tiltOpen' | 'tiltStop' | 'tiltSlider' | 'tiltClose' | 'brightnessSlider' | 'colorTempSlider' | 'colorWheel' | 'tempUpd' | 'tempUpdHighLow' | 'media-back' + | 'media-pause' | 'media-next' | 'media-shuffle' | 'volumeSlider' | 'mode-speakerlist' | 'mode-playlist' | 'mode-tracklist' | 'mode-repeat' | 'mode-equalizer' | 'mode-seek' | 'mode-crossfade' + | 'mode-favorites' | 'mode-insel' | 'media-OnOff' | 'timer-start' | 'timer-pause' | 'timer-cancle' | 'timer-finish' | 'hvac_action' | 'mode-modus1' | 'mode-modus2' | 'mode-modus3' | 'number-set' + | 'mode-preset_modes' | 'A1' | 'A2' | 'A3' | 'A4' | 'D1' | 'U1' + + + + export type RGB = { + red: number, + green: number, + blue: number + }; + + export type Payload = { + payload: string; + }; + + export type PageBaseType = { + type: PagetypeType, + heading: string, + items: PageItem[], + useColor: boolean, + subPage?: boolean, + parent?: PageType, + parentIcon?: string, + parentIconColor?: RGB, + prev?: string, + prevIcon?: string, + prevIconColor?: RGB, + next?: string, + nextIcon?: string, + nextIconColor?: RGB, + home?: string, + homeIcon?: string, + homeIconColor?: RGB + }; + + + export type PagetypeType = 'cardChart' | 'cardLChart' | 'cardEntities' |'cardGrid'|'cardGrid2'|'cardThermo'|'cardMedia'|'cardUnlock'|'cardQR'|'cardAlarm'|'cardPower' //| 'cardBurnRec' + + export type PageType = PageChart | PageEntities | PageGrid | PageGrid2 | PageThermo | PageMedia | PageUnlock | PageQR | PageAlarm | PagePower + + export type PageEntities = { + type: 'cardEntities', + items: PageItem[], + } & PageBaseType + + export type PageGrid = { + type: 'cardGrid', + items: PageItem[], + } & PageBaseType + + export type PageGrid2 = { + type: 'cardGrid2', + items: PageItem[], + } & PageBaseType + + export type PageThermo = { + type: 'cardThermo', + items: PageThermoItem[], + + } & Omit + + export type PageMedia = { + type: 'cardMedia', + items: PageMediaItem[], + } & Omit + + export type PageAlarm = { + type: 'cardAlarm', + items: PageItem[], + } & Omit + + export type PageUnlock = { + type: 'cardUnlock', + items: PageItem[], + } & Omit & Partial> + + export type PageQR = { + type: 'cardQR', + items: PageItem[], + } & Omit + + export type PagePower = { + type: 'cardPower', + items: PageItem[], + } & Omit + + export type PageChart = { + type: 'cardChart' | 'cardLChart', + items: PageItem[], + } & Omit + + export type PageItem = PageBaseItem | PageMediaItem | PageThermoItem + + export type PageMediaItem = { + adapterPlayerInstance: adapterPlayerInstanceType, + mediaDevice?: string, + colorMediaIcon?: RGB, + colorMediaArtist?: RGB, + colorMediaTitle?: RGB, + speakerList?: string[], + playList?: string[], + equalizerList?: string[], + repeatList?: string[], + globalTracklist?: string[], + crossfade?: boolean, + } & PageBaseItem + + export type PageThermoItem = { + popupThermoMode1?: string[], + popupThermoMode2?: string[], + popupThermoMode3?: string[], + popUpThermoName?: string[], + setThermoAlias?: string[], + setThermoDestTemp2?: string, + } & PageBaseItem | + { + popupThermoMode1?: string[], + popupThermoMode2?: string[], + popupThermoMode3?: string[], + popUpThermoName?: string[], + setThermoAlias?: string[], + setThermoDestTemp2?: string, + } & PageBaseItem + + export type PageBaseItem = { + id?: string | null, + icon?: string, + icon2?: string, + onColor?: RGB, + offColor?: RGB, + useColor?: boolean, + interpolateColor?: boolean, + minValueBrightness?: number, + maxValueBrightness?: number, + minValueColorTemp?: number, + maxValueColorTemp?: number, + minValueLevel?: number, + maxValueLevel?: number, + minValueTilt?: number, + maxValueTilt?: number, + minValue?: number, + maxValue?: number, + stepValue?: number, + prefixName?: string, + suffixName?: string, + name?: string, + secondRow?: string, + buttonText?: string, + unit?: string, + navigate?: boolean, + colormode?: string, + colorScale?: IconScaleElement, + //adapterPlayerInstance?: adapterPlayerInstanceType, + targetPage?: string, + modeList?: string[], + hidePassword?: boolean, + autoCreateALias?: boolean + yAxis?: string, + yAxisTicks?: number[] | string, + xAxisDecorationId?: string, + useValue?: boolean, + monobutton?: boolean, + inSel_ChoiceState?: boolean, + iconArray?: string[], + fontSize?: number, + actionStringArray?: string[], + alwaysOnDisplay?: boolean, + } + + export type DimMode = { + dimmodeOn: (boolean | undefined), + brightnessDay: (number | undefined), + brightnessNight: (number | undefined), + timeDay: (string | undefined), + timeNight: (string | undefined) + } + + export type ConfigButtonFunction = { + mode: 'page' | 'toggle' | 'set' | null, + page: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PageGrid2 | PagePower | PageChart | PageUnlock | null), + entity: string | null, + setValue: string | number | boolean | null + } + + export type Config = { + panelRecvTopic: string, + panelSendTopic: string, + weatherEntity: string, + leftScreensaverEntity: leftScreensaverEntityType + bottomScreensaverEntity: ScreenSaverElement[], + indicatorScreensaverEntity: indicatorScreensaverEntityType + mrIcon1ScreensaverEntity: ScreenSaverMRElement, + mrIcon2ScreensaverEntity: ScreenSaverMRElement, + defaultColor: RGB, + defaultOnColor: RGB, + defaultOffColor: RGB, + defaultBackgroundColor: RGB, + pages: PageType[], + subPages: PageType[], + button1: ConfigButtonFunction, + button2: ConfigButtonFunction + } + export type leftScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; + export type indicatorScreensaverEntityType = [ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?] | []; + export type ScreenSaverElementWithUndefined = null | undefined | ScreenSaverElement + export type ScreenSaverElement = { + ScreensaverEntity: string, + ScreensaverEntityText: string, + ScreensaverEntityFactor?: number, + ScreensaverEntityDecimalPlaces?: number, + ScreensaverEntityDateFormat?: Intl.DateTimeFormatOptions, + ScreensaverEntityIconOn?: string | null, + ScreensaverEntityIconOff?: string | null, + ScreensaverEntityUnitText?: string, + ScreensaverEntityIconColor?: RGB | IconScaleElement | string + ScreensaverEntityOnColor?: RGB + ScreensaverEntityOffColor?: RGB + ScreensaverEntityOnText?: string | null, + ScreensaverEntityOffText?: string | null, + } + + export type ScreenSaverMRElement = { + ScreensaverEntity: string | null, + ScreensaverEntityIconOn: string | null, + ScreensaverEntityIconOff: string | null, + ScreensaverEntityValue: string | null, + ScreensaverEntityValueDecimalPlace: number | null, + ScreensaverEntityValueUnit: string | null, + ScreensaverEntityOnColor: RGB, + ScreensaverEntityOffColor: RGB + } + + export type IconScaleElement = { + val_min:number, + val_max:number, + val_best?: number + } + /** we need this to have a nice order when using switch() */ + export type adapterPlayerInstanceType = + 'alexa2.0.' | 'alexa2.1.'| 'alexa2.2.' | 'alexa2.3.' | 'alexa2.4.' | 'alexa2.5.' | 'alexa2.6.' | 'alexa2.7.' | 'alexa2.8.' | 'alexa2.9.' + | 'sonos.0.' | 'sonos.1.' | 'sonos.2.' | 'sonos.3.' | 'sonos.4.' | 'sonos.5.' | 'sonos.6.' | 'sonos.7.' | 'sonos.8.' | 'sonos.9.' + | 'spotify-premium.0.' | 'spotify-premium.1.' | 'spotify-premium.2.' | 'spotify-premium.3.' | 'spotify-premium.4.' | 'spotify-premium.5.' | 'spotify-premium.6.' | 'spotify-premium.7.' | 'spotify-premium.8.' | 'spotify-premium.9.' + | 'volumio.0.' | 'volumio.1.' | 'volumio.2.' | 'volumio.3.' |'volumio.4.' | 'volumio.5.' | 'volumio.6.' | 'volumio.7.' | 'volumio.8.' | 'volumio.9.' + | 'squeezeboxrpc.0.' | 'squeezeboxrpc.1.' | 'squeezeboxrpc.2.' | 'squeezeboxrpc.3.' | 'squeezeboxrpc.4.' | 'squeezeboxrpc.5.' | 'squeezeboxrpc.6.' | 'squeezeboxrpc.7.' | 'squeezeboxrpc.8.' | 'squeezeboxrpc.9.' + | 'bosesoundtouch.0.' | 'bosesoundtouch.1.' | 'bosesoundtouch.2.' | 'bosesoundtouch.3.' |'bosesoundtouch.4.' | 'bosesoundtouch.5.' | 'bosesoundtouch.6.' | 'bosesoundtouch.7.' | 'bosesoundtouch.8.' | 'bosesoundtouch.9.' + + export type PlayerType = _PlayerTypeWithMediaDevice | _PlayerTypeWithOutMediaDevice; + + export type _PlayerTypeWithOutMediaDevice = typeof ArrayPlayerTypeWithOutMediaDevice[number] + export type _PlayerTypeWithMediaDevice = typeof ArrayPlayerTypeWithMediaDevice[number] + + export type notSortedPlayerType = `${PlayerType}.0.` | `${PlayerType}.1.` | `${PlayerType}.2.` | `${PlayerType}.3.` | `${PlayerType}.4.` | `${PlayerType}.5.` | `${PlayerType}.6.` | `${PlayerType}.7.` | `${PlayerType}.8.` | `${PlayerType}.9.` + + export type mediaOptional = 'seek' | 'crossfade' | 'speakerlist' | 'playlist' | 'tracklist' | 'equalizer' | 'repeat' | 'favorites' + +} From 9b98cac4c87b7fad75c9074848d30c55174a72c9 Mon Sep 17 00:00:00 2001 From: ticaki Date: Sun, 7 Jan 2024 13:49:36 +0100 Subject: [PATCH 56/99] More types without namespace for compatibility. --- ioBroker/DEV/NSPanelTs.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 05f618e4..2c3638e5 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -9606,10 +9606,22 @@ function spotifyGetDeviceID(vDeviceString: string): string { let strDevID = arrayDeviceListIds[indexPos]; return strDevID; } + type RGB = NSPanel.RGB; type PageItem = NSPanel.PageItem; type PageType = NSPanel.PageType; type Config = NSPanel.Config; +type PageEntities = NSPanel.PageEntities; +type PageChart = NSPanel.PageChart; +type PagePower = NSPanel.PagePower; +type PageGrid = NSPanel.PageGrid; +type PageQR = NSPanel.PageQR; +type PageGrid2 = NSPanel.PageGrid2; +type PageMedia = NSPanel.PageMedia; +type PageThermo = NSPanel.PageThermo; +type PageUnlock = NSPanel.PageUnlock; +type PageAlarm = NSPanel.PageAlarm; + const ArrayPlayerTypeWithMediaDevice = ['alexa2', 'sonos', 'squeezeboxrpc'] as const const ArrayPlayerTypeWithOutMediaDevice = ['spotify-premium', 'volumio', 'bosesoundtouch'] as const From 4d3f54439e05c6affa5e82081e290e8a6e319784 Mon Sep 17 00:00:00 2001 From: kuckuckmann <99131208+kuckuckmann@users.noreply.github.com> Date: Sun, 7 Jan 2024 14:41:07 +0100 Subject: [PATCH 57/99] Update Alarm_Page_Erweitertes_Skript_mit_PopupNotifyPage.xml Fix Number Value from decimal to integer value and convert to string for Datapoint PopupNotifyPage [string] at Block Value. --- ...Erweitertes_Skript_mit_PopupNotifyPage.xml | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/ioBroker/Blockly/Alarm_Page_Erweitertes_Skript_mit_PopupNotifyPage.xml b/ioBroker/Blockly/Alarm_Page_Erweitertes_Skript_mit_PopupNotifyPage.xml index 6dadf28b..ab1b6bb9 100644 --- a/ioBroker/Blockly/Alarm_Page_Erweitertes_Skript_mit_PopupNotifyPage.xml +++ b/ioBroker/Blockly/Alarm_Page_Erweitertes_Skript_mit_PopupNotifyPage.xml @@ -971,12 +971,27 @@ - - - TRUE - - - + + + TRUE + + + + + + + 1 + + + + + 100 + + + + + + 0 From 56703ec458f2f83168a9f66be041b79fb4c22aaa Mon Sep 17 00:00:00 2001 From: kuckuckmann <99131208+kuckuckmann@users.noreply.github.com> Date: Sun, 7 Jan 2024 18:28:37 +0100 Subject: [PATCH 58/99] Update Alarm_Page_Erweitertes_Skript_mit_PopupNotifyPage.xml Add further Text to create String for ID --- ...Erweitertes_Skript_mit_PopupNotifyPage.xml | 52 +++++++++++-------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/ioBroker/Blockly/Alarm_Page_Erweitertes_Skript_mit_PopupNotifyPage.xml b/ioBroker/Blockly/Alarm_Page_Erweitertes_Skript_mit_PopupNotifyPage.xml index ab1b6bb9..b7000c36 100644 --- a/ioBroker/Blockly/Alarm_Page_Erweitertes_Skript_mit_PopupNotifyPage.xml +++ b/ioBroker/Blockly/Alarm_Page_Erweitertes_Skript_mit_PopupNotifyPage.xml @@ -971,27 +971,37 @@ - - - TRUE - - - - - - - 1 - - - - - 100 - - - - - - + + + TRUE + + + + + + ID + + + + + + + + + 1 + + + + + 100 + + + + + + + + 0 From ff7d2020f7d40d6ac45f63520b41b13f143e96fc Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Sun, 7 Jan 2024 23:42:35 +0100 Subject: [PATCH 59/99] Update NSPanelTs.ts --- ioBroker/DEV/NSPanelTs.ts | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 2c3638e5..e72f9d64 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.33 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.34 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -103,6 +103,7 @@ ReleaseNotes: - 05.01.2024 - v4.3.3.32 Add Body for BoseSoundtouch-Player - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity + - 05.01.2024 - v4.3.3.33 Fix BoseSoundtouch Proto Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -966,7 +967,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.33'; +const scriptVersion: string = 'v4.3.3.34'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -6872,7 +6873,11 @@ function HandleButtonEvent(words: any): void { case "bosesoundtouch": if (Debug) log('bosesoundtouch - playlist ' + pageItemPL.adapterPlayerInstance + ' - ' + words[4]); if (Debug) log(adapterInstancePL + 'key'); - setState(adapterInstancePL + 'key', 'PRESET_' + (parseInt(words[4]) + 1)); + if (words[4] < 6) { + setState(adapterInstancePL + 'key', 'PRESET_' + (parseInt(words[4]) + 1)); + } else if (words[4] == 6) { + setState(adapterInstancePL + 'key', 'AUX_INPUT'); + } break; default: log('Hello Mr. Developer u miss in mode-playlist something!', 'warn'); @@ -7026,12 +7031,12 @@ function HandleButtonEvent(words: any): void { case 'mode-insel': setIfExists(id + '.VALUE', parseInt(words[4])); break; - case 'media-OnOff': - let pageItemTem = findPageItem(id); - if (!isPageMediaItem(pageItemTem)) break; - let adaInstanceSpli = pageItemTem.adapterPlayerInstance.split('.'); - if (adaInstanceSpli[0] == 'squeezeboxrpc') { - let adapterPlayerInstancePowerSelector: string = [pageItemTem.adapterPlayerInstance, 'Players', pageItemTem.mediaDevice, 'Power'].join('.'); + case 'media-OnOff': { + let pageItemTemp = findPageItem(id); + if (!isPageMediaItem(pageItemTemp)) break; + let adapterInstance = pageItemTemp.adapterPlayerInstance.split('.'); + if (adapterInstance[0] == 'squeezeboxrpc') { + let adapterPlayerInstancePowerSelector: string = [pageItemTemp.adapterPlayerInstance, 'Players', pageItemTemp.mediaDevice, 'Power'].join('.'); let stateVal = getState(adapterPlayerInstancePowerSelector).val; if (stateVal === 0) { setState(adapterPlayerInstancePowerSelector, 1); @@ -7042,11 +7047,14 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.STOP', true); setIfExists(id + '.STATE', 0); } + } else if (adapterInstance[0] == 'bosesoundtouch') { + setState(pageItemTemp.adapterPlayerInstance + 'key', 'POWER'); } else { setIfExists(id + '.STOP', true); } GeneratePage(activePage!); break; + } case 'timer-start': if (words[4] != undefined) { let timer_panel = words[4].split(':'); @@ -8122,6 +8130,7 @@ function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOpti tempPlayList[i - 1] = formatInSelText(vPreset.replace('_',' ')); if (Debug) log(formatInSelText(vPreset.replace('_',' '))) } + tempPlayList[6] = 'AUX INPUT'; optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' } else if (vAdapter == 'sonos') { if (Debug) log(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set', 'info'); From 02004f4b6d4a0b3e03ffb82923420a5d8e978dce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 09:15:39 +0100 Subject: [PATCH 60/99] Bump home-assistant/builder from 2023.12.0 to 2024.01.0 (#1129) Bumps [home-assistant/builder](https://github.com/home-assistant/builder) from 2023.12.0 to 2024.01.0. - [Release notes](https://github.com/home-assistant/builder/releases) - [Commits](https://github.com/home-assistant/builder/compare/2023.12.0...2024.01.0) --- updated-dependencies: - dependency-name: home-assistant/builder dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/builder.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/builder.yaml b/.github/workflows/builder.yaml index 02928946..8eb81597 100644 --- a/.github/workflows/builder.yaml +++ b/.github/workflows/builder.yaml @@ -100,7 +100,7 @@ jobs: - name: Build ${{ matrix.addon }} add-on if: steps.check.outputs.build_arch == 'true' - uses: home-assistant/builder@2023.12.0 + uses: home-assistant/builder@2024.01.0 with: args: | ${{ env.BUILD_ARGS }} \ From 54422eccaaaa0f6c6cd38fdb88902d4cff68bcfe Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Mon, 8 Jan 2024 11:29:19 +0100 Subject: [PATCH 61/99] v4.3.3.34 - Bose Soundtouch final Proto Fix: Disabled Icon Status while bug by updating data points in ioBroker (reason unknown) --- ioBroker/DEV/NSPanelTs.ts | 46 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index e72f9d64..c8245a63 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -31,20 +31,8 @@ https://github.com/joBr99/nspanel-lovelace-ui/wiki/iobroker---Basisinstallation# ReleaseNotes: Bugfixes und Erweiterungen: - - - 17.09.2023 - v4.3.1 Upgrade TFT 53 / 4.3.1 - - 17.09.2023 - v4.3.1.1 Add Parameter fontSize (0-4) to cardGrid (with useValue) - - 23.09.2023 - v4.3.1.2 Upgrade BerryDriver v9 - - 23.09.2023 - v4.3.1.3 Fix - Change ServivceMenu from Fake-SSId to real Tasmota-SSIdParam - - 03.10.2023 - v4.3.1.4 Removing the examples from the NSPanelTs.ts --> https://github.com/joBr99/nspanel-lovelace-ui/wiki/NSPanel-Page-%E2%80%90-Typen_How-2_Beispiele - - 03.10.2023 - v4.3.1.4 Delete NsPanelTs_without_Examples.ts - - 12.10.2023 - v4.3.1.5 Fix Datapoint for Role timetable -> Attention use new script from TT-Tom https://github.com/tt-tom17/MyScripts/blob/main/Sonoff_NSPanel/Fahrplan_to_NSPanel.ts - - 19.10.2023 - v4.3.1.6 Add more Alias Device-Types to Navigation / Minor Fixes - - 22.10.2023 - v4.3.1.7 Fix CreateEntity (navigate) role 'light' and 'socket' and 'temperature' - - 30.10.2023 - v4.3.2 Upgrade TFT 53 / 4.3.2 - - 30.10.2023 - v4.3.2.1 Fix formatDate/Date.parse with moment.js (Bugs in JS-Methodes) - - 07.11.2023 - v4.3.2.2 Fix Selection of screensaver layout (alternative / advanced) - - 08.11.2023 - v4.3.2.3 Fix Issues #1013 by laluz742 -> Parameter count mismatch: screensaver color + See ChangeLog all Release Notes: https://github.com/joBr99/nspanel-lovelace-ui/wiki/Release-Notes + - 08.11.2023 - v4.3.3 Upgrade TFT 53 / 4.3.3 - 11.11.2023 - v4.3.3.1 Fix for Issues #1020 HandleHardwareButton buttonConfig.mode -> 'toggle' and 'set' - 12.11.2023 - v4.3.3.2 Add autoCreateALias to cardUnlock @@ -103,8 +91,9 @@ ReleaseNotes: - 05.01.2024 - v4.3.3.32 Add Body for BoseSoundtouch-Player - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity - - 05.01.2024 - v4.3.3.33 Fix BoseSoundtouch Proto - + - 07.01.2024 - v4.3.3.33 Fix BoseSoundtouch Proto + - 08.01.2024 - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) + Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -3771,13 +3760,18 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = if (Debug) log('min_Level: ' + min_Level, 'info'); if (Debug) log('max_Level: ' + max_Level, 'info'); + let icon_up_status = 'enable'; + let icon_down_status = 'enable'; + let tempVal: number = getState(pageItem.id + '.ACTUAL').val - let icon_up_status = tempVal === min_Level ? 'disable' : 'enable'; + + //Disabled Status while bug in updating origin adapter data points of lift values + //let icon_up_status = tempVal === min_Level ? 'disable' : 'enable'; let icon_stop_status = 'enable'; if (tempVal === min_Level || tempVal === max_Level || checkBlindActive === false) { - icon_stop_status = 'disable'; + //icon_stop_status = 'disable'; } - let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; + //let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; let value = icon_up + '|' + icon_stop + '|' + icon_down + '|' + icon_up_status + '|' + icon_stop_status + '|' + icon_down_status if (Debug) log('CreateEntity Icon role blind ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + value, 'info'); @@ -7807,12 +7801,17 @@ function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOpti let icon_stop = Icons.GetIcon('stop'); let icon_down = Icons.GetIcon('arrow-down'); let tempVal: number = getState(pageItem.id + '.ACTUAL').val - let icon_up_status = tempVal === min_Level ? 'disable' : 'enable'; + + //Disabled Status while bug in updating origin adapter data points of lift values + let icon_up_status = 'enable'; + //let icon_up_status = tempVal === min_Level ? 'disable' : 'enable'; let icon_stop_status = 'enable'; if (tempVal === min_Level || tempVal === max_Level || checkBlindActive === false) { - icon_stop_status = 'disable'; + //icon_stop_status = 'disable'; } - let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; + let icon_down_status = 'enable'; + //let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; + let textTilt = ''; let iconTiltLeft = ''; let iconTiltStop = ''; @@ -7841,7 +7840,7 @@ function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOpti out_msgs.push({ payload: 'entityUpdateDetail' + '~' //entityUpdateDetail - + tempId + '~' //entity_id + + tempId + '~' //entity_id + val + '~' //Shutterposition + textSecondRow + '~' //pos_status 2.line + findLocale('blinds', 'Position') + '~' //pos_translation @@ -8595,6 +8594,7 @@ function HandleScreensaverUpdate(): void { //Alternativ Layout bekommt zusätzlichen Status if (config.bottomScreensaverEntity[4] && getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { + log('alternativ'); let val = getState(config.bottomScreensaverEntity[4].ScreensaverEntity).val; if (parseFloat(val+"") == val) { val = parseFloat(val); From f11de05eb374e5bb9cb89add6a5e66441e7137a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 16:38:05 +0100 Subject: [PATCH 62/99] Bump github/codeql-action from 2 to 3 (#1094) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v2...v3) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d0dfd689..b44f8abc 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -47,7 +47,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -58,7 +58,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -72,4 +72,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 From 0c6cd158dd104f301626258536267cc813563271 Mon Sep 17 00:00:00 2001 From: ticaki Date: Mon, 8 Jan 2024 18:52:33 +0100 Subject: [PATCH 63/99] change schedule (testing needed) add 1 extendObjectfor bgColorIndicator --- ioBroker/DEV/NSPanelTs.ts | 94 ++++++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index c8245a63..d11d2538 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -976,6 +976,8 @@ const moment = require('moment'); const parseFormat = require('moment-parseformat'); moment.locale(getState(NSPanel_Path + 'Config.locale').val); +const scheduleList:{[key:string]: any} = {}; + const globalTextColor: any = White; const Sliders2: number = 0; let checkBlindActive: boolean = false; @@ -1387,8 +1389,27 @@ Init_ActivePageData(); //switch BackgroundColors for Screensaver Indicators async function Init_Screensaver_Backckground_Color_Switch() { try { - if (existsState(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator') == false ) { - await createStateAsync(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator', 0, true, { type: 'number' }); + const objDef: iobJS.StateObject = { + _id: '', + type: "state", + common: { + type: "number", + name: "Color Indicator", + role: "level", + states: {0:'black', 1:'red', 2:'green', 3:'attention', 4: 'pink'}, + read: true, + write: true + }, + "native": {}, + }; + await extendObjectAsync(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator', objDef) + if (await existsStateAsync(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator')) { + const obj = await getStateAsync(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator'); + if (obj && obj.val !== null && obj.val !== undefined) { + bgColorScrSaver = obj.val; + } else { + setStateAsync(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator', bgColorScrSaver) + } } } catch (err: any) { log('error at function Init_Screensaver_Backckground_Color_Switch: ' + err.message, 'warn'); @@ -1939,11 +1960,11 @@ async function InitDimmode() { timeNight: (vTimeNight < 10) ? `0${vTimeNight}:00` : `${vTimeNight}:00` }; // timeDimMode Day - scheduleInitDimModeDay = schedule({ hour: getState(NSPanel_Path + 'NSPanel_Dimmode_hourDay').val, minute: 0 }, () => { + scheduleInitDimModeDay = adapterSchedule({ hour: getState(NSPanel_Path + 'NSPanel_Dimmode_hourDay').val, minute: 0}, 24 * 60 * 60, () => { ScreensaverDimmode(timeDimMode); }); // timeDimMode Night - scheduleInitDimModeNight = schedule({ hour: getState(NSPanel_Path + 'NSPanel_Dimmode_hourNight').val, minute: 0 }, () => { + scheduleInitDimModeNight = adapterSchedule({ hour: getState(NSPanel_Path + 'NSPanel_Dimmode_hourNight').val, minute: 0 }, 24 * 60 * 60, () => { ScreensaverDimmode(timeDimMode); }); if (getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val != null && getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val != -1) { @@ -2142,7 +2163,7 @@ let pageId = 0; let activePage: PageType | undefined = undefined; //Send time to NSPanel -let scheduleSendTime = schedule('* * * * *', () => { +let scheduleSendTime = adapterSchedule(new Date().setMilliseconds(0), 1, () => { try { SendTime(); HandleScreensaverUpdate(); @@ -2152,7 +2173,7 @@ let scheduleSendTime = schedule('* * * * *', () => { }); //Switch between Screensaver Entities and WeatherForecast -let scheduleSwichScreensaver = schedule('*/' + getState(NSPanel_Path + 'ScreensaverInfo.entityChangeTime').val + ' * * * * *', () => { +let scheduleSwichScreensaver = adapterSchedule(undefined, parseInt(getState(NSPanel_Path + 'ScreensaverInfo.entityChangeTime').val), () => { try { //WeatherForecast true/false Switchover delayed if (getState(NSPanel_Path + "ScreensaverInfo.popupNotifyHeading").val == '' && getState(NSPanel_Path + "ScreensaverInfo.popupNotifyText").val == '' && getState(NSPanel_Path + "ScreensaverInfo.weatherForecast").val == true && getState(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer").val == true) { @@ -2211,17 +2232,17 @@ on({id: [config.weatherEntity + '.TEMP', } }); -let scheduleSendDate = schedule('0 * * * *', () => { +let scheduleSendDate = adapterSchedule((new Date().setMinutes(0,0)),60*60, () => { SendDate(); }); // 3:30 a.m. Perform startup and receive current TFT version -let scheduleStartup = schedule({ hour: 3, minute: 30 }, async () => { +let scheduleStartup = adapterSchedule({ hour: 3, minute: 30 }, 24*60*60, async () => { setIfExists(config.panelSendTopic, 'pageType~pageStartup'); }); // Updates currently compare every 12 hours -let scheduleCheckUpdates = schedule('{"time":{"start":"00:00","end":"23:59","mode":"hours","interval":12},"period":{"days":1}}', () => { +let scheduleCheckUpdates = adapterSchedule(undefined,60*60*12, () => { get_tasmota_status0(); get_panel_update_data(); check_updates(); @@ -3330,19 +3351,19 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = // ioBroker if (pageItem.id && existsObject(pageItem.id) || pageItem.navigate === true) { - let iconColor = rgb_dec565(config.defaultColor); - let optVal = '0'; + let iconColor:number = rgb_dec565(config.defaultColor); + let optVal:string = '0'; let val: any = null; - let o:any + let o:any = undefined; if (pageItem.id != null && existsObject(pageItem.id)) { o = getObject(pageItem.id); } // Fallback if no name is given name = pageItem.name !== undefined ? pageItem.name : o.common.name.de == undefined ? o.common.name : o.common.name.de; - let prefix = pageItem.prefixName !== undefined ? pageItem.prefixName : ''; - let suffix = pageItem.suffixName !== undefined ? pageItem.suffixName : ''; + const prefix = pageItem.prefixName !== undefined ? pageItem.prefixName : ''; + const suffix = pageItem.suffixName !== undefined ? pageItem.suffixName : ''; // If name is used with changing values if ((name || '').indexOf('getState(') != -1) { @@ -3350,6 +3371,10 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = name = getState(dpName).val; RegisterEntityWatcher(dpName); } + else if ((name || '').split('.').length > 3 && existsState(name)) { + name = getState(name).val; + RegisterEntityWatcher(name); + } name = prefix + name + suffix; if (existsState(pageItem.id + '.GET')) { @@ -8594,7 +8619,6 @@ function HandleScreensaverUpdate(): void { //Alternativ Layout bekommt zusätzlichen Status if (config.bottomScreensaverEntity[4] && getState(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout').val) { - log('alternativ'); let val = getState(config.bottomScreensaverEntity[4].ScreensaverEntity).val; if (parseFloat(val+"") == val) { val = parseFloat(val); @@ -9024,6 +9048,8 @@ function HandleScreensaverColors(): void { scrSvrBGCol = rgb_dec565(scbackgroundInd2); } else if (bgColorScrSaver == 3) { scrSvrBGCol = rgb_dec565(scbackgroundInd3); + } else if (bgColorScrSaver == 4) { + scrSvrBGCol = rgb_dec565({red:255, green:16, blue:240}); } let payloadString = 'color' + '~' + @@ -9632,6 +9658,39 @@ type PageUnlock = NSPanel.PageUnlock; type PageAlarm = NSPanel.PageAlarm; + +// dont work with summer/winter time has to be fixed +function adapterSchedule(time: {hour?: number, minute?: number} | undefined | number, repeatTime: number, callback: () => void): number|null { + if (typeof callback !== 'function') return null + const ref = Math.random() + 1; + scheduleList[ref] = setTimeout(_schedule, 1, time, ref, repeatTime, callback); + return ref; +} + +function _schedule(time: {hour?: number, minute?: number} | undefined | number, ref: number, repeatTime, callback) { + if (!scheduleList[ref]) return; + callback(); + let targetTime: number; + if ( time === undefined) { + targetTime = new Date().setMilliseconds(0) + repeatTime * 1000; + } else if (typeof time === 'number') { + targetTime = time + repeatTime * 1000; + } else { + time.hour = time.hour !== undefined ? time.hour : 0; + time.minute = time.minute !== undefined ? time.minute : 0; + targetTime = time.hour !== undefined ? new Date().setHours(time.hour, time.minute, 0) : new Date().setMinutes(time.minute, 0); + if (new Date().getTime() > targetTime) { + targetTime += repeatTime * 1000; + } + } + const timeout = targetTime - new Date().getTime(); + scheduleList[ref] = setTimeout(_schedule, timeout, targetTime, ref, repeatTime, callback); +} +function _clearSchedule(ref: number): null { + if (scheduleList[ref]) clearTimeout(scheduleList[ref]); + delete scheduleList[ref]; + return null; +} const ArrayPlayerTypeWithMediaDevice = ['alexa2', 'sonos', 'squeezeboxrpc'] as const const ArrayPlayerTypeWithOutMediaDevice = ['spotify-premium', 'volumio', 'bosesoundtouch'] as const @@ -9844,7 +9903,8 @@ namespace NSPanel { setThermoAlias?: string[], setThermoDestTemp2?: string, } & PageBaseItem - + // mean string start with getState(' and end with ').val + type getStateID = string; export type PageBaseItem = { id?: string | null, icon?: string, @@ -9866,7 +9926,7 @@ namespace NSPanel { stepValue?: number, prefixName?: string, suffixName?: string, - name?: string, + name?: string | getStateID, secondRow?: string, buttonText?: string, unit?: string, From e45560c27f13a7fd1dad855c0ffe449b4b33320c Mon Sep 17 00:00:00 2001 From: ticaki Date: Mon, 8 Jan 2024 20:22:41 +0100 Subject: [PATCH 64/99] add relays show status --- ioBroker/DEV/NSPanelTs.ts | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index d11d2538..381f6e01 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.34 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.35 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -93,6 +93,7 @@ ReleaseNotes: - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity - 07.01.2024 - v4.3.3.33 Fix BoseSoundtouch Proto - 08.01.2024 - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) + - 08.01.2024 - v4.3.3.35 Add: relay.1/relay.2 show the confirmed status Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -203,6 +204,7 @@ let Debug: boolean = false; // EN: Adapt to the MQTT adapter instance directories const NSPanelReceiveTopic: string = 'mqtt.0.SmartHome.NSPanel_1.tele.RESULT'; const NSPanelSendTopic: string = 'mqtt.0.SmartHome.NSPanel_1.cmnd.CustomSend'; + NSPanelStateTopic = 'mqtt.0.SmartHome.NSPanel_1.stat' // DE: nur ändern, falls der User im Tasmota vor dem Kompilieren umbenannt wurde (Standard Tasmota: admin) // EN: only change if the user was renamed in Tasmota before compiling (default Tasmota: admin) @@ -956,7 +958,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.34'; +const scriptVersion: string = 'v4.3.3.35'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -970,6 +972,9 @@ let weatherForecast: boolean; let pageCounter: number = 0; let alwaysOn: boolean = false; +var NSPanelStateTopic = NSPanelStateTopic !== undefined ? NSPanelStateTopic : '' + + const axios = require('axios'); const dayjs = require('dayjs'); const moment = require('moment'); @@ -1725,8 +1730,20 @@ on({id: [String(NSPanel_Path) + 'Config.Dateformat.Switch.weekday', } }); +//Set Relays from Tasmota +if (NSPanelStateTopic != '') { + on({id: [String(NSPanelStateTopic) + '.POWER1',String(NSPanelStateTopic) + '.POWER2'], change: "ne"}, (obj) => { + if (!obj || !obj.id) return + const n = obj.id.substring(obj.id.length-1); + if ( n === '1' || n === '2') { + if (getState(NSPanel_Path + 'Relay.' + n).val != obj.state.val) { + setState(NSPanel_Path + 'Relay.' + n, obj.state.val == 'ON' ? true : false, true); + } + } + }) +} //Control Relays from DP's -on({id: [String(NSPanel_Path) + 'Relay.1',String(NSPanel_Path) + 'Relay.2'], change: "ne"}, async function (obj) { +on({id: [String(NSPanel_Path) + 'Relay.1',String(NSPanel_Path) + 'Relay.2'], change: "ne", ack: false}, async function (obj) { try { let Button = obj.id!.split('.'); let urlString: string = ['http://',get_current_tasmota_ip_address(),'/cm?cmnd=Power',Button[Button.length - 1],' ',(obj.state ? obj.state.val : "")].join(''); From 2621b22ffdfe0b56b6cd1bed218c6139caa9c14e Mon Sep 17 00:00:00 2001 From: ticaki Date: Mon, 8 Jan 2024 21:55:53 +0100 Subject: [PATCH 65/99] fix schedule --- ioBroker/DEV/NSPanelTs.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 381f6e01..72eeb1c7 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1021,13 +1021,13 @@ let scheduleInitDimModeDay: any; let scheduleInitDimModeNight: any; onStop (function scriptStop () { - if (scheduleSendTime!=null) clearSchedule(scheduleSendTime); - if (scheduleSendDate!=null) clearSchedule(scheduleSendDate); - if (scheduleSwichScreensaver!=null) clearSchedule(scheduleSwichScreensaver); - if (scheduleStartup!=null) clearSchedule(scheduleStartup); - if (scheduleCheckUpdates!=null) clearSchedule(scheduleCheckUpdates); - if (scheduleInitDimModeDay!=null) clearSchedule(scheduleInitDimModeDay); - if (scheduleInitDimModeNight!=null) clearSchedule(scheduleInitDimModeNight); + if (scheduleSendTime!=null) _clearSchedule(scheduleSendTime); + if (scheduleSendDate!=null) _clearSchedule(scheduleSendDate); + if (scheduleSwichScreensaver!=null) _clearSchedule(scheduleSwichScreensaver); + if (scheduleStartup!=null) _clearSchedule(scheduleStartup); + if (scheduleCheckUpdates!=null) _clearSchedule(scheduleCheckUpdates); + if (scheduleInitDimModeDay!=null) _clearSchedule(scheduleInitDimModeDay); + if (scheduleInitDimModeNight!=null) _clearSchedule(scheduleInitDimModeNight); UnsubscribeWatcher(); }, 1000); @@ -9680,13 +9680,13 @@ type PageAlarm = NSPanel.PageAlarm; function adapterSchedule(time: {hour?: number, minute?: number} | undefined | number, repeatTime: number, callback: () => void): number|null { if (typeof callback !== 'function') return null const ref = Math.random() + 1; - scheduleList[ref] = setTimeout(_schedule, 1, time, ref, repeatTime, callback); + scheduleList[ref] = setTimeout(_schedule, 1, time, ref, repeatTime, callback), true; return ref; } -function _schedule(time: {hour?: number, minute?: number} | undefined | number, ref: number, repeatTime, callback) { +function _schedule(time: {hour?: number, minute?: number} | undefined | number, ref: number, repeatTime, callback, init: boolean = false) { if (!scheduleList[ref]) return; - callback(); + if (!init) callback(); let targetTime: number; if ( time === undefined) { targetTime = new Date().setMilliseconds(0) + repeatTime * 1000; @@ -9707,7 +9707,7 @@ function _clearSchedule(ref: number): null { if (scheduleList[ref]) clearTimeout(scheduleList[ref]); delete scheduleList[ref]; return null; -} +} const ArrayPlayerTypeWithMediaDevice = ['alexa2', 'sonos', 'squeezeboxrpc'] as const const ArrayPlayerTypeWithOutMediaDevice = ['spotify-premium', 'volumio', 'bosesoundtouch'] as const From aa3e90ef9896ce3e0110f03001c81c7b53d61202 Mon Sep 17 00:00:00 2001 From: ticaki Date: Mon, 8 Jan 2024 22:23:06 +0100 Subject: [PATCH 66/99] Get dp from NSPanelSendTopic --- ioBroker/DEV/NSPanelTs.ts | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 72eeb1c7..c9d7d60c 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -204,7 +204,6 @@ let Debug: boolean = false; // EN: Adapt to the MQTT adapter instance directories const NSPanelReceiveTopic: string = 'mqtt.0.SmartHome.NSPanel_1.tele.RESULT'; const NSPanelSendTopic: string = 'mqtt.0.SmartHome.NSPanel_1.cmnd.CustomSend'; - NSPanelStateTopic = 'mqtt.0.SmartHome.NSPanel_1.stat' // DE: nur ändern, falls der User im Tasmota vor dem Kompilieren umbenannt wurde (Standard Tasmota: admin) // EN: only change if the user was renamed in Tasmota before compiling (default Tasmota: admin) @@ -972,9 +971,6 @@ let weatherForecast: boolean; let pageCounter: number = 0; let alwaysOn: boolean = false; -var NSPanelStateTopic = NSPanelStateTopic !== undefined ? NSPanelStateTopic : '' - - const axios = require('axios'); const dayjs = require('dayjs'); const moment = require('moment'); @@ -1730,18 +1726,17 @@ on({id: [String(NSPanel_Path) + 'Config.Dateformat.Switch.weekday', } }); -//Set Relays from Tasmota -if (NSPanelStateTopic != '') { - on({id: [String(NSPanelStateTopic) + '.POWER1',String(NSPanelStateTopic) + '.POWER2'], change: "ne"}, (obj) => { - if (!obj || !obj.id) return - const n = obj.id.substring(obj.id.length-1); - if ( n === '1' || n === '2') { - if (getState(NSPanel_Path + 'Relay.' + n).val != obj.state.val) { - setState(NSPanel_Path + 'Relay.' + n, obj.state.val == 'ON' ? true : false, true); - } +//Set Relays from Tasmota +const NSPanelStatTopic = NSPanelSendTopic.replace('.tele.','.stat.').replace('.CustomSend','.'); +on({id: [String(NSPanelStatTopic) + 'POWER1',String(NSPanelStatTopic) + 'POWER2'], change: "ne"}, (obj) => { + if (!obj || !obj.id) return + const n = obj.id.substring(obj.id.length-1); + if ( n === '1' || n === '2') { + if (getState(NSPanel_Path + 'Relay.' + n).val != obj.state.val) { + setState(NSPanel_Path + 'Relay.' + n, obj.state.val == 'ON' ? true : false, true); } - }) -} + } +}) //Control Relays from DP's on({id: [String(NSPanel_Path) + 'Relay.1',String(NSPanel_Path) + 'Relay.2'], change: "ne", ack: false}, async function (obj) { try { From fd3ce243a6aff7f95ee9967172d67bcaa4a1ad48 Mon Sep 17 00:00:00 2001 From: ticaki Date: Mon, 8 Jan 2024 22:29:08 +0100 Subject: [PATCH 67/99] update on replace --- ioBroker/DEV/NSPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index c9d7d60c..85da63ad 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1727,7 +1727,7 @@ on({id: [String(NSPanel_Path) + 'Config.Dateformat.Switch.weekday', }); //Set Relays from Tasmota -const NSPanelStatTopic = NSPanelSendTopic.replace('.tele.','.stat.').replace('.CustomSend','.'); +const NSPanelStatTopic = NSPanelSendTopic.replace('.cmnd.','.stat.').replace(/\.CustomSend$/g,'.'); on({id: [String(NSPanelStatTopic) + 'POWER1',String(NSPanelStatTopic) + 'POWER2'], change: "ne"}, (obj) => { if (!obj || !obj.id) return const n = obj.id.substring(obj.id.length-1); From ce0892b98679cf5e4bce7751c31b66113fc8ff88 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 9 Jan 2024 21:09:43 +0100 Subject: [PATCH 68/99] Fixed: update every minute Fixed: Schedule: {hour: minutes:} works with summer/winter time --- ioBroker/DEV/NSPanelTs.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 85da63ad..6d112d7d 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1397,7 +1397,7 @@ async function Init_Screensaver_Backckground_Color_Switch() { type: "number", name: "Color Indicator", role: "level", - states: {0:'black', 1:'red', 2:'green', 3:'attention', 4: 'pink'}, + states: {0:'black', 1:'red', 2:'green', 3:'attention', 4: 'pink', 5: 'dark red'}, read: true, write: true }, @@ -2175,7 +2175,7 @@ let pageId = 0; let activePage: PageType | undefined = undefined; //Send time to NSPanel -let scheduleSendTime = adapterSchedule(new Date().setMilliseconds(0), 1, () => { +let scheduleSendTime = adapterSchedule(new Date().setSeconds(0,0), 60, () => { try { SendTime(); HandleScreensaverUpdate(); @@ -9062,8 +9062,10 @@ function HandleScreensaverColors(): void { scrSvrBGCol = rgb_dec565(scbackgroundInd3); } else if (bgColorScrSaver == 4) { scrSvrBGCol = rgb_dec565({red:255, green:16, blue:240}); + } else if (bgColorScrSaver == 5) { + scrSvrBGCol = rgb_dec565({ red: 100, green: 0, blue: 0 }); } - + let payloadString = 'color' + '~' + scrSvrBGCol + '~' + //background rgb_dec565(sctime) + '~' + //time @@ -9671,7 +9673,13 @@ type PageAlarm = NSPanel.PageAlarm; -// dont work with summer/winter time has to be fixed +/** + * + * @param time object: { hour: number, minutes: number } | starttime + * @param repeatTime in ms + * @param callback what todo + * @returns + */ function adapterSchedule(time: {hour?: number, minute?: number} | undefined | number, repeatTime: number, callback: () => void): number|null { if (typeof callback !== 'function') return null const ref = Math.random() + 1; @@ -9688,11 +9696,12 @@ function _schedule(time: {hour?: number, minute?: number} | undefined | number, } else if (typeof time === 'number') { targetTime = time + repeatTime * 1000; } else { - time.hour = time.hour !== undefined ? time.hour : 0; + time.hour = time.hour !== undefined ? time.hour : 1; time.minute = time.minute !== undefined ? time.minute : 0; - targetTime = time.hour !== undefined ? new Date().setHours(time.hour, time.minute, 0) : new Date().setMinutes(time.minute, 0); + targetTime = time.hour !== -1 ? new Date().setHours(time.hour, time.minute, 0) : new Date().setMinutes(time.minute, 0); if (new Date().getTime() > targetTime) { targetTime += repeatTime * 1000; + targetTime = time.hour !== -1 ? new Date(targetTime).setHours(time.hour, time.minute, 0) : new Date(targetTime).setMinutes(time.minute, 0); } } const timeout = targetTime - new Date().getTime(); From dd14e66f106e42036cd65d938133eee778ab9ad3 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 9 Jan 2024 21:24:52 +0100 Subject: [PATCH 69/99] update summer/winter fix --- ioBroker/DEV/NSPanelTs.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 6d112d7d..a5828915 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -9693,8 +9693,10 @@ function _schedule(time: {hour?: number, minute?: number} | undefined | number, let targetTime: number; if ( time === undefined) { targetTime = new Date().setMilliseconds(0) + repeatTime * 1000; + time = targetTime; } else if (typeof time === 'number') { targetTime = time + repeatTime * 1000; + time = targetTime; } else { time.hour = time.hour !== undefined ? time.hour : 1; time.minute = time.minute !== undefined ? time.minute : 0; @@ -9705,7 +9707,7 @@ function _schedule(time: {hour?: number, minute?: number} | undefined | number, } } const timeout = targetTime - new Date().getTime(); - scheduleList[ref] = setTimeout(_schedule, timeout, targetTime, ref, repeatTime, callback); + scheduleList[ref] = setTimeout(_schedule, timeout, time, ref, repeatTime, callback); } function _clearSchedule(ref: number): null { if (scheduleList[ref]) clearTimeout(scheduleList[ref]); From 14e944885fbb96277ec0b8d9c3fb29806119346d Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Tue, 9 Jan 2024 22:37:18 +0100 Subject: [PATCH 70/99] v4.3.3.36 Update NSPanel.ts - Fix: change ScreensaverTimeout and activeBrightness - Fix: schedule SendTime - Fix: Function _schedule SummerTime/WinterTime --- ioBroker/DEV/NSPanelTs.ts | 52 +++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index a5828915..5c4f601f 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.35 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.36 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -89,11 +89,14 @@ ReleaseNotes: - 04.01.2024 - v4.3.3.32 Add more details to types for: leftScreensaverEntity, indicatorScreensaverEntity, PageThermo, PageMedia - 04.01.2024 - v4.3.3.32 Remove not uses propertys from PageItem - 05.01.2024 - v4.3.3.32 Add Body for BoseSoundtouch-Player - - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions - - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity - - 07.01.2024 - v4.3.3.33 Fix BoseSoundtouch Proto - - 08.01.2024 - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) - - 08.01.2024 - v4.3.3.35 Add: relay.1/relay.2 show the confirmed status + - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions + - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity + - 07.01.2024 - v4.3.3.33 Fix BoseSoundtouch Proto + - 08.01.2024 - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) + - 08.01.2024 - v4.3.3.35 Add: relay.1/relay.2 show the confirmed status + - 09.01.2024 - v4.3.3.36 Fix: change ScreensaverTimeout and activeBrightness + - 09.01.2024 - v4.3.3.36 Fix: schedule SendTime + - 09.01.2024 - v4.3.3.36 Fix: Function _schedule SummerTime/WinterTime Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -912,10 +915,11 @@ export const config: Config = { ScreensaverEntityOnColor: On, ScreensaverEntityOffColor: HMIOff }, - // ------ DE: Ende der Screensaver Einstellungen -------------------- - // ------ EN: End of screensaver settings --------------------------- - //-------DE: Anfang Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- - //-------EN: Start Settings for Hardware Button, if used in software (Rule2) -------------------------------------- +// ------ DE: Ende der Screensaver Einstellungen -------------------- +// ------ EN: End of screensaver settings --------------------------- + +//-------DE: Anfang Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- +//-------EN: Start Settings for Hardware Button, if used in software (Rule2) -------------------------------------- // DE: Konfiguration des linken Schalters des NSPanels // EN: Configuration of the left switch of the NSPanel button1: { @@ -941,8 +945,10 @@ export const config: Config = { entity: null, setValue: null }, - //--------- DE: Ende - Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- - //--------- EN: End - settings for hardware button if they are used in software (Rule2) ------------------------------ + +//--------- DE: Ende - Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- +//--------- EN: End - settings for hardware button if they are used in software (Rule2) ------------------------------ + // DE: WICHTIG !! Parameter nicht ändern WICHTIG!! // EN: IMPORTANT !! Do not change parameters IMPORTANT!! panelRecvTopic: NSPanelReceiveTopic, @@ -957,7 +963,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.35'; +const scriptVersion: string = 'v4.3.3.36'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -1493,6 +1499,19 @@ async function InitActiveBrightness() { } InitActiveBrightness(); +on({id: [NSPanel_Path + 'ScreensaverInfo.activeBrightness'], change: 'ne'}, async function (obj) { + try { + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val; + if (obj.state.val >= 0 || obj.state.val <= 100) { + log('action at trigger activeBrightness: ' + obj.state.val + ' - activeDimmodeBrightness: ' + active, 'info'); + SendToPanel({ payload: 'dimmode~' + active + '~' + obj.state.val + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); + InitDimmode(); + } + } catch (err:any) { + log('error at trigger activeBrightness: ' + err.message, 'warn'); + } +}); + on({id: [NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness'], change: "ne"}, async function (obj) { try { let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val; @@ -6241,11 +6260,8 @@ function HandleButtonEvent(words: any): void { if (words[2] == 'bNext' || words[2] == 'bPrev' || words[2] == 'bUp' || words[2] == 'bHome' || words[2] == 'bSubNext' || words[2] == 'bSubPrev' ) { buttonAction = words[2]; pageCounter = 0; - // Turn off the display if the alwaysOnDisplay parameter was specified - if (alwaysOn == true) { - alwaysOn = false; - SendToPanel({ payload: 'timeout~' + getState(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver').val }); - } + alwaysOn = false; + SendToPanel({ payload: 'timeout~' + getState(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver').val }); } if (Debug) { From d6d12bc93cfcc402928443a73cc995804eb68202 Mon Sep 17 00:00:00 2001 From: ticaki Date: Wed, 10 Jan 2024 22:19:44 +0100 Subject: [PATCH 71/99] Fixed: schedule with objects starts only 1 time --- ioBroker/DEV/NSPanelTs.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index a5828915..dce70644 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -9675,8 +9675,8 @@ type PageAlarm = NSPanel.PageAlarm; /** * - * @param time object: { hour: number, minutes: number } | starttime - * @param repeatTime in ms + * @param time object { hour: number, minutes: number } | number: Time as number in ms + * @param repeatTime in seconds * @param callback what todo * @returns */ @@ -9687,7 +9687,7 @@ function adapterSchedule(time: {hour?: number, minute?: number} | undefined | nu return ref; } -function _schedule(time: {hour?: number, minute?: number} | undefined | number, ref: number, repeatTime, callback, init: boolean = false) { +function _schedule(time: {hour?: number, minute?: number} | undefined | number, ref: number, repeatTime: number, callback, init: boolean = false) { if (!scheduleList[ref]) return; if (!init) callback(); let targetTime: number; @@ -9698,12 +9698,12 @@ function _schedule(time: {hour?: number, minute?: number} | undefined | number, targetTime = time + repeatTime * 1000; time = targetTime; } else { - time.hour = time.hour !== undefined ? time.hour : 1; + time.hour = time.hour !== undefined ? time.hour : -1; time.minute = time.minute !== undefined ? time.minute : 0; - targetTime = time.hour !== -1 ? new Date().setHours(time.hour, time.minute, 0) : new Date().setMinutes(time.minute, 0); - if (new Date().getTime() > targetTime) { + targetTime = time.hour !== -1 ? new Date().setHours(time.hour, time.minute, 0, 0) : new Date().setMinutes(time.minute, 0, 0); + if (new Date().getTime() >= targetTime) { targetTime += repeatTime * 1000; - targetTime = time.hour !== -1 ? new Date(targetTime).setHours(time.hour, time.minute, 0) : new Date(targetTime).setMinutes(time.minute, 0); + targetTime = time.hour !== -1 ? new Date(targetTime).setHours(time.hour, time.minute, 0, 0) : new Date(targetTime).setMinutes(time.minute, 0, 0); } } const timeout = targetTime - new Date().getTime(); From 7194d7f6133ec6924e9ba159e592dfc807cdf67d Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Wed, 10 Jan 2024 22:31:29 +0100 Subject: [PATCH 72/99] v4.3.3.36 - Update NSPanelTs.ts Fix Alexa Elapsed --- ioBroker/DEV/NSPanelTs.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 9c4bfa5e..3e9c9ca0 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -5130,6 +5130,9 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { vElapsed = vElapsed.slice(1); } } + if (vElapsed == 0) { + vElapsed = '0:00'; + } let vDuration = Duration; if (vDuration.length == 5) { if(parseInt(vDuration.slice(0,2)) < 9) { From 60f31595d42be209d5e4f4bf3fa949b0354e0bc2 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Wed, 10 Jan 2024 22:39:48 +0100 Subject: [PATCH 73/99] v4.3.3.36 - Update NSPanelTs.ts --- ioBroker/DEV/NSPanelTs.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 3e9c9ca0..94f7defc 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -5130,8 +5130,8 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { vElapsed = vElapsed.slice(1); } } - if (vElapsed == 0) { - vElapsed = '0:00'; + if (vElapsed == 0) { + vElapsed = '0:00'; } let vDuration = Duration; if (vDuration.length == 5) { From c36202878f93d27151387572b3d59388c9754f74 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Thu, 11 Jan 2024 12:00:26 +0100 Subject: [PATCH 74/99] Update ioBroker_NSPanel_locales_service.json --- ioBroker/ioBroker_NSPanel_locales_service.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ioBroker/ioBroker_NSPanel_locales_service.json b/ioBroker/ioBroker_NSPanel_locales_service.json index f122caf7..cd402b6d 100644 --- a/ioBroker/ioBroker_NSPanel_locales_service.json +++ b/ioBroker/ioBroker_NSPanel_locales_service.json @@ -2697,5 +2697,9 @@ "update_message":{ "en-US":"Update Notifications", "de-DE":"Update Mitteilungen" + }, + "scriptname":{ + "en-US":"Script name", + "de-DE":"Skriptname" } } From bc69af7b6b3c362ae2fb03d83b84484dd318a576 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Thu, 11 Jan 2024 12:51:34 +0100 Subject: [PATCH 75/99] v4.3.3.36 - Update NSPanelTs.ts Add common write false/true --- ioBroker/DEV/NSPanelTs.ts | 216 +++++++++++++++++++------------------- 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 94f7defc..14dad67e 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -89,10 +89,10 @@ ReleaseNotes: - 04.01.2024 - v4.3.3.32 Add more details to types for: leftScreensaverEntity, indicatorScreensaverEntity, PageThermo, PageMedia - 04.01.2024 - v4.3.3.32 Remove not uses propertys from PageItem - 05.01.2024 - v4.3.3.32 Add Body for BoseSoundtouch-Player - - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions - - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity - - 07.01.2024 - v4.3.3.33 Fix BoseSoundtouch Proto - - 08.01.2024 - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) + - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions + - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity + - 07.01.2024 - v4.3.3.33 Fix BoseSoundtouch Proto + - 08.01.2024 - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) - 08.01.2024 - v4.3.3.35 Add: relay.1/relay.2 show the confirmed status - 09.01.2024 - v4.3.3.36 Fix: change ScreensaverTimeout and activeBrightness - 09.01.2024 - v4.3.3.36 Fix: schedule SendTime @@ -1117,19 +1117,19 @@ async function InitIoBrokerInfo() { try { if (isSetOptionActive) { // Script Version - await createStateAsync(NSPanel_Path + 'IoBroker.ScriptVersion', scriptVersion, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'IoBroker.ScriptVersion', scriptVersion, { type: 'string', write: false }); setObject(AliasPath + 'IoBroker.ScriptVersion', {type: 'channel', common: {role: 'info', name:'Version NSPanelTS'}, native: {}}); await createAliasAsync(AliasPath + 'IoBroker.ScriptVersion.ACTUAL', NSPanel_Path + 'IoBroker.ScriptVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); // NodeJS Verion - await createStateAsync(NSPanel_Path + 'IoBroker.NodeJSVersion', 'v' + nodeVersion, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'IoBroker.NodeJSVersion', 'v' + nodeVersion, { type: 'string', write: false }); setObject(AliasPath + 'IoBroker.NodeJSVersion', {type: 'channel', common: {role: 'info', name:'Version NodeJS'}, native: {}}); await createAliasAsync(AliasPath + 'IoBroker.NodeJSVersion.ACTUAL', NSPanel_Path + 'IoBroker.NodeJSVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); // JavaScript Version - await createStateAsync(NSPanel_Path + 'IoBroker.JavaScriptVersion', 'v' + javaScriptVersion, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'IoBroker.JavaScriptVersion', 'v' + javaScriptVersion, { type: 'string', write: false }); setObject(AliasPath + 'IoBroker.JavaScriptVersion', {type: 'channel', common: {role: 'info', name:'Version JavaScript Instanz'}, native: {}}); await createAliasAsync(AliasPath + 'IoBroker.JavaScriptVersion.ACTUAL', NSPanel_Path + 'IoBroker.JavaScriptVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); // ScriptName - await createStateAsync(NSPanel_Path + 'IoBroker.ScriptName', 'v' + javaScriptVersion, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'IoBroker.ScriptName', 'v' + javaScriptVersion, { type: 'string', write: false }); setObject(AliasPath + 'IoBroker.ScriptName', {type: 'channel', common: {role: 'info', name:'Scriptname'}, native: {}}); await createAliasAsync(AliasPath + 'IoBroker.ScriptName.ACTUAL', NSPanel_Path + 'IoBroker.ScriptName', true, { type: 'string', role: 'state', name: 'ACTUAL' }); } @@ -1143,7 +1143,7 @@ InitIoBrokerInfo(); async function CheckDebugMode() { try { if (isSetOptionActive) { - await createStateAsync(NSPanel_Path + 'Config.ScripgtDebugStatus', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.ScripgtDebugStatus', false, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.ScripgtDebugStatus', {type: 'channel', common: {role: 'socket', name:'ScripgtDebugStatus'}, native: {}}); await createAliasAsync(AliasPath + 'Config.ScripgtDebugStatus.ACTUAL', NSPanel_Path + 'Config.ScripgtDebugStatus', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.ScripgtDebugStatus.SET', NSPanel_Path + 'Config.ScripgtDebugStatus', true, { type: 'boolean', role: 'switch', name: 'SET' }); @@ -1168,7 +1168,7 @@ async function CheckMQTTPorts() { let instanceName: string = config.panelRecvTopic.substring(0,6); if (isSetOptionActive) { - await createStateAsync(NSPanel_Path + 'Config.MQTT.portCheck', true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.MQTT.portCheck', true, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.MQTT.portCheck', {type: 'channel', common: {role: 'socket', name:'mqttPortCheck'}, native: {}}); await createAliasAsync(AliasPath + 'Config.MQTT.portCheck.ACTUAL', NSPanel_Path + 'Config.MQTT.portCheck', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.MQTT.portCheck.SET', NSPanel_Path + 'Config.MQTT.portCheck', true, { type: 'boolean', role: 'switch', name: 'SET' }); @@ -1226,13 +1226,13 @@ async function Init_Release() { const FWRelease = ['3.3.1','3.4.0','3.5.0','3.5.X','3.6.0','3.7.3','3.8.0','3.8.3','3.9.4','4.0.5','4.1.4','4.2.1','4.3.3','4.4.0','4.5.0']; try { if (existsObject(NSPanel_Path + 'Display_Firmware.desiredVersion') == false) { - await createStateAsync(NSPanel_Path + 'Display_Firmware.desiredVersion', desired_display_firmware_version, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Display_Firmware.desiredVersion', desired_display_firmware_version, { type: 'number', write: false }); } else { await setStateAsync(NSPanel_Path + 'Display_Firmware.desiredVersion', desired_display_firmware_version); } if (existsObject(NSPanel_Path + 'Config.Update.activ') == false) { - await createStateAsync(NSPanel_Path + 'Config.Update.activ', 1, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Config.Update.activ', 1, { type: 'number', write: false }); } else { await setStateAsync(NSPanel_Path + 'Config.Update.activ', 0); } @@ -1249,8 +1249,8 @@ async function Init_Release() { if (existsObject(NSPanel_Path + 'Display_Firmware.TFT.desiredVersion') == false) { //Create TFT DP's if (isSetOptionActive) { - await createStateAsync(NSPanel_Path + 'Display_Firmware.TFT.currentVersion', currentFW + ' / v' + FWRelease[findFWIndex], { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Display_Firmware.TFT.desiredVersion', desired_display_firmware_version, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Display_Firmware.TFT.currentVersion', currentFW + ' / v' + FWRelease[findFWIndex], { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Display_Firmware.TFT.desiredVersion', desired_display_firmware_version, { type: 'string', write: false }); setObject(AliasPath + 'Display_Firmware.TFT.currentVersion', {type: 'channel', common: {role: 'info', name:'current TFT-Version'}, native: {}}); setObject(AliasPath + 'Display_Firmware.TFT.desiredVersion', {type: 'channel', common: {role: 'info', name:'desired TFT-Version'}, native: {}}); await createAliasAsync(AliasPath + 'Display_Firmware.TFT.currentVersion.ACTUAL', NSPanel_Path + 'Display_Firmware.TFT.currentVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); @@ -1271,54 +1271,54 @@ async function InitConfigParameters() { try { if (isSetOptionActive) { // alternativeScreensaverLayout (socket) - await createStateAsync(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', false, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.Screensaver.alternativeScreensaverLayout', {type: 'channel', common: {role: 'socket', name:'alternativeScreensaverLayout'}, native: {}}); await createAliasAsync(AliasPath + 'Config.Screensaver.alternativeScreensaverLayout.ACTUAL', NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.Screensaver.alternativeScreensaverLayout.SET', NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', true, { type: 'boolean', role: 'switch', name: 'SET' }); - await createStateAsync(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.Screensaver.ScreensaverAdvanced', {type: 'channel', common: {role: 'socket', name:'ScreensaverAdvanced'}, native: {}}); await createAliasAsync(AliasPath + 'Config.Screensaver.ScreensaverAdvanced.ACTUAL', NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.Screensaver.ScreensaverAdvanced.SET', NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', true, { type: 'boolean', role: 'switch', name: 'SET' }); // autoWeatherColorScreensaverLayout (socket) - await createStateAsync(NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout', true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout', true, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout', {type: 'channel', common: {role: 'socket', name:'alternativeScreensaverLayout'}, native: {}}); await createAliasAsync(AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout.ACTUAL', NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout.SET', NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout', true, { type: 'boolean', role: 'switch', name: 'SET' }); // timeoutScreensaver 0-60 (Slider) - await createStateAsync(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver', 10, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver', 10, { type: 'number', write: true }); setObject(AliasPath + 'Config.Screensaver.timeoutScreensaver', {type: 'channel', common: {role: 'slider', name:'timeoutScreensaver'}, native: {}}); await createAliasAsync(AliasPath + 'Config.Screensaver.timeoutScreensaver.ACTUAL', NSPanel_Path + 'Config.Screensaver.timeoutScreensaver', true, { type: 'number', role: 'value', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.Screensaver.timeoutScreensaver.SET', NSPanel_Path + 'Config.Screensaver.timeoutScreensaver', true, { type: 'number', role: 'level', name: 'SET' }); // screenSaverDoubleClick (socket) - await createStateAsync(NSPanel_Path + 'Config.Screensaver.screenSaverDoubleClick', true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Screensaver.screenSaverDoubleClick', true, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.Screensaver.screenSaverDoubleClick', {type: 'channel', common: {role: 'socket', name:'screenSaverDoubleClick'}, native: {}}); await createAliasAsync(AliasPath + 'Config.Screensaver.screenSaverDoubleClick.ACTUAL', NSPanel_Path + 'Config.Screensaver.screenSaverDoubleClick', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.Screensaver.screenSaverDoubleClick.SET', NSPanel_Path + 'Config.Screensaver.screenSaverDoubleClick', true, { type: 'boolean', role: 'switch', name: 'SET' }); if (existsObject(NSPanel_Path + 'Config.locale') == false) { // en-US, de-DE, nl-NL, da-DK, es-ES, fr-FR, it-IT, ru-RU, etc. - await createStateAsync(NSPanel_Path + 'Config.locale', 'de-DE', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Config.locale', 'de-DE', { type: 'string', write: true }); setStateAsync(NSPanel_Path + 'Config.locale', 'de-DE'); } if (existsObject(NSPanel_Path + 'Config.temperatureUnit') == false) { // '°C', '°F', 'K' - await createStateAsync(NSPanel_Path + 'Config.temperatureUnit', '°C', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Config.temperatureUnit', '°C', { type: 'string', write: true }); } // locale Tastensensor popupInSel buttonSensor if (existsObject(NSPanel_Path + 'Config.localeNumber') == false) { - await createStateAsync(NSPanel_Path + 'Config.localeNumber', 1, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Config.localeNumber', 1, { type: 'number', write: true }); setObject(AliasPath + 'Config.localeNumber', {type: 'channel', common: {role: 'buttonSensor', name:'localeNumber'}, native: {}}); await createAliasAsync(AliasPath + 'Config.localeNumber.VALUE', NSPanel_Path + 'Config.localeNumber', true, { type: 'number', role: 'state', name: 'VALUE' }); } // temperatureUnit popupInSel buttonSensor if (existsObject(NSPanel_Path + 'Config.temperatureUnitNumber') == false) { - await createStateAsync(NSPanel_Path + 'Config.temperatureUnitNumber', 0, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Config.temperatureUnitNumber', 0, { type: 'number', write: true }); setObject(AliasPath + 'Config.temperatureUnitNumber', {type: 'channel', common: {role: 'buttonSensor', name:'temperatureUnitNumber'}, native: {}}); await createAliasAsync(AliasPath + 'Config.temperatureUnitNumber.VALUE', NSPanel_Path + 'Config.temperatureUnitNumber', true, { type: 'number', role: 'state', name: 'VALUE' }); } @@ -1361,7 +1361,7 @@ on({id: [NSPanel_Path + 'Config.localeNumber', async function Init_ScreensaverAdvanced() { try { if (existsState(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced') == false ) { - await createStateAsync(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false, true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false, true, { type: 'boolean', write: true }); } } catch (err: any) { log('error at function Init_ScreensaverAdvanced: ' + err.message, 'warn'); @@ -1379,13 +1379,13 @@ function CheckEnableSetObject() { async function Init_ActivePageData() { try { if (existsState(NSPanel_Path + 'ActivePage.heading') == false ) { - await createStateAsync(NSPanel_Path + 'ActivePage.heading', '', true, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'ActivePage.heading', '', true, { type: 'string', write: false }); } if (existsState(NSPanel_Path + 'ActivePage.type') == false ) { - await createStateAsync(NSPanel_Path + 'ActivePage.type', '', true, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'ActivePage.type', '', true, { type: 'string', write: false }); } if (existsState(NSPanel_Path + 'ActivePage.id0') == false ) { - await createStateAsync(NSPanel_Path + 'ActivePage.id0', '', true, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'ActivePage.id0', '', true, { type: 'string', write: false }); } } catch (err: any) { log('error at function Init_ActivePageData: ' + err.message, 'warn'); @@ -1460,7 +1460,7 @@ async function Init_bExit_Page_Change() { alwaysOn = false; pageCounter = 0; if (existsState(NSPanel_Path + 'ScreensaverInfo.bExitPage') == false ) { - await createStateAsync(NSPanel_Path + 'ScreensaverInfo.bExitPage', -1, true, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.bExitPage', -1, true, { type: 'number', write: true }); } } catch (err: any) { log('error at function Init_bExit_Page_Change: ' + err.message, 'warn'); @@ -1472,7 +1472,7 @@ Init_bExit_Page_Change(); async function Init_Dimmode_Trigger() { try { if (existsState(NSPanel_Path + 'ScreensaverInfo.Trigger_Dimmode') == false ) { - await createStateAsync(NSPanel_Path + 'ScreensaverInfo.Trigger_Dimmode', false, true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.Trigger_Dimmode', false, true, { type: 'boolean', write: true }); } } catch (err: any) { log('error at function Init_Dimmode_Trigger: ' + err.message, 'warn'); @@ -1485,8 +1485,8 @@ async function InitActiveBrightness() { if (isSetOptionActive) { if (existsState(NSPanel_Path + 'ScreensaverInfo.activeBrightness') == false || existsState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness') == false) { - await createStateAsync(NSPanel_Path + 'ScreensaverInfo.activeBrightness', 100, { type: 'number' }); - await createStateAsync(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness', -1, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.activeBrightness', 100, { type: 'number', write: true }); + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness', -1, { type: 'number', write: true }); } //Create Alias activeBrightness setObject(AliasPath + 'ScreensaverInfo.activeBrightness', {type: 'channel', common: {role: 'slider', name:'activeBrightness'}, native: {}}); @@ -1558,7 +1558,7 @@ on({id: String(NSPanel_Path) + 'ScreensaverInfo.Trigger_Dimmode', change: "ne"}, async function InitRebootPanel() { try { if (existsState(NSPanel_Path + 'Config.rebootNSPanel') == false) { - await createStateAsync(NSPanel_Path + 'Config.rebootNSPanel', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.rebootNSPanel', false, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.rebootNSPanel', {type: 'channel', common: {role: 'button', name:'Reboot NSPanel'}, native: {}}); await createAliasAsync(AliasPath + 'Config.rebootNSPanel.SET', NSPanel_Path + 'Config.rebootNSPanel', true, { type: 'boolean', role: 'state', name: 'SET' }); } @@ -1607,9 +1607,9 @@ async function InitUpdateDatapoints() { try { if (existsState(NSPanel_Path + 'Config.Update.UpdateTasmota') == false) { if (isSetOptionActive) { - await createStateAsync(NSPanel_Path + 'Config.Update.UpdateTasmota', false, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + 'Config.Update.UpdateBerry', false, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + 'Config.Update.UpdateNextion', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Update.UpdateTasmota', false, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + 'Config.Update.UpdateBerry', false, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + 'Config.Update.UpdateNextion', false, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.Update.UpdateTasmota', {type: 'channel', common: {role: 'button', name:'Tassmota update'}, native: {}}); setObject(AliasPath + 'Config.Update.UpdateBerry', {type: 'channel', common: {role: 'button', name:'Berry-Driver update'}, native: {}}); setObject(AliasPath + 'Config.Update.UpdateNextion', {type: 'channel', common: {role: 'button', name:'Nextion TFT update'}, native: {}}); @@ -1653,8 +1653,8 @@ async function Init_Relays() { if (isSetOptionActive) { if (existsState(NSPanel_Path + 'Relay.1') == false || existsState(NSPanel_Path + 'Relay.2') == false) { - await createStateAsync(NSPanel_Path + 'Relay.1', true, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + 'Relay.2', true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Relay.1', true, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + 'Relay.2', true, { type: 'boolean', write: true }); } setObject(AliasPath + 'Relay.1', {type: 'channel', common: {role: 'socket', name:'Relay.1'}, native: {}}); await createAliasAsync(AliasPath + 'Relay.1.ACTUAL', NSPanel_Path + 'Relay.1', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); @@ -1676,8 +1676,8 @@ async function InitAlternateMRIconsSize() { if (isSetOptionActive) { if (existsState(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1') == false || existsState(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2') == false) { - await createStateAsync(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1', false, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1', false, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2', false, { type: 'boolean', write: true }); } //Create Alias alternateMRIconSize 1 setObject(AliasPath + 'Config.MRIcons.alternateMRIconSize.1', {type: 'channel', common: {role: 'socket', name:'alternateMRIconSize.1'}, native: {}}); @@ -1701,14 +1701,14 @@ async function InitDateformat() { if (existsState(NSPanel_Path + 'Config.Dateformat.weekday') == false || existsState(NSPanel_Path + 'Config.Dateformat.month') == false || existsState(NSPanel_Path + 'Config.Dateformat.customFormat') == false) { - await createStateAsync(NSPanel_Path + 'Config.Dateformat.weekday', 'long', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Config.Dateformat.month', 'long', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Config.Dateformat.customFormat', '', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.weekday', 'long', { type: 'string', write: true }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.month', 'long', { type: 'string', write: true }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.customFormat', '', { type: 'string', write: true }); } if (existsState(NSPanel_Path + 'Config.Dateformat.Switch.weekday') == false || existsState(NSPanel_Path + 'Config.Dateformat.Switch.month') == false) { - await createStateAsync(NSPanel_Path + 'Config.Dateformat.Switch.weekday', true, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + 'Config.Dateformat.Switch.month', true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.Switch.weekday', true, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.Switch.month', true, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.Dateformat.Switch.weekday', {type: 'channel', common: {role: 'socket', name:'Dateformat Switch weekday'}, native: {}}); await createAliasAsync(AliasPath + 'Config.Dateformat.Switch.weekday.ACTUAL', NSPanel_Path + 'Config.Dateformat.Switch.weekday', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.Dateformat.Switch.weekday.SET', NSPanel_Path + 'Config.Dateformat.Switch.weekday', true, { type: 'boolean', role: 'switch', name: 'SET' }); @@ -1863,7 +1863,7 @@ CreateWeatherAlias(); async function InitPageNavi() { try { if (!existsState(NSPanel_Path + 'PageNavi')) { - await createStateAsync(NSPanel_Path + 'PageNavi', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'PageNavi', { type: 'string', write: true }); await setStateAsync(NSPanel_Path + 'PageNavi', { val: {"pagetype": "page","pageId": 0}, ack: true }); } } catch (err: any) { @@ -1926,9 +1926,9 @@ async function InitWeatherForecast() { if (existsState(NSPanel_Path + "ScreensaverInfo.weatherForecast") == false || existsState(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer") == false || existsState(NSPanel_Path + "ScreensaverInfo.entityChangeTime") == false) { - await createStateAsync(NSPanel_Path + "ScreensaverInfo.weatherForecast", true, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer", true, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + "ScreensaverInfo.entityChangeTime", 60, { type: 'number' }); + await createStateAsync(NSPanel_Path + "ScreensaverInfo.weatherForecast", true, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer", true, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + "ScreensaverInfo.entityChangeTime", 60, { type: 'number', write: true }); } //Create Alias weatherForecast setObject(AliasPath + 'ScreensaverInfo.weatherForecast', {type: 'channel', common: {role: 'socket', name:'weatherForecast'}, native: {}}); @@ -1954,28 +1954,28 @@ async function InitDimmode() { if (isSetOptionActive) { // Screensaver on dark at night ("brightnessNight: e.g. 2") or off ("brightnessNight:0") if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay')) { - await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', { type: 'number', write: true }); await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', { val: 8, ack: true }); setObject(AliasPath + 'Dimmode.brightnessDay', {type: 'channel', common: {role: 'slider', name:'brightnessDay'}, native: {}}); await createAliasAsync(AliasPath + 'Dimmode.brightnessDay.ACTUAL', NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', true, { type: 'number', role: 'value', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Dimmode.brightnessDay.SET', NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', true, { type: 'number', role: 'level', name: 'SET' }); } if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_hourDay')) { - await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourDay', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourDay', { type: 'number', write: true }); await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourDay', { val: 7, ack: true }); setObject(AliasPath + 'Dimmode.hourDay', {type: 'channel', common: {role: 'slider', name:'hourDay'}, native: {}}); await createAliasAsync(AliasPath + 'Dimmode.hourDay.ACTUAL', NSPanel_Path + 'NSPanel_Dimmode_hourDay', true, { type: 'number', role: 'value', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Dimmode.hourDay.SET', NSPanel_Path + 'NSPanel_Dimmode_hourDay', true, { type: 'number', role: 'level', name: 'SET' }); } if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight')) { - await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', { type: 'number', write: true }); await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', { val: 1, ack: true }); setObject(AliasPath + 'Dimmode.brightnessNight', {type: 'channel', common: {role: 'slider', name:'brightnessNight'}, native: {}}); await createAliasAsync(AliasPath + 'Dimmode.brightnessNight.ACTUAL', NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', true, { type: 'number', role: 'value', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Dimmode.brightnessNight.SET', NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', true, { type: 'number', role: 'level', name: 'SET' }); } if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_hourNight')) { - await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourNight', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourNight', { type: 'number', write: true }); await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourNight', { val: 22, ack: true }); setObject(AliasPath + 'Dimmode.hourNight', {type: 'channel', common: {role: 'slider', name:'hourNight'}, native: {}}); await createAliasAsync(AliasPath + 'Dimmode.hourNight.ACTUAL', NSPanel_Path + 'NSPanel_Dimmode_hourNight', true, { type: 'number', role: 'value', name: 'ACTUAL' }); @@ -2072,31 +2072,31 @@ async function InitPopupNotify() { try { if (!existsState(screensaverNotifyHeading)) { - await createStateAsync(screensaverNotifyHeading, { type: 'string' }); + await createStateAsync(screensaverNotifyHeading, { type: 'string', write: true }); await setStateAsync(screensaverNotifyHeading, { val: '', ack: true }); } if (!existsState(screensaverNotifyText)) { - await createStateAsync(screensaverNotifyText, { type: 'string' }); + await createStateAsync(screensaverNotifyText, { type: 'string', write: true }); await setStateAsync(screensaverNotifyText, { val: '', ack: true }); } - await createStateAsync(popupNotifyHeading, { type: 'string' }); - await createStateAsync(popupNotifyHeadingColor, { type: 'string' }); - await createStateAsync(popupNotifyText, { type: 'string' }); - await createStateAsync(popupNotifyTextColor, { type: 'string' }); - await createStateAsync(popupNotifyInternalName, { type: 'string' }); - await createStateAsync(popupNotifyButton1Text, { type: 'string' }); - await createStateAsync(popupNotifyButton1TextColor, { type: 'string' }); - await createStateAsync(popupNotifyButton2Text, { type: 'string' }); - await createStateAsync(popupNotifyButton2TextColor, { type: 'string' }); - await createStateAsync(popupNotifySleepTimeout, { type: 'number' }); - await createStateAsync(popupNotifyAction, { type: 'boolean' }); - await createStateAsync(popupNotifyLayout, { type: 'number' }); - await createStateAsync(popupNotifyFontIdText, { type: 'number' }); - await createStateAsync(popupNotifyIcon, { type: 'string' }); - await createStateAsync(popupNotifyIconColor, { type: 'string' }); - await createStateAsync(popupNotifyBuzzer,{type: 'string', def: '0'}); + await createStateAsync(popupNotifyHeading, { type: 'string', write: true }); + await createStateAsync(popupNotifyHeadingColor, { type: 'string', write: true }); + await createStateAsync(popupNotifyText, { type: 'string', write: true }); + await createStateAsync(popupNotifyTextColor, { type: 'string', write: true }); + await createStateAsync(popupNotifyInternalName, { type: 'string', write: true }); + await createStateAsync(popupNotifyButton1Text, { type: 'string', write: true }); + await createStateAsync(popupNotifyButton1TextColor, { type: 'string', write: true }); + await createStateAsync(popupNotifyButton2Text, { type: 'string', write: true }); + await createStateAsync(popupNotifyButton2TextColor, { type: 'string', write: true }); + await createStateAsync(popupNotifySleepTimeout, { type: 'number', write: true }); + await createStateAsync(popupNotifyAction, { type: 'boolean', write: true }); + await createStateAsync(popupNotifyLayout, { type: 'number', write: true }); + await createStateAsync(popupNotifyFontIdText, { type: 'number', write: true }); + await createStateAsync(popupNotifyIcon, { type: 'string', write: true }); + await createStateAsync(popupNotifyIconColor, { type: 'string', write: true }); + await createStateAsync(popupNotifyBuzzer,{type: 'string', def: '0', write: true}); // Notification to screensaver on({ id: [screensaverNotifyHeading, screensaverNotifyText], change: 'ne', ack: false }, async (obj) => { @@ -2322,7 +2322,7 @@ async function get_locales() { if (Debug) { log(JSON.stringify(response.data), 'info'); } - await createStateAsync(NSPanel_Path + 'NSPanel_locales_json', { type: 'string', role: 'json' }); + await createStateAsync(NSPanel_Path + 'NSPanel_locales_json', { type: 'string', role: 'json', write: false }); await setStateAsync(NSPanel_Path + 'NSPanel_locales_json', { val: JSON.stringify(response.data), ack: true }); } else { log('Axios Status - Requesting locales: ' + response.state, 'warn'); @@ -2350,7 +2350,7 @@ async function get_locales_servicemenu() { if (Debug) { log(JSON.stringify(response.data), 'info'); } - await createStateAsync(NSPanel_Path + 'NSPanel_locales_service_json', { type: 'string', role: 'json' }); + await createStateAsync(NSPanel_Path + 'NSPanel_locales_service_json', { type: 'string', role: 'json', write: false }); await setStateAsync(NSPanel_Path + 'NSPanel_locales_service_json', { val: JSON.stringify(response.data), ack: true }); } else { log('Axios Status - Requesting locales Service Menu: ' + response.state, 'warn'); @@ -2538,7 +2538,7 @@ async function get_panel_update_data() { await createAliasAsync(AliasPath + 'autoUpdate.ACTUAL', NSPanel_Path + 'NSPanel_autoUpdate', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'autoUpdate.SET', NSPanel_Path + 'NSPanel_autoUpdate', true, { type: 'boolean', role: 'switch', name: 'SET' }); } - await createStateAsync(NSPanel_Path + 'NSPanel_ipAddress', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'NSPanel_ipAddress', { type: 'string', write: false }); await setStateAsync(NSPanel_Path + 'NSPanel_ipAddress', { val: get_current_tasmota_ip_address(), ack: true }); if (autoCreateAlias) { setObject(AliasPath + 'ipAddress', {type: 'channel', common: {role: 'info', name:'ipAddress'}, native: {}}); @@ -2588,7 +2588,7 @@ function get_online_tasmota_firmware_version() { const Tasmota_JSON = JSON.parse(JSON.stringify(response.data));// Write JSON result to variable const TasmotaTagName = Tasmota_JSON.tag_name; // Filter JSON by "tag_name" and write to variable const TasmotaVersionOnline = TasmotaTagName.replace(/v/i, ''); // Filter unnecessary "v" from variable and write to release variable - await createStateAsync(NSPanel_Path + 'Tasmota_Firmware.onlineVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota_Firmware.onlineVersion', { type: 'string', write: false }); setObject(AliasPath + 'Tasmota_Firmware.onlineVersion', {type: 'channel', common: {role: 'info', name:'onlineVersion'}, native: {}}); await createAliasAsync(AliasPath + 'Tasmota_Firmware.onlineVersion.ACTUAL', NSPanel_Path + 'Tasmota_Firmware.onlineVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); await setStateAsync(NSPanel_Path + 'Tasmota_Firmware.onlineVersion', { val: TasmotaVersionOnline, ack: true }); @@ -2626,7 +2626,7 @@ function get_current_berry_driver_version() { } if (isSetOptionActive) { const BerryDriverVersionCurrent: string = JSON.parse(JSON.stringify(response.data)).nlui_driver_version; - await createStateAsync(NSPanel_Path + 'Berry_Driver.currentVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Berry_Driver.currentVersion', { type: 'string', write: false }); await setStateAsync(NSPanel_Path + 'Berry_Driver.currentVersion', { val: JSON.parse(JSON.stringify(response.data)).nlui_driver_version, ack: true }); if (autoCreateAlias) { setObject(AliasPath + 'Display.BerryDriver', {type: 'channel', common: {role: 'info', name: 'Berry Driver'}, native: {}}); @@ -2667,18 +2667,18 @@ function get_tasmota_status0() { log(JSON.stringify(response.data), 'info'); } if (isSetOptionActive) { - await createStateAsync(NSPanel_Path + 'Tasmota_Firmware.currentVersion', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Uptime', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Version', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Hardware', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.AP', { type: 'number' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.SSId', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.BSSId', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Channel', { type: 'number' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Mode', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.RSSI', { type: 'number' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Signal', { type: 'number' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Product', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota_Firmware.currentVersion', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Uptime', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Version', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Hardware', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.AP', { type: 'number', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.SSId', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.BSSId', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Channel', { type: 'number', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Mode', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.RSSI', { type: 'number', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Signal', { type: 'number', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Product', { type: 'string', write: false }); try { const Tasmota_JSON = JSON.parse(JSON.stringify(response.data)); @@ -2758,7 +2758,7 @@ function get_online_berry_driver_version() { } if (isSetOptionActive) { const BerryDriverVersionOnline = response.data.substring((response.data.indexOf('version_of_this_script = ') + 24), response.data.indexOf('version_of_this_script = ') + 27).replace(/\s+/g, ''); - await createStateAsync(NSPanel_Path + 'Berry_Driver.onlineVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Berry_Driver.onlineVersion', { type: 'string', write: false }); setObject(AliasPath + 'Berry_Driver.onlineVersion', {type: 'channel', common: {role: 'info', name:'onlineVersion'}, native: {}}); await createAliasAsync(AliasPath + 'Berry_Driver.onlineVersion.ACTUAL', NSPanel_Path + 'Berry_Driver.onlineVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); await setStateAsync(NSPanel_Path + 'Berry_Driver.onlineVersion', { val: BerryDriverVersionOnline, ack: true }); @@ -2796,7 +2796,7 @@ function check_version_tft_firmware() { let NSPanelTagName = NSPanel_JSON.tag_name; // created_at; published_at; name ; draft ; prerelease let NSPanelVersion = NSPanelTagName.replace(/v/i, ''); // Filter unnecessary "v" from variable and write to release variable - await createStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { type: 'string', write: false }); await setStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { val: NSPanelVersion, ack: true }); if (Debug) log('online TFT firmware version => ' + NSPanelVersion, 'info'); } else { @@ -2828,7 +2828,7 @@ function check_online_display_firmware() { } let desired_display_firmware_version = response.data.substring((response.data.indexOf('desired_display_firmware_version =') + 34), response.data.indexOf('desired_display_firmware_version =') + 38).replace(/\s+/g, ''); - await createStateAsync(NSPanel_Path + 'Display_Firmware.onlineVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Display_Firmware.onlineVersion', { type: 'string', write: false }); await setStateAsync(NSPanel_Path + 'Display_Firmware.onlineVersion', { val: desired_display_firmware_version, ack: true }); if (Debug) log('online display firmware version => ' + desired_display_firmware_version, 'info'); } else { @@ -2853,8 +2853,8 @@ on({ id: config.panelRecvTopic }, async (obj) => { if (isSetOptionActive) { if (split[0] == 'event' && split[1] == 'startup') { - await createStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'NSPanel_Version', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'NSPanel_Version', { type: 'string', write: false }); await setStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { val: split[2], ack: true }); await setStateAsync(NSPanel_Path + 'NSPanel_Version', { val: split[3], ack: true }); @@ -2932,7 +2932,7 @@ function update_tft_firmware() { if (Debug) { log(response.data, 'info'); } - await createStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { type: 'string', write: false }); await setStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { val: tft_version, ack: true }); Init_Release(); } else { @@ -5639,11 +5639,11 @@ async function createAutoAlarmAlias (id: string, nsPath: string){ if (autoCreateAlias) { if (isSetOptionActive) { if (existsState(nsPath + '.AlarmPin') == false || existsState(nsPath + '.AlarmState') == false || existsState(nsPath + '.AlarmType') == false || existsState(nsPath + '.PIN_Failed') == false || existsState(nsPath + '.PANEL') == false) { - await createStateAsync(nsPath + '.AlarmPin', '0000', { type: 'string' }); - await createStateAsync(nsPath + '.AlarmState', 'disarmed', { type: 'string' }); - await createStateAsync(nsPath + '.AlarmType', 'D1', { type: 'string' }); - await createStateAsync(nsPath + '.PIN_Failed', 0, { type: 'number' }); - await createStateAsync(nsPath + '.PANEL', NSPanel_Path, { type: 'string' }); + await createStateAsync(nsPath + '.AlarmPin', '0000', { type: 'string', write: true }); + await createStateAsync(nsPath + '.AlarmState', 'disarmed', { type: 'string', write: false }); + await createStateAsync(nsPath + '.AlarmType', 'D1', { type: 'string', write: false }); + await createStateAsync(nsPath + '.PIN_Failed', 0, { type: 'number', write: false }); + await createStateAsync(nsPath + '.PANEL', NSPanel_Path, { type: 'string', write: false }); setObject(id, {_id: id, type: 'channel', common: {role: 'sensor.fire.alarm', name:'alarm'}, native: {}}); await createAliasAsync(id + '.ACTUAL', nsPath + '.AlarmState', true, { type: 'string', role: 'state', name: 'ACTUAL' }); await createAliasAsync(id + '.PIN', nsPath + '.AlarmPin', true, { type: 'string', role: 'state', name: 'PIN' }); @@ -5803,8 +5803,8 @@ async function createAutoUnlockAlias(id: string, dpPath: string) { if (autoCreateAlias) { if (isSetOptionActive) { if (existsState(dpPath + 'UnlockPin') == false || existsState(dpPath + 'Access') == false) { - await createStateAsync(dpPath + 'UnlockPin', '0000', { type: 'string' }); - await createStateAsync(dpPath + 'Access', 'false', { type: 'boolean' }); + await createStateAsync(dpPath + 'UnlockPin', '0000', { type: 'string', write: true }); + await createStateAsync(dpPath + 'Access', 'false', { type: 'boolean', write: false }); setObject(id, { _id: id, type: 'channel', common: { role: 'sensor.fire.alarm', name: 'sensor.fire.alarm' }, native: {} }); await createAliasAsync(id + '.PIN', dpPath + 'UnlockPin', true, { type: 'string', role: 'state', name: 'PIN' }); await createAliasAsync(id + '.ACTUAL', dpPath + 'Access', true, { type: 'boolean', role: 'sensor.fire.alarm', name: 'ACTUAL' }); @@ -5885,8 +5885,8 @@ async function createAutoQRAlias(id:string, dpPath:string) { if (autoCreateAlias) { if (isSetOptionActive) { if (existsState(dpPath + 'Daten') == false) { - await createStateAsync(dpPath + 'Daten', 'WIFI:T:undefined;S:undefined;P:undefined;H:undefined;', { type: 'string' }); - await createStateAsync(dpPath + 'Switch', false, { type: 'boolean' }); + await createStateAsync(dpPath + 'Daten', 'WIFI:T:undefined;S:undefined;P:undefined;H:undefined;', { type: 'string', write: true }); + await createStateAsync(dpPath + 'Switch', false, { type: 'boolean', write: true }); setObject(id, { _id: id, type: 'channel', common: { role: 'switch.mode.wlan', name: 'QR Page' }, native: {} }); await createAliasAsync(id + '.ACTUAL', dpPath + 'Daten', true, { type: 'string', role: 'state', name: 'ACTUAL' }); await createAliasAsync(id + '.SWITCH', dpPath + 'Switch', true, { type: 'boolean', role: 'state', name: 'SWITCH' }); @@ -8275,8 +8275,8 @@ function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOpti if (existsObject(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode') == false || existsObject(NSPanel_Path + 'Media.Player.' + lastIndex + '.Speaker') == false) { - createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode', {type: 'string'}); - createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.Speaker', {type: 'string'}); + createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode', {type: 'string', write: false}); + createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.Speaker', {type: 'string', write: false}); } actualState = '' @@ -9465,10 +9465,10 @@ on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESU try { const Tasmota_Sensor = JSON.parse(obj.state.val); - await createStateAsync(NSPanel_Path + 'Sensor.Time', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Sensor.TempUnit', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Sensor.ANALOG.Temperature', { type: 'number', 'unit': '°C' }); - await createStateAsync(NSPanel_Path + 'Sensor.ESP32.Temperature', { type: 'number', 'unit': '°C' }); + await createStateAsync(NSPanel_Path + 'Sensor.Time', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Sensor.TempUnit', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Sensor.ANALOG.Temperature', { type: 'number', 'unit': '°C', write: false }); + await createStateAsync(NSPanel_Path + 'Sensor.ESP32.Temperature', { type: 'number', 'unit': '°C', write: false }); let dateTime: string = Tasmota_Sensor.Time.split('T'); await setStateAsync(NSPanel_Path + 'Sensor.Time', { val: dateTime[0] + '\r\n' + dateTime[1] , ack: true }); await setStateAsync(NSPanel_Path + 'Sensor.TempUnit', { val: '°' + Tasmota_Sensor.TempUnit, ack: true }); From a2b805f4e189add18d2b967402fe911d8536ca8e Mon Sep 17 00:00:00 2001 From: ticaki Date: Fri, 12 Jan 2024 20:38:47 +0100 Subject: [PATCH 76/99] SendTime - optimated --- ioBroker/DEV/NSPanelTs.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 14dad67e..13c99002 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -3267,11 +3267,12 @@ function SendDate(): void { function SendTime(): void { try { - const d = new Date(); + /*const d = new Date(); const hr = (d.getHours() < 10 ? '0' : '') + d.getHours(); const min = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); - SendToPanel({ payload: 'time~' + hr + ':' + min }); + SendToPanel({ payload: 'time~' + hr + ':' + min });*/ + SendToPanel({ payload: `time~${new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}`, }); } catch (err: any) { log('error at function SendTime: ' + err.message, 'warn'); } From b7fd06413dea74fef986b6e826bda5b4729f21c7 Mon Sep 17 00:00:00 2001 From: ticaki Date: Fri, 12 Jan 2024 20:42:54 +0100 Subject: [PATCH 77/99] remove all --- ioBroker/DEV/NSPanelTs.ts | 42 +++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 13c99002..27164030 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -3049,7 +3049,7 @@ on({ id: NSPanel_Alarm_Path + 'Alarm.AlarmState', change: 'ne' }, async (obj) => } }); -function HandleMessage(typ: string, method: NSPanel.EventMethod, page: number | undefined, words: Array | undefined): void { +function HandleMessage(typ: string, method: NSPanel.EventMethod, page: number | undefined, words: string[] | undefined): void { try { if (typ == 'event') { switch (method as NSPanel.EventMethod) { @@ -3254,7 +3254,7 @@ function SendDate(): void { const options: any = { weekday: dpWeekday, year: 'numeric', month: dpMonth, day: 'numeric' }; const _SendDate = dpCustomFormat != '' ? dayjs().format(dpCustomFormat) : date.toLocaleDateString(getState(NSPanel_Path + 'Config.locale').val, options); - SendToPanel({ payload: 'date~' + _SendDate }); + SendToPanel({ payload: 'date~' + _SendDate }); } } catch (err: any) { if (err.message = 'Cannot convert undefined or null to object') { @@ -3271,8 +3271,8 @@ function SendTime(): void { const hr = (d.getHours() < 10 ? '0' : '') + d.getHours(); const min = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); - SendToPanel({ payload: 'time~' + hr + ':' + min });*/ - SendToPanel({ payload: `time~${new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}`, }); + SendToPanel({ payload: 'time~' + hr + ':' + min });*/ + SendToPanel({ payload: `time~${new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}`, }); } catch (err: any) { log('error at function SendTime: ' + err.message, 'warn'); } @@ -3280,7 +3280,7 @@ function SendTime(): void { function GenerateEntitiesPage(page: NSPanel.PageEntities): NSPanel.Payload[] { try { - let out_msgs: Array; + let out_msgs: NSPanel.Payload[]; out_msgs = [{ payload: 'pageType~cardEntities' }] out_msgs.push({ payload: GeneratePageElements(page) }); return out_msgs @@ -3292,7 +3292,7 @@ function GenerateEntitiesPage(page: NSPanel.PageEntities): NSPanel.Payload[] { function GenerateGridPage(page: NSPanel.PageGrid): NSPanel.Payload[] { try { - let out_msgs: Array = [{ payload: 'pageType~cardGrid' }]; + let out_msgs: NSPanel.Payload[] = [{ payload: 'pageType~cardGrid' }]; out_msgs.push({ payload: GeneratePageElements(page) }); return out_msgs; } catch (err: any) { @@ -3303,7 +3303,7 @@ function GenerateGridPage(page: NSPanel.PageGrid): NSPanel.Payload[] { function GenerateGridPage2(page: NSPanel.PageGrid2): NSPanel.Payload[] { try { - let out_msgs: Array = [{ payload: 'pageType~cardGrid2' }]; + let out_msgs: NSPanel.Payload[] = [{ payload: 'pageType~cardGrid2' }]; out_msgs.push({ payload: GeneratePageElements(page) }); return out_msgs; } catch (err: any) { @@ -4311,7 +4311,7 @@ function GenerateThermoPage(page: NSPanel.PageThermo): NSPanel.Payload[] { try { UnsubscribeWatcher(); let id = page.items[0].id - let out_msgs: Array = []; + let out_msgs: NSPanel.Payload[] = []; out_msgs.push({ payload: 'pageType~cardThermo' }); // ioBroker @@ -5047,7 +5047,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { if (!page.items[0].id) throw new Error ('Missing page id for cardMedia!'); let id = page.items[0].id; - let out_msgs: Array = []; + let out_msgs: NSPanel.Payload[] = []; if (!page.items[0].adapterPlayerInstance!) throw new Error('page.items[0].adapterPlayerInstance is undefined!') let vInstance = page.items[0].adapterPlayerInstance!; @@ -5335,7 +5335,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { //------------------------------------------------------------------------------------------------------------- // All Alexa devices (the online / player and commands directory is available) are listed and linked below // If the constant alexaSpeakerList contains at least one entry, the constant is used - otherwise all devices from the Alexa adapter - let speakerListArray: Array = []; + let speakerListArray: string[] = []; if (page.items[0].speakerList && page.items[0].speakerList.length > 0) { for (let i_index in page.items[0].speakerList) { speakerListArray.push(page.items[0].speakerList[i_index]); @@ -5666,7 +5666,7 @@ function GenerateAlarmPage(page: NSPanel.PageAlarm): NSPanel.Payload[] { let id = page.items[0].id let name = page.heading; - let out_msgs: Array = []; + let out_msgs: NSPanel.Payload[] = []; out_msgs.push({ payload: 'pageType~cardAlarm' }); let nsPath = NSPanel_Alarm_Path + 'Alarm'; @@ -5824,7 +5824,7 @@ function GenerateUnlockPage(page: NSPanel.PageUnlock): NSPanel.Payload[] { let id = page.items[0].id let name = page.heading; - let out_msgs: Array = []; + let out_msgs: NSPanel.Payload[] = []; out_msgs.push({ payload: 'pageType~cardAlarm' }); let dpPath : string = '' @@ -5905,7 +5905,7 @@ function GenerateQRPage(page: NSPanel.PageQR): NSPanel.Payload[] { activePage = page; if (!page.items[0].id) throw new Error ('Missing pageItem.id for cardQRPage!'); let id = page.items[0].id; - let out_msgs: Array = []; + let out_msgs: NSPanel.Payload[] = []; out_msgs.push({ payload: 'pageType~cardQR' }); let dpPath : string = '' @@ -6046,7 +6046,7 @@ function GeneratePowerPage(page: NSPanel.PagePower): NSPanel.Payload[] { obj = JSON.parse((getState(page.items[0].id + '.ACTUAL').val)); } - let out_msgs: Array = []; + let out_msgs: NSPanel.Payload[] = []; // Leave the display on if the alwaysOnDisplay parameter is specified (true) if (page.type == 'cardPower' && pageCounter == 0 && page.items[0].alwaysOnDisplay != undefined) { @@ -6145,7 +6145,7 @@ function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { activePage = page; let id = page.items[0].id; - let out_msgs: Array = []; + let out_msgs: NSPanel.Payload[] = []; out_msgs.push({ payload: 'pageType~' + page.type }); let heading = page.heading !== undefined ? page.heading : "Chart..."; @@ -7408,7 +7408,7 @@ function GetNavigationString(pageId: number): string { function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOptional | undefined, pageItem: PageItem, placeId: number | undefined): NSPanel.Payload[] { if (Debug) log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); try { - let out_msgs: Array = []; + let out_msgs: NSPanel.Payload[] = []; let id = pageItem.id; if (id && existsObject(id)) { @@ -8210,7 +8210,7 @@ function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOpti // Playlist browsing not supported by squeezeboxrpc adapter. But Favorites can be used actualState = ''; // Not supported by squeezeboxrpc adapter let tempPlayList: string[] = []; - let pathParts: Array = pageItem.adapterPlayerInstance!.split('.'); + let pathParts: string[] = pageItem.adapterPlayerInstance!.split('.'); for (let favorite_index = 0; favorite_index < 45; favorite_index++) { let favorite_name_selector: string = [pathParts[0], pathParts[1], 'Favorites', favorite_index, 'Name'].join('.'); if (!existsObject(favorite_name_selector)) { @@ -8812,7 +8812,7 @@ function HandleScreensaverUpdate(): void { } if (Debug) log('HandleScreensaverUpdate payload: weatherUpdate~' + payloadString, 'info'); - SendToPanel({ payload: 'weatherUpdate~' + payloadString }); + SendToPanel({ payload: 'weatherUpdate~' + payloadString }); HandleScreensaverStatusIcons(); } @@ -9009,7 +9009,7 @@ function HandleScreensaverStatusIcons() : void { payloadString += '~'; } - SendToPanel({ payload: 'statusUpdate~' + payloadString }); + SendToPanel({ payload: 'statusUpdate~' + payloadString }); } catch (err: any) { log('error at function HandleScreensaverStatusIcons: ' + err.message, 'warn'); @@ -9104,7 +9104,7 @@ function HandleScreensaverColors(): void { rgb_dec565(sctMainTextAlt) + '~' + //tMainTextAlt rgb_dec565(sctTimeAdd); //tTimeAdd - SendToPanel({ payload: payloadString }); + SendToPanel({ payload: payloadString }); } catch (err: any) { log('error at function HandleScreensaverColors: '+ err.message, 'warn'); } @@ -9538,7 +9538,7 @@ function Interpolate(color1: RGB, color2: RGB, fraction: number): RGB { let r: number = InterpolateNum(color1.red, color2.red, fraction); let g: number = InterpolateNum(color1.green, color2.green, fraction); let b: number = InterpolateNum(color1.blue, color2.blue, fraction); - return { red: Math.round(r), green: Math.round(g), blue: Math.round(b) }; + return { red: Math.round(r), green: Math.round(g), blue: Math.round(b) }; } function InterpolateNum(d1: number, d2: number, fraction: number): number { From 0a1eb8c2e59bca3ff9a7798a0cc6e97618c13e94 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Sun, 14 Jan 2024 20:41:38 +0100 Subject: [PATCH 78/99] v4.3.3.26 - Update NsPanelTs.ts - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) - v4.3.3.35 Add: relay.1/relay.2 show the confirmed status - v4.3.3.36 Fix: change ScreensaverTimeout and activeBrightness - v4.3.3.36 Fix: schedule SendTime - v4.3.3.36 Fix: Function _schedule SummerTime/WinterTime - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) - v4.3.3.35 Add: relay.1/relay.2 show the confirmed status - v4.3.3.36 Fix: change ScreensaverTimeout and activeBrightness - v4.3.3.36 Fix: schedule SendTime - v4.3.3.36 Fix: Some Types and Minor Fixes --- ioBroker/NsPanelTs.ts | 1507 +++++++++++++++++++++++------------------ 1 file changed, 847 insertions(+), 660 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index e80df03f..e508405a 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.33 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.36 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -31,20 +31,8 @@ https://github.com/joBr99/nspanel-lovelace-ui/wiki/iobroker---Basisinstallation# ReleaseNotes: Bugfixes und Erweiterungen: - - - 17.09.2023 - v4.3.1 Upgrade TFT 53 / 4.3.1 - - 17.09.2023 - v4.3.1.1 Add Parameter fontSize (0-4) to cardGrid (with useValue) - - 23.09.2023 - v4.3.1.2 Upgrade BerryDriver v9 - - 23.09.2023 - v4.3.1.3 Fix - Change ServivceMenu from Fake-SSId to real Tasmota-SSIdParam - - 03.10.2023 - v4.3.1.4 Removing the examples from the NSPanelTs.ts --> https://github.com/joBr99/nspanel-lovelace-ui/wiki/NSPanel-Page-%E2%80%90-Typen_How-2_Beispiele - - 03.10.2023 - v4.3.1.4 Delete NsPanelTs_without_Examples.ts - - 12.10.2023 - v4.3.1.5 Fix Datapoint for Role timetable -> Attention use new script from TT-Tom https://github.com/tt-tom17/MyScripts/blob/main/Sonoff_NSPanel/Fahrplan_to_NSPanel.ts - - 19.10.2023 - v4.3.1.6 Add more Alias Device-Types to Navigation / Minor Fixes - - 22.10.2023 - v4.3.1.7 Fix CreateEntity (navigate) role 'light' and 'socket' and 'temperature' - - 30.10.2023 - v4.3.2 Upgrade TFT 53 / 4.3.2 - - 30.10.2023 - v4.3.2.1 Fix formatDate/Date.parse with moment.js (Bugs in JS-Methodes) - - 07.11.2023 - v4.3.2.2 Fix Selection of screensaver layout (alternative / advanced) - - 08.11.2023 - v4.3.2.3 Fix Issues #1013 by laluz742 -> Parameter count mismatch: screensaver color + See ChangeLog all Release Notes: https://github.com/joBr99/nspanel-lovelace-ui/wiki/Release-Notes + - 08.11.2023 - v4.3.3 Upgrade TFT 53 / 4.3.3 - 11.11.2023 - v4.3.3.1 Fix for Issues #1020 HandleHardwareButton buttonConfig.mode -> 'toggle' and 'set' - 12.11.2023 - v4.3.3.2 Add autoCreateALias to cardUnlock @@ -101,9 +89,15 @@ ReleaseNotes: - 04.01.2024 - v4.3.3.32 Add more details to types for: leftScreensaverEntity, indicatorScreensaverEntity, PageThermo, PageMedia - 04.01.2024 - v4.3.3.32 Remove not uses propertys from PageItem - 05.01.2024 - v4.3.3.32 Add Body for BoseSoundtouch-Player - - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions - - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity - + - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions + - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity + - 07.01.2024 - v4.3.3.33 Fix BoseSoundtouch Proto + - 08.01.2024 - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) + - 08.01.2024 - v4.3.3.35 Add: relay.1/relay.2 show the confirmed status + - 09.01.2024 - v4.3.3.36 Fix: change ScreensaverTimeout and activeBrightness + - 09.01.2024 - v4.3.3.36 Fix: schedule SendTime + - 09.01.2024 - v4.3.3.36 Fix: Function _schedule SummerTime/WinterTime + Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -412,9 +406,9 @@ let Unlock_Service: PageType = 'type': 'cardUnlock', 'heading': findLocaleServMenu('service_pages'), 'useColor': true, - 'items': [/*PageItem*/{ id: 'alias.0.NSPanel.Unlock', - targetPage: 'NSPanel_Service_SubPage', - autoCreateALias: true } + 'items': [{ id: 'alias.0.NSPanel.Unlock', + targetPage: 'NSPanel_Service_SubPage', + autoCreateALias: true } ] }; @@ -425,10 +419,10 @@ let NSPanel_Service: PageType = 'heading': findLocaleServMenu('service_menu'), 'useColor': true, 'items': [ - /*PageItem*/{ navigate: true, id: 'NSPanel_Infos', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('infos'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_Einstellungen', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('settings'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_Firmware', icon: 'update', offColor: Menu, onColor: Menu, name: findLocaleServMenu('firmware'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ id: AliasPath + 'Config.rebootNSPanel', name: findLocaleServMenu('reboot') ,icon: 'refresh', offColor: MSRed, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + { navigate: true, id: 'NSPanel_Infos', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('infos'), buttonText: findLocaleServMenu('more')}, + { navigate: true, id: 'NSPanel_Einstellungen', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('settings'), buttonText: findLocaleServMenu('more')}, + { navigate: true, id: 'NSPanel_Firmware', icon: 'update', offColor: Menu, onColor: Menu, name: findLocaleServMenu('firmware'), buttonText: findLocaleServMenu('more')}, + { id: AliasPath + 'Config.rebootNSPanel', name: findLocaleServMenu('reboot') ,icon: 'refresh', offColor: MSRed, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, ] }; @@ -442,10 +436,10 @@ let NSPanel_Service_SubPage: PageType = 'parent': Unlock_Service, 'home': 'Unlock_Service', 'items': [ - /*PageItem*/{ navigate: true, id: 'NSPanel_Infos', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('infos'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_Einstellungen', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('settings'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_Firmware', icon: 'update', offColor: Menu, onColor: Menu, name: findLocaleServMenu('firmware'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ id: AliasPath + 'Config.rebootNSPanel', name: findLocaleServMenu('reboot') ,icon: 'refresh', offColor: MSRed, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + { navigate: true, id: 'NSPanel_Infos', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('infos'), buttonText: findLocaleServMenu('more')}, + { navigate: true, id: 'NSPanel_Einstellungen', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('settings'), buttonText: findLocaleServMenu('more')}, + { navigate: true, id: 'NSPanel_Firmware', icon: 'update', offColor: Menu, onColor: Menu, name: findLocaleServMenu('firmware'), buttonText: findLocaleServMenu('more')}, + { id: AliasPath + 'Config.rebootNSPanel', name: findLocaleServMenu('reboot') ,icon: 'refresh', offColor: MSRed, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, ] }; @@ -459,10 +453,10 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Service, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ navigate: true, id: 'NSPanel_Wifi_Info_1', icon: 'wifi', offColor: Menu, onColor: Menu, name: findLocaleServMenu('wifi'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_Sensoren', icon: 'memory', offColor: Menu, onColor: Menu, name: findLocaleServMenu('sensors_hardware'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_IoBroker', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('info_iobroker'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ id: AliasPath + 'Config.Update.UpdateMessage', name: findLocaleServMenu('update_message') ,icon: 'message-alert-outline', offColor: HMIOff, onColor: MSGreen}, + { navigate: true, id: 'NSPanel_Wifi_Info_1', icon: 'wifi', offColor: Menu, onColor: Menu, name: findLocaleServMenu('wifi'), buttonText: findLocaleServMenu('more')}, + { navigate: true, id: 'NSPanel_Sensoren', icon: 'memory', offColor: Menu, onColor: Menu, name: findLocaleServMenu('sensors_hardware'), buttonText: findLocaleServMenu('more')}, + { navigate: true, id: 'NSPanel_IoBroker', icon: 'information-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('info_iobroker'), buttonText: findLocaleServMenu('more')}, + { id: AliasPath + 'Config.Update.UpdateMessage', name: findLocaleServMenu('update_message') ,icon: 'message-alert-outline', offColor: HMIOff, onColor: MSGreen}, ] }; //Level_2 @@ -475,10 +469,10 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Infos, 'next': 'NSPanel_Wifi_Info_2', 'items': [ - /*PageItem*/{ id: AliasPath + 'ipAddress', name: findLocaleServMenu('ip_address'), icon: 'ip-network-outline', offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.BSSId', name: findLocaleServMenu('mac_address'), icon: 'check-network', offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.RSSI', name: findLocaleServMenu('rssi'), icon: 'signal', unit: '%', colorScale: {'val_min': 100, 'val_max': 0} }, - /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.Signal', name: findLocaleServMenu('wifi_signal'), icon: 'signal-distance-variant', unit: 'dBm', colorScale: {'val_min': 0, 'val_max': -100} }, + { id: AliasPath + 'ipAddress', name: findLocaleServMenu('ip_address'), icon: 'ip-network-outline', offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Tasmota.Wifi.BSSId', name: findLocaleServMenu('mac_address'), icon: 'check-network', offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Tasmota.Wifi.RSSI', name: findLocaleServMenu('rssi'), icon: 'signal', unit: '%', colorScale: {'val_min': 100, 'val_max': 0} }, + { id: AliasPath + 'Tasmota.Wifi.Signal', name: findLocaleServMenu('wifi_signal'), icon: 'signal-distance-variant', unit: 'dBm', colorScale: {'val_min': 0, 'val_max': -100} }, ] }; @@ -491,10 +485,10 @@ let NSPanel_Service_SubPage: PageType = 'prev': 'NSPanel_Wifi_Info_1', 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.SSId', name: findLocaleServMenu('ssid'), icon: 'signal-distance-variant', offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.Mode', name: findLocaleServMenu('mode'), icon: 'signal-distance-variant', offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.Channel', name: findLocaleServMenu('channel'), icon: 'timeline-clock-outline', offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Tasmota.Wifi.AP', name: findLocaleServMenu('accesspoint'), icon: 'router-wireless-settings', offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Tasmota.Wifi.SSId', name: findLocaleServMenu('ssid'), icon: 'signal-distance-variant', offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Tasmota.Wifi.Mode', name: findLocaleServMenu('mode'), icon: 'signal-distance-variant', offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Tasmota.Wifi.Channel', name: findLocaleServMenu('channel'), icon: 'timeline-clock-outline', offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Tasmota.Wifi.AP', name: findLocaleServMenu('accesspoint'), icon: 'router-wireless-settings', offColor: Menu, onColor: Menu }, ] }; @@ -507,14 +501,14 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Infos, 'next': 'NSPanel_Hardware', 'items': [ - /*PageItem*/{ id: AliasPath + 'Sensor.ANALOG.Temperature', name: findLocaleServMenu('room_temperature'), icon: 'home-thermometer-outline', unit: '°C', colorScale: {'val_min': 0, 'val_max': 40, 'val_best': 22 } }, - /*PageItem*/{ id: AliasPath + 'Sensor.ESP32.Temperature', name: findLocaleServMenu('esp_temperature'), icon: 'thermometer', unit: '°C', colorScale: {'val_min': 0, 'val_max': 100, 'val_best': 50 } }, - /*PageItem*/{ id: AliasPath + 'Sensor.TempUnit', name: findLocaleServMenu('temperature_unit'), icon: 'temperature-celsius', offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Sensor.Time', name: findLocaleServMenu('refresh'), icon: 'clock-check-outline', offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Sensor.ANALOG.Temperature', name: findLocaleServMenu('room_temperature'), icon: 'home-thermometer-outline', unit: '°C', colorScale: {'val_min': 0, 'val_max': 40, 'val_best': 22 } }, + { id: AliasPath + 'Sensor.ESP32.Temperature', name: findLocaleServMenu('esp_temperature'), icon: 'thermometer', unit: '°C', colorScale: {'val_min': 0, 'val_max': 100, 'val_best': 50 } }, + { id: AliasPath + 'Sensor.TempUnit', name: findLocaleServMenu('temperature_unit'), icon: 'temperature-celsius', offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Sensor.Time', name: findLocaleServMenu('refresh'), icon: 'clock-check-outline', offColor: Menu, onColor: Menu }, ] }; - let NSPanel_Hardware: PageEntities = + let NSPanel_Hardware: PageType = { 'type': 'cardEntities', 'heading': findLocaleServMenu('hardware2'), @@ -523,10 +517,10 @@ let NSPanel_Service_SubPage: PageType = 'prev': 'NSPanel_Sensoren', 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'Tasmota.Product', name: findLocaleServMenu('product'), icon: 'devices', offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Tasmota.Hardware', name: findLocaleServMenu('esp32_hardware'), icon: 'memory', offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Display.Model', name: findLocaleServMenu('nspanel_version'), offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Tasmota.Uptime', name: findLocaleServMenu('operating_time'), icon: 'timeline-clock-outline', offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Tasmota.Product', name: findLocaleServMenu('product'), icon: 'devices', offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Tasmota.Hardware', name: findLocaleServMenu('esp32_hardware'), icon: 'memory', offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Display.Model', name: findLocaleServMenu('nspanel_version'), offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Tasmota.Uptime', name: findLocaleServMenu('operating_time'), icon: 'timeline-clock-outline', offColor: Menu, onColor: Menu }, ] }; @@ -539,9 +533,10 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Infos, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'IoBroker.ScriptVersion', name: findLocaleServMenu('script_version_nspanelts'), offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'IoBroker.NodeJSVersion', name: findLocaleServMenu('nodejs_version'), offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'IoBroker.JavaScriptVersion', name: findLocaleServMenu('instance_javascript'), offColor: Menu, onColor: Menu }, + { id: AliasPath + 'IoBroker.ScriptVersion', name: findLocaleServMenu('script_version_nspanelts'), offColor: Menu, onColor: Menu }, + { id: AliasPath + 'IoBroker.NodeJSVersion', name: findLocaleServMenu('nodejs_version'), offColor: Menu, onColor: Menu }, + { id: AliasPath + 'IoBroker.JavaScriptVersion', name: findLocaleServMenu('instance_javascript'), offColor: Menu, onColor: Menu }, + { id: AliasPath + 'IoBroker.ScriptName', name: findLocaleServMenu('scriptname'), offColor: Menu, onColor: Menu }, ] }; @@ -555,15 +550,15 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Service, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ navigate: true, id: 'NSPanel_Screensaver', icon: 'monitor-dashboard',offColor: Menu, onColor: Menu, name: findLocaleServMenu('screensaver'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_Relays', icon: 'electric-switch', offColor: Menu, onColor: Menu, name: findLocaleServMenu('relays'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ id:AliasPath + 'Config.temperatureUnitNumber', icon: 'gesture-double-tap', name: findLocaleServMenu('temp_unit'), offColor: Menu, onColor: Menu, + { navigate: true, id: 'NSPanel_Screensaver', icon: 'monitor-dashboard',offColor: Menu, onColor: Menu, name: findLocaleServMenu('screensaver'), buttonText: findLocaleServMenu('more')}, + { navigate: true, id: 'NSPanel_Relays', icon: 'electric-switch', offColor: Menu, onColor: Menu, name: findLocaleServMenu('relays'), buttonText: findLocaleServMenu('more')}, + { id:AliasPath + 'Config.temperatureUnitNumber', icon: 'gesture-double-tap', name: findLocaleServMenu('temp_unit'), offColor: Menu, onColor: Menu, modeList: ['°C', '°F', 'K']}, - /*PageItem*/{ id: AliasPath + 'Config.localeNumber', icon: 'select-place', name: findLocaleServMenu('language'), offColor: Menu, onColor: Menu, + { id: AliasPath + 'Config.localeNumber', icon: 'select-place', name: findLocaleServMenu('language'), offColor: Menu, onColor: Menu, modeList: ['en-US', 'de-DE', 'nl-NL', 'da-DK', 'es-ES', 'fr-FR', 'it-IT', 'ru-RU', 'nb-NO', 'nn-NO', 'pl-PL', 'pt-PT', 'af-ZA', 'ar-SY', 'bg-BG', 'ca-ES', 'cs-CZ', 'el-GR', 'et-EE', 'fa-IR', 'fi-FI', 'he-IL', 'hr-xx', 'hu-HU', 'hy-AM', 'id-ID', 'is-IS', 'lb-xx', 'lt-LT', 'ro-RO', 'sk-SK', 'sl-SI', 'sv-SE', 'th-TH', 'tr-TR', 'uk-UA', 'vi-VN', 'zh-CN', 'zh-TW']}, - /*PageItem*/{ navigate: true, id: 'NSPanel_Script', icon: 'code-json',offColor: Menu, onColor: Menu, name: findLocaleServMenu('script'), buttonText: findLocaleServMenu('more')}, + { navigate: true, id: 'NSPanel_Script', icon: 'code-json',offColor: Menu, onColor: Menu, name: findLocaleServMenu('script'), buttonText: findLocaleServMenu('more')}, ] }; @@ -577,12 +572,12 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Einstellungen, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverDimmode', icon: 'sun-clock', offColor: Menu, onColor: Menu, name: findLocaleServMenu('dimmode')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverBrightness', icon: 'brightness-5', offColor: Menu, onColor: Menu, name: findLocaleServMenu('brightness')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverLayout', icon: 'page-next-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('layout')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverWeather', icon: 'weather-partly-rainy', offColor: Menu, onColor: Menu, name: findLocaleServMenu('weather')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverDateformat', icon: 'calendar-expand-horizontal', offColor: Menu, onColor: Menu, name: findLocaleServMenu('date_format')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_ScreensaverIndicators', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('indicators')} + { navigate: true, id: 'NSPanel_ScreensaverDimmode', icon: 'sun-clock', offColor: Menu, onColor: Menu, name: findLocaleServMenu('dimmode')}, + { navigate: true, id: 'NSPanel_ScreensaverBrightness', icon: 'brightness-5', offColor: Menu, onColor: Menu, name: findLocaleServMenu('brightness')}, + { navigate: true, id: 'NSPanel_ScreensaverLayout', icon: 'page-next-outline', offColor: Menu, onColor: Menu, name: findLocaleServMenu('layout')}, + { navigate: true, id: 'NSPanel_ScreensaverWeather', icon: 'weather-partly-rainy', offColor: Menu, onColor: Menu, name: findLocaleServMenu('weather')}, + { navigate: true, id: 'NSPanel_ScreensaverDateformat', icon: 'calendar-expand-horizontal', offColor: Menu, onColor: Menu, name: findLocaleServMenu('date_format')}, + { navigate: true, id: 'NSPanel_ScreensaverIndicators', icon: 'monitor-edit', offColor: Menu, onColor: Menu, name: findLocaleServMenu('indicators')} ] }; @@ -596,10 +591,10 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Screensaver, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'Dimmode.brightnessDay', name: findLocaleServMenu('brightness_day'), icon: 'brightness-5', offColor: Menu, onColor: Menu, minValue: 5, maxValue: 10}, - /*PageItem*/{ id: AliasPath + 'Dimmode.brightnessNight', name: findLocaleServMenu('brightness_night'), icon: 'brightness-4', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 4}, - /*PageItem*/{ id: AliasPath + 'Dimmode.hourDay', name: findLocaleServMenu('hour_day'), icon: 'sun-clock', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 23}, - /*PageItem*/{ id: AliasPath + 'Dimmode.hourNight', name: findLocaleServMenu('hour_night'), icon: 'sun-clock-outline', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 23} + { id: AliasPath + 'Dimmode.brightnessDay', name: findLocaleServMenu('brightness_day'), icon: 'brightness-5', offColor: Menu, onColor: Menu, minValue: 5, maxValue: 10}, + { id: AliasPath + 'Dimmode.brightnessNight', name: findLocaleServMenu('brightness_night'), icon: 'brightness-4', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 4}, + { id: AliasPath + 'Dimmode.hourDay', name: findLocaleServMenu('hour_day'), icon: 'sun-clock', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 23}, + { id: AliasPath + 'Dimmode.hourNight', name: findLocaleServMenu('hour_night'), icon: 'sun-clock-outline', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 23} ] }; @@ -613,9 +608,9 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Screensaver, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'ScreensaverInfo.activeBrightness', name: findLocaleServMenu('brightness_activ'), icon: 'brightness-5', offColor: Menu, onColor: Menu, minValue: 20, maxValue: 100}, - /*PageItem*/{ id: AliasPath + 'Config.Screensaver.timeoutScreensaver', name: findLocaleServMenu('screensaver_timeout'), icon: 'clock-end', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 60}, - /*PageItem*/{ id: AliasPath + 'Config.Screensaver.screenSaverDoubleClick', name: findLocaleServMenu('wakeup_doublecklick') ,icon: 'gesture-two-double-tap', offColor: HMIOff, onColor: HMIOn} + { id: AliasPath + 'ScreensaverInfo.activeBrightness', name: findLocaleServMenu('brightness_activ'), icon: 'brightness-5', offColor: Menu, onColor: Menu, minValue: 20, maxValue: 100}, + { id: AliasPath + 'Config.Screensaver.timeoutScreensaver', name: findLocaleServMenu('screensaver_timeout'), icon: 'clock-end', offColor: Menu, onColor: Menu, minValue: 0, maxValue: 60}, + { id: AliasPath + 'Config.Screensaver.screenSaverDoubleClick', name: findLocaleServMenu('wakeup_doublecklick') ,icon: 'gesture-two-double-tap', offColor: HMIOff, onColor: HMIOn} ] }; @@ -629,8 +624,8 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Screensaver, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'Config.Screensaver.alternativeScreensaverLayout', name: findLocaleServMenu('alternative_layout') ,icon: 'page-previous-outline', offColor: HMIOff, onColor: HMIOn}, - /*PageItem*/{ id: AliasPath + 'Config.Screensaver.ScreensaverAdvanced', name: findLocaleServMenu('advanced_layout') ,icon: 'page-next-outline', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'Config.Screensaver.alternativeScreensaverLayout', name: findLocaleServMenu('alternative_layout') ,icon: 'page-previous-outline', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'Config.Screensaver.ScreensaverAdvanced', name: findLocaleServMenu('advanced_layout') ,icon: 'page-next-outline', offColor: HMIOff, onColor: HMIOn}, ] }; @@ -644,10 +639,10 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Screensaver, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'ScreensaverInfo.weatherForecast', name: findLocaleServMenu('weather_forecast_offon') ,icon: 'weather-sunny-off', offColor: HMIOff, onColor: HMIOn}, - /*PageItem*/{ id: AliasPath + 'ScreensaverInfo.weatherForecastTimer', name: findLocaleServMenu('weather_forecast_change_switch') ,icon: 'devices', offColor: HMIOff, onColor: HMIOn}, - /*PageItem*/{ id: AliasPath + 'ScreensaverInfo.entityChangeTime', name: findLocaleServMenu('weather_forecast_change_time'), icon: 'cog-sync', offColor: Menu, onColor: Menu, minValue: 15, maxValue: 60}, - /*PageItem*/{ id: AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout', name: findLocaleServMenu('weather_forecast_icon_colors') ,icon: 'format-color-fill', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'ScreensaverInfo.weatherForecast', name: findLocaleServMenu('weather_forecast_offon') ,icon: 'weather-sunny-off', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'ScreensaverInfo.weatherForecastTimer', name: findLocaleServMenu('weather_forecast_change_switch') ,icon: 'devices', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'ScreensaverInfo.entityChangeTime', name: findLocaleServMenu('weather_forecast_change_time'), icon: 'cog-sync', offColor: Menu, onColor: Menu, minValue: 15, maxValue: 60}, + { id: AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout', name: findLocaleServMenu('weather_forecast_icon_colors') ,icon: 'format-color-fill', offColor: HMIOff, onColor: HMIOn}, ] }; @@ -661,8 +656,8 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Screensaver, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'Config.Dateformat.Switch.weekday', name: findLocaleServMenu('weekday_large') ,icon: 'calendar-expand-horizontal', offColor: HMIOff, onColor: HMIOn}, - /*PageItem*/{ id: AliasPath + 'Config.Dateformat.Switch.month', name: findLocaleServMenu('month_large') ,icon: 'calendar-expand-horizontal', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'Config.Dateformat.Switch.weekday', name: findLocaleServMenu('weekday_large') ,icon: 'calendar-expand-horizontal', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'Config.Dateformat.Switch.month', name: findLocaleServMenu('month_large') ,icon: 'calendar-expand-horizontal', offColor: HMIOff, onColor: HMIOn}, ] }; @@ -676,8 +671,8 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Screensaver, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'Config.MRIcons.alternateMRIconSize.1', name: findLocaleServMenu('mr_icon1_size') ,icon: 'format-size', offColor: HMIOff, onColor: HMIOn}, - /*PageItem*/{ id: AliasPath + 'Config.MRIcons.alternateMRIconSize.2', name: findLocaleServMenu('mr_icon2_size') ,icon: 'format-size', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'Config.MRIcons.alternateMRIconSize.1', name: findLocaleServMenu('mr_icon1_size') ,icon: 'format-size', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'Config.MRIcons.alternateMRIconSize.2', name: findLocaleServMenu('mr_icon2_size') ,icon: 'format-size', offColor: HMIOff, onColor: HMIOn}, ] }; @@ -691,8 +686,8 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Einstellungen, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'Relay.1', name: findLocaleServMenu('relay1_onoff'), icon: 'power', offColor: HMIOff, onColor: HMIOn}, - /*PageItem*/{ id: AliasPath + 'Relay.2', name: findLocaleServMenu('relay2_onoff'), icon: 'power', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'Relay.1', name: findLocaleServMenu('relay1_onoff'), icon: 'power', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'Relay.2', name: findLocaleServMenu('relay2_onoff'), icon: 'power', offColor: HMIOff, onColor: HMIOn}, ] }; @@ -706,8 +701,8 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Einstellungen, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'Config.ScripgtDebugStatus', name: findLocaleServMenu('debugmode_offon') ,icon: 'code-tags-check', offColor: HMIOff, onColor: HMIOn}, - /*PageItem*/{ id: AliasPath + 'Config.MQTT.portCheck', name: findLocaleServMenu('port_check_offon') ,icon: 'check-network', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'Config.ScripgtDebugStatus', name: findLocaleServMenu('debugmode_offon') ,icon: 'code-tags-check', offColor: HMIOff, onColor: HMIOn}, + { id: AliasPath + 'Config.MQTT.portCheck', name: findLocaleServMenu('port_check_offon') ,icon: 'check-network', offColor: HMIOff, onColor: HMIOn}, ] }; @@ -721,10 +716,10 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Service, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'autoUpdate', name: findLocaleServMenu('automatically_updates') ,icon: 'power', offColor: HMIOff, onColor: HMIOn}, - /*PageItem*/{ navigate: true, id: 'NSPanel_FirmwareTasmota', icon: 'usb-flash-drive', offColor: Menu, onColor: Menu, name: findLocaleServMenu('tasmota_firmware'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_FirmwareBerry', icon: 'usb-flash-drive', offColor: Menu, onColor: Menu, name: findLocaleServMenu('berry_driver'), buttonText: findLocaleServMenu('more')}, - /*PageItem*/{ navigate: true, id: 'NSPanel_FirmwareNextion', icon: 'cellphone-cog', offColor: Menu, onColor: Menu, name: findLocaleServMenu('nextion_tft_firmware'), buttonText: findLocaleServMenu('more')} + { id: AliasPath + 'autoUpdate', name: findLocaleServMenu('automatically_updates') ,icon: 'power', offColor: HMIOff, onColor: HMIOn}, + { navigate: true, id: 'NSPanel_FirmwareTasmota', icon: 'usb-flash-drive', offColor: Menu, onColor: Menu, name: findLocaleServMenu('tasmota_firmware'), buttonText: findLocaleServMenu('more')}, + { navigate: true, id: 'NSPanel_FirmwareBerry', icon: 'usb-flash-drive', offColor: Menu, onColor: Menu, name: findLocaleServMenu('berry_driver'), buttonText: findLocaleServMenu('more')}, + { navigate: true, id: 'NSPanel_FirmwareNextion', icon: 'cellphone-cog', offColor: Menu, onColor: Menu, name: findLocaleServMenu('nextion_tft_firmware'), buttonText: findLocaleServMenu('more')} ] }; @@ -737,10 +732,10 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Firmware, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'Tasmota.Version', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Tasmota_Firmware.onlineVersion', name: findLocaleServMenu('available_release'), offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: 'Divider' }, - /*PageItem*/{ id: AliasPath + 'Config.Update.UpdateTasmota', name: findLocaleServMenu('update_tasmota') ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + { id: AliasPath + 'Tasmota.Version', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Tasmota_Firmware.onlineVersion', name: findLocaleServMenu('available_release'), offColor: Menu, onColor: Menu }, + { id: 'Divider' }, + { id: AliasPath + 'Config.Update.UpdateTasmota', name: findLocaleServMenu('update_tasmota') ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, ] }; @@ -753,10 +748,10 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Firmware, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'Display.BerryDriver', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Berry_Driver.onlineVersion', name: findLocaleServMenu('available_release'), offColor: Menu, onColor: Menu}, - /*PageItem*/{ id: 'Divider' }, - /*PageItem*/{ id: AliasPath + 'Config.Update.UpdateBerry', name: findLocaleServMenu('update_berry_driver') ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + { id: AliasPath + 'Display.BerryDriver', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Berry_Driver.onlineVersion', name: findLocaleServMenu('available_release'), offColor: Menu, onColor: Menu}, + { id: 'Divider' }, + { id: AliasPath + 'Config.Update.UpdateBerry', name: findLocaleServMenu('update_berry_driver') ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, ] }; @@ -769,10 +764,10 @@ let NSPanel_Service_SubPage: PageType = 'parent': NSPanel_Firmware, 'home': 'NSPanel_Service', 'items': [ - /*PageItem*/{ id: AliasPath + 'Display_Firmware.TFT.currentVersion', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Display_Firmware.TFT.desiredVersion', name: findLocaleServMenu('desired_release'), offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Display.Model', name: findLocaleServMenu('nspanel_model'), offColor: Menu, onColor: Menu }, - /*PageItem*/{ id: AliasPath + 'Config.Update.UpdateNextion', name: 'Nextion TFT Update' ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, + { id: AliasPath + 'Display_Firmware.TFT.currentVersion', name: findLocaleServMenu('installed_release'), offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Display_Firmware.TFT.desiredVersion', name: findLocaleServMenu('desired_release'), offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Display.Model', name: findLocaleServMenu('nspanel_model'), offColor: Menu, onColor: Menu }, + { id: AliasPath + 'Config.Update.UpdateNextion', name: 'Nextion TFT Update' ,icon: 'refresh', offColor: HMIOff, onColor: MSGreen, buttonText: findLocaleServMenu('start')}, ] }; @@ -920,10 +915,11 @@ export const config: Config = { ScreensaverEntityOnColor: On, ScreensaverEntityOffColor: HMIOff }, - // ------ DE: Ende der Screensaver Einstellungen -------------------- - // ------ EN: End of screensaver settings --------------------------- - //-------DE: Anfang Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- - //-------EN: Start Settings for Hardware Button, if used in software (Rule2) -------------------------------------- +// ------ DE: Ende der Screensaver Einstellungen -------------------- +// ------ EN: End of screensaver settings --------------------------- + +//-------DE: Anfang Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- +//-------EN: Start Settings for Hardware Button, if used in software (Rule2) -------------------------------------- // DE: Konfiguration des linken Schalters des NSPanels // EN: Configuration of the left switch of the NSPanel button1: { @@ -949,8 +945,10 @@ export const config: Config = { entity: null, setValue: null }, - //--------- DE: Ende - Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- - //--------- EN: End - settings for hardware button if they are used in software (Rule2) ------------------------------ + +//--------- DE: Ende - Einstellungen für Hardware Button, wenn Sie softwareseitig genutzt werden (Rule2) ------------- +//--------- EN: End - settings for hardware button if they are used in software (Rule2) ------------------------------ + // DE: WICHTIG !! Parameter nicht ändern WICHTIG!! // EN: IMPORTANT !! Do not change parameters IMPORTANT!! panelRecvTopic: NSPanelReceiveTopic, @@ -965,7 +963,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.33'; +const scriptVersion: string = 'v4.3.3.36'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -985,6 +983,8 @@ const moment = require('moment'); const parseFormat = require('moment-parseformat'); moment.locale(getState(NSPanel_Path + 'Config.locale').val); +const scheduleList:{[key:string]: any} = {}; + const globalTextColor: any = White; const Sliders2: number = 0; let checkBlindActive: boolean = false; @@ -1023,13 +1023,13 @@ let scheduleInitDimModeDay: any; let scheduleInitDimModeNight: any; onStop (function scriptStop () { - if (scheduleSendTime!=null) clearSchedule(scheduleSendTime); - if (scheduleSendDate!=null) clearSchedule(scheduleSendDate); - if (scheduleSwichScreensaver!=null) clearSchedule(scheduleSwichScreensaver); - if (scheduleStartup!=null) clearSchedule(scheduleStartup); - if (scheduleCheckUpdates!=null) clearSchedule(scheduleCheckUpdates); - if (scheduleInitDimModeDay!=null) clearSchedule(scheduleInitDimModeDay); - if (scheduleInitDimModeNight!=null) clearSchedule(scheduleInitDimModeNight); + if (scheduleSendTime!=null) _clearSchedule(scheduleSendTime); + if (scheduleSendDate!=null) _clearSchedule(scheduleSendDate); + if (scheduleSwichScreensaver!=null) _clearSchedule(scheduleSwichScreensaver); + if (scheduleStartup!=null) _clearSchedule(scheduleStartup); + if (scheduleCheckUpdates!=null) _clearSchedule(scheduleCheckUpdates); + if (scheduleInitDimModeDay!=null) _clearSchedule(scheduleInitDimModeDay); + if (scheduleInitDimModeNight!=null) _clearSchedule(scheduleInitDimModeNight); UnsubscribeWatcher(); }, 1000); @@ -1039,7 +1039,18 @@ async function CheckConfigParameters() { log('Config-Parameter: << config.panelRecvTopic - ' + config.panelRecvTopic + ' >> is not reachable. Please Check Parameters!','error'); } if (existsObject(config.panelSendTopic) == false) { - log('Config-Parameter: << config.panelSendTopic - ' + config.panelSendTopic + ' >> is not reachable. Please Check Parameters!','error'); + const n = config.panelSendTopic.split('.'); + const a = n.shift(); + const i = n.shift(); + + if (a === 'mqtt' && !isNaN(Number(i))) { + sendTo(`${a}.${i}`, 'sendMessage2Client', {topic: n.join('/'), message: 'time~12:00'}); + await sleep(500); + } + if (await existsObjectAsync(config.panelSendTopic) == false) { + log('Config-Parameter: << config.panelSendTopic - ' + config.panelSendTopic + ' >> is not reachable. Please Check Parameters!','error'); + stopScript(scriptName); + } } if (weatherAdapterInstance.substring(0, weatherAdapterInstance.length - 3) == 'daswetter') { if (existsObject(weatherAdapterInstance + 'NextHours.Location_1.Day_1.current.symbol_value') == false) { @@ -1064,6 +1075,7 @@ async function CheckConfigParameters() { if (common.name == 'javascript') { javaScriptVersion = common.version; setIfExists(NSPanel_Path + 'IoBroker.JavaScriptVersion', 'v' + javaScriptVersion); + setIfExists(NSPanel_Path + 'IoBroker.ScriptName', (name as unknown as string).split('.').slice(2).join('.')); let jsVersion = common.version.split('.'); let jsV = 10*parseInt(jsVersion[0]) + parseInt(jsVersion[1]); if (jsV<61) log('JS-Adapter: ' + common.name + ' must be at least v6.1.3. Currently: v' + common.version, 'error'); @@ -1105,17 +1117,21 @@ async function InitIoBrokerInfo() { try { if (isSetOptionActive) { // Script Version - await createStateAsync(NSPanel_Path + 'IoBroker.ScriptVersion', scriptVersion, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'IoBroker.ScriptVersion', scriptVersion, { type: 'string', write: false }); setObject(AliasPath + 'IoBroker.ScriptVersion', {type: 'channel', common: {role: 'info', name:'Version NSPanelTS'}, native: {}}); await createAliasAsync(AliasPath + 'IoBroker.ScriptVersion.ACTUAL', NSPanel_Path + 'IoBroker.ScriptVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); // NodeJS Verion - await createStateAsync(NSPanel_Path + 'IoBroker.NodeJSVersion', 'v' + nodeVersion, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'IoBroker.NodeJSVersion', 'v' + nodeVersion, { type: 'string', write: false }); setObject(AliasPath + 'IoBroker.NodeJSVersion', {type: 'channel', common: {role: 'info', name:'Version NodeJS'}, native: {}}); await createAliasAsync(AliasPath + 'IoBroker.NodeJSVersion.ACTUAL', NSPanel_Path + 'IoBroker.NodeJSVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); // JavaScript Version - await createStateAsync(NSPanel_Path + 'IoBroker.JavaScriptVersion', 'v' + javaScriptVersion, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'IoBroker.JavaScriptVersion', 'v' + javaScriptVersion, { type: 'string', write: false }); setObject(AliasPath + 'IoBroker.JavaScriptVersion', {type: 'channel', common: {role: 'info', name:'Version JavaScript Instanz'}, native: {}}); await createAliasAsync(AliasPath + 'IoBroker.JavaScriptVersion.ACTUAL', NSPanel_Path + 'IoBroker.JavaScriptVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); + // ScriptName + await createStateAsync(NSPanel_Path + 'IoBroker.ScriptName', 'v' + javaScriptVersion, { type: 'string', write: false }); + setObject(AliasPath + 'IoBroker.ScriptName', {type: 'channel', common: {role: 'info', name:'Scriptname'}, native: {}}); + await createAliasAsync(AliasPath + 'IoBroker.ScriptName.ACTUAL', NSPanel_Path + 'IoBroker.ScriptName', true, { type: 'string', role: 'state', name: 'ACTUAL' }); } setIfExists(NSPanel_Path + 'IoBroker.ScriptVersion', scriptVersion); } catch (err: any) { @@ -1127,7 +1143,7 @@ InitIoBrokerInfo(); async function CheckDebugMode() { try { if (isSetOptionActive) { - await createStateAsync(NSPanel_Path + 'Config.ScripgtDebugStatus', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.ScripgtDebugStatus', false, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.ScripgtDebugStatus', {type: 'channel', common: {role: 'socket', name:'ScripgtDebugStatus'}, native: {}}); await createAliasAsync(AliasPath + 'Config.ScripgtDebugStatus.ACTUAL', NSPanel_Path + 'Config.ScripgtDebugStatus', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.ScripgtDebugStatus.SET', NSPanel_Path + 'Config.ScripgtDebugStatus', true, { type: 'boolean', role: 'switch', name: 'SET' }); @@ -1152,7 +1168,7 @@ async function CheckMQTTPorts() { let instanceName: string = config.panelRecvTopic.substring(0,6); if (isSetOptionActive) { - await createStateAsync(NSPanel_Path + 'Config.MQTT.portCheck', true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.MQTT.portCheck', true, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.MQTT.portCheck', {type: 'channel', common: {role: 'socket', name:'mqttPortCheck'}, native: {}}); await createAliasAsync(AliasPath + 'Config.MQTT.portCheck.ACTUAL', NSPanel_Path + 'Config.MQTT.portCheck', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.MQTT.portCheck.SET', NSPanel_Path + 'Config.MQTT.portCheck', true, { type: 'boolean', role: 'switch', name: 'SET' }); @@ -1210,13 +1226,13 @@ async function Init_Release() { const FWRelease = ['3.3.1','3.4.0','3.5.0','3.5.X','3.6.0','3.7.3','3.8.0','3.8.3','3.9.4','4.0.5','4.1.4','4.2.1','4.3.3','4.4.0','4.5.0']; try { if (existsObject(NSPanel_Path + 'Display_Firmware.desiredVersion') == false) { - await createStateAsync(NSPanel_Path + 'Display_Firmware.desiredVersion', desired_display_firmware_version, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Display_Firmware.desiredVersion', desired_display_firmware_version, { type: 'number', write: false }); } else { await setStateAsync(NSPanel_Path + 'Display_Firmware.desiredVersion', desired_display_firmware_version); } if (existsObject(NSPanel_Path + 'Config.Update.activ') == false) { - await createStateAsync(NSPanel_Path + 'Config.Update.activ', 1, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Config.Update.activ', 1, { type: 'number', write: false }); } else { await setStateAsync(NSPanel_Path + 'Config.Update.activ', 0); } @@ -1233,8 +1249,8 @@ async function Init_Release() { if (existsObject(NSPanel_Path + 'Display_Firmware.TFT.desiredVersion') == false) { //Create TFT DP's if (isSetOptionActive) { - await createStateAsync(NSPanel_Path + 'Display_Firmware.TFT.currentVersion', currentFW + ' / v' + FWRelease[findFWIndex], { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Display_Firmware.TFT.desiredVersion', desired_display_firmware_version, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Display_Firmware.TFT.currentVersion', currentFW + ' / v' + FWRelease[findFWIndex], { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Display_Firmware.TFT.desiredVersion', desired_display_firmware_version, { type: 'string', write: false }); setObject(AliasPath + 'Display_Firmware.TFT.currentVersion', {type: 'channel', common: {role: 'info', name:'current TFT-Version'}, native: {}}); setObject(AliasPath + 'Display_Firmware.TFT.desiredVersion', {type: 'channel', common: {role: 'info', name:'desired TFT-Version'}, native: {}}); await createAliasAsync(AliasPath + 'Display_Firmware.TFT.currentVersion.ACTUAL', NSPanel_Path + 'Display_Firmware.TFT.currentVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); @@ -1255,54 +1271,54 @@ async function InitConfigParameters() { try { if (isSetOptionActive) { // alternativeScreensaverLayout (socket) - await createStateAsync(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', false, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.Screensaver.alternativeScreensaverLayout', {type: 'channel', common: {role: 'socket', name:'alternativeScreensaverLayout'}, native: {}}); await createAliasAsync(AliasPath + 'Config.Screensaver.alternativeScreensaverLayout.ACTUAL', NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.Screensaver.alternativeScreensaverLayout.SET', NSPanel_Path + 'Config.Screensaver.alternativeScreensaverLayout', true, { type: 'boolean', role: 'switch', name: 'SET' }); - await createStateAsync(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.Screensaver.ScreensaverAdvanced', {type: 'channel', common: {role: 'socket', name:'ScreensaverAdvanced'}, native: {}}); await createAliasAsync(AliasPath + 'Config.Screensaver.ScreensaverAdvanced.ACTUAL', NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.Screensaver.ScreensaverAdvanced.SET', NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', true, { type: 'boolean', role: 'switch', name: 'SET' }); // autoWeatherColorScreensaverLayout (socket) - await createStateAsync(NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout', true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout', true, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout', {type: 'channel', common: {role: 'socket', name:'alternativeScreensaverLayout'}, native: {}}); await createAliasAsync(AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout.ACTUAL', NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.Screensaver.autoWeatherColorScreensaverLayout.SET', NSPanel_Path + 'Config.Screensaver.autoWeatherColorScreensaverLayout', true, { type: 'boolean', role: 'switch', name: 'SET' }); // timeoutScreensaver 0-60 (Slider) - await createStateAsync(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver', 10, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver', 10, { type: 'number', write: true }); setObject(AliasPath + 'Config.Screensaver.timeoutScreensaver', {type: 'channel', common: {role: 'slider', name:'timeoutScreensaver'}, native: {}}); await createAliasAsync(AliasPath + 'Config.Screensaver.timeoutScreensaver.ACTUAL', NSPanel_Path + 'Config.Screensaver.timeoutScreensaver', true, { type: 'number', role: 'value', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.Screensaver.timeoutScreensaver.SET', NSPanel_Path + 'Config.Screensaver.timeoutScreensaver', true, { type: 'number', role: 'level', name: 'SET' }); // screenSaverDoubleClick (socket) - await createStateAsync(NSPanel_Path + 'Config.Screensaver.screenSaverDoubleClick', true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Screensaver.screenSaverDoubleClick', true, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.Screensaver.screenSaverDoubleClick', {type: 'channel', common: {role: 'socket', name:'screenSaverDoubleClick'}, native: {}}); await createAliasAsync(AliasPath + 'Config.Screensaver.screenSaverDoubleClick.ACTUAL', NSPanel_Path + 'Config.Screensaver.screenSaverDoubleClick', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.Screensaver.screenSaverDoubleClick.SET', NSPanel_Path + 'Config.Screensaver.screenSaverDoubleClick', true, { type: 'boolean', role: 'switch', name: 'SET' }); if (existsObject(NSPanel_Path + 'Config.locale') == false) { // en-US, de-DE, nl-NL, da-DK, es-ES, fr-FR, it-IT, ru-RU, etc. - await createStateAsync(NSPanel_Path + 'Config.locale', 'de-DE', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Config.locale', 'de-DE', { type: 'string', write: true }); setStateAsync(NSPanel_Path + 'Config.locale', 'de-DE'); } if (existsObject(NSPanel_Path + 'Config.temperatureUnit') == false) { // '°C', '°F', 'K' - await createStateAsync(NSPanel_Path + 'Config.temperatureUnit', '°C', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Config.temperatureUnit', '°C', { type: 'string', write: true }); } // locale Tastensensor popupInSel buttonSensor if (existsObject(NSPanel_Path + 'Config.localeNumber') == false) { - await createStateAsync(NSPanel_Path + 'Config.localeNumber', 1, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Config.localeNumber', 1, { type: 'number', write: true }); setObject(AliasPath + 'Config.localeNumber', {type: 'channel', common: {role: 'buttonSensor', name:'localeNumber'}, native: {}}); await createAliasAsync(AliasPath + 'Config.localeNumber.VALUE', NSPanel_Path + 'Config.localeNumber', true, { type: 'number', role: 'state', name: 'VALUE' }); } // temperatureUnit popupInSel buttonSensor if (existsObject(NSPanel_Path + 'Config.temperatureUnitNumber') == false) { - await createStateAsync(NSPanel_Path + 'Config.temperatureUnitNumber', 0, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'Config.temperatureUnitNumber', 0, { type: 'number', write: true }); setObject(AliasPath + 'Config.temperatureUnitNumber', {type: 'channel', common: {role: 'buttonSensor', name:'temperatureUnitNumber'}, native: {}}); await createAliasAsync(AliasPath + 'Config.temperatureUnitNumber.VALUE', NSPanel_Path + 'Config.temperatureUnitNumber', true, { type: 'number', role: 'state', name: 'VALUE' }); } @@ -1345,7 +1361,7 @@ on({id: [NSPanel_Path + 'Config.localeNumber', async function Init_ScreensaverAdvanced() { try { if (existsState(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced') == false ) { - await createStateAsync(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false, true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced', false, true, { type: 'boolean', write: true }); } } catch (err: any) { log('error at function Init_ScreensaverAdvanced: ' + err.message, 'warn'); @@ -1363,13 +1379,13 @@ function CheckEnableSetObject() { async function Init_ActivePageData() { try { if (existsState(NSPanel_Path + 'ActivePage.heading') == false ) { - await createStateAsync(NSPanel_Path + 'ActivePage.heading', '', true, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'ActivePage.heading', '', true, { type: 'string', write: false }); } if (existsState(NSPanel_Path + 'ActivePage.type') == false ) { - await createStateAsync(NSPanel_Path + 'ActivePage.type', '', true, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'ActivePage.type', '', true, { type: 'string', write: false }); } if (existsState(NSPanel_Path + 'ActivePage.id0') == false ) { - await createStateAsync(NSPanel_Path + 'ActivePage.id0', '', true, { type: 'string' }); + await createStateAsync(NSPanel_Path + 'ActivePage.id0', '', true, { type: 'string', write: false }); } } catch (err: any) { log('error at function Init_ActivePageData: ' + err.message, 'warn'); @@ -1380,8 +1396,27 @@ Init_ActivePageData(); //switch BackgroundColors for Screensaver Indicators async function Init_Screensaver_Backckground_Color_Switch() { try { - if (existsState(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator') == false ) { - await createStateAsync(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator', 0, true, { type: 'number' }); + const objDef: iobJS.StateObject = { + _id: '', + type: "state", + common: { + type: "number", + name: "Color Indicator", + role: "level", + states: {0:'black', 1:'red', 2:'green', 3:'attention', 4: 'pink', 5: 'dark red'}, + read: true, + write: true + }, + "native": {}, + }; + await extendObjectAsync(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator', objDef) + if (await existsStateAsync(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator')) { + const obj = await getStateAsync(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator'); + if (obj && obj.val !== null && obj.val !== undefined) { + bgColorScrSaver = obj.val; + } else { + setStateAsync(NSPanel_Path + 'ScreensaverInfo.bgColorIndicator', bgColorScrSaver) + } } } catch (err: any) { log('error at function Init_Screensaver_Backckground_Color_Switch: ' + err.message, 'warn'); @@ -1425,7 +1460,7 @@ async function Init_bExit_Page_Change() { alwaysOn = false; pageCounter = 0; if (existsState(NSPanel_Path + 'ScreensaverInfo.bExitPage') == false ) { - await createStateAsync(NSPanel_Path + 'ScreensaverInfo.bExitPage', -1, true, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.bExitPage', -1, true, { type: 'number', write: true }); } } catch (err: any) { log('error at function Init_bExit_Page_Change: ' + err.message, 'warn'); @@ -1437,7 +1472,7 @@ Init_bExit_Page_Change(); async function Init_Dimmode_Trigger() { try { if (existsState(NSPanel_Path + 'ScreensaverInfo.Trigger_Dimmode') == false ) { - await createStateAsync(NSPanel_Path + 'ScreensaverInfo.Trigger_Dimmode', false, true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.Trigger_Dimmode', false, true, { type: 'boolean', write: true }); } } catch (err: any) { log('error at function Init_Dimmode_Trigger: ' + err.message, 'warn'); @@ -1450,8 +1485,8 @@ async function InitActiveBrightness() { if (isSetOptionActive) { if (existsState(NSPanel_Path + 'ScreensaverInfo.activeBrightness') == false || existsState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness') == false) { - await createStateAsync(NSPanel_Path + 'ScreensaverInfo.activeBrightness', 100, { type: 'number' }); - await createStateAsync(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness', -1, { type: 'number' }); + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.activeBrightness', 100, { type: 'number', write: true }); + await createStateAsync(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness', -1, { type: 'number', write: true }); } //Create Alias activeBrightness setObject(AliasPath + 'ScreensaverInfo.activeBrightness', {type: 'channel', common: {role: 'slider', name:'activeBrightness'}, native: {}}); @@ -1464,6 +1499,19 @@ async function InitActiveBrightness() { } InitActiveBrightness(); +on({id: [NSPanel_Path + 'ScreensaverInfo.activeBrightness'], change: 'ne'}, async function (obj) { + try { + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val; + if (obj.state.val >= 0 || obj.state.val <= 100) { + log('action at trigger activeBrightness: ' + obj.state.val + ' - activeDimmodeBrightness: ' + active, 'info'); + SendToPanel({ payload: 'dimmode~' + active + '~' + obj.state.val + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); + InitDimmode(); + } + } catch (err:any) { + log('error at trigger activeBrightness: ' + err.message, 'warn'); + } +}); + on({id: [NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness'], change: "ne"}, async function (obj) { try { let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val; @@ -1510,7 +1558,7 @@ on({id: String(NSPanel_Path) + 'ScreensaverInfo.Trigger_Dimmode', change: "ne"}, async function InitRebootPanel() { try { if (existsState(NSPanel_Path + 'Config.rebootNSPanel') == false) { - await createStateAsync(NSPanel_Path + 'Config.rebootNSPanel', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.rebootNSPanel', false, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.rebootNSPanel', {type: 'channel', common: {role: 'button', name:'Reboot NSPanel'}, native: {}}); await createAliasAsync(AliasPath + 'Config.rebootNSPanel.SET', NSPanel_Path + 'Config.rebootNSPanel', true, { type: 'boolean', role: 'state', name: 'SET' }); } @@ -1540,7 +1588,9 @@ on({id: AliasPath + 'Config.rebootNSPanel.SET', change: "any"}, async function ( } }) .catch(function (error) { - log(error, 'warn'); + if (error.code === 'EHOSTUNREACH') { + log(`Can't connect to display!`, 'warn') + } else log(error, 'warn'); }) .finally(function () { if (Debug) { @@ -1557,9 +1607,9 @@ async function InitUpdateDatapoints() { try { if (existsState(NSPanel_Path + 'Config.Update.UpdateTasmota') == false) { if (isSetOptionActive) { - await createStateAsync(NSPanel_Path + 'Config.Update.UpdateTasmota', false, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + 'Config.Update.UpdateBerry', false, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + 'Config.Update.UpdateNextion', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Update.UpdateTasmota', false, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + 'Config.Update.UpdateBerry', false, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + 'Config.Update.UpdateNextion', false, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.Update.UpdateTasmota', {type: 'channel', common: {role: 'button', name:'Tassmota update'}, native: {}}); setObject(AliasPath + 'Config.Update.UpdateBerry', {type: 'channel', common: {role: 'button', name:'Berry-Driver update'}, native: {}}); setObject(AliasPath + 'Config.Update.UpdateNextion', {type: 'channel', common: {role: 'button', name:'Nextion TFT update'}, native: {}}); @@ -1603,8 +1653,8 @@ async function Init_Relays() { if (isSetOptionActive) { if (existsState(NSPanel_Path + 'Relay.1') == false || existsState(NSPanel_Path + 'Relay.2') == false) { - await createStateAsync(NSPanel_Path + 'Relay.1', true, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + 'Relay.2', true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Relay.1', true, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + 'Relay.2', true, { type: 'boolean', write: true }); } setObject(AliasPath + 'Relay.1', {type: 'channel', common: {role: 'socket', name:'Relay.1'}, native: {}}); await createAliasAsync(AliasPath + 'Relay.1.ACTUAL', NSPanel_Path + 'Relay.1', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); @@ -1626,8 +1676,8 @@ async function InitAlternateMRIconsSize() { if (isSetOptionActive) { if (existsState(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1') == false || existsState(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2') == false) { - await createStateAsync(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1', false, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2', false, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1', false, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2', false, { type: 'boolean', write: true }); } //Create Alias alternateMRIconSize 1 setObject(AliasPath + 'Config.MRIcons.alternateMRIconSize.1', {type: 'channel', common: {role: 'socket', name:'alternateMRIconSize.1'}, native: {}}); @@ -1651,14 +1701,14 @@ async function InitDateformat() { if (existsState(NSPanel_Path + 'Config.Dateformat.weekday') == false || existsState(NSPanel_Path + 'Config.Dateformat.month') == false || existsState(NSPanel_Path + 'Config.Dateformat.customFormat') == false) { - await createStateAsync(NSPanel_Path + 'Config.Dateformat.weekday', 'long', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Config.Dateformat.month', 'long', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Config.Dateformat.customFormat', '', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.weekday', 'long', { type: 'string', write: true }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.month', 'long', { type: 'string', write: true }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.customFormat', '', { type: 'string', write: true }); } if (existsState(NSPanel_Path + 'Config.Dateformat.Switch.weekday') == false || existsState(NSPanel_Path + 'Config.Dateformat.Switch.month') == false) { - await createStateAsync(NSPanel_Path + 'Config.Dateformat.Switch.weekday', true, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + 'Config.Dateformat.Switch.month', true, { type: 'boolean' }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.Switch.weekday', true, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + 'Config.Dateformat.Switch.month', true, { type: 'boolean', write: true }); setObject(AliasPath + 'Config.Dateformat.Switch.weekday', {type: 'channel', common: {role: 'socket', name:'Dateformat Switch weekday'}, native: {}}); await createAliasAsync(AliasPath + 'Config.Dateformat.Switch.weekday.ACTUAL', NSPanel_Path + 'Config.Dateformat.Switch.weekday', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Config.Dateformat.Switch.weekday.SET', NSPanel_Path + 'Config.Dateformat.Switch.weekday', true, { type: 'boolean', role: 'switch', name: 'SET' }); @@ -1695,8 +1745,19 @@ on({id: [String(NSPanel_Path) + 'Config.Dateformat.Switch.weekday', } }); +//Set Relays from Tasmota +const NSPanelStatTopic = NSPanelSendTopic.replace('.cmnd.','.stat.').replace(/\.CustomSend$/g,'.'); +on({id: [String(NSPanelStatTopic) + 'POWER1',String(NSPanelStatTopic) + 'POWER2'], change: "ne"}, (obj) => { + if (!obj || !obj.id) return + const n = obj.id.substring(obj.id.length-1); + if ( n === '1' || n === '2') { + if (getState(NSPanel_Path + 'Relay.' + n).val != obj.state.val) { + setState(NSPanel_Path + 'Relay.' + n, obj.state.val == 'ON' ? true : false, true); + } + } +}) //Control Relays from DP's -on({id: [String(NSPanel_Path) + 'Relay.1',String(NSPanel_Path) + 'Relay.2'], change: "ne"}, async function (obj) { +on({id: [String(NSPanel_Path) + 'Relay.1',String(NSPanel_Path) + 'Relay.2'], change: "ne", ack: false}, async function (obj) { try { let Button = obj.id!.split('.'); let urlString: string = ['http://',get_current_tasmota_ip_address(),'/cm?cmnd=Power',Button[Button.length - 1],' ',(obj.state ? obj.state.val : "")].join(''); @@ -1710,7 +1771,9 @@ on({id: [String(NSPanel_Path) + 'Relay.1',String(NSPanel_Path) + 'Relay.2'], cha } }) .catch(function (error) { - log(error, 'warn'); + if (error.code === 'EHOSTUNREACH') { + log(`Can't connect to display!`, 'warn') + } else log(error, 'warn'); }) } catch (err: any) { @@ -1800,7 +1863,7 @@ CreateWeatherAlias(); async function InitPageNavi() { try { if (!existsState(NSPanel_Path + 'PageNavi')) { - await createStateAsync(NSPanel_Path + 'PageNavi', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'PageNavi', { type: 'string', write: true }); await setStateAsync(NSPanel_Path + 'PageNavi', { val: {"pagetype": "page","pageId": 0}, ack: true }); } } catch (err: any) { @@ -1826,7 +1889,7 @@ on({id: [NSPanel_Path + 'PageNavi'], change: "any"}, async function (obj) { }); //----------------------Begin Dimmode -function ScreensaverDimmode(timeDimMode: DimMode) { +function ScreensaverDimmode(timeDimMode:NSPanel.DimMode) { try { let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val let dimmode = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val @@ -1840,12 +1903,12 @@ function ScreensaverDimmode(timeDimMode: DimMode) { if (compareTime(timeDimMode.timeNight != undefined ? timeDimMode.timeNight : '22:00', timeDimMode.timeDay != undefined ? timeDimMode.timeDay : '07:00', 'not between', undefined)) { SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessDay + '~' + active + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); if (Debug) { - log('function ScreensaverDimmode -> Day Payload: ' + 'dimmode~' + timeDimMode.brightnessDay + '~' + active, 'info'); + log('function ScreensaverDimmode -> Day NSPanel.Payload: ' + 'dimmode~' + timeDimMode.brightnessDay + '~' + active, 'info'); } } else { SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessNight + '~' + active + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); if (Debug) { - log('function ScreensaverDimmode -> Night Payload: ' + 'dimmode~' + timeDimMode.brightnessNight + '~' + active, 'info'); + log('function ScreensaverDimmode -> Night NSPanel.Payload: ' + 'dimmode~' + timeDimMode.brightnessNight + '~' + active, 'info'); } } } else { @@ -1863,9 +1926,9 @@ async function InitWeatherForecast() { if (existsState(NSPanel_Path + "ScreensaverInfo.weatherForecast") == false || existsState(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer") == false || existsState(NSPanel_Path + "ScreensaverInfo.entityChangeTime") == false) { - await createStateAsync(NSPanel_Path + "ScreensaverInfo.weatherForecast", true, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer", true, { type: 'boolean' }); - await createStateAsync(NSPanel_Path + "ScreensaverInfo.entityChangeTime", 60, { type: 'number' }); + await createStateAsync(NSPanel_Path + "ScreensaverInfo.weatherForecast", true, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer", true, { type: 'boolean', write: true }); + await createStateAsync(NSPanel_Path + "ScreensaverInfo.entityChangeTime", 60, { type: 'number', write: true }); } //Create Alias weatherForecast setObject(AliasPath + 'ScreensaverInfo.weatherForecast', {type: 'channel', common: {role: 'socket', name:'weatherForecast'}, native: {}}); @@ -1891,28 +1954,28 @@ async function InitDimmode() { if (isSetOptionActive) { // Screensaver on dark at night ("brightnessNight: e.g. 2") or off ("brightnessNight:0") if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay')) { - await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', { type: 'number', write: true }); await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', { val: 8, ack: true }); setObject(AliasPath + 'Dimmode.brightnessDay', {type: 'channel', common: {role: 'slider', name:'brightnessDay'}, native: {}}); await createAliasAsync(AliasPath + 'Dimmode.brightnessDay.ACTUAL', NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', true, { type: 'number', role: 'value', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Dimmode.brightnessDay.SET', NSPanel_Path + 'NSPanel_Dimmode_brightnessDay', true, { type: 'number', role: 'level', name: 'SET' }); } if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_hourDay')) { - await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourDay', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourDay', { type: 'number', write: true }); await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourDay', { val: 7, ack: true }); setObject(AliasPath + 'Dimmode.hourDay', {type: 'channel', common: {role: 'slider', name:'hourDay'}, native: {}}); await createAliasAsync(AliasPath + 'Dimmode.hourDay.ACTUAL', NSPanel_Path + 'NSPanel_Dimmode_hourDay', true, { type: 'number', role: 'value', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Dimmode.hourDay.SET', NSPanel_Path + 'NSPanel_Dimmode_hourDay', true, { type: 'number', role: 'level', name: 'SET' }); } if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight')) { - await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', { type: 'number', write: true }); await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', { val: 1, ack: true }); setObject(AliasPath + 'Dimmode.brightnessNight', {type: 'channel', common: {role: 'slider', name:'brightnessNight'}, native: {}}); await createAliasAsync(AliasPath + 'Dimmode.brightnessNight.ACTUAL', NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', true, { type: 'number', role: 'value', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'Dimmode.brightnessNight.SET', NSPanel_Path + 'NSPanel_Dimmode_brightnessNight', true, { type: 'number', role: 'level', name: 'SET' }); } if (!existsState(NSPanel_Path + 'NSPanel_Dimmode_hourNight')) { - await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourNight', { type: 'number' }); + await createStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourNight', { type: 'number', write: true }); await setStateAsync(NSPanel_Path + 'NSPanel_Dimmode_hourNight', { val: 22, ack: true }); setObject(AliasPath + 'Dimmode.hourNight', {type: 'channel', common: {role: 'slider', name:'hourNight'}, native: {}}); await createAliasAsync(AliasPath + 'Dimmode.hourNight.ACTUAL', NSPanel_Path + 'NSPanel_Dimmode_hourNight', true, { type: 'number', role: 'value', name: 'ACTUAL' }); @@ -1920,7 +1983,7 @@ async function InitDimmode() { } const vTimeDay = getState(NSPanel_Path + 'NSPanel_Dimmode_hourDay').val; const vTimeNight = getState(NSPanel_Path + 'NSPanel_Dimmode_hourNight').val; - const timeDimMode: DimMode = { + const timeDimMode: NSPanel.DimMode = { dimmodeOn: true, brightnessDay: getState(NSPanel_Path + 'NSPanel_Dimmode_brightnessDay').val, brightnessNight: getState(NSPanel_Path + 'NSPanel_Dimmode_brightnessNight').val, @@ -1928,11 +1991,11 @@ async function InitDimmode() { timeNight: (vTimeNight < 10) ? `0${vTimeNight}:00` : `${vTimeNight}:00` }; // timeDimMode Day - scheduleInitDimModeDay = schedule({ hour: getState(NSPanel_Path + 'NSPanel_Dimmode_hourDay').val, minute: 0 }, () => { + scheduleInitDimModeDay = adapterSchedule({ hour: getState(NSPanel_Path + 'NSPanel_Dimmode_hourDay').val, minute: 0}, 24 * 60 * 60, () => { ScreensaverDimmode(timeDimMode); }); // timeDimMode Night - scheduleInitDimModeNight = schedule({ hour: getState(NSPanel_Path + 'NSPanel_Dimmode_hourNight').val, minute: 0 }, () => { + scheduleInitDimModeNight = adapterSchedule({ hour: getState(NSPanel_Path + 'NSPanel_Dimmode_hourNight').val, minute: 0 }, 24 * 60 * 60, () => { ScreensaverDimmode(timeDimMode); }); if (getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val != null && getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val != -1) { @@ -2009,31 +2072,31 @@ async function InitPopupNotify() { try { if (!existsState(screensaverNotifyHeading)) { - await createStateAsync(screensaverNotifyHeading, { type: 'string' }); + await createStateAsync(screensaverNotifyHeading, { type: 'string', write: true }); await setStateAsync(screensaverNotifyHeading, { val: '', ack: true }); } if (!existsState(screensaverNotifyText)) { - await createStateAsync(screensaverNotifyText, { type: 'string' }); + await createStateAsync(screensaverNotifyText, { type: 'string', write: true }); await setStateAsync(screensaverNotifyText, { val: '', ack: true }); } - await createStateAsync(popupNotifyHeading, { type: 'string' }); - await createStateAsync(popupNotifyHeadingColor, { type: 'string' }); - await createStateAsync(popupNotifyText, { type: 'string' }); - await createStateAsync(popupNotifyTextColor, { type: 'string' }); - await createStateAsync(popupNotifyInternalName, { type: 'string' }); - await createStateAsync(popupNotifyButton1Text, { type: 'string' }); - await createStateAsync(popupNotifyButton1TextColor, { type: 'string' }); - await createStateAsync(popupNotifyButton2Text, { type: 'string' }); - await createStateAsync(popupNotifyButton2TextColor, { type: 'string' }); - await createStateAsync(popupNotifySleepTimeout, { type: 'number' }); - await createStateAsync(popupNotifyAction, { type: 'boolean' }); - await createStateAsync(popupNotifyLayout, { type: 'number' }); - await createStateAsync(popupNotifyFontIdText, { type: 'number' }); - await createStateAsync(popupNotifyIcon, { type: 'string' }); - await createStateAsync(popupNotifyIconColor, { type: 'string' }); - await createStateAsync(popupNotifyBuzzer,{type: 'string', def: '0'}); + await createStateAsync(popupNotifyHeading, { type: 'string', write: true }); + await createStateAsync(popupNotifyHeadingColor, { type: 'string', write: true }); + await createStateAsync(popupNotifyText, { type: 'string', write: true }); + await createStateAsync(popupNotifyTextColor, { type: 'string', write: true }); + await createStateAsync(popupNotifyInternalName, { type: 'string', write: true }); + await createStateAsync(popupNotifyButton1Text, { type: 'string', write: true }); + await createStateAsync(popupNotifyButton1TextColor, { type: 'string', write: true }); + await createStateAsync(popupNotifyButton2Text, { type: 'string', write: true }); + await createStateAsync(popupNotifyButton2TextColor, { type: 'string', write: true }); + await createStateAsync(popupNotifySleepTimeout, { type: 'number', write: true }); + await createStateAsync(popupNotifyAction, { type: 'boolean', write: true }); + await createStateAsync(popupNotifyLayout, { type: 'number', write: true }); + await createStateAsync(popupNotifyFontIdText, { type: 'number', write: true }); + await createStateAsync(popupNotifyIcon, { type: 'string', write: true }); + await createStateAsync(popupNotifyIconColor, { type: 'string', write: true }); + await createStateAsync(popupNotifyBuzzer,{type: 'string', def: '0', write: true}); // Notification to screensaver on({ id: [screensaverNotifyHeading, screensaverNotifyText], change: 'ne', ack: false }, async (obj) => { @@ -2107,7 +2170,9 @@ async function InitPopupNotify() { } }) .catch(function (error) { - log(error, 'warn'); + if (error.code === 'EHOSTUNREACH') { + log(`Can't connect to display!`, 'warn') + } else log(error, 'warn'); }); } else { if (Debug){ @@ -2129,7 +2194,7 @@ let pageId = 0; let activePage: PageType | undefined = undefined; //Send time to NSPanel -let scheduleSendTime = schedule('* * * * *', () => { +let scheduleSendTime = adapterSchedule(new Date().setSeconds(0,0), 60, () => { try { SendTime(); HandleScreensaverUpdate(); @@ -2139,7 +2204,7 @@ let scheduleSendTime = schedule('* * * * *', () => { }); //Switch between Screensaver Entities and WeatherForecast -let scheduleSwichScreensaver = schedule('*/' + getState(NSPanel_Path + 'ScreensaverInfo.entityChangeTime').val + ' * * * * *', () => { +let scheduleSwichScreensaver = adapterSchedule(undefined, parseInt(getState(NSPanel_Path + 'ScreensaverInfo.entityChangeTime').val), () => { try { //WeatherForecast true/false Switchover delayed if (getState(NSPanel_Path + "ScreensaverInfo.popupNotifyHeading").val == '' && getState(NSPanel_Path + "ScreensaverInfo.popupNotifyText").val == '' && getState(NSPanel_Path + "ScreensaverInfo.weatherForecast").val == true && getState(NSPanel_Path + "ScreensaverInfo.weatherForecastTimer").val == true) { @@ -2198,17 +2263,17 @@ on({id: [config.weatherEntity + '.TEMP', } }); -let scheduleSendDate = schedule('0 * * * *', () => { +let scheduleSendDate = adapterSchedule((new Date().setMinutes(0,0)),60*60, () => { SendDate(); }); // 3:30 a.m. Perform startup and receive current TFT version -let scheduleStartup = schedule({ hour: 3, minute: 30 }, async () => { - await setStateAsync(config.panelSendTopic, 'pageType~pageStartup'); +let scheduleStartup = adapterSchedule({ hour: 3, minute: 30 }, 24*60*60, async () => { + setIfExists(config.panelSendTopic, 'pageType~pageStartup'); }); // Updates currently compare every 12 hours -let scheduleCheckUpdates = schedule('{"time":{"start":"00:00","end":"23:59","mode":"hours","interval":12},"period":{"days":1}}', () => { +let scheduleCheckUpdates = adapterSchedule(undefined,60*60*12, () => { get_tasmota_status0(); get_panel_update_data(); check_updates(); @@ -2217,7 +2282,7 @@ let scheduleCheckUpdates = schedule('{"time":{"start":"00:00","end":"23:59","mod // Check for updates with Start get_locales(); get_locales_servicemenu(); -setState(config.panelSendTopic, 'pageType~pageStartup'); +setIfExists(config.panelSendTopic, 'pageType~pageStartup'); get_tasmota_status0(); get_panel_update_data(); check_updates(); @@ -2257,7 +2322,7 @@ async function get_locales() { if (Debug) { log(JSON.stringify(response.data), 'info'); } - await createStateAsync(NSPanel_Path + 'NSPanel_locales_json', { type: 'string', role: 'json' }); + await createStateAsync(NSPanel_Path + 'NSPanel_locales_json', { type: 'string', role: 'json', write: false }); await setStateAsync(NSPanel_Path + 'NSPanel_locales_json', { val: JSON.stringify(response.data), ack: true }); } else { log('Axios Status - Requesting locales: ' + response.state, 'warn'); @@ -2285,7 +2350,7 @@ async function get_locales_servicemenu() { if (Debug) { log(JSON.stringify(response.data), 'info'); } - await createStateAsync(NSPanel_Path + 'NSPanel_locales_service_json', { type: 'string', role: 'json' }); + await createStateAsync(NSPanel_Path + 'NSPanel_locales_service_json', { type: 'string', role: 'json', write: false }); await setStateAsync(NSPanel_Path + 'NSPanel_locales_service_json', { val: JSON.stringify(response.data), ack: true }); } else { log('Axios Status - Requesting locales Service Menu: ' + response.state, 'warn'); @@ -2326,7 +2391,7 @@ async function check_updates() { if (existsState(NSPanel_Path + 'NSPanel_autoUpdate')) { if (getState(NSPanel_Path + 'NSPanel_autoUpdate').val) { - if (Debug) log('Auto-Updates eingeschaltet - Update Tasmota wird durchgeführt', 'info'); + log('Auto-Updates eingeschaltet - Update Tasmota wird durchgeführt', 'info'); // Perform Tasmota upgrade update_tasmota_firmware(); @@ -2354,7 +2419,7 @@ async function check_updates() { if (existsState(NSPanel_Path + 'NSPanel_autoUpdate')) { if (getState(NSPanel_Path + 'NSPanel_autoUpdate').val) { - if (Debug) log('Auto-updates switched on - Berry driver update is carried out', 'info'); + log('Auto-updates switched on - Berry driver update is carried out', 'info'); // Tasmota Berry-Driver Update durchführen update_berry_driver_version(); @@ -2384,7 +2449,7 @@ async function check_updates() { if (existsState(NSPanel_Path + 'NSPanel_autoUpdate')) { if (getState(NSPanel_Path + 'NSPanel_autoUpdate').val) { - if (Debug) log('Auto-updates switched on - update TFT firmware is carried out', 'info'); + log('Auto-updates switched on - update TFT firmware is carried out', 'info'); // TFT-Firmware Update durchführen update_tft_firmware(); @@ -2473,7 +2538,7 @@ async function get_panel_update_data() { await createAliasAsync(AliasPath + 'autoUpdate.ACTUAL', NSPanel_Path + 'NSPanel_autoUpdate', true, { type: 'boolean', role: 'switch', name: 'ACTUAL' }); await createAliasAsync(AliasPath + 'autoUpdate.SET', NSPanel_Path + 'NSPanel_autoUpdate', true, { type: 'boolean', role: 'switch', name: 'SET' }); } - await createStateAsync(NSPanel_Path + 'NSPanel_ipAddress', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'NSPanel_ipAddress', { type: 'string', write: false }); await setStateAsync(NSPanel_Path + 'NSPanel_ipAddress', { val: get_current_tasmota_ip_address(), ack: true }); if (autoCreateAlias) { setObject(AliasPath + 'ipAddress', {type: 'channel', common: {role: 'info', name:'ipAddress'}, native: {}}); @@ -2523,7 +2588,7 @@ function get_online_tasmota_firmware_version() { const Tasmota_JSON = JSON.parse(JSON.stringify(response.data));// Write JSON result to variable const TasmotaTagName = Tasmota_JSON.tag_name; // Filter JSON by "tag_name" and write to variable const TasmotaVersionOnline = TasmotaTagName.replace(/v/i, ''); // Filter unnecessary "v" from variable and write to release variable - await createStateAsync(NSPanel_Path + 'Tasmota_Firmware.onlineVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota_Firmware.onlineVersion', { type: 'string', write: false }); setObject(AliasPath + 'Tasmota_Firmware.onlineVersion', {type: 'channel', common: {role: 'info', name:'onlineVersion'}, native: {}}); await createAliasAsync(AliasPath + 'Tasmota_Firmware.onlineVersion.ACTUAL', NSPanel_Path + 'Tasmota_Firmware.onlineVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); await setStateAsync(NSPanel_Path + 'Tasmota_Firmware.onlineVersion', { val: TasmotaVersionOnline, ack: true }); @@ -2561,7 +2626,7 @@ function get_current_berry_driver_version() { } if (isSetOptionActive) { const BerryDriverVersionCurrent: string = JSON.parse(JSON.stringify(response.data)).nlui_driver_version; - await createStateAsync(NSPanel_Path + 'Berry_Driver.currentVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Berry_Driver.currentVersion', { type: 'string', write: false }); await setStateAsync(NSPanel_Path + 'Berry_Driver.currentVersion', { val: JSON.parse(JSON.stringify(response.data)).nlui_driver_version, ack: true }); if (autoCreateAlias) { setObject(AliasPath + 'Display.BerryDriver', {type: 'channel', common: {role: 'info', name: 'Berry Driver'}, native: {}}); @@ -2574,7 +2639,9 @@ function get_current_berry_driver_version() { } }) .catch(function (error) { - log(error, 'warn'); + if (error.code === 'EHOSTUNREACH') { + log(`Can't connect to display!`, 'warn') + } else log(error, 'warn'); }); } catch (err: any) { @@ -2600,18 +2667,18 @@ function get_tasmota_status0() { log(JSON.stringify(response.data), 'info'); } if (isSetOptionActive) { - await createStateAsync(NSPanel_Path + 'Tasmota_Firmware.currentVersion', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Uptime', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Version', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Hardware', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.AP', { type: 'number' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.SSId', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.BSSId', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Channel', { type: 'number' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Mode', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.RSSI', { type: 'number' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Signal', { type: 'number' }); - await createStateAsync(NSPanel_Path + 'Tasmota.Product', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Tasmota_Firmware.currentVersion', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Uptime', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Version', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Hardware', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.AP', { type: 'number', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.SSId', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.BSSId', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Channel', { type: 'number', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Mode', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.RSSI', { type: 'number', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Wifi.Signal', { type: 'number', write: false }); + await createStateAsync(NSPanel_Path + 'Tasmota.Product', { type: 'string', write: false }); try { const Tasmota_JSON = JSON.parse(JSON.stringify(response.data)); @@ -2664,7 +2731,9 @@ function get_tasmota_status0() { } }) .catch(function (error) { - log(error, 'warn'); + if (error.code === 'EHOSTUNREACH') { + log(`Can't connect to display!`, 'warn') + } else log(error, 'error'); }); } catch (err: any) { @@ -2689,7 +2758,7 @@ function get_online_berry_driver_version() { } if (isSetOptionActive) { const BerryDriverVersionOnline = response.data.substring((response.data.indexOf('version_of_this_script = ') + 24), response.data.indexOf('version_of_this_script = ') + 27).replace(/\s+/g, ''); - await createStateAsync(NSPanel_Path + 'Berry_Driver.onlineVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Berry_Driver.onlineVersion', { type: 'string', write: false }); setObject(AliasPath + 'Berry_Driver.onlineVersion', {type: 'channel', common: {role: 'info', name:'onlineVersion'}, native: {}}); await createAliasAsync(AliasPath + 'Berry_Driver.onlineVersion.ACTUAL', NSPanel_Path + 'Berry_Driver.onlineVersion', true, { type: 'string', role: 'state', name: 'ACTUAL' }); await setStateAsync(NSPanel_Path + 'Berry_Driver.onlineVersion', { val: BerryDriverVersionOnline, ack: true }); @@ -2727,7 +2796,7 @@ function check_version_tft_firmware() { let NSPanelTagName = NSPanel_JSON.tag_name; // created_at; published_at; name ; draft ; prerelease let NSPanelVersion = NSPanelTagName.replace(/v/i, ''); // Filter unnecessary "v" from variable and write to release variable - await createStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { type: 'string', write: false }); await setStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { val: NSPanelVersion, ack: true }); if (Debug) log('online TFT firmware version => ' + NSPanelVersion, 'info'); } else { @@ -2759,7 +2828,7 @@ function check_online_display_firmware() { } let desired_display_firmware_version = response.data.substring((response.data.indexOf('desired_display_firmware_version =') + 34), response.data.indexOf('desired_display_firmware_version =') + 38).replace(/\s+/g, ''); - await createStateAsync(NSPanel_Path + 'Display_Firmware.onlineVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Display_Firmware.onlineVersion', { type: 'string', write: false }); await setStateAsync(NSPanel_Path + 'Display_Firmware.onlineVersion', { val: desired_display_firmware_version, ack: true }); if (Debug) log('online display firmware version => ' + desired_display_firmware_version, 'info'); } else { @@ -2784,8 +2853,8 @@ on({ id: config.panelRecvTopic }, async (obj) => { if (isSetOptionActive) { if (split[0] == 'event' && split[1] == 'startup') { - await createStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'NSPanel_Version', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'NSPanel_Version', { type: 'string', write: false }); await setStateAsync(NSPanel_Path + 'Display_Firmware.currentVersion', { val: split[2], ack: true }); await setStateAsync(NSPanel_Path + 'NSPanel_Version', { val: split[3], ack: true }); @@ -2863,7 +2932,7 @@ function update_tft_firmware() { if (Debug) { log(response.data, 'info'); } - await createStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { type: 'string' }); + await createStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { type: 'string', write: false }); await setStateAsync(NSPanel_Path + 'TFT_Firmware.onlineVersion', { val: tft_version, ack: true }); Init_Release(); } else { @@ -2947,17 +3016,17 @@ on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESU //------------------End Update Functions -async function SendToPanel(val: Payload | Payload[]) { +async function SendToPanel(val: NSPanel.Payload | NSPanel.Payload[]) { try { if (Array.isArray(val)) { val.forEach(function (id) { - setStateAsync(config.panelSendTopic, id.payload); + setIfExists(config.panelSendTopic, id.payload); if (Debug) { log('function SendToPanel payload: ' + id.payload, 'info'); } }); } else { - setState(config.panelSendTopic, val.payload); + setIfExists(config.panelSendTopic, val.payload); } } catch (err: any) { @@ -2980,10 +3049,10 @@ on({ id: NSPanel_Alarm_Path + 'Alarm.AlarmState', change: 'ne' }, async (obj) => } }); -function HandleMessage(typ: string, method: EventMethod, page: number | undefined, words: Array | undefined): void { +function HandleMessage(typ: string, method: NSPanel.EventMethod, page: number | undefined, words: Array | undefined): void { try { if (typ == 'event') { - switch (method as EventMethod) { + switch (method as NSPanel.EventMethod) { case 'startup': screensaverEnabled = false; UnsubscribeWatcher(); @@ -3021,8 +3090,8 @@ function HandleMessage(typ: string, method: EventMethod, page: number | undefine tempId = tempPageItem[0]; } let pageItem: PageItem = findPageItem(tempId); - if (pageItem !== undefined) { - let temp: string | mediaOptional | undefined = tempPageItem[1] + if (pageItem !== undefined && isPopupType(words[2])) { + let temp: string | NSPanel.mediaOptional | undefined = tempPageItem[1] if (isMediaOptional(temp)) SendToPanel(GenerateDetailPage(words[2], temp, pageItem, placeId)); else SendToPanel(GenerateDetailPage(words[2], undefined, pageItem, placeId)); } @@ -3129,9 +3198,9 @@ function GeneratePage(page: PageType): void { } } -function HandleHardwareButton(method: EventMethod): void { +function HandleHardwareButton(method: NSPanel.EventMethod): void { try { - let buttonConfig: ConfigButtonFunction = config[method]; + let buttonConfig: NSPanel.ConfigButtonFunction = config[method]; if(buttonConfig.mode === null) { return; } @@ -3185,7 +3254,7 @@ function SendDate(): void { const options: any = { weekday: dpWeekday, year: 'numeric', month: dpMonth, day: 'numeric' }; const _SendDate = dpCustomFormat != '' ? dayjs().format(dpCustomFormat) : date.toLocaleDateString(getState(NSPanel_Path + 'Config.locale').val, options); - SendToPanel({ payload: 'date~' + _SendDate }); + SendToPanel({ payload: 'date~' + _SendDate }); } } catch (err: any) { if (err.message = 'Cannot convert undefined or null to object') { @@ -3202,15 +3271,15 @@ function SendTime(): void { const hr = (d.getHours() < 10 ? '0' : '') + d.getHours(); const min = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); - SendToPanel({ payload: 'time~' + hr + ':' + min }); + SendToPanel({ payload: 'time~' + hr + ':' + min }); } catch (err: any) { log('error at function SendTime: ' + err.message, 'warn'); } } -function GenerateEntitiesPage(page: PageEntities): Payload[] { +function GenerateEntitiesPage(page: NSPanel.PageEntities): NSPanel.Payload[] { try { - let out_msgs: Array; + let out_msgs: Array; out_msgs = [{ payload: 'pageType~cardEntities' }] out_msgs.push({ payload: GeneratePageElements(page) }); return out_msgs @@ -3220,9 +3289,9 @@ function GenerateEntitiesPage(page: PageEntities): Payload[] { } } -function GenerateGridPage(page: PageGrid): Payload[] { +function GenerateGridPage(page: NSPanel.PageGrid): NSPanel.Payload[] { try { - let out_msgs: Array = [{ payload: 'pageType~cardGrid' }]; + let out_msgs: Array = [{ payload: 'pageType~cardGrid' }]; out_msgs.push({ payload: GeneratePageElements(page) }); return out_msgs; } catch (err: any) { @@ -3231,9 +3300,9 @@ function GenerateGridPage(page: PageGrid): Payload[] { } } -function GenerateGridPage2(page: PageGrid2): Payload[] { +function GenerateGridPage2(page: NSPanel.PageGrid2): NSPanel.Payload[] { try { - let out_msgs: Array = [{ payload: 'pageType~cardGrid2' }]; + let out_msgs: Array = [{ payload: 'pageType~cardGrid2' }]; out_msgs.push({ payload: GeneratePageElements(page) }); return out_msgs; } catch (err: any) { @@ -3308,24 +3377,24 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = let name: string; let buttonText: string = 'PRESS'; - let type: SerialType; + let type: NSPanel.SerialType; // ioBroker if (pageItem.id && existsObject(pageItem.id) || pageItem.navigate === true) { - let iconColor = rgb_dec565(config.defaultColor); - let optVal = '0'; + let iconColor:number = rgb_dec565(config.defaultColor); + let optVal:string = '0'; let val: any = null; - let o:any + let o:any = undefined; if (pageItem.id != null && existsObject(pageItem.id)) { o = getObject(pageItem.id); } // Fallback if no name is given name = pageItem.name !== undefined ? pageItem.name : o.common.name.de == undefined ? o.common.name : o.common.name.de; - let prefix = pageItem.prefixName !== undefined ? pageItem.prefixName : ''; - let suffix = pageItem.suffixName !== undefined ? pageItem.suffixName : ''; + const prefix = pageItem.prefixName !== undefined ? pageItem.prefixName : ''; + const suffix = pageItem.suffixName !== undefined ? pageItem.suffixName : ''; // If name is used with changing values if ((name || '').indexOf('getState(') != -1) { @@ -3333,6 +3402,10 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = name = getState(dpName).val; RegisterEntityWatcher(dpName); } + else if ((name || '').split('.').length > 3 && existsState(name)) { + name = getState(name).val; + RegisterEntityWatcher(name); + } name = prefix + name + suffix; if (existsState(pageItem.id + '.GET')) { @@ -3381,8 +3454,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = } else if (pageItem.id != null && pageItem.targetPage != undefined) { type = 'button'; - const role = o.common.role as roles; - switch (role as roles) { + const role = o.common.role as NSPanel.roles; + switch (role) { case 'socket': case 'light': iconId = pageItem.icon !== undefined ? Icons.GetIcon(pageItem.icon) : role == 'socket' ? Icons.GetIcon('power-socket-de') : Icons.GetIcon('lightbulb'); @@ -3566,8 +3639,8 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = return '~' + type + '~' + 'navigate.' + pageItem.id + '~' + iconId + '~' + iconColor + '~' + name + '~' + buttonText; } } - const role = o.common.role as roles - switch (role as roles) { + const role = o.common.role as NSPanel.roles + switch (role) { case 'socket': case 'light': type = 'light'; @@ -3743,13 +3816,18 @@ function CreateEntity(pageItem: PageItem, placeId: number, useColors: boolean = if (Debug) log('min_Level: ' + min_Level, 'info'); if (Debug) log('max_Level: ' + max_Level, 'info'); + let icon_up_status = 'enable'; + let icon_down_status = 'enable'; + let tempVal: number = getState(pageItem.id + '.ACTUAL').val - let icon_up_status = tempVal === min_Level ? 'disable' : 'enable'; + + //Disabled Status while bug in updating origin adapter data points of lift values + //let icon_up_status = tempVal === min_Level ? 'disable' : 'enable'; let icon_stop_status = 'enable'; if (tempVal === min_Level || tempVal === max_Level || checkBlindActive === false) { - icon_stop_status = 'disable'; + //icon_stop_status = 'disable'; } - let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; + //let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; let value = icon_up + '|' + icon_stop + '|' + icon_down + '|' + icon_up_status + '|' + icon_stop_status + '|' + icon_down_status if (Debug) log('CreateEntity Icon role blind ~' + type + '~' + placeId + '~' + iconId + '~' + iconColor + '~' + name + '~' + value, 'info'); @@ -4191,7 +4269,7 @@ function RegisterEntityWatcher(id: string): void { } } -function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: string, placeId: number | undefined): void { +function RegisterDetailEntityWatcher(id: string, pageItem: PageItem, type: NSPanel.PopupType, placeId: number | undefined): void { try { if (subscriptions.hasOwnProperty(id)) { return; @@ -4228,11 +4306,11 @@ function GetUnitOfMeasurement(id: string): string { } } -function GenerateThermoPage(page: PageThermo): Payload[] { +function GenerateThermoPage(page: NSPanel.PageThermo): NSPanel.Payload[] { try { UnsubscribeWatcher(); let id = page.items[0].id - let out_msgs: Array = []; + let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~cardThermo' }); // ioBroker @@ -4277,7 +4355,7 @@ function GenerateThermoPage(page: PageThermo): Payload[] { if ((i_list.length - 3) != 0) { let i = 0; - switch (o.common.role as roles) { + switch (o.common.role as NSPanel.roles) { case 'thermostat': { if (existsState(id + '.AUTOMATIC') && getState(id + '.AUTOMATIC').val != null) { @@ -4711,9 +4789,9 @@ function subscribeMediaSubscriptionsBoseAdd(id: string): void { }); } -async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPlayerInstance: adapterPlayerInstanceType) { +async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPlayerInstance: NSPanel.adapterPlayerInstanceType) { if (autoCreateAlias) { - if (isSetOptionActive) { + if (isSetOptionActive) { switch (adapterPlayerInstance) { case "alexa2.0.": case "alexa2.1.": @@ -4961,19 +5039,19 @@ async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPla } } -function GenerateMediaPage(page: PageMedia): Payload[] { +function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { try { unsubscribeMediaSubscriptions(); if (!page.items[0].id) throw new Error ('Missing page id for cardMedia!'); let id = page.items[0].id; - let out_msgs: Array = []; + let out_msgs: Array = []; if (!page.items[0].adapterPlayerInstance!) throw new Error('page.items[0].adapterPlayerInstance is undefined!') let vInstance = page.items[0].adapterPlayerInstance!; let v1Adapter = vInstance.split('.'); - let v2Adapter:PlayerType = v1Adapter[0] as PlayerType; + let v2Adapter:NSPanel.PlayerType = v1Adapter[0] as NSPanel.PlayerType; // Some magic to change the ID of the alias, since speakers are not a property but separate objects if(v2Adapter == 'squeezeboxrpc') { @@ -5052,6 +5130,9 @@ function GenerateMediaPage(page: PageMedia): Payload[] { vElapsed = vElapsed.slice(1); } } + if (vElapsed == 0) { + vElapsed = '0:00'; + } let vDuration = Duration; if (vDuration.length == 5) { if(parseInt(vDuration.slice(0,2)) < 9) { @@ -5203,7 +5284,7 @@ function GenerateMediaPage(page: PageMedia): Payload[] { let shuffle_icon = Icons.GetIcon('shuffle-variant'); //shuffle let onoffbutton = 1374; - if (shuffle == 'off' || shuffle == false || shuffle == 0) { + if (shuffle == 'off' || shuffle == false || shuffle == 0 || shuffle == 'false') { shuffle_icon = Icons.GetIcon('shuffle-disabled'); //shuffle } if (v2Adapter == 'volumio') { shuffle_icon = Icons.GetIcon('refresh'); } //Volumio: refresh playlist @@ -5558,11 +5639,11 @@ async function createAutoAlarmAlias (id: string, nsPath: string){ if (autoCreateAlias) { if (isSetOptionActive) { if (existsState(nsPath + '.AlarmPin') == false || existsState(nsPath + '.AlarmState') == false || existsState(nsPath + '.AlarmType') == false || existsState(nsPath + '.PIN_Failed') == false || existsState(nsPath + '.PANEL') == false) { - await createStateAsync(nsPath + '.AlarmPin', '0000', { type: 'string' }); - await createStateAsync(nsPath + '.AlarmState', 'disarmed', { type: 'string' }); - await createStateAsync(nsPath + '.AlarmType', 'D1', { type: 'string' }); - await createStateAsync(nsPath + '.PIN_Failed', 0, { type: 'number' }); - await createStateAsync(nsPath + '.PANEL', NSPanel_Path, { type: 'string' }); + await createStateAsync(nsPath + '.AlarmPin', '0000', { type: 'string', write: true }); + await createStateAsync(nsPath + '.AlarmState', 'disarmed', { type: 'string', write: false }); + await createStateAsync(nsPath + '.AlarmType', 'D1', { type: 'string', write: false }); + await createStateAsync(nsPath + '.PIN_Failed', 0, { type: 'number', write: false }); + await createStateAsync(nsPath + '.PANEL', NSPanel_Path, { type: 'string', write: false }); setObject(id, {_id: id, type: 'channel', common: {role: 'sensor.fire.alarm', name:'alarm'}, native: {}}); await createAliasAsync(id + '.ACTUAL', nsPath + '.AlarmState', true, { type: 'string', role: 'state', name: 'ACTUAL' }); await createAliasAsync(id + '.PIN', nsPath + '.AlarmPin', true, { type: 'string', role: 'state', name: 'PIN' }); @@ -5577,14 +5658,14 @@ async function createAutoAlarmAlias (id: string, nsPath: string){ } } -function GenerateAlarmPage(page: PageAlarm): Payload[] { +function GenerateAlarmPage(page: NSPanel.PageAlarm): NSPanel.Payload[] { try { activePage = page; let id = page.items[0].id let name = page.heading; - let out_msgs: Array = []; + let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~cardAlarm' }); let nsPath = NSPanel_Alarm_Path + 'Alarm'; @@ -5604,7 +5685,7 @@ function GenerateAlarmPage(page: PageAlarm): Payload[] { } //let entityType = getState(nsPath + 'AlarmType').val; let arm1: string, arm2: string, arm3: string, arm4: string; - let arm1ActionName: ButtonActionType | '', arm2ActionName: ButtonActionType | '', arm3ActionName: ButtonActionType | '', arm4ActionName: ButtonActionType | ''; + let arm1ActionName: NSPanel.ButtonActionType | '', arm2ActionName: NSPanel.ButtonActionType | '', arm3ActionName: NSPanel.ButtonActionType | '', arm4ActionName: NSPanel.ButtonActionType | ''; let icon = '0'; let iconcolor = 63488; let numpadStatus = 'disable'; @@ -5722,8 +5803,8 @@ async function createAutoUnlockAlias(id: string, dpPath: string) { if (autoCreateAlias) { if (isSetOptionActive) { if (existsState(dpPath + 'UnlockPin') == false || existsState(dpPath + 'Access') == false) { - await createStateAsync(dpPath + 'UnlockPin', '0000', { type: 'string' }); - await createStateAsync(dpPath + 'Access', 'false', { type: 'boolean' }); + await createStateAsync(dpPath + 'UnlockPin', '0000', { type: 'string', write: true }); + await createStateAsync(dpPath + 'Access', 'false', { type: 'boolean', write: false }); setObject(id, { _id: id, type: 'channel', common: { role: 'sensor.fire.alarm', name: 'sensor.fire.alarm' }, native: {} }); await createAliasAsync(id + '.PIN', dpPath + 'UnlockPin', true, { type: 'string', role: 'state', name: 'PIN' }); await createAliasAsync(id + '.ACTUAL', dpPath + 'Access', true, { type: 'boolean', role: 'sensor.fire.alarm', name: 'ACTUAL' }); @@ -5736,13 +5817,13 @@ async function createAutoUnlockAlias(id: string, dpPath: string) { } -function GenerateUnlockPage(page: PageUnlock): Payload[] { +function GenerateUnlockPage(page: NSPanel.PageUnlock): NSPanel.Payload[] { try { activePage = page; let id = page.items[0].id let name = page.heading; - let out_msgs: Array = []; + let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~cardAlarm' }); let dpPath : string = '' @@ -5758,7 +5839,7 @@ function GenerateUnlockPage(page: PageUnlock): Payload[] { } let unlock1 = findLocale('lock', 'UNLOCK'); //unlock1*~* - let unlock1ActionName: ButtonActionType | '' = 'U1'; //unlock1ActionName*~* + let unlock1ActionName: NSPanel.ButtonActionType | '' = 'U1'; //unlock1ActionName*~* let iconcolor = rgb_dec565({ red: 223, green: 76, blue: 30 }); //icon*~* let icon = Icons.GetIcon('lock-remove'); //iconcolor*~* @@ -5804,8 +5885,8 @@ async function createAutoQRAlias(id:string, dpPath:string) { if (autoCreateAlias) { if (isSetOptionActive) { if (existsState(dpPath + 'Daten') == false) { - await createStateAsync(dpPath + 'Daten', 'WIFI:T:undefined;S:undefined;P:undefined;H:undefined;', { type: 'string' }); - await createStateAsync(dpPath + 'Switch', false, { type: 'boolean' }); + await createStateAsync(dpPath + 'Daten', 'WIFI:T:undefined;S:undefined;P:undefined;H:undefined;', { type: 'string', write: true }); + await createStateAsync(dpPath + 'Switch', false, { type: 'boolean', write: true }); setObject(id, { _id: id, type: 'channel', common: { role: 'switch.mode.wlan', name: 'QR Page' }, native: {} }); await createAliasAsync(id + '.ACTUAL', dpPath + 'Daten', true, { type: 'string', role: 'state', name: 'ACTUAL' }); await createAliasAsync(id + '.SWITCH', dpPath + 'Switch', true, { type: 'boolean', role: 'state', name: 'SWITCH' }); @@ -5818,12 +5899,12 @@ async function createAutoQRAlias(id:string, dpPath:string) { } } -function GenerateQRPage(page: PageQR): Payload[] { +function GenerateQRPage(page: NSPanel.PageQR): NSPanel.Payload[] { try { activePage = page; if (!page.items[0].id) throw new Error ('Missing pageItem.id for cardQRPage!'); let id = page.items[0].id; - let out_msgs: Array = []; + let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~cardQR' }); let dpPath : string = '' @@ -5936,7 +6017,7 @@ function subscribePowerSubscriptions(id: string): void { }); } -function GeneratePowerPage(page: PagePower): Payload[] { +function GeneratePowerPage(page: NSPanel.PagePower): NSPanel.Payload[] { try { if (!page.items[0].id) throw new Error ('Missing pageItem.id for PowerPage!'); @@ -5964,7 +6045,7 @@ function GeneratePowerPage(page: PagePower): Payload[] { obj = JSON.parse((getState(page.items[0].id + '.ACTUAL').val)); } - let out_msgs: Array = []; + let out_msgs: Array = []; // Leave the display on if the alwaysOnDisplay parameter is specified (true) if (page.type == 'cardPower' && pageCounter == 0 && page.items[0].alwaysOnDisplay != undefined) { @@ -6058,12 +6139,12 @@ function GeneratePowerPage(page: PagePower): Payload[] { } } -function GenerateChartPage(page: PageChart): Payload[] { +function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { try { activePage = page; let id = page.items[0].id; - let out_msgs: Array = []; + let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~' + page.type }); let heading = page.heading !== undefined ? page.heading : "Chart..."; @@ -6158,7 +6239,7 @@ function HandleButtonEvent(words: any): void { let tempid = words[2].split('?'); let id = tempid[0]; - let buttonAction: ButtonActionType = words[3] as ButtonActionType; + let buttonAction: NSPanel.ButtonActionType = words[3] as NSPanel.ButtonActionType; let pageItemID: string = ''; if (!isNaN(id)) { @@ -6182,11 +6263,8 @@ function HandleButtonEvent(words: any): void { if (words[2] == 'bNext' || words[2] == 'bPrev' || words[2] == 'bUp' || words[2] == 'bHome' || words[2] == 'bSubNext' || words[2] == 'bSubPrev' ) { buttonAction = words[2]; pageCounter = 0; - // Turn off the display if the alwaysOnDisplay parameter was specified - if (alwaysOn == true) { - alwaysOn = false; - SendToPanel({ payload: 'timeout~' + getState(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver').val }); - } + alwaysOn = false; + SendToPanel({ payload: 'timeout~' + getState(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver').val }); } if (Debug) { @@ -6337,8 +6415,8 @@ function HandleButtonEvent(words: any): void { if (Debug) { log('HandleButtonEvent -> OnOff: ' + words[4] + ' - ' + id + ' - Role - ' + o.common.role, 'info') } - const role = o.common.role as roles; - switch (role as roles) { + const role = o.common.role as NSPanel.roles; + switch (role) { case 'level.mode.fan': case 'socket': case 'light': @@ -6374,7 +6452,7 @@ function HandleButtonEvent(words: any): void { if (words[4] == '1') action = true; let o = getObject(id); - switch (o.common.role as roles) { + switch (o.common.role as NSPanel.roles) { case 'lock': case 'button': toggleState(id + '.SET') ? true : toggleState(id + '.ON_SET'); @@ -6419,7 +6497,7 @@ function HandleButtonEvent(words: any): void { if (isPageMediaItem(pageItemRepeat)) { let adapterInstanceRepeat = pageItemRepeat.adapterPlayerInstance; let adapterRepeat = adapterInstanceRepeat.split('.'); - const deviceAdapterRP: PlayerType = adapterRepeat[0] as PlayerType; + const deviceAdapterRP: NSPanel.PlayerType = adapterRepeat[0] as NSPanel.PlayerType; switch (deviceAdapterRP) { case 'spotify-premium': @@ -6434,7 +6512,7 @@ function HandleButtonEvent(words: any): void { GeneratePage(activePage!); break; case 'bosesoundtouch': - log(adapterInstanceRepeat); + if (Debug) log(adapterInstanceRepeat); let stateBoseRepeat = getState(id + '.REPEAT').val if (stateBoseRepeat == 'REPEAT_OFF') { setIfExists(adapterInstanceRepeat + 'key', 'REPEAT_ALL'); @@ -6560,8 +6638,8 @@ function HandleButtonEvent(words: any): void { if (existsObject(id)) { let o = getObject(id); let pageItem = findPageItem(id); - const role = o.common.role as roles; - switch (role as roles) { + const role = o.common.role as NSPanel.roles; + switch (role) { case 'dimmer': if (pageItem.minValueBrightness != undefined && pageItem.maxValueBrightness != undefined) { let sliderPos = Math.trunc(scale(parseInt(words[4]), 0, 100, pageItem.maxValueBrightness, pageItem.minValueBrightness)); @@ -6607,7 +6685,7 @@ function HandleButtonEvent(words: any): void { log('HandleButtonEvent colorWeel -> getHue-Werte: ' + getHue(rgb.red, rgb.green, rgb.blue), 'info'); } let o = getObject(id); - switch (o.common.role as roles) { + switch (o.common.role as NSPanel.roles) { case 'hue': setIfExists(id + '.HUE', getHue(rgb.red, rgb.green, rgb.blue)); break; @@ -6644,10 +6722,18 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.SET', parseInt(temps[0]) / 10); } break; - case 'media-back': - setIfExists(id + '.PREV', true); - GeneratePage(activePage!); + case 'media-back': { + const tempPage = findPageItem(id); + if (isPageMediaItem(tempPage)) { + if (tempPage.adapterPlayerInstance.startsWith('bosesoundtouch')) { + setIfExists(tempPage.adapterPlayerInstance + 'key', 'PREV_TRACK'); + } else { + setIfExists(id + '.PREV', true); + } + GeneratePage(activePage!); + } break; + } case 'media-pause': let pageItemTemp = findPageItem(id); if (isPageMediaItem(pageItemTemp)) { @@ -6663,6 +6749,8 @@ function HandleButtonEvent(words: any): void { } else if (stateVal == null) { setState(adapterPlayerInstanceStateSeceltor, 1); } + } else if (pageItemTemp.adapterPlayerInstance.startsWith('bosesoundtouch')) { + setIfExists(pageItemTemp.adapterPlayerInstance + 'key', 'PLAY_PAUSE'); } else { if (Debug) log('HandleButtonEvent media-pause -> .STATE Value: ' + getState(id + '.STATE').val, 'info'); if (getState(id + '.STATE').val === true) { @@ -6674,11 +6762,19 @@ function HandleButtonEvent(words: any): void { GeneratePage(activePage!); } break; - case 'media-next': - setIfExists(id + '.NEXT', true); - GeneratePage(activePage!); + case 'media-next': { + const tempPage = findPageItem(id); + if (isPageMediaItem(tempPage)) { + if (tempPage.adapterPlayerInstance.startsWith('bosesoundtouch')) { + setIfExists(tempPage.adapterPlayerInstance + 'key', 'NEXT_TRACK'); + } else { + setIfExists(id + '.NEXT', true); + } + GeneratePage(activePage!); + } break; - case 'media-shuffle': + } + case 'media-shuffle': { const tempPage = findPageItem(id); if (isPageMediaItem(tempPage)) { if (tempPage.adapterPlayerInstance.startsWith("volumio")) { @@ -6708,8 +6804,8 @@ function HandleButtonEvent(words: any): void { } } if ((tempPage.adapterPlayerInstance).startsWith("bosesoundtouch")) { - log(tempPage.adapterPlayerInstance); - if (getState(tempPage.adapterPlayerInstance + '.SHUFFLE').val == false) { + if (Debug) log(tempPage.adapterPlayerInstance + 'nowPlaying.shuffle'); + if (getState(tempPage.adapterPlayerInstance + 'nowPlaying.shuffle').val == 'false') { setIfExists(tempPage.adapterPlayerInstance + 'key', 'SHUFFLE_ON'); } else { setIfExists(tempPage.adapterPlayerInstance + 'key', 'SHUFFLE_OFF'); @@ -6718,6 +6814,7 @@ function HandleButtonEvent(words: any): void { GeneratePage(activePage!); } break; + } case 'volumeSlider': pageCounter = -1; (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); @@ -6734,7 +6831,7 @@ function HandleButtonEvent(words: any): void { if (isPageMediaItem(pageItem)) { let adapterInstance = pageItem.adapterPlayerInstance!; let adapter = adapterInstance!.split('.'); - const deviceAdapter: PlayerType = adapter[0] as PlayerType; + const deviceAdapter: NSPanel.PlayerType = adapter[0] as NSPanel.PlayerType; switch (deviceAdapter) { case 'spotify-premium': @@ -6780,7 +6877,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemPL)) break; let adapterInstancePL = pageItemPL.adapterPlayerInstance!; let adapterPL = adapterInstancePL.split('.'); - const deviceAdapterPL: PlayerType = adapterPL[0] as PlayerType; + const deviceAdapterPL: NSPanel.PlayerType = adapterPL[0] as NSPanel.PlayerType; switch (deviceAdapterPL) { case 'spotify-premium': @@ -6824,9 +6921,13 @@ function HandleButtonEvent(words: any): void { setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'cmdPlayFavorite'].join('.'), words[4]); break; case "bosesoundtouch": - log('bosesoundtouch - playlist ' + pageItemPL.adapterPlayerInstance + ' - ' + words[4]); - log(adapterInstancePL + 'key'); - setState(adapterInstancePL + 'key', 'PRESET_' + (parseInt(words[4]) + 1)); + if (Debug) log('bosesoundtouch - playlist ' + pageItemPL.adapterPlayerInstance + ' - ' + words[4]); + if (Debug) log(adapterInstancePL + 'key'); + if (words[4] < 6) { + setState(adapterInstancePL + 'key', 'PRESET_' + (parseInt(words[4]) + 1)); + } else if (words[4] == 6) { + setState(adapterInstancePL + 'key', 'AUX_INPUT'); + } break; default: log('Hello Mr. Developer u miss in mode-playlist something!', 'warn'); @@ -6843,7 +6944,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemTL)) break; let adapterInstanceTL = pageItemTL.adapterPlayerInstance!; let adapterTL = adapterInstanceTL.split('.'); - const deviceAdapterTL: PlayerType = adapterTL[0] as PlayerType; + const deviceAdapterTL: NSPanel.PlayerType = adapterTL[0] as NSPanel.PlayerType; switch (deviceAdapterTL) { case 'spotify-premium': @@ -6892,7 +6993,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemRP)) break; let adapterInstanceRP = pageItemRP.adapterPlayerInstance!; let adapterRP = adapterInstanceRP.split('.'); - let deviceAdapterRP: PlayerType = adapterRP[0] as PlayerType; + let deviceAdapterRP: NSPanel.PlayerType = adapterRP[0] as NSPanel.PlayerType; if (Debug) log(pageItemRP.repeatList![words[4]], 'warn'); switch (deviceAdapterRP) { @@ -6923,7 +7024,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemSeek)) break; let adapterInstanceSK = pageItemSeek.adapterPlayerInstance!; let adapterSK = adapterInstanceSK.split('.'); - let deviceAdapterSK: PlayerType = adapterSK[0] as PlayerType; + let deviceAdapterSK: NSPanel.PlayerType = adapterSK[0] as NSPanel.PlayerType; switch (deviceAdapterSK) { case 'spotify-premium': break; @@ -6944,7 +7045,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemCrossfade)) break; let adapterInstanceCF = pageItemCrossfade.adapterPlayerInstance!; let adapterCF = adapterInstanceCF.split('.'); - let deviceAdapterCF: PlayerType = adapterCF[0] as PlayerType; + let deviceAdapterCF: NSPanel.PlayerType = adapterCF[0] as NSPanel.PlayerType; switch (deviceAdapterCF) { case 'spotify-premium': break; @@ -6980,12 +7081,12 @@ function HandleButtonEvent(words: any): void { case 'mode-insel': setIfExists(id + '.VALUE', parseInt(words[4])); break; - case 'media-OnOff': - let pageItemTem = findPageItem(id); - if (!isPageMediaItem(pageItemTem)) break; - let adaInstanceSpli = pageItemTem.adapterPlayerInstance.split('.'); - if (adaInstanceSpli[0] == 'squeezeboxrpc') { - let adapterPlayerInstancePowerSelector: string = [pageItemTem.adapterPlayerInstance, 'Players', pageItemTem.mediaDevice, 'Power'].join('.'); + case 'media-OnOff': { + let pageItemTemp = findPageItem(id); + if (!isPageMediaItem(pageItemTemp)) break; + let adapterInstance = pageItemTemp.adapterPlayerInstance.split('.'); + if (adapterInstance[0] == 'squeezeboxrpc') { + let adapterPlayerInstancePowerSelector: string = [pageItemTemp.adapterPlayerInstance, 'Players', pageItemTemp.mediaDevice, 'Power'].join('.'); let stateVal = getState(adapterPlayerInstancePowerSelector).val; if (stateVal === 0) { setState(adapterPlayerInstancePowerSelector, 1); @@ -6996,11 +7097,14 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.STOP', true); setIfExists(id + '.STATE', 0); } + } else if (adapterInstance[0] == 'bosesoundtouch') { + setState(pageItemTemp.adapterPlayerInstance + 'key', 'POWER'); } else { setIfExists(id + '.STOP', true); } GeneratePage(activePage!); break; + } case 'timer-start': if (words[4] != undefined) { let timer_panel = words[4].split(':'); @@ -7093,7 +7197,7 @@ function HandleButtonEvent(words: any): void { break; case 'number-set': let nobj = getObject(id); - switch (nobj.common.role as roles) { + switch (nobj.common.role as NSPanel.roles) { case 'level.mode.fan': (function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })(); timeoutSlider = setTimeout(async function () { @@ -7300,10 +7404,10 @@ function GetNavigationString(pageId: number): string { } return ''; } -function GenerateDetailPage(type: string, optional: mediaOptional | undefined, pageItem: PageItem, placeId: number | undefined): Payload[] { +function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOptional | undefined, pageItem: PageItem, placeId: number | undefined): NSPanel.Payload[] { if (Debug) log('GenerateDetailPage Übergabe Type: ' + type + ' - optional: ' + optional + ' - pageItem.id: ' + pageItem.id, 'info'); try { - let out_msgs: Array = []; + let out_msgs: Array = []; let id = pageItem.id; if (id && existsObject(id)) { @@ -7312,7 +7416,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p let val: (boolean | number) = 0; let icon = Icons.GetIcon('lightbulb'); let iconColor = rgb_dec565(config.defaultColor); - const role = o.common.role as roles; + const role = o.common.role as NSPanel.roles; if (type == 'popupLight') { @@ -7753,12 +7857,17 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p let icon_stop = Icons.GetIcon('stop'); let icon_down = Icons.GetIcon('arrow-down'); let tempVal: number = getState(pageItem.id + '.ACTUAL').val - let icon_up_status = tempVal === min_Level ? 'disable' : 'enable'; + + //Disabled Status while bug in updating origin adapter data points of lift values + let icon_up_status = 'enable'; + //let icon_up_status = tempVal === min_Level ? 'disable' : 'enable'; let icon_stop_status = 'enable'; if (tempVal === min_Level || tempVal === max_Level || checkBlindActive === false) { - icon_stop_status = 'disable'; + //icon_stop_status = 'disable'; } - let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; + let icon_down_status = 'enable'; + //let icon_down_status = tempVal === max_Level ? 'disable' : 'enable'; + let textTilt = ''; let iconTiltLeft = ''; let iconTiltStop = ''; @@ -7787,7 +7896,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p out_msgs.push({ payload: 'entityUpdateDetail' + '~' //entityUpdateDetail - + tempId + '~' //entity_id + + tempId + '~' //entity_id + val + '~' //Shutterposition + textSecondRow + '~' //pos_status 2.line + findLocale('blinds', 'Position') + '~' //pos_translation @@ -7968,7 +8077,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p let actualMode = pageItem.modeList![getState(id + '.MODE').val]; let tempId = placeId != undefined ? placeId : id; - + // {tempid | icon | iconColor | switchVal | actualSpeed | maxSpeed: | findLocale | actualMode | modeList} out_msgs.push({ payload: 'entityUpdateDetail' + '~' // entityUpdateDetail + tempId + '~' @@ -7988,35 +8097,13 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p if (role == 'media') { let actualState: any = ''; let optionalString: string = 'Kein Eintrag'; - let mode: string = ''; + let mode: NSPanel.mediaOptional | '' = ''; if (isPageMediaItem(pageItem)) { const vTempAdapter = (pageItem.adapterPlayerInstance!).split('.'); - const vAdapter: PlayerType = vTempAdapter[0] as PlayerType; + const vAdapter: NSPanel.PlayerType = vTempAdapter[0] as NSPanel.PlayerType; if (optional == 'seek') { - let actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; - if (actualStateTemp >= 95) { - actualState = '100%'; - } else if (actualStateTemp >= 85) { - actualState = '90%'; - } else if (actualStateTemp >= 75) { - actualState = '80%'; - } else if (actualStateTemp >= 65) { - actualState = '70%'; - } else if (actualStateTemp >= 55) { - actualState = '60%'; - } else if (actualStateTemp >= 45) { - actualState = '50%'; - } else if (actualStateTemp >= 35) { - actualState = '40%'; - } else if (actualStateTemp >= 25) { - actualState = '30%'; - } else if (actualStateTemp >= 15) { - actualState = '20%'; - } else if (actualStateTemp >= 5) { - actualState = '10%'; - } else if (actualStateTemp >= 0) { - actualState = '0%'; - } + const actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; + actualState = Math.round(actualStateTemp / 10) * 10 + '%'; if (vAdapter == 'sonos') { optionalString = '0%?10%?20%?30%?40%?50%?60%?70%?80%?90%?100%'; } @@ -8086,12 +8173,19 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p } else if (vAdapter == 'bosesoundtouch') { if (existsObject(pageItem.adapterPlayerInstance + 'deviceInfo.name')) { actualState = formatInSelText(getState(pageItem.adapterPlayerInstance + 'deviceInfo.name').val); - log(actualState); } let tempPlayList: string[] = []; - for (let i = 0; i < pageItem.playList!.length; i++) { - tempPlayList[i] = formatInSelText(pageItem.playList![i]); + let vPreset: string = 'No Entry'; + for (let i = 1; i < 7; i++) { + if (getState(pageItem.adapterPlayerInstance + 'presets.'+ i +'.source').val !== null) { + vPreset = getState(pageItem.adapterPlayerInstance + 'presets.'+ i + '.source').val; + } else { + vPreset = 'Preset ' + i.toFixed; + } + tempPlayList[i - 1] = formatInSelText(vPreset.replace('_',' ')); + if (Debug) log(formatInSelText(vPreset.replace('_',' '))) } + tempPlayList[6] = 'AUX INPUT'; optionalString = pageItem.playList != undefined ? tempPlayList.join('?') : '' } else if (vAdapter == 'sonos') { if (Debug) log(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.playlist_set', 'info'); @@ -8181,8 +8275,8 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p if (existsObject(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode') == false || existsObject(NSPanel_Path + 'Media.Player.' + lastIndex + '.Speaker') == false) { - createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode', {type: 'string'}); - createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.Speaker', {type: 'string'}); + createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.EQ.activeMode', {type: 'string', write: false}); + createState(NSPanel_Path + 'Media.Player.' + lastIndex + '.Speaker', {type: 'string', write: false}); } actualState = '' @@ -8215,7 +8309,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p } let tempId = placeId != undefined ? placeId : id; - + // {tempid | color | NSPanel.mediaOptional | actualState | optionalString} out_msgs.push({ payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail + tempId + '?' + optional + '~~' //{entity_id} @@ -8244,7 +8338,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p let valueList = pageItem.modeList != undefined ? tempModeList.join('?') : ''; let tempId = placeId != undefined ? placeId : id; - + // {tempid | color | NSPanel.mediaOptional | actualValue | valueList} out_msgs.push({ payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail2 + tempId + '~~' //{entity_id} @@ -8280,7 +8374,7 @@ function GenerateDetailPage(type: string, optional: mediaOptional | undefined, p //log(valueList); let tempId = placeId != undefined ? placeId : id; - + // {tempid | color | 'insel' | actualValue | valueList} out_msgs.push({ payload: 'entityUpdateDetail2' + '~' //entityUpdateDetail2 + tempId + '~~' //{entity_id} @@ -8673,10 +8767,8 @@ function HandleScreensaverUpdate(): void { if (screensaverAdvanced) { // 5 indicatorScreensaverEntities for (let i = 0; i < 5 && i < config.indicatorScreensaverEntity.length; i++) { - let checkpoint = true; - const indicatorScreensaverEntity:ScreenSaverElementWithUndefined = config.indicatorScreensaverEntity[i]; + const indicatorScreensaverEntity:NSPanel.ScreenSaverElementWithUndefined = config.indicatorScreensaverEntity[i]; if (indicatorScreensaverEntity === null || indicatorScreensaverEntity === undefined) { - checkpoint = false; break; } RegisterScreensaverEntityWatcher(indicatorScreensaverEntity.ScreensaverEntity) @@ -8719,7 +8811,7 @@ function HandleScreensaverUpdate(): void { } if (Debug) log('HandleScreensaverUpdate payload: weatherUpdate~' + payloadString, 'info'); - SendToPanel({ payload: 'weatherUpdate~' + payloadString }); + SendToPanel({ payload: 'weatherUpdate~' + payloadString }); HandleScreensaverStatusIcons(); } @@ -8916,7 +9008,7 @@ function HandleScreensaverStatusIcons() : void { payloadString += '~'; } - SendToPanel({ payload: 'statusUpdate~' + payloadString }); + SendToPanel({ payload: 'statusUpdate~' + payloadString }); } catch (err: any) { log('error at function HandleScreensaverStatusIcons: ' + err.message, 'warn'); @@ -8987,8 +9079,12 @@ function HandleScreensaverColors(): void { scrSvrBGCol = rgb_dec565(scbackgroundInd2); } else if (bgColorScrSaver == 3) { scrSvrBGCol = rgb_dec565(scbackgroundInd3); + } else if (bgColorScrSaver == 4) { + scrSvrBGCol = rgb_dec565({red:255, green:16, blue:240}); + } else if (bgColorScrSaver == 5) { + scrSvrBGCol = rgb_dec565({ red: 100, green: 0, blue: 0 }); } - + let payloadString = 'color' + '~' + scrSvrBGCol + '~' + //background rgb_dec565(sctime) + '~' + //time @@ -9007,17 +9103,17 @@ function HandleScreensaverColors(): void { rgb_dec565(sctMainTextAlt) + '~' + //tMainTextAlt rgb_dec565(sctTimeAdd); //tTimeAdd - SendToPanel({ payload: payloadString }); + SendToPanel({ payload: payloadString }); } catch (err: any) { log('error at function HandleScreensaverColors: '+ err.message, 'warn'); } } -function GetScreenSaverEntityColor(configElement: ScreenSaverElement | null): number { +function GetScreenSaverEntityColor(configElement: NSPanel.ScreenSaverElement | null): number { try { let colorReturn: number; if (configElement && configElement.ScreensaverEntityIconColor != undefined) { - const ScreensaverEntityIconColor = configElement.ScreensaverEntityIconColor as IconScaleElement; + const ScreensaverEntityIconColor = configElement.ScreensaverEntityIconColor as NSPanel.IconScaleElement; if (typeof getState(configElement.ScreensaverEntity).val == 'boolean') { let iconvalbest = (typeof ScreensaverEntityIconColor == 'object' && ScreensaverEntityIconColor.val_best !== undefined ) ? ScreensaverEntityIconColor.val_best : false ; colorReturn = (getState(configElement.ScreensaverEntity).val == iconvalbest) ? rgb_dec565(colorScale0) : rgb_dec565(colorScale10); @@ -9369,10 +9465,10 @@ on({ id: config.panelRecvTopic.substring(0, config.panelRecvTopic.length - 'RESU try { const Tasmota_Sensor = JSON.parse(obj.state.val); - await createStateAsync(NSPanel_Path + 'Sensor.Time', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Sensor.TempUnit', { type: 'string' }); - await createStateAsync(NSPanel_Path + 'Sensor.ANALOG.Temperature', { type: 'number', 'unit': '°C' }); - await createStateAsync(NSPanel_Path + 'Sensor.ESP32.Temperature', { type: 'number', 'unit': '°C' }); + await createStateAsync(NSPanel_Path + 'Sensor.Time', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Sensor.TempUnit', { type: 'string', write: false }); + await createStateAsync(NSPanel_Path + 'Sensor.ANALOG.Temperature', { type: 'number', 'unit': '°C', write: false }); + await createStateAsync(NSPanel_Path + 'Sensor.ESP32.Temperature', { type: 'number', 'unit': '°C', write: false }); let dateTime: string = Tasmota_Sensor.Time.split('T'); await setStateAsync(NSPanel_Path + 'Sensor.Time', { val: dateTime[0] + '\r\n' + dateTime[1] , ack: true }); await setStateAsync(NSPanel_Path + 'Sensor.TempUnit', { val: '°' + Tasmota_Sensor.TempUnit, ack: true }); @@ -9563,8 +9659,9 @@ function rgb_to_cie(red: number, green: number, blue: number): string return cie; } + /** - * + * * @param vDeviceString * @returns */ @@ -9578,290 +9675,77 @@ function spotifyGetDeviceID(vDeviceString: string): string { return strDevID; } -type EventMethod = 'startup' | 'sleepReached' | 'pageOpenDetail' | 'buttonPress2' | 'renderCurrentPage' | 'button1' | 'button2' - -type SerialType = 'button' | 'light' | 'shutter' | 'text' | 'input_sel' | 'timer' | 'number' | 'fan' - -type roles = 'light' |'socket'|'dimmer'| 'hue' | 'rgb' | 'rgbSingle' | 'cd' | 'blind' | 'door' | 'window' | 'volumeGroup' | 'volume' - | 'info' | 'humidity' | 'temperature' | 'value.temperature' | 'value.humidity' | 'sensor.door' | 'sensor.window' | 'thermostat' | 'warning' | 'ct' - | 'cie' | 'gate' | 'motion' | 'buttonSensor' | 'button' | 'value.time' | 'level.timer' | 'value.alarmtime' | 'level.mode.fan' | 'lock' | 'slider' - | 'switch.mode.wlan' | 'media' | 'timeTable' | 'airCondition' - -type ButtonActionType = 'bExit' | 'bUp' | 'bNext' | 'bSubNext' | 'bPrev' | 'bSubPrev' | 'bHome' | 'notifyAction' | 'OnOff' | 'button' | 'up' | 'stop' | 'down' - | 'positionSlider' | 'tiltOpen' | 'tiltStop' | 'tiltSlider' | 'tiltClose' | 'brightnessSlider' | 'colorTempSlider' | 'colorWheel' | 'tempUpd' | 'tempUpdHighLow' | 'media-back' - | 'media-pause' | 'media-next' | 'media-shuffle' | 'volumeSlider' | 'mode-speakerlist' | 'mode-playlist' | 'mode-tracklist' | 'mode-repeat' | 'mode-equalizer' | 'mode-seek' | 'mode-crossfade' - | 'mode-favorites' | 'mode-insel' | 'media-OnOff' | 'timer-start' | 'timer-pause' | 'timer-cancle' | 'timer-finish' | 'hvac_action' | 'mode-modus1' | 'mode-modus2' | 'mode-modus3' | 'number-set' - | 'mode-preset_modes' | 'A1' | 'A2' | 'A3' | 'A4' | 'D1' | 'U1' - +type RGB = NSPanel.RGB; +type PageItem = NSPanel.PageItem; +type PageType = NSPanel.PageType; +type Config = NSPanel.Config; +type PageEntities = NSPanel.PageEntities; +type PageChart = NSPanel.PageChart; +type PagePower = NSPanel.PagePower; +type PageGrid = NSPanel.PageGrid; +type PageQR = NSPanel.PageQR; +type PageGrid2 = NSPanel.PageGrid2; +type PageMedia = NSPanel.PageMedia; +type PageThermo = NSPanel.PageThermo; +type PageUnlock = NSPanel.PageUnlock; +type PageAlarm = NSPanel.PageAlarm; -type RGB = { - red: number, - green: number, - blue: number -}; -type Payload = { - payload: string; -}; - -type PageBaseType = { - type: PagetypeType, - heading: string, - items: PageItem[], - useColor: boolean, - subPage?: boolean, - parent?: PageType, - parentIcon?: string, - parentIconColor?: RGB, - prev?: string, - prevIcon?: string, - prevIconColor?: RGB, - next?: string, - nextIcon?: string, - nextIconColor?: RGB, - home?: string, - homeIcon?: string, - homeIconColor?: RGB -}; - -type PagetypeType = 'cardChart' | 'cardLChart' | 'cardEntities' |'cardGrid'|'cardGrid2'|'cardThermo'|'cardMedia'|'cardUnlock'|'cardQR'|'cardAlarm'|'cardPower' - -type PageType = PageChart | PageEntities | PageGrid | PageGrid2 | PageThermo | PageMedia | PageUnlock | PageQR | PageAlarm | PagePower - -// If u get a error here u forgot something in PagetypeType or PageType -function checkPageType(F: PagetypeType, A: PageType) { - A.type = F; +/** + * + * @param time object { hour: number, minutes: number } | number: Time as number in ms + * @param repeatTime in seconds + * @param callback what todo + * @returns + */ +function adapterSchedule(time: {hour?: number, minute?: number} | undefined | number, repeatTime: number, callback: () => void): number|null { + if (typeof callback !== 'function') return null + const ref = Math.random() + 1; + scheduleList[ref] = setTimeout(_schedule, 1, time, ref, repeatTime, callback), true; + return ref; } -type PageEntities = { - type: 'cardEntities', - items: PageItem[], -} & PageBaseType - -type PageGrid = { - type: 'cardGrid', - items: PageItem[], -} & PageBaseType - -type PageGrid2 = { - type: 'cardGrid2', - items: PageItem[], -} & PageBaseType - -type PageThermo = { - type: 'cardThermo', - items: PageThermoItem[], - -} & Omit - -type PageMedia = { - type: 'cardMedia', - items: PageMediaItem[], -} & Omit - -type PageAlarm = { - type: 'cardAlarm', - items: PageItem[], -} & Omit - -type PageUnlock = { - type: 'cardUnlock', - items: PageItem[], -} & Omit & Partial> - -type PageQR = { - type: 'cardQR', - items: PageItem[], -} & Omit - -type PagePower = { - type: 'cardPower', - items: PageItem[], -} & Omit - -type PageChart = { - type: 'cardChart' | 'cardLChart', - items: PageItem[], -} & Omit - -type PageItem = PageBaseItem | PageMediaItem | PageThermoItem - -function isPageMediaItem(F: PageItem | PageMediaItem):F is PageMediaItem { - return 'adapterPlayerInstance' in F +function _schedule(time: {hour?: number, minute?: number} | undefined | number, ref: number, repeatTime: number, callback, init: boolean = false) { + if (!scheduleList[ref]) return; + if (!init) callback(); + let targetTime: number; + if ( time === undefined) { + targetTime = new Date().setMilliseconds(0) + repeatTime * 1000; + time = targetTime; + } else if (typeof time === 'number') { + targetTime = time + repeatTime * 1000; + time = targetTime; + } else { + time.hour = time.hour !== undefined ? time.hour : -1; + time.minute = time.minute !== undefined ? time.minute : 0; + targetTime = time.hour !== -1 ? new Date().setHours(time.hour, time.minute, 0, 0) : new Date().setMinutes(time.minute, 0, 0); + if (new Date().getTime() >= targetTime) { + targetTime += repeatTime * 1000; + targetTime = time.hour !== -1 ? new Date(targetTime).setHours(time.hour, time.minute, 0, 0) : new Date(targetTime).setMinutes(time.minute, 0, 0); + } + } + const timeout = targetTime - new Date().getTime(); + scheduleList[ref] = setTimeout(_schedule, timeout, time, ref, repeatTime, callback); } - -function isPageThermoItem(F: PageItem | PageThermoItem):F is PageThermoItem { - return 'popupThermoMode1' in F; -} -type PageMediaItem = { - adapterPlayerInstance: adapterPlayerInstanceType, - mediaDevice?: string, - colorMediaIcon?: RGB, - colorMediaArtist?: RGB, - colorMediaTitle?: RGB, - speakerList?: string[], - playList?: string[], - equalizerList?: string[], - repeatList?: string[], - globalTracklist?: string[], - crossfade?: boolean, -} & PageBaseItem - -type PageThermoItem = { - popupThermoMode1?: string[], - popupThermoMode2?: string[], - popupThermoMode3?: string[], - popUpThermoName?: string[], - setThermoAlias?: string[], - setThermoDestTemp2?: string, -} & PageBaseItem - -type PageBaseItem = { - id?: string | null, - icon?: string, - icon2?: string, - onColor?: RGB, - offColor?: RGB, - useColor?: boolean, - interpolateColor?: boolean, - minValueBrightness?: number, - maxValueBrightness?: number, - minValueColorTemp?: number, - maxValueColorTemp?: number, - minValueLevel?: number, - maxValueLevel?: number, - minValueTilt?: number, - maxValueTilt?: number, - minValue?: number, - maxValue?: number, - stepValue?: number, - prefixName?: string, - suffixName?: string, - name?: string, - secondRow?: string, - buttonText?: string, - unit?: string, - navigate?: boolean, - colormode?: string, - colorScale?: IconScaleElement, - //adapterPlayerInstance?: adapterPlayerInstanceType, - targetPage?: string, - modeList?: string[], - hidePassword?: boolean, - autoCreateALias?: boolean - yAxis?: string, - yAxisTicks?: number[] | string, - xAxisDecorationId?: string, - useValue?: boolean, - monobutton?: boolean, - inSel_ChoiceState?: boolean, - iconArray?: string[], - fontSize?: number, - actionStringArray?: string[], - alwaysOnDisplay?: boolean, -} - -type DimMode = { - dimmodeOn: (boolean | undefined), - brightnessDay: (number | undefined), - brightnessNight: (number | undefined), - timeDay: (string | undefined), - timeNight: (string | undefined) -} - -type ConfigButtonFunction = { - mode: 'page' | 'toggle' | 'set' | null, - page: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PageGrid2 | PagePower | PageChart | PageUnlock | null), - entity: string | null, - setValue: string | number | boolean | null -} - -type Config = { - panelRecvTopic: string, - panelSendTopic: string, - weatherEntity: string, - leftScreensaverEntity: leftScreensaverEntityType - bottomScreensaverEntity: ScreenSaverElement[], - indicatorScreensaverEntity: indicatorScreensaverEntityType - mrIcon1ScreensaverEntity: ScreenSaverMRElement, - mrIcon2ScreensaverEntity: ScreenSaverMRElement, - defaultColor: RGB, - defaultOnColor: RGB, - defaultOffColor: RGB, - defaultBackgroundColor: RGB, - pages: PageType[], - subPages: PageType[], - button1: ConfigButtonFunction, - button2: ConfigButtonFunction -} -type leftScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; -type indicatorScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; -type ScreenSaverElementWithUndefined = null | undefined | ScreenSaverElement -type ScreenSaverElement = { - ScreensaverEntity: string, - ScreensaverEntityText: string, - ScreensaverEntityFactor?: number, - ScreensaverEntityDecimalPlaces?: number, - ScreensaverEntityDateFormat?: Intl.DateTimeFormatOptions, - ScreensaverEntityIconOn?: string | null, - ScreensaverEntityIconOff?: string | null, - ScreensaverEntityUnitText?: string, - ScreensaverEntityIconColor?: RGB | IconScaleElement | string - ScreensaverEntityOnColor?: RGB - ScreensaverEntityOffColor?: RGB - ScreensaverEntityOnText?: string | null, - ScreensaverEntityOffText?: string | null, -} - -type ScreenSaverMRElement = { - ScreensaverEntity: string | null, - ScreensaverEntityIconOn: string | null, - ScreensaverEntityIconOff: string | null, - ScreensaverEntityValue: string | null, - ScreensaverEntityValueDecimalPlace: number | null, - ScreensaverEntityValueUnit: string | null, - ScreensaverEntityOnColor: RGB, - ScreensaverEntityOffColor: RGB -} - -type IconScaleElement = { - val_min:number, - val_max:number, - val_best?: number -} -/** we need this to have a nice order when using switch() */ -type adapterPlayerInstanceType = - 'alexa2.0.' | 'alexa2.1.'| 'alexa2.2.' | 'alexa2.3.' | 'alexa2.4.' | 'alexa2.5.' | 'alexa2.6.' | 'alexa2.7.' | 'alexa2.8.' | 'alexa2.9.' -| 'sonos.0.' | 'sonos.1.' | 'sonos.2.' | 'sonos.3.' | 'sonos.4.' | 'sonos.5.' | 'sonos.6.' | 'sonos.7.' | 'sonos.8.' | 'sonos.9.' -| 'spotify-premium.0.' | 'spotify-premium.1.' | 'spotify-premium.2.' | 'spotify-premium.3.' | 'spotify-premium.4.' | 'spotify-premium.5.' | 'spotify-premium.6.' | 'spotify-premium.7.' | 'spotify-premium.8.' | 'spotify-premium.9.' -| 'volumio.0.' | 'volumio.1.' | 'volumio.2.' | 'volumio.3.' |'volumio.4.' | 'volumio.5.' | 'volumio.6.' | 'volumio.7.' | 'volumio.8.' | 'volumio.9.' -| 'squeezeboxrpc.0.' | 'squeezeboxrpc.1.' | 'squeezeboxrpc.2.' | 'squeezeboxrpc.3.' | 'squeezeboxrpc.4.' | 'squeezeboxrpc.5.' | 'squeezeboxrpc.6.' | 'squeezeboxrpc.7.' | 'squeezeboxrpc.8.' | 'squeezeboxrpc.9.' -| 'bosesoundtouch.0.' | 'bosesoundtouch.1.' | 'bosesoundtouch.2.' | 'bosesoundtouch.3.' |'bosesoundtouch.4.' | 'bosesoundtouch.5.' | 'bosesoundtouch.6.' | 'bosesoundtouch.7.' | 'bosesoundtouch.8.' | 'bosesoundtouch.9.' - -type PlayerType = _PlayerTypeWithMediaDevice | _PlayerTypeWithOutMediaDevice; - +function _clearSchedule(ref: number): null { + if (scheduleList[ref]) clearTimeout(scheduleList[ref]); + delete scheduleList[ref]; + return null; +} const ArrayPlayerTypeWithMediaDevice = ['alexa2', 'sonos', 'squeezeboxrpc'] as const const ArrayPlayerTypeWithOutMediaDevice = ['spotify-premium', 'volumio', 'bosesoundtouch'] as const -type _PlayerTypeWithOutMediaDevice = typeof ArrayPlayerTypeWithOutMediaDevice[number] -type _PlayerTypeWithMediaDevice = typeof ArrayPlayerTypeWithMediaDevice[number] -function isPlayerWithMediaDevice (F: string | _PlayerTypeWithMediaDevice): F is _PlayerTypeWithMediaDevice { - return ArrayPlayerTypeWithMediaDevice.indexOf(F as _PlayerTypeWithMediaDevice) != -1; +function isPlayerWithMediaDevice (F: string | NSPanel._PlayerTypeWithMediaDevice): F is NSPanel._PlayerTypeWithMediaDevice { + return ArrayPlayerTypeWithMediaDevice.indexOf(F as NSPanel._PlayerTypeWithMediaDevice) != -1; +} +/** check if NSPanel.adapterPlayerInstanceType has all Playertypes */ +function checkSortedPlayerType(F: NSPanel.notSortedPlayerType) { + const test: NSPanel.adapterPlayerInstanceType = F; } -type notSortedPlayerType = `${PlayerType}.0.` | `${PlayerType}.1.` | `${PlayerType}.2.` | `${PlayerType}.3.` | `${PlayerType}.4.` | `${PlayerType}.5.` | `${PlayerType}.6.` | `${PlayerType}.7.` | `${PlayerType}.8.` | `${PlayerType}.9.` - -/** check if adapterPlayerInstanceType has all Playertypes */ -function checkSortedPlayerType(F: notSortedPlayerType) { - const test: adapterPlayerInstanceType = F; -} - -type mediaOptional = 'seek' | 'crossfade' | 'speakerlist' | 'playlist' | 'tracklist' | 'equalizer' | 'repeat' | 'favorites' - - -function isMediaOptional(F: string | mediaOptional): F is mediaOptional { - switch(F as mediaOptional) { +function isMediaOptional(F: string | NSPanel.mediaOptional): F is NSPanel.mediaOptional { + switch(F as NSPanel.mediaOptional) { case "seek": case "crossfade": case "speakerlist": @@ -9876,8 +9760,8 @@ function isMediaOptional(F: string | mediaOptional): F is mediaOptional { } } -function isEventMethod(F: string | EventMethod): F is EventMethod { - switch(F as EventMethod) { +function isEventMethod(F: string | NSPanel.EventMethod): F is NSPanel.EventMethod { + switch(F as NSPanel.EventMethod) { case "startup": case "sleepReached": case "pageOpenDetail": @@ -9888,7 +9772,310 @@ function isEventMethod(F: string | EventMethod): F is EventMethod { return true; default: // Have to talk about this. - log(`Please report to developer: Unknown EventMethod: ${F} `, 'warn'); + log(`Please report to developer: Unknown NSPanel.EventMethod: ${F} `, 'warn'); return false; } } + +function isPopupType(F: NSPanel.PopupType | string): F is NSPanel.PopupType { + switch(F as NSPanel.PopupType) { + case "popupFan": + case "popupInSel": + case "popupLight": + case "popupLightNew": + case "popupNotify": + case "popupShutter": + case "popupThermo": + case "popupTimer": + return true; + default: + log(`Please report to developer: Unknown NSPanel.PopupType: ${F} `, 'warn'); + return false; + } +} +// If u get a error here u forgot something in PagetypeType or PageType +function checkPageType(F: NSPanel.PagetypeType, A: NSPanel.PageType) { + A.type = F; +} +function isPageMediaItem(F: NSPanel.PageItem | NSPanel.PageMediaItem):F is NSPanel.PageMediaItem { + return 'adapterPlayerInstance' in F +} + +function isPageThermoItem(F: PageItem | NSPanel.PageThermoItem):F is NSPanel.PageThermoItem { + return 'popupThermoMode1' in F; +} + +namespace NSPanel { + export type PopupType = 'popupFan' | 'popupInSel' | 'popupLight' | 'popupLightNew' | 'popupNotify' | 'popupShutter' | 'popupThermo' | 'popupTimer' + + + + export type EventMethod = 'startup' | 'sleepReached' | 'pageOpenDetail' | 'buttonPress2' | 'renderCurrentPage' | 'button1' | 'button2' + + export type SerialType = 'button' | 'light' | 'shutter' | 'text' | 'input_sel' | 'timer' | 'number' | 'fan' + + export type roles = 'light' |'socket'|'dimmer'| 'hue' | 'rgb' | 'rgbSingle' | 'cd' | 'blind' | 'door' | 'window' | 'volumeGroup' | 'volume' + | 'info' | 'humidity' | 'temperature' | 'value.temperature' | 'value.humidity' | 'sensor.door' | 'sensor.window' | 'thermostat' | 'warning' | 'ct' + | 'cie' | 'gate' | 'motion' | 'buttonSensor' | 'button' | 'value.time' | 'level.timer' | 'value.alarmtime' | 'level.mode.fan' | 'lock' | 'slider' + | 'switch.mode.wlan' | 'media' | 'timeTable' | 'airCondition' + + export type ButtonActionType = 'bExit' | 'bUp' | 'bNext' | 'bSubNext' | 'bPrev' | 'bSubPrev' | 'bHome' | 'notifyAction' | 'OnOff' | 'button' | 'up' | 'stop' | 'down' + | 'positionSlider' | 'tiltOpen' | 'tiltStop' | 'tiltSlider' | 'tiltClose' | 'brightnessSlider' | 'colorTempSlider' | 'colorWheel' | 'tempUpd' | 'tempUpdHighLow' | 'media-back' + | 'media-pause' | 'media-next' | 'media-shuffle' | 'volumeSlider' | 'mode-speakerlist' | 'mode-playlist' | 'mode-tracklist' | 'mode-repeat' | 'mode-equalizer' | 'mode-seek' | 'mode-crossfade' + | 'mode-favorites' | 'mode-insel' | 'media-OnOff' | 'timer-start' | 'timer-pause' | 'timer-cancle' | 'timer-finish' | 'hvac_action' | 'mode-modus1' | 'mode-modus2' | 'mode-modus3' | 'number-set' + | 'mode-preset_modes' | 'A1' | 'A2' | 'A3' | 'A4' | 'D1' | 'U1' + + + + export type RGB = { + red: number, + green: number, + blue: number + }; + + export type Payload = { + payload: string; + }; + + export type PageBaseType = { + type: PagetypeType, + heading: string, + items: PageItem[], + useColor: boolean, + subPage?: boolean, + parent?: PageType, + parentIcon?: string, + parentIconColor?: RGB, + prev?: string, + prevIcon?: string, + prevIconColor?: RGB, + next?: string, + nextIcon?: string, + nextIconColor?: RGB, + home?: string, + homeIcon?: string, + homeIconColor?: RGB + }; + + + export type PagetypeType = 'cardChart' | 'cardLChart' | 'cardEntities' |'cardGrid'|'cardGrid2'|'cardThermo'|'cardMedia'|'cardUnlock'|'cardQR'|'cardAlarm'|'cardPower' //| 'cardBurnRec' + + export type PageType = PageChart | PageEntities | PageGrid | PageGrid2 | PageThermo | PageMedia | PageUnlock | PageQR | PageAlarm | PagePower + + export type PageEntities = { + type: 'cardEntities', + items: PageItem[], + } & PageBaseType + + export type PageGrid = { + type: 'cardGrid', + items: PageItem[], + } & PageBaseType + + export type PageGrid2 = { + type: 'cardGrid2', + items: PageItem[], + } & PageBaseType + + export type PageThermo = { + type: 'cardThermo', + items: PageThermoItem[], + + } & Omit + + export type PageMedia = { + type: 'cardMedia', + items: PageMediaItem[], + } & Omit + + export type PageAlarm = { + type: 'cardAlarm', + items: PageItem[], + } & Omit + + export type PageUnlock = { + type: 'cardUnlock', + items: PageItem[], + } & Omit & Partial> + + export type PageQR = { + type: 'cardQR', + items: PageItem[], + } & Omit + + export type PagePower = { + type: 'cardPower', + items: PageItem[], + } & Omit + + export type PageChart = { + type: 'cardChart' | 'cardLChart', + items: PageItem[], + } & Omit + + export type PageItem = PageBaseItem | PageMediaItem | PageThermoItem + + export type PageMediaItem = { + adapterPlayerInstance: adapterPlayerInstanceType, + mediaDevice?: string, + colorMediaIcon?: RGB, + colorMediaArtist?: RGB, + colorMediaTitle?: RGB, + speakerList?: string[], + playList?: string[], + equalizerList?: string[], + repeatList?: string[], + globalTracklist?: string[], + crossfade?: boolean, + } & PageBaseItem + + export type PageThermoItem = { + popupThermoMode1?: string[], + popupThermoMode2?: string[], + popupThermoMode3?: string[], + popUpThermoName?: string[], + setThermoAlias?: string[], + setThermoDestTemp2?: string, + } & PageBaseItem | + { + popupThermoMode1?: string[], + popupThermoMode2?: string[], + popupThermoMode3?: string[], + popUpThermoName?: string[], + setThermoAlias?: string[], + setThermoDestTemp2?: string, + } & PageBaseItem + // mean string start with getState(' and end with ').val + type getStateID = string; + export type PageBaseItem = { + id?: string | null, + icon?: string, + icon2?: string, + onColor?: RGB, + offColor?: RGB, + useColor?: boolean, + interpolateColor?: boolean, + minValueBrightness?: number, + maxValueBrightness?: number, + minValueColorTemp?: number, + maxValueColorTemp?: number, + minValueLevel?: number, + maxValueLevel?: number, + minValueTilt?: number, + maxValueTilt?: number, + minValue?: number, + maxValue?: number, + stepValue?: number, + prefixName?: string, + suffixName?: string, + name?: string | getStateID, + secondRow?: string, + buttonText?: string, + unit?: string, + navigate?: boolean, + colormode?: string, + colorScale?: IconScaleElement, + //adapterPlayerInstance?: adapterPlayerInstanceType, + targetPage?: string, + modeList?: string[], + hidePassword?: boolean, + autoCreateALias?: boolean + yAxis?: string, + yAxisTicks?: number[] | string, + xAxisDecorationId?: string, + useValue?: boolean, + monobutton?: boolean, + inSel_ChoiceState?: boolean, + iconArray?: string[], + fontSize?: number, + actionStringArray?: string[], + alwaysOnDisplay?: boolean, + } + + export type DimMode = { + dimmodeOn: (boolean | undefined), + brightnessDay: (number | undefined), + brightnessNight: (number | undefined), + timeDay: (string | undefined), + timeNight: (string | undefined) + } + + export type ConfigButtonFunction = { + mode: 'page' | 'toggle' | 'set' | null, + page: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PageGrid2 | PagePower | PageChart | PageUnlock | null), + entity: string | null, + setValue: string | number | boolean | null + } + + export type Config = { + panelRecvTopic: string, + panelSendTopic: string, + weatherEntity: string, + leftScreensaverEntity: leftScreensaverEntityType + bottomScreensaverEntity: ScreenSaverElement[], + indicatorScreensaverEntity: indicatorScreensaverEntityType + mrIcon1ScreensaverEntity: ScreenSaverMRElement, + mrIcon2ScreensaverEntity: ScreenSaverMRElement, + defaultColor: RGB, + defaultOnColor: RGB, + defaultOffColor: RGB, + defaultBackgroundColor: RGB, + pages: PageType[], + subPages: PageType[], + button1: ConfigButtonFunction, + button2: ConfigButtonFunction + } + export type leftScreensaverEntityType = [ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined, ScreenSaverElementWithUndefined] | []; + export type indicatorScreensaverEntityType = [ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?, ScreenSaverElementWithUndefined?] | []; + export type ScreenSaverElementWithUndefined = null | undefined | ScreenSaverElement + export type ScreenSaverElement = { + ScreensaverEntity: string, + ScreensaverEntityText: string, + ScreensaverEntityFactor?: number, + ScreensaverEntityDecimalPlaces?: number, + ScreensaverEntityDateFormat?: Intl.DateTimeFormatOptions, + ScreensaverEntityIconOn?: string | null, + ScreensaverEntityIconOff?: string | null, + ScreensaverEntityUnitText?: string, + ScreensaverEntityIconColor?: RGB | IconScaleElement | string + ScreensaverEntityOnColor?: RGB + ScreensaverEntityOffColor?: RGB + ScreensaverEntityOnText?: string | null, + ScreensaverEntityOffText?: string | null, + } + + export type ScreenSaverMRElement = { + ScreensaverEntity: string | null, + ScreensaverEntityIconOn: string | null, + ScreensaverEntityIconOff: string | null, + ScreensaverEntityValue: string | null, + ScreensaverEntityValueDecimalPlace: number | null, + ScreensaverEntityValueUnit: string | null, + ScreensaverEntityOnColor: RGB, + ScreensaverEntityOffColor: RGB + } + + export type IconScaleElement = { + val_min:number, + val_max:number, + val_best?: number + } + /** we need this to have a nice order when using switch() */ + export type adapterPlayerInstanceType = + 'alexa2.0.' | 'alexa2.1.'| 'alexa2.2.' | 'alexa2.3.' | 'alexa2.4.' | 'alexa2.5.' | 'alexa2.6.' | 'alexa2.7.' | 'alexa2.8.' | 'alexa2.9.' + | 'sonos.0.' | 'sonos.1.' | 'sonos.2.' | 'sonos.3.' | 'sonos.4.' | 'sonos.5.' | 'sonos.6.' | 'sonos.7.' | 'sonos.8.' | 'sonos.9.' + | 'spotify-premium.0.' | 'spotify-premium.1.' | 'spotify-premium.2.' | 'spotify-premium.3.' | 'spotify-premium.4.' | 'spotify-premium.5.' | 'spotify-premium.6.' | 'spotify-premium.7.' | 'spotify-premium.8.' | 'spotify-premium.9.' + | 'volumio.0.' | 'volumio.1.' | 'volumio.2.' | 'volumio.3.' |'volumio.4.' | 'volumio.5.' | 'volumio.6.' | 'volumio.7.' | 'volumio.8.' | 'volumio.9.' + | 'squeezeboxrpc.0.' | 'squeezeboxrpc.1.' | 'squeezeboxrpc.2.' | 'squeezeboxrpc.3.' | 'squeezeboxrpc.4.' | 'squeezeboxrpc.5.' | 'squeezeboxrpc.6.' | 'squeezeboxrpc.7.' | 'squeezeboxrpc.8.' | 'squeezeboxrpc.9.' + | 'bosesoundtouch.0.' | 'bosesoundtouch.1.' | 'bosesoundtouch.2.' | 'bosesoundtouch.3.' |'bosesoundtouch.4.' | 'bosesoundtouch.5.' | 'bosesoundtouch.6.' | 'bosesoundtouch.7.' | 'bosesoundtouch.8.' | 'bosesoundtouch.9.' + + export type PlayerType = _PlayerTypeWithMediaDevice | _PlayerTypeWithOutMediaDevice; + + export type _PlayerTypeWithOutMediaDevice = typeof ArrayPlayerTypeWithOutMediaDevice[number] + export type _PlayerTypeWithMediaDevice = typeof ArrayPlayerTypeWithMediaDevice[number] + + export type notSortedPlayerType = `${PlayerType}.0.` | `${PlayerType}.1.` | `${PlayerType}.2.` | `${PlayerType}.3.` | `${PlayerType}.4.` | `${PlayerType}.5.` | `${PlayerType}.6.` | `${PlayerType}.7.` | `${PlayerType}.8.` | `${PlayerType}.9.` + + export type mediaOptional = 'seek' | 'crossfade' | 'speakerlist' | 'playlist' | 'tracklist' | 'equalizer' | 'repeat' | 'favorites' + +} From 943bb933987f83f7ead005b5c00beb9ff9c6ddff Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Sun, 14 Jan 2024 20:43:14 +0100 Subject: [PATCH 79/99] v4.3.3.36 - Update NsPanelTs.ts - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) - v4.3.3.35 Add: relay.1/relay.2 show the confirmed status - v4.3.3.36 Fix: change ScreensaverTimeout and activeBrightness - v4.3.3.36 Fix: schedule SendTime - v4.3.3.36 Fix: Some Types and Minor Fixes --- ioBroker/NsPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index e508405a..b09f6574 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.36 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.36 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 From 4cc8455fff8369981dc396fe95506bfc9cbd7ead Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Sun, 14 Jan 2024 20:46:19 +0100 Subject: [PATCH 80/99] v4.3.3.36 - Update NsPanelTs.ts - v4.3.3.34 Fix: Disabled Icon Status for Blinds while bug in updating data points in ioBroker (reason unknown) - v4.3.3.35 Add: relay.1/relay.2 show the confirmed status - v4.3.3.36 Fix: change ScreensaverTimeout and activeBrightness - v4.3.3.36 Fix: schedule SendTime - v4.3.3.36 Fix: Some Types and Minor Fixes --- ioBroker/NsPanelTs.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index b09f6574..e5f3adea 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.36 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.36 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -92,7 +92,7 @@ ReleaseNotes: - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity - 07.01.2024 - v4.3.3.33 Fix BoseSoundtouch Proto - - 08.01.2024 - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) + - 08.01.2024 - v4.3.3.34 Fix: Disabled Icon Status for Blinds while bug in updating data points in ioBroker (reason unknown) - 08.01.2024 - v4.3.3.35 Add: relay.1/relay.2 show the confirmed status - 09.01.2024 - v4.3.3.36 Fix: change ScreensaverTimeout and activeBrightness - 09.01.2024 - v4.3.3.36 Fix: schedule SendTime From e94c711f123c3f0ecfed075f3bd9143df61c6890 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Mon, 15 Jan 2024 11:00:22 +0100 Subject: [PATCH 81/99] v4.3.3.37 - Update NSPanelTs.ts Change: Allow data points to be flushed for popUpNotify. Activate screensaver with one click. --- ioBroker/DEV/NSPanelTs.ts | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 14dad67e..6aa86713 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.36 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.37 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -89,14 +89,15 @@ ReleaseNotes: - 04.01.2024 - v4.3.3.32 Add more details to types for: leftScreensaverEntity, indicatorScreensaverEntity, PageThermo, PageMedia - 04.01.2024 - v4.3.3.32 Remove not uses propertys from PageItem - 05.01.2024 - v4.3.3.32 Add Body for BoseSoundtouch-Player - - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions - - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity - - 07.01.2024 - v4.3.3.33 Fix BoseSoundtouch Proto - - 08.01.2024 - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) + - 05.01.2024 - v4.3.3.33 Add BoseSoundtouch Functions + - 05.01.2024 - v4.3.3.33 Screensaver Fix max Number of indicatorScreensaverEntity + - 07.01.2024 - v4.3.3.33 Fix BoseSoundtouch Proto + - 08.01.2024 - v4.3.3.34 Fix: Disabled Icon Status while bug in updating data points in ioBroker (reason unknown) - 08.01.2024 - v4.3.3.35 Add: relay.1/relay.2 show the confirmed status - 09.01.2024 - v4.3.3.36 Fix: change ScreensaverTimeout and activeBrightness - 09.01.2024 - v4.3.3.36 Fix: schedule SendTime - 09.01.2024 - v4.3.3.36 Fix: Function _schedule SummerTime/WinterTime + - 15.01.2024 - v4.3.3.37 Change: Allow data points to be flushed for popUpNotify. Activate screensaver with one click. Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -963,7 +964,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.36'; +const scriptVersion: string = 'v4.3.3.37'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -2103,7 +2104,7 @@ async function InitPopupNotify() { const heading = getState(screensaverNotifyHeading).val; const text = getState(screensaverNotifyText).val; - if (screensaverEnabled) { + if (screensaverEnabled && heading != '' && text != '') { setIfExists(config.panelSendTopic, `notify~${heading}~${text}`); } @@ -2113,10 +2114,8 @@ async function InitPopupNotify() { }); // popupNotify - Notification to a separate page - //on({ id: [popupNotifyInternalName], change: 'ne' }, async () => { on({ id: [popupNotifyText], change: 'any' }, async() => { - let notification: string; let v_popupNotifyHeadingColor = (getState(popupNotifyHeadingColor).val != null) ? getState(popupNotifyHeadingColor).val : '65504'// Farbe Headline - gelb 65504 @@ -2127,16 +2126,19 @@ async function InitPopupNotify() { let v_popupNotifyFontIdText = (getState(popupNotifyFontIdText).val != null) ? getState(popupNotifyFontIdText).val : '1' let v_popupNotifyIcon = (getState(popupNotifyIcon).val != null) ? getState(popupNotifyIcon).val : 'alert' let v_popupNotifyBuzzer = (getState(popupNotifyBuzzer).val != null) ? getState(popupNotifyBuzzer).val : '0'; - + + const heading = getState(popupNotifyHeading).val; + const text = getState(popupNotifyText).val; + notification = 'entityUpdateDetail' + '~' + getState(popupNotifyInternalName).val + '~' - + getState(popupNotifyHeading).val + '~' + + heading + '~' + v_popupNotifyHeadingColor + '~' + getState(popupNotifyButton1Text).val + '~' + v_popupNotifyButton1TextColor + '~' + getState(popupNotifyButton2Text).val + '~' + v_popupNotifyButton2TextColor + '~' - + getState(popupNotifyText).val + '~' + + text + '~' + v_popupNotifyTextColor + '~' + getState(popupNotifySleepTimeout).val; @@ -2147,8 +2149,10 @@ async function InitPopupNotify() { + v_popupNotifyIconColor; } - setIfExists(config.panelSendTopic, 'pageType~popupNotify'); - setIfExists(config.panelSendTopic, notification); + if (heading != '' && text != '') { + setIfExists(config.panelSendTopic, 'pageType~popupNotify'); + setIfExists(config.panelSendTopic, notification); + } //------ Tasmota Buzzer ------ @@ -6367,6 +6371,7 @@ function HandleButtonEvent(words: any): void { if (existsObject(NSPanel_Path + 'ScreensaverInfo.bExitPage') && getState(NSPanel_Path + 'ScreensaverInfo.bExitPage').val != null && getState(NSPanel_Path + 'ScreensaverInfo.bExitPage').val != -1) { pageId = getState(NSPanel_Path + 'ScreensaverInfo.bExitPage').val } + screensaverEnabled = true; // Activating screensaver also on One-Time click } activePage = config.pages[pageId]; } From f65ff57a953ddf101c92ca80dab75c74b6ee04b6 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 16 Jan 2024 15:55:46 +0100 Subject: [PATCH 82/99] HandleScreensaverStatusIcons rewritten fixed #1098 types: Number of PageItems defined --- ioBroker/DEV/NSPanelTs.ts | 329 ++++++++++++++++++++++++-------------- 1 file changed, 206 insertions(+), 123 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 1bd70320..827bf247 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -3154,9 +3154,9 @@ function findPageItem(searching: String): PageItem { function GeneratePage(page: PageType): void { try { activePage = page; - setIfExists(NSPanel_Path + 'ActivePage.type', activePage!.type); - setIfExists(NSPanel_Path + 'ActivePage.heading', activePage!.heading); - setIfExists(NSPanel_Path + 'ActivePage.id0', activePage!.items[0].id); + setIfExists(NSPanel_Path + 'ActivePage.type', activePage.type); + setIfExists(NSPanel_Path + 'ActivePage.heading', activePage.heading); + setIfExists(NSPanel_Path + 'ActivePage.id0', activePage.items[0] !== undefined ? activePage.items[0].id : ''); switch (page.type) { case 'cardEntities': SendToPanel(GenerateEntitiesPage(page)); @@ -4696,8 +4696,9 @@ function GenerateThermoPage(page: NSPanel.PageThermo): NSPanel.Payload[] { function unsubscribeMediaSubscriptions(): void { for (let i = 0; i < config.pages.length; i++) { - if (config.pages[i].type == 'cardMedia') { - let mediaID = config.pages[i].items[0].id; + const page: NSPanel.PageType = config.pages[i]; + if (isPageMedia(page)) { + let mediaID = page.items[0].id; unsubscribe(mediaID + '.STATE'); unsubscribe(mediaID + '.ARTIST'); unsubscribe(mediaID + '.TITLE'); @@ -4711,8 +4712,9 @@ function unsubscribeMediaSubscriptions(): void { } } for (let i = 0; i < config.subPages.length; i++) { - if (config.subPages[i].type == 'cardMedia') { - let mediaID = config.subPages[i].items[0].id; + const page: NSPanel.PageType = config.subPages[i]; + if (isPageMedia(page)) { + let mediaID = page.items[0].id; unsubscribe(mediaID + '.STATE'); unsubscribe(mediaID + '.ARTIST'); unsubscribe(mediaID + '.TITLE'); @@ -5999,14 +6001,16 @@ function GenerateQRPage(page: NSPanel.PageQR): NSPanel.Payload[] { function unsubscribePowerSubscriptions(): void { for (let i = 0; i < config.pages.length; i++) { - if (config.pages[i].type == 'cardPower') { - let powerID = config.pages[i].items[0].id; + const page: NSPanel.PageType = config.pages[i]; + if (isPagePower(page)) { + let powerID = page.items[0].id; unsubscribe(powerID + '.ACTUAL'); } } for (let i = 0; i < config.subPages.length; i++) { - if (config.subPages[i].type == 'cardPower') { - let powerID = config.subPages[i].items[0].id; + const page: NSPanel.PageType = config.pages[i]; + if (isPagePower(page)) { + let powerID = page.items[0].id; unsubscribe(powerID + '.ACTUAL'); } } @@ -8844,97 +8848,155 @@ function RegisterScreensaverEntityWatcher(id: string): void { function HandleScreensaverStatusIcons() : void { try { let payloadString = ''; - let hwBtn1Col: any = config.mrIcon1ScreensaverEntity.ScreensaverEntityOffColor; - if (config.mrIcon1ScreensaverEntity.ScreensaverEntity != null) { - // Prüfung ob ScreensaverEntity vom Typ String ist - if (typeof (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val) == 'string') { - if (Debug) log('Entity ist String', 'info') - let hwBtn1: string = getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val; - if (hwBtn1 == 'ON') { - hwBtn1Col = config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor; - } - if (Debug) log('Value: ' + hwBtn1 + ' Color: ' + JSON.stringify(hwBtn1Col), 'info') + const iconData: Record<'mrIcon1' | 'mrIcon2', NSPanel.ScreenSaverMRDataElement> = { + mrIcon1: { + ScreensaverEntity: config.mrIcon1ScreensaverEntity.ScreensaverEntity != null + && existsState(config.mrIcon1ScreensaverEntity.ScreensaverEntity) + ? getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val + : null, + ScreensaverEntityIconOn: config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn != null + ? Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn) + : null, + ScreensaverEntityIconOff: config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff != null + ? Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff) + : null, + ScreensaverEntityOnColor: config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor, + ScreensaverEntityOffColor: config.mrIcon1ScreensaverEntity.ScreensaverEntityOffColor, + ScreensaverEntityValue: config.mrIcon1ScreensaverEntity.ScreensaverEntityValue === null + ? null + : getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val, + ScreensaverEntityValueDecimalPlace: config.mrIcon1ScreensaverEntity.ScreensaverEntityValueDecimalPlace, + ScreensaverEntityValueUnit: config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit, + - // Icon ermitteln - if (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val) { - payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn); - if (Debug) log('Icon if true '+payloadString, 'info') - } else { - if (config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff != null) { - payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff); - if (Debug) log('Icon else true '+payloadString, 'info') - } else { - payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn); - if (Debug) log('Icon else false '+payloadString, 'info') - } - } - if (config.mrIcon1ScreensaverEntity.ScreensaverEntityValue != null) { - if (isNaN(getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val) == false) { - payloadString += (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val).toFixed(config.mrIcon1ScreensaverEntity.ScreensaverEntityValueDecimalPlace); - payloadString += (config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit; - if (Debug) log('Value ist eine Zahl ' + payloadString, 'info') - } else { - payloadString += getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val - if (Debug) log('Value ist keine Zahl ' + payloadString, 'info') - } + }, + mrIcon2: { + ScreensaverEntity: config.mrIcon2ScreensaverEntity.ScreensaverEntity != null + && existsState(config.mrIcon2ScreensaverEntity.ScreensaverEntity) + ? getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val + : null, + ScreensaverEntityIconOn: config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn != null + ? Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn) + : null, + ScreensaverEntityIconOff: config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff != null + ? Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff) + : null, + ScreensaverEntityOnColor: config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor, + ScreensaverEntityOffColor: config.mrIcon2ScreensaverEntity.ScreensaverEntityOffColor, + ScreensaverEntityValue: config.mrIcon2ScreensaverEntity.ScreensaverEntityValue === null + ? null + : getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val, + ScreensaverEntityValueDecimalPlace: config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace, + ScreensaverEntityValueUnit: config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit, + } + } + for (const a in iconData) { + if (iconData[a].ScreensaverEntityValue === null) { + switch (typeof iconData[a].ScreensaverEntityValue) { + case "string": + if (iconData[a].ScreensaverEntityValue === '' || isNaN(iconData[a].ScreensaverEntityValue)) break; + case "number": + case "bigint": + iconData[a].ScreensaverEntityValue = Number(iconData[a].ScreensaverEntityValue).toFixed(iconData[a].ScreensaverEntityValueDecimalPlace); + break; + case "boolean": + break; + case "symbol": + case "undefined": + case "object": + case "function": + iconData[a].ScreensaverEntityValue = null; } - payloadString += '~' + rgb_dec565(hwBtn1Col) + '~'; - } else if (typeof (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val) == 'boolean') { - let hwBtn1: boolean = getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val; - if (hwBtn1) { - hwBtn1Col = config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor; - } - if (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val) { - payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn); - } else { - if (config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff != null) { - payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff); - } else { - payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn); + } + let hwBtn1Col: RGB = iconData[a].ScreensaverEntityOffColor; + if (iconData[a].ScreensaverEntity != null) { + // Prüfung ob ScreensaverEntity vom Typ String ist + if (typeof (iconData[a].ScreensaverEntity) == 'string') { + if (Debug) log('Entity ist String', 'info') + let hwBtn1: string = iconData[a].ScreensaverEntity; + if (hwBtn1 == 'ON') { + hwBtn1Col = iconData[a].ScreensaverEntityOnColor; } - } - if (config.mrIcon1ScreensaverEntity.ScreensaverEntityValue != null) { - if (isNaN(getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val) == false) { - payloadString += (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val).toFixed(config.mrIcon1ScreensaverEntity.ScreensaverEntityValueDecimalPlace); - payloadString += (config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit; + if (Debug) log('Value: ' + hwBtn1 + ' Color: ' + JSON.stringify(hwBtn1Col), 'info') + + // Icon ermitteln + if (iconData[a].ScreensaverEntity) { + payloadString += iconData[a].ScreensaverEntityIconOn; + if (Debug) log('Icon if true '+payloadString, 'info') } else { - payloadString += getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val + if (iconData[a].ScreensaverEntityIconOff != null) { + payloadString += iconData[a].ScreensaverEntityIconOff; + if (Debug) log('Icon1 else true '+payloadString, 'info') + } else { + payloadString += iconData[a].ScreensaverEntityIconOn; + if (Debug) log('Icon1 else false '+payloadString, 'info') + } + } + + if (iconData[a].ScreensaverEntityValue != null) { + payloadString += iconData[a].ScreensaverEntityValue; + if (typeof iconData[a].ScreensaverEntityValue == 'number') { + //payloadString += iconData[a].ScreensaverEntityValue.toFixed(iconData[a].ScreensaverEntityValueDecimalPlace); + payloadString += (iconData[a].ScreensaverEntityValueUnit == null) ? '' : iconData[a].ScreensaverEntityValueUnit; + if (Debug) log('Value ist eine Zahl ' + payloadString, 'info') + } else { + if (Debug) log('Value ist keine Zahl ' + payloadString, 'info') + } + } + + payloadString += '~' + rgb_dec565(hwBtn1Col) + '~'; + } else if (typeof (iconData[a].ScreensaverEntity) == 'boolean') { + let hwBtn1: boolean = iconData[a].ScreensaverEntity; + if (hwBtn1) { + hwBtn1Col = iconData[a].ScreensaverEntityOnColor; + } + if (iconData[a].ScreensaverEntity) { + payloadString += iconData[a].ScreensaverEntityIconOn; + } else { + if (iconData[a].ScreensaverEntityIconOff != null) { + payloadString += iconData[a].ScreensaverEntityIconOff; + } else { + payloadString += iconData[a].ScreensaverEntityIconOn; + } + } + if (iconData[a].ScreensaverEntityValue != null) { + payloadString += iconData[a].ScreensaverEntityValue; + if (typeof iconData[a].ScreensaverEntityValue == 'number') { + //payloadString += iconData[a].ScreensaverEntityValue.toFixed(iconData[a].ScreensaverEntityValueDecimalPlace); + payloadString += (iconData[a].ScreensaverEntityValueUnit == null) ? '' : iconData[a].ScreensaverEntityValueUnit; + } + } + payloadString += '~' + rgb_dec565(hwBtn1Col) + '~'; + } + } else if (iconData[a].ScreensaverEntity == null && iconData[a].ScreensaverEntityValue != null){ + if(iconData[a].ScreensaverEntityOnColor != null){ + hwBtn1Col = iconData[a].ScreensaverEntityOnColor; + } + if(iconData[a].ScreensaverEntityIconOn != null){ + payloadString += iconData[a].ScreensaverEntityIconOn; + } + if (iconData[a].ScreensaverEntityValue != null) { + payloadString += iconData[a].ScreensaverEntityValue; + if (typeof iconData[a].ScreensaverEntityValue == 'number') { + //payloadString += (iconData[a].ScreensaverEntityValue).toFixed(iconData[a].ScreensaverEntityValueDecimalPlace); + payloadString += (iconData[a].ScreensaverEntityValueUnit == null) ? '' : iconData[a].ScreensaverEntityValueUnit; } } payloadString += '~' + rgb_dec565(hwBtn1Col) + '~'; } - } else if (config.mrIcon1ScreensaverEntity.ScreensaverEntity == null && config.mrIcon1ScreensaverEntity.ScreensaverEntityValue != null){ - - if(config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor != null){ - hwBtn1Col = config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor; + else { + hwBtn1Col = Black; + payloadString += '~~'; } - if(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn != null){ - payloadString += Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn); - } - - if (config.mrIcon1ScreensaverEntity.ScreensaverEntityValue != null) { - if (isNaN(getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val) == false) { - payloadString += (getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val).toFixed(config.mrIcon1ScreensaverEntity.ScreensaverEntityValueDecimalPlace); - payloadString += (config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit; - } else { - payloadString += getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val - } - } - payloadString += '~' + rgb_dec565(hwBtn1Col) + '~'; } - else { - hwBtn1Col = Black; - payloadString += '~~'; - } - - let hwBtn2Col: any = config.mrIcon2ScreensaverEntity.ScreensaverEntityOffColor; - if (config.mrIcon2ScreensaverEntity.ScreensaverEntity != null) { - if (typeof (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val) == 'string') { - let hwBtn2: string = getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val; + /*let hwBtn2Col: any = config.mrIcon2ScreensaverEntity.ScreensaverEntityOffColor; + if (config.mrIcon2ScreensaverEntity.ScreensaverEntity != null && existsState(config.mrIcon2ScreensaverEntity.ScreensaverEntity)) { + if (typeof (iconData.mrIcon2.ScreensaverEntity) == 'string') { + let hwBtn2: string = iconData.mrIcon2.ScreensaverEntity; if (hwBtn2 == 'ON') { hwBtn2Col = config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor; } - if (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val) { + if (iconData.mrIcon2.ScreensaverEntity) { payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); } else { if (config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff != null) { @@ -8943,21 +9005,22 @@ function HandleScreensaverStatusIcons() : void { payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); } } - if (config.mrIcon2ScreensaverEntity.ScreensaverEntityValue != null) { - if (isNaN(getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val) == false) { - payloadString += (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val).toFixed(config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace); - payloadString += (config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit; + const value = config.mrIcon2ScreensaverEntity.ScreensaverEntityValue == null ? null : getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val; + if (value != null) { + if (value != '' && isNaN(value) == false) { + payloadString += value.toFixed(config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace); + payloadString += (config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit; } else { - payloadString += getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val - } - } + payloadString += value; + } + } payloadString += '~' + rgb_dec565(hwBtn2Col) + '~'; - } else if (typeof (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val) == 'boolean') { - let hwBtn2: boolean = getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val; + } else if (typeof (iconData.mrIcon2.ScreensaverEntity) == 'boolean') { + let hwBtn2: boolean = iconData.mrIcon2.ScreensaverEntity; if (hwBtn2) { hwBtn2Col = config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor; } - if (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val) { + if (iconData.mrIcon2.ScreensaverEntity) { payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); } else { if (config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff != null) { @@ -8966,14 +9029,15 @@ function HandleScreensaverStatusIcons() : void { payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); } } - if (config.mrIcon2ScreensaverEntity.ScreensaverEntityValue != null) { - if (isNaN(getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val) == false) { - payloadString += (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val).toFixed(config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace); + const value = config.mrIcon2ScreensaverEntity.ScreensaverEntityValue == null ? null : getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val; + if (value != null) { + if (value != '' && isNaN(value) == false) { + payloadString += value.toFixed(config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace); payloadString += (config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit; } else { - payloadString += getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val - } - } + payloadString += value; + } + } payloadString += '~' + rgb_dec565(hwBtn2Col) + '~'; } } else if (config.mrIcon2ScreensaverEntity.ScreensaverEntity == null && config.mrIcon2ScreensaverEntity.ScreensaverEntityValue != null){ @@ -8986,20 +9050,21 @@ function HandleScreensaverStatusIcons() : void { payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); } - if (config.mrIcon2ScreensaverEntity.ScreensaverEntityValue != null) { - if (isNaN(getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val) == false) { - payloadString += (getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val).toFixed(config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace); - payloadString += (config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit; - } else { - payloadString += getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val - } - } + const value = config.mrIcon2ScreensaverEntity.ScreensaverEntityValue == null ? null : getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val; + if (value != null) { + if (value != '' && isNaN(value) == false) { + payloadString += value.toFixed(config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace); + payloadString += (config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit; + } else { + payloadString += value; + } + } payloadString += '~' + rgb_dec565(hwBtn2Col) + '~'; } else { hwBtn2Col = Black; payloadString += '~~'; } - + */ let alternateScreensaverMFRIcon1Size = getState(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1').val let alternateScreensaverMFRIcon2Size = getState(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2').val //Alternate MRIcon Size @@ -9811,6 +9876,13 @@ function isPageThermoItem(F: PageItem | NSPanel.PageThermoItem):F is NSPanel.Pag return 'popupThermoMode1' in F; } +function isPageMedia(F: NSPanel.PageType | NSPanel.PageMedia):F is NSPanel.PageMedia { + return F.type == 'cardMedia'; +} +function isPagePower(F: NSPanel.PageType | NSPanel.PagePower):F is NSPanel.PagePower { + return F.type == 'cardPower'; +} + namespace NSPanel { export type PopupType = 'popupFan' | 'popupInSel' | 'popupLight' | 'popupLightNew' | 'popupNotify' | 'popupShutter' | 'popupThermo' | 'popupTimer' @@ -9870,48 +9942,49 @@ namespace NSPanel { export type PageEntities = { type: 'cardEntities', - items: PageItem[], + items: [PageItem?, PageItem?, PageItem?, PageItem?, PageItem?], } & PageBaseType export type PageGrid = { type: 'cardGrid', - items: PageItem[], + items: [PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?], } & PageBaseType export type PageGrid2 = { type: 'cardGrid2', - items: PageItem[], + items: [PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?], } & PageBaseType export type PageThermo = { type: 'cardThermo', - items: PageThermoItem[], + items: [PageThermoItem], } & Omit export type PageMedia = { type: 'cardMedia', - items: PageMediaItem[], + items: [PageMediaItem], } & Omit + export type PageAlarm = { type: 'cardAlarm', - items: PageItem[], + items: [PageItem], } & Omit export type PageUnlock = { type: 'cardUnlock', - items: PageItem[], + items: [PageItem], } & Omit & Partial> export type PageQR = { type: 'cardQR', - items: PageItem[], + items: [PageItem], } & Omit export type PagePower = { type: 'cardPower', - items: PageItem[], + items: [PageItem], } & Omit export type PageChart = { @@ -10060,6 +10133,16 @@ namespace NSPanel { ScreensaverEntityOnColor: RGB, ScreensaverEntityOffColor: RGB } + export type ScreenSaverMRDataElement = { + ScreensaverEntity: string | number | boolean | null, + ScreensaverEntityIconOn: string | null, + ScreensaverEntityIconOff: string | null, + ScreensaverEntityValue: string | number | boolean | null, + ScreensaverEntityValueDecimalPlace: number | null, + ScreensaverEntityValueUnit: string | null, + ScreensaverEntityOnColor: RGB, + ScreensaverEntityOffColor: RGB + } export type IconScaleElement = { val_min:number, From e7a6a05a1bcad7e25176ab32352b68eebbef55e3 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 16 Jan 2024 15:59:28 +0100 Subject: [PATCH 83/99] Update Version and Changelog --- ioBroker/DEV/NSPanelTs.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 827bf247..46c2bd16 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.37 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.38 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne - abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.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 @@ -98,7 +98,10 @@ ReleaseNotes: - 09.01.2024 - v4.3.3.36 Fix: schedule SendTime - 09.01.2024 - v4.3.3.36 Fix: Function _schedule SummerTime/WinterTime - 15.01.2024 - v4.3.3.37 Change: Allow data points to be flushed for popUpNotify. Activate screensaver with one click. - + - 16.01.2024 - v4.3.3.38 Fix: joBr99#1098 + - 16.01.2024 - v4.3.3.38 Types: Number of PageItems defined & HandleScreensaverStatusIcons rewritten + - 16.01.2024 - v4.3.3.38 Optimate: function SendTime() + Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -964,7 +967,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.37'; +const scriptVersion: string = 'v4.3.3.38'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; From f3b545fd9026652f5ff5acb78fbee6c96cd42046 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 16 Jan 2024 16:04:22 +0100 Subject: [PATCH 84/99] remove commented out code --- ioBroker/DEV/NSPanelTs.ts | 77 +-------------------------------------- 1 file changed, 1 insertion(+), 76 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 46c2bd16..f0898c1f 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -8992,82 +8992,7 @@ function HandleScreensaverStatusIcons() : void { payloadString += '~~'; } } - /*let hwBtn2Col: any = config.mrIcon2ScreensaverEntity.ScreensaverEntityOffColor; - if (config.mrIcon2ScreensaverEntity.ScreensaverEntity != null && existsState(config.mrIcon2ScreensaverEntity.ScreensaverEntity)) { - if (typeof (iconData.mrIcon2.ScreensaverEntity) == 'string') { - let hwBtn2: string = iconData.mrIcon2.ScreensaverEntity; - if (hwBtn2 == 'ON') { - hwBtn2Col = config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor; - } - if (iconData.mrIcon2.ScreensaverEntity) { - payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); - } else { - if (config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff != null) { - payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff); - } else { - payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); - } - } - const value = config.mrIcon2ScreensaverEntity.ScreensaverEntityValue == null ? null : getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val; - if (value != null) { - if (value != '' && isNaN(value) == false) { - payloadString += value.toFixed(config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace); - payloadString += (config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit; - } else { - payloadString += value; - } - } - payloadString += '~' + rgb_dec565(hwBtn2Col) + '~'; - } else if (typeof (iconData.mrIcon2.ScreensaverEntity) == 'boolean') { - let hwBtn2: boolean = iconData.mrIcon2.ScreensaverEntity; - if (hwBtn2) { - hwBtn2Col = config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor; - } - if (iconData.mrIcon2.ScreensaverEntity) { - payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); - } else { - if (config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff != null) { - payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff); - } else { - payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); - } - } - const value = config.mrIcon2ScreensaverEntity.ScreensaverEntityValue == null ? null : getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val; - if (value != null) { - if (value != '' && isNaN(value) == false) { - payloadString += value.toFixed(config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace); - payloadString += (config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit; - } else { - payloadString += value; - } - } - payloadString += '~' + rgb_dec565(hwBtn2Col) + '~'; - } - } else if (config.mrIcon2ScreensaverEntity.ScreensaverEntity == null && config.mrIcon2ScreensaverEntity.ScreensaverEntityValue != null){ - - if(config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor != null){ - hwBtn2Col = config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor; - } - - if(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn != null){ - payloadString += Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn); - } - - const value = config.mrIcon2ScreensaverEntity.ScreensaverEntityValue == null ? null : getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val; - if (value != null) { - if (value != '' && isNaN(value) == false) { - payloadString += value.toFixed(config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace); - payloadString += (config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit == null) ? '' : config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit; - } else { - payloadString += value; - } - } - payloadString += '~' + rgb_dec565(hwBtn2Col) + '~'; - } else { - hwBtn2Col = Black; - payloadString += '~~'; - } - */ + let alternateScreensaverMFRIcon1Size = getState(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.1').val let alternateScreensaverMFRIcon2Size = getState(NSPanel_Path + 'Config.MRIcons.alternateMRIconSize.2').val //Alternate MRIcon Size From 5a3478d91630223337aebb83173faea4f706dda1 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 16 Jan 2024 16:06:47 +0100 Subject: [PATCH 85/99] ups :D --- ioBroker/DEV/NSPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index f0898c1f..08859d14 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -8894,7 +8894,7 @@ function HandleScreensaverStatusIcons() : void { } } for (const a in iconData) { - if (iconData[a].ScreensaverEntityValue === null) { + if (iconData[a].ScreensaverEntityValue !== null) { switch (typeof iconData[a].ScreensaverEntityValue) { case "string": if (iconData[a].ScreensaverEntityValue === '' || isNaN(iconData[a].ScreensaverEntityValue)) break; From 01392bcbf807aa17c25f86d6a86fe5c12d3b6e65 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 16 Jan 2024 16:32:38 +0100 Subject: [PATCH 86/99] fix unsubscribePowerSubscriptions --- ioBroker/DEV/NSPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 08859d14..b686805b 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -6011,7 +6011,7 @@ function unsubscribePowerSubscriptions(): void { } } for (let i = 0; i < config.subPages.length; i++) { - const page: NSPanel.PageType = config.pages[i]; + const page: NSPanel.PageType = config.subPages[i]; if (isPagePower(page)) { let powerID = page.items[0].id; unsubscribe(powerID + '.ACTUAL'); From 117798a3f526cb99f2cfc2e1e5d6d9975e82f1bd Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 16 Jan 2024 17:34:09 +0100 Subject: [PATCH 87/99] icon fix --- ioBroker/DEV/NSPanelTs.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index b686805b..93966019 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -8859,10 +8859,10 @@ function HandleScreensaverStatusIcons() : void { : null, ScreensaverEntityIconOn: config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn != null ? Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn) - : null, + : '', ScreensaverEntityIconOff: config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff != null ? Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff) - : null, + : '', ScreensaverEntityOnColor: config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor, ScreensaverEntityOffColor: config.mrIcon1ScreensaverEntity.ScreensaverEntityOffColor, ScreensaverEntityValue: config.mrIcon1ScreensaverEntity.ScreensaverEntityValue === null @@ -8880,10 +8880,10 @@ function HandleScreensaverStatusIcons() : void { : null, ScreensaverEntityIconOn: config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn != null ? Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn) - : null, + : '', ScreensaverEntityIconOff: config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff != null ? Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff) - : null, + : '', ScreensaverEntityOnColor: config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor, ScreensaverEntityOffColor: config.mrIcon2ScreensaverEntity.ScreensaverEntityOffColor, ScreensaverEntityValue: config.mrIcon2ScreensaverEntity.ScreensaverEntityValue === null From 2bd3d0d290ace0da8043a459893d24b9cf38a551 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 16 Jan 2024 20:51:24 +0100 Subject: [PATCH 88/99] reduce HandleScreensaverStatusIcons --- ioBroker/DEV/NSPanelTs.ts | 102 +++++++++++++------------------------- 1 file changed, 35 insertions(+), 67 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 93966019..14f1da7d 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -8912,82 +8912,50 @@ function HandleScreensaverStatusIcons() : void { } } let hwBtn1Col: RGB = iconData[a].ScreensaverEntityOffColor; - if (iconData[a].ScreensaverEntity != null) { + if (iconData[a].ScreensaverEntity != null || iconData[a].ScreensaverEntityValue != null) { // Prüfung ob ScreensaverEntity vom Typ String ist - if (typeof (iconData[a].ScreensaverEntity) == 'string') { - if (Debug) log('Entity ist String', 'info') - let hwBtn1: string = iconData[a].ScreensaverEntity; - if (hwBtn1 == 'ON') { - hwBtn1Col = iconData[a].ScreensaverEntityOnColor; + if (iconData[a].ScreensaverEntity != null) { + if (typeof (iconData[a].ScreensaverEntity) == 'string') { + if (Debug) log('Entity ist String', 'info') + if (iconData[a].ScreensaverEntity == 'ON') { + hwBtn1Col = iconData[a].ScreensaverEntityOnColor; + } + if (Debug) log('Value: ' + iconData[a].ScreensaverEntity + ' Color: ' + JSON.stringify(hwBtn1Col), 'info') + // Alles was kein String ist in Boolean umwandeln + } else { + if (Debug) log('Entity ist kein String', 'info') + if (!!iconData[a].ScreensaverEntity) { + hwBtn1Col = iconData[a].ScreensaverEntityOnColor; + } } - if (Debug) log('Value: ' + hwBtn1 + ' Color: ' + JSON.stringify(hwBtn1Col), 'info') + } - // Icon ermitteln - if (iconData[a].ScreensaverEntity) { - payloadString += iconData[a].ScreensaverEntityIconOn; - if (Debug) log('Icon if true '+payloadString, 'info') - } else { - if (iconData[a].ScreensaverEntityIconOff != null) { - payloadString += iconData[a].ScreensaverEntityIconOff; - if (Debug) log('Icon1 else true '+payloadString, 'info') - } else { - payloadString += iconData[a].ScreensaverEntityIconOn; - if (Debug) log('Icon1 else false '+payloadString, 'info') - } - } - - if (iconData[a].ScreensaverEntityValue != null) { - payloadString += iconData[a].ScreensaverEntityValue; - if (typeof iconData[a].ScreensaverEntityValue == 'number') { - //payloadString += iconData[a].ScreensaverEntityValue.toFixed(iconData[a].ScreensaverEntityValueDecimalPlace); - payloadString += (iconData[a].ScreensaverEntityValueUnit == null) ? '' : iconData[a].ScreensaverEntityValueUnit; - if (Debug) log('Value ist eine Zahl ' + payloadString, 'info') - } else { - if (Debug) log('Value ist keine Zahl ' + payloadString, 'info') - } - } - - payloadString += '~' + rgb_dec565(hwBtn1Col) + '~'; - } else if (typeof (iconData[a].ScreensaverEntity) == 'boolean') { - let hwBtn1: boolean = iconData[a].ScreensaverEntity; - if (hwBtn1) { - hwBtn1Col = iconData[a].ScreensaverEntityOnColor; - } - if (iconData[a].ScreensaverEntity) { - payloadString += iconData[a].ScreensaverEntityIconOn; - } else { - if (iconData[a].ScreensaverEntityIconOff != null) { - payloadString += iconData[a].ScreensaverEntityIconOff; - } else { - payloadString += iconData[a].ScreensaverEntityIconOn; - } - } - if (iconData[a].ScreensaverEntityValue != null) { - payloadString += iconData[a].ScreensaverEntityValue; - if (typeof iconData[a].ScreensaverEntityValue == 'number') { - //payloadString += iconData[a].ScreensaverEntityValue.toFixed(iconData[a].ScreensaverEntityValueDecimalPlace); - payloadString += (iconData[a].ScreensaverEntityValueUnit == null) ? '' : iconData[a].ScreensaverEntityValueUnit; - } - } - payloadString += '~' + rgb_dec565(hwBtn1Col) + '~'; - } - } else if (iconData[a].ScreensaverEntity == null && iconData[a].ScreensaverEntityValue != null){ - if(iconData[a].ScreensaverEntityOnColor != null){ - hwBtn1Col = iconData[a].ScreensaverEntityOnColor; - } - if(iconData[a].ScreensaverEntityIconOn != null){ + // Icon ermitteln + if (iconData[a].ScreensaverEntity) { payloadString += iconData[a].ScreensaverEntityIconOn; - } + if (Debug) log('Icon if true '+payloadString, 'info') + } else { + if (iconData[a].ScreensaverEntityIconOff != null) { + payloadString += iconData[a].ScreensaverEntityIconOff; + if (Debug) log('Icon1 else true '+payloadString, 'info') + } else { + payloadString += iconData[a].ScreensaverEntityIconOn; + if (Debug) log('Icon1 else false '+payloadString, 'info') + } + } + if (iconData[a].ScreensaverEntityValue != null) { payloadString += iconData[a].ScreensaverEntityValue; if (typeof iconData[a].ScreensaverEntityValue == 'number') { - //payloadString += (iconData[a].ScreensaverEntityValue).toFixed(iconData[a].ScreensaverEntityValueDecimalPlace); payloadString += (iconData[a].ScreensaverEntityValueUnit == null) ? '' : iconData[a].ScreensaverEntityValueUnit; - } - } + if (Debug) log('Value ist eine Zahl ' + payloadString, 'info') + } else { + if (Debug) log('Value ist keine Zahl ' + payloadString, 'info') + } + } + payloadString += '~' + rgb_dec565(hwBtn1Col) + '~'; - } - else { + } else { hwBtn1Col = Black; payloadString += '~~'; } From 8449257628e365e08d274e9c70179deb8cdc3ab2 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 16 Jan 2024 21:39:43 +0100 Subject: [PATCH 89/99] fix number/string --- ioBroker/DEV/NSPanelTs.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 14f1da7d..b55c9576 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -8946,13 +8946,8 @@ function HandleScreensaverStatusIcons() : void { if (iconData[a].ScreensaverEntityValue != null) { payloadString += iconData[a].ScreensaverEntityValue; - if (typeof iconData[a].ScreensaverEntityValue == 'number') { - payloadString += (iconData[a].ScreensaverEntityValueUnit == null) ? '' : iconData[a].ScreensaverEntityValueUnit; - if (Debug) log('Value ist eine Zahl ' + payloadString, 'info') - } else { - if (Debug) log('Value ist keine Zahl ' + payloadString, 'info') - } - } + payloadString += (iconData[a].ScreensaverEntityValueUnit == null) ? '' : iconData[a].ScreensaverEntityValueUnit; + } payloadString += '~' + rgb_dec565(hwBtn1Col) + '~'; } else { @@ -9785,6 +9780,11 @@ namespace NSPanel { export type EventMethod = 'startup' | 'sleepReached' | 'pageOpenDetail' | 'buttonPress2' | 'renderCurrentPage' | 'button1' | 'button2' + export type panelRecvType = { + event: 'event'; + method: EventMethod + } + export type SerialType = 'button' | 'light' | 'shutter' | 'text' | 'input_sel' | 'timer' | 'number' | 'fan' From f76f2ca3936a055b68091235f40f81cf688174da Mon Sep 17 00:00:00 2001 From: ticaki Date: Wed, 17 Jan 2024 17:25:51 +0100 Subject: [PATCH 90/99] tweak HandleScreensaverStatusIcons --- ioBroker/DEV/NSPanelTs.ts | 40 +++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index b55c9576..905381cc 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -8857,10 +8857,10 @@ function HandleScreensaverStatusIcons() : void { && existsState(config.mrIcon1ScreensaverEntity.ScreensaverEntity) ? getState(config.mrIcon1ScreensaverEntity.ScreensaverEntity).val : null, - ScreensaverEntityIconOn: config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn != null + ScreensaverEntityIconOn: config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn ? Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOn) : '', - ScreensaverEntityIconOff: config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff != null + ScreensaverEntityIconOff: config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff ? Icons.GetIcon(config.mrIcon1ScreensaverEntity.ScreensaverEntityIconOff) : '', ScreensaverEntityOnColor: config.mrIcon1ScreensaverEntity.ScreensaverEntityOnColor, @@ -8870,6 +8870,10 @@ function HandleScreensaverStatusIcons() : void { : getState(config.mrIcon1ScreensaverEntity.ScreensaverEntityValue).val, ScreensaverEntityValueDecimalPlace: config.mrIcon1ScreensaverEntity.ScreensaverEntityValueDecimalPlace, ScreensaverEntityValueUnit: config.mrIcon1ScreensaverEntity.ScreensaverEntityValueUnit, + ScreensaverEntityIconSelect: config.mrIcon1ScreensaverEntity.ScreensaverEntityIconSelect + && typeof config.mrIcon1ScreensaverEntity.ScreensaverEntityIconSelect === 'object' + ? config.mrIcon1ScreensaverEntity.ScreensaverEntityIconSelect + : null, }, @@ -8878,10 +8882,10 @@ function HandleScreensaverStatusIcons() : void { && existsState(config.mrIcon2ScreensaverEntity.ScreensaverEntity) ? getState(config.mrIcon2ScreensaverEntity.ScreensaverEntity).val : null, - ScreensaverEntityIconOn: config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn != null + ScreensaverEntityIconOn: config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn ? Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOn) : '', - ScreensaverEntityIconOff: config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff != null + ScreensaverEntityIconOff: config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff ? Icons.GetIcon(config.mrIcon2ScreensaverEntity.ScreensaverEntityIconOff) : '', ScreensaverEntityOnColor: config.mrIcon2ScreensaverEntity.ScreensaverEntityOnColor, @@ -8891,6 +8895,10 @@ function HandleScreensaverStatusIcons() : void { : getState(config.mrIcon2ScreensaverEntity.ScreensaverEntityValue).val, ScreensaverEntityValueDecimalPlace: config.mrIcon2ScreensaverEntity.ScreensaverEntityValueDecimalPlace, ScreensaverEntityValueUnit: config.mrIcon2ScreensaverEntity.ScreensaverEntityValueUnit, + ScreensaverEntityIconSelect: config.mrIcon2ScreensaverEntity.ScreensaverEntityIconSelect + && typeof config.mrIcon2ScreensaverEntity.ScreensaverEntityIconSelect === 'object' + ? config.mrIcon2ScreensaverEntity.ScreensaverEntityIconSelect + : null, } } for (const a in iconData) { @@ -8917,8 +8925,16 @@ function HandleScreensaverStatusIcons() : void { if (iconData[a].ScreensaverEntity != null) { if (typeof (iconData[a].ScreensaverEntity) == 'string') { if (Debug) log('Entity ist String', 'info') - if (iconData[a].ScreensaverEntity == 'ON') { - hwBtn1Col = iconData[a].ScreensaverEntityOnColor; + switch (String(iconData[a].ScreensaverEntity).toUpperCase()) { + case 'ON': + case 'OK': + case 'AN': + case 'YES': + case 'TRUE': + case 'ONLINE': + hwBtn1Col = iconData[a].ScreensaverEntityOnColor; + break; + default: } if (Debug) log('Value: ' + iconData[a].ScreensaverEntity + ' Color: ' + JSON.stringify(hwBtn1Col), 'info') // Alles was kein String ist in Boolean umwandeln @@ -8931,11 +8947,17 @@ function HandleScreensaverStatusIcons() : void { } // Icon ermitteln - if (iconData[a].ScreensaverEntity) { + if (iconData[a].ScreensaverEntityIconSelect && iconData[a].ScreensaverEntity != null) { + const icon = iconData[a].ScreensaverEntityIconSelect[iconData[a].ScreensaverEntity]; + if (icon !== undefined) { + payloadString += Icons.GetIcon(icon); + if (Debug) log('SelectIcon: '+payloadString, 'info') + } + } else if (iconData[a].ScreensaverEntity) { payloadString += iconData[a].ScreensaverEntityIconOn; if (Debug) log('Icon if true '+payloadString, 'info') } else { - if (iconData[a].ScreensaverEntityIconOff != null) { + if (iconData[a].ScreensaverEntityIconOff) { payloadString += iconData[a].ScreensaverEntityIconOff; if (Debug) log('Icon1 else true '+payloadString, 'info') } else { @@ -10022,6 +10044,7 @@ namespace NSPanel { export type ScreenSaverMRElement = { ScreensaverEntity: string | null, ScreensaverEntityIconOn: string | null, + ScreensaverEntityIconSelect?: {[key: string]: string} | null | undefined, ScreensaverEntityIconOff: string | null, ScreensaverEntityValue: string | null, ScreensaverEntityValueDecimalPlace: number | null, @@ -10038,6 +10061,7 @@ namespace NSPanel { ScreensaverEntityValueUnit: string | null, ScreensaverEntityOnColor: RGB, ScreensaverEntityOffColor: RGB + ScreensaverEntityIconSelect: {[key: string]: string} | null, } export type IconScaleElement = { From db32de68e3cae55c74df1f2b11c50e3ac369d67f Mon Sep 17 00:00:00 2001 From: ticaki Date: Wed, 17 Jan 2024 23:14:54 +0100 Subject: [PATCH 91/99] add ScreensaverEntityValue to on() --- ioBroker/DEV/NSPanelTs.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 905381cc..903cd29d 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -101,6 +101,8 @@ ReleaseNotes: - 16.01.2024 - v4.3.3.38 Fix: joBr99#1098 - 16.01.2024 - v4.3.3.38 Types: Number of PageItems defined & HandleScreensaverStatusIcons rewritten - 16.01.2024 - v4.3.3.38 Optimate: function SendTime() + - 17.01.2024 - v4.3.3.38 Add: ScreensaverEntityIconSelect for MRIcons is like common.states for states. + - 17.01.2024 - v4.3.3.38 Add: Changing the ScreensaverEntityValue value updates the screensaver. Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -1431,7 +1433,7 @@ Init_Screensaver_Backckground_Color_Switch(); on({id: NSPanel_Path + 'ScreensaverInfo.bgColorIndicator', change: "ne"}, async function (obj) { try { bgColorScrSaver = obj.state.val; - if (bgColorScrSaver < 4) { + if (bgColorScrSaver < 6) { HandleScreensaverUpdate(); } } catch (err: any) { @@ -1787,9 +1789,11 @@ on({id: [String(NSPanel_Path) + 'Relay.1',String(NSPanel_Path) + 'Relay.2'], cha async function SubscribeMRIcons () { try { - if (config.mrIcon1ScreensaverEntity.ScreensaverEntity != null) { - on({id: config.mrIcon1ScreensaverEntity.ScreensaverEntity, change: "ne"}, async function (obj) { - if (obj.id!.substring(0,4) == 'mqtt') { + let arr = config.mrIcon1ScreensaverEntity.ScreensaverEntity != null ? [config.mrIcon1ScreensaverEntity.ScreensaverEntity] : []; + arr = config.mrIcon1ScreensaverEntity.ScreensaverEntityValue != null ? [...arr, config.mrIcon1ScreensaverEntity.ScreensaverEntityValue] : arr; + if (arr.length > 0) { + on({id: arr, change: "ne"}, async function (obj) { + if (obj.id!.substring(0,4) == 'mqtt') { let Button = obj.id!.split('.'); if (getState(NSPanel_Path + 'Relay.' + Button[Button.length - 1].substring(5,6)).val != obj.state.val) { await setStateAsync(NSPanel_Path + 'Relay.' + Button[Button.length - 1].substring(5,6), obj.state.val == 'ON' ? true : false); @@ -1799,8 +1803,10 @@ async function SubscribeMRIcons () { } }); } - if (config.mrIcon2ScreensaverEntity.ScreensaverEntity != null) { - on({id: config.mrIcon2ScreensaverEntity.ScreensaverEntity, change: "ne"}, async function (obj) { + arr = config.mrIcon2ScreensaverEntity.ScreensaverEntity != null ? [config.mrIcon2ScreensaverEntity.ScreensaverEntity] : []; + arr = config.mrIcon2ScreensaverEntity.ScreensaverEntityValue != null ? [...arr, config.mrIcon2ScreensaverEntity.ScreensaverEntityValue] : arr; + if (arr.length > 0) { + on({id: arr, change: "ne"}, async function (obj) { if (obj.id!.substring(0,4) == 'mqtt') { let Button = obj.id!.split('.'); if (getState(NSPanel_Path + 'Relay.' + Button[Button.length - 1].substring(5,6)).val != obj.state.val) { From c3ded4d817f705dcfe04eca5b84619051f793c3f Mon Sep 17 00:00:00 2001 From: ticaki Date: Thu, 18 Jan 2024 22:15:04 +0100 Subject: [PATCH 92/99] buildNSPanelString --- ioBroker/DEV/NSPanelTs.ts | 46 ++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 903cd29d..846d5955 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1050,7 +1050,7 @@ async function CheckConfigParameters() { const i = n.shift(); if (a === 'mqtt' && !isNaN(Number(i))) { - sendTo(`${a}.${i}`, 'sendMessage2Client', {topic: n.join('/'), message: 'time~12:00'}); + sendTo(`${a}.${i}`, 'sendMessage2Client', {topic: n.join('/'), message: buildNSPanelString('time', '12:00')}); await sleep(500); } if (await existsObjectAsync(config.panelSendTopic) == false) { @@ -9075,23 +9075,25 @@ function HandleScreensaverColors(): void { scrSvrBGCol = rgb_dec565({ red: 100, green: 0, blue: 0 }); } - let payloadString = 'color' + '~' + - scrSvrBGCol + '~' + //background - rgb_dec565(sctime) + '~' + //time - rgb_dec565(sctimeAMPM) + '~' + //timeAMPM~ - rgb_dec565(scdate) + '~' + //date~ - rgb_dec565(sctMainText) + '~' + //tMainText~ - rgb_dec565(sctForecast1) + '~' + //tForecast1~ - rgb_dec565(sctForecast2) + '~' + //tForecast2~ - rgb_dec565(sctForecast3) + '~' + //tForecast3~ - rgb_dec565(sctForecast4) + '~' + //tForecast4~ - rgb_dec565(sctForecast1Val) + '~' + //tForecast1Val~ - rgb_dec565(sctForecast2Val) + '~' + //tForecast2Val~ - rgb_dec565(sctForecast3Val) + '~' + //tForecast3Val~ - rgb_dec565(sctForecast4Val) + '~' + //tForecast4Val~ - rgb_dec565(scbar) + '~' + //bar~ - rgb_dec565(sctMainTextAlt) + '~' + //tMainTextAlt - rgb_dec565(sctTimeAdd); //tTimeAdd + let payloadString = buildNSPanelString( + 'color' , + scrSvrBGCol , //background + rgb_dec565(sctime) , //time + rgb_dec565(sctimeAMPM) , //timeAMPM~ + rgb_dec565(scdate) , //date~ + rgb_dec565(sctMainText) , //tMainText~ + rgb_dec565(sctForecast1) , //tForecast1~ + rgb_dec565(sctForecast2) , //tForecast2~ + rgb_dec565(sctForecast3) , //tForecast3~ + rgb_dec565(sctForecast4) , //tForecast4~ + rgb_dec565(sctForecast1Val) , //tForecast1Val~ + rgb_dec565(sctForecast2Val) , //tForecast2Val~ + rgb_dec565(sctForecast3Val) , //tForecast3Val~ + rgb_dec565(sctForecast4Val) , //tForecast4Val~ + rgb_dec565(scbar) , //bar~ + rgb_dec565(sctMainTextAlt) , //tMainTextAlt + rgb_dec565(sctTimeAdd) //tTimeAdd + ); SendToPanel({ payload: payloadString }); } catch (err: any) { @@ -9664,6 +9666,14 @@ function spotifyGetDeviceID(vDeviceString: string): string { let strDevID = arrayDeviceListIds[indexPos]; return strDevID; } +/** + * Join arguments with ~ and return the string; + * @param tokens unlimited numbers of strings + * @returns + */ +function buildNSPanelString(...tokens: (string|number)[]): string { + return tokens.join('~'); +} type RGB = NSPanel.RGB; type PageItem = NSPanel.PageItem; From 8c84c1050f987700d72a314103041746a4aa728d Mon Sep 17 00:00:00 2001 From: ticaki Date: Fri, 19 Jan 2024 00:03:15 +0100 Subject: [PATCH 93/99] fix pm/am --- ioBroker/DEV/NSPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 846d5955..4594f3fe 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -3285,7 +3285,7 @@ function SendTime(): void { const min = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); SendToPanel({ payload: 'time~' + hr + ':' + min });*/ - SendToPanel({ payload: `time~${new Date().toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}`, }); + SendToPanel({ payload: `time~${new Date().toLocaleTimeString('de-DE', { hour: "2-digit", minute: "2-digit" })}`, }); } catch (err: any) { log('error at function SendTime: ' + err.message, 'warn'); } From a986e588b5ddbd2e1b34230947f0f310659f4f69 Mon Sep 17 00:00:00 2001 From: theknut Date: Fri, 19 Jan 2024 00:27:10 +0100 Subject: [PATCH 94/99] feat: calculate yAxisTicks based on given values If no yAxisTicks are provided for the signal, try to calculate it based on the given values. --- ioBroker/DEV/NSPanelTs.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 6aa86713..15803ddb 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -6143,6 +6143,7 @@ function GeneratePowerPage(page: NSPanel.PagePower): NSPanel.Payload[] { } } +const timeValueRegEx = /\~\d+:(\d+)/g; function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { try { activePage = page; @@ -6153,9 +6154,26 @@ function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { let heading = page.heading !== undefined ? page.heading : "Chart..."; - let txt = getState(id + '.ACTUAL').val; + const txt = getState(id + '.ACTUAL').val; if (!page.items[0].yAxisTicks) { - throw new Error (`Page item ${id} yAxisTicks is undefined!`) + const sorted = [...txt.matchAll(timeValueRegEx)].map(x => Number(x[1])).sort((x, y) => x < y ? -1 : 1); + if (sorted.length === 0) { + throw new Error (`Page item ${id} yAxisTicks is undefined and unable to be calculated!`) + } + const minValue = sorted[0]; + const maxValue = sorted[sorted.length - 1]; + const tick = Math.max(Number(((maxValue - minValue) / 5).toFixed()), 10); + + page.items[0].yAxisTicks = []; + let currentTick = minValue - tick; + while(currentTick < (maxValue + tick)) { + page.items[0].yAxisTicks.push(currentTick); + currentTick += tick; + } + + if (Debug) { + log(`Calculated yAxisTicks for ${id} (Min: ${minValue}, Max: ${maxValue}, Tick: ${tick}): ${page.items[0].yAxisTicks}`); + } } if (!page.items[0].onColor) { throw new Error (`Page item ${id} onColor is undefined!`) From ae5cab9830e6bfabd396da4ef40bbff97e4c1cff Mon Sep 17 00:00:00 2001 From: theknut Date: Fri, 19 Jan 2024 10:27:01 +0100 Subject: [PATCH 95/99] refactor: ensure yAxisTicks are calculated every time if not provided --- ioBroker/DEV/NSPanelTs.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 15803ddb..c022983a 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -6154,7 +6154,13 @@ function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { let heading = page.heading !== undefined ? page.heading : "Chart..."; - const txt = getState(id + '.ACTUAL').val; + const txt = getState(id + '.ACTUAL')?.val; + if (!txt) { + throw new Error(`Unable to get the state of ${id}.ACTUAL`) + } + + let yAxisTicks : number[] = []; + if (!page.items[0].yAxisTicks) { const sorted = [...txt.matchAll(timeValueRegEx)].map(x => Number(x[1])).sort((x, y) => x < y ? -1 : 1); if (sorted.length === 0) { @@ -6164,23 +6170,25 @@ function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { const maxValue = sorted[sorted.length - 1]; const tick = Math.max(Number(((maxValue - minValue) / 5).toFixed()), 10); - page.items[0].yAxisTicks = []; let currentTick = minValue - tick; while(currentTick < (maxValue + tick)) { - page.items[0].yAxisTicks.push(currentTick); + yAxisTicks.push(currentTick); currentTick += tick; } if (Debug) { log(`Calculated yAxisTicks for ${id} (Min: ${minValue}, Max: ${maxValue}, Tick: ${tick}): ${page.items[0].yAxisTicks}`); } + } else { + yAxisTicks = typeof page.items[0].yAxisTicks === 'string' + ? JSON.parse(getState(page.items[0].yAxisTicks).val) + : page.items[0].yAxisTicks; } + if (!page.items[0].onColor) { throw new Error (`Page item ${id} onColor is undefined!`) } - let yAxisTicks = (typeof page.items[0].yAxisTicks == 'object') ? page.items[0].yAxisTicks : JSON.parse(getState(page.items[0].yAxisTicks).val); - out_msgs.push({ payload: 'entityUpd~' + //entityUpd heading + '~' + //heading @@ -6193,7 +6201,6 @@ function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { if (Debug) log('GenerateChartPage payload: ' + JSON.stringify(out_msgs), 'info'); return out_msgs; - } catch (err: any) { log('error at function GenerateChartPage: ' + err.message, 'warn'); return []; From 29ae1b4034e95cd4f274e9f8e04f4e652de38b0b Mon Sep 17 00:00:00 2001 From: theknut Date: Fri, 19 Jan 2024 10:34:50 +0100 Subject: [PATCH 96/99] fix: wrong yAxisTicks logged in debug log --- ioBroker/DEV/NSPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index c022983a..18e19a40 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -6177,7 +6177,7 @@ function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { } if (Debug) { - log(`Calculated yAxisTicks for ${id} (Min: ${minValue}, Max: ${maxValue}, Tick: ${tick}): ${page.items[0].yAxisTicks}`); + log(`Calculated yAxisTicks for ${id} (Min: ${minValue}, Max: ${maxValue}, Tick: ${tick}): ${yAxisTicks}`); } } else { yAxisTicks = typeof page.items[0].yAxisTicks === 'string' From b2f338cad8a9edc8651d255a3a3b7a0c9a6702f5 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Fri, 19 Jan 2024 12:33:35 +0100 Subject: [PATCH 97/99] Change cardLChart - no yAxisTicks required --- ioBroker/DEV/NSPanelTs.ts | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 4594f3fe..5ecd0251 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -6157,26 +6157,52 @@ function GeneratePowerPage(page: NSPanel.PagePower): NSPanel.Payload[] { } } +const timeValueRegEx = /\~\d+:(\d+)/g; function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { try { activePage = page; let id = page.items[0].id; - let out_msgs: NSPanel.Payload[] = []; + let out_msgs: Array = []; out_msgs.push({ payload: 'pageType~' + page.type }); let heading = page.heading !== undefined ? page.heading : "Chart..."; - let txt = getState(id + '.ACTUAL').val; - if (!page.items[0].yAxisTicks) { - throw new Error (`Page item ${id} yAxisTicks is undefined!`) + const txt = getState(id + '.ACTUAL')?.val; + if (!txt) { + throw new Error(`Unable to get the state of ${id}.ACTUAL`) } + + let yAxisTicks : number[] = []; + + if (!page.items[0].yAxisTicks) { + const sorted = [...txt.matchAll(timeValueRegEx)].map(x => Number(x[1])).sort((x, y) => x < y ? -1 : 1); + if (sorted.length === 0) { + throw new Error (`Page item ${id} yAxisTicks is undefined and unable to be calculated!`) + } + const minValue = sorted[0]; + const maxValue = sorted[sorted.length - 1]; + const tick = Math.max(Number(((maxValue - minValue) / 5).toFixed()), 10); + + let currentTick = minValue - tick; + while(currentTick < (maxValue + tick)) { + yAxisTicks.push(currentTick); + currentTick += tick; + } + + if (Debug) { + log(`Calculated yAxisTicks for ${id} (Min: ${minValue}, Max: ${maxValue}, Tick: ${tick}): ${yAxisTicks}`); + } + } else { + yAxisTicks = typeof page.items[0].yAxisTicks === 'string' + ? JSON.parse(getState(page.items[0].yAxisTicks).val) + : page.items[0].yAxisTicks; + } + if (!page.items[0].onColor) { throw new Error (`Page item ${id} onColor is undefined!`) } - let yAxisTicks = (typeof page.items[0].yAxisTicks == 'object') ? page.items[0].yAxisTicks : JSON.parse(getState(page.items[0].yAxisTicks).val); - out_msgs.push({ payload: 'entityUpd~' + //entityUpd heading + '~' + //heading @@ -6189,7 +6215,6 @@ function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { if (Debug) log('GenerateChartPage payload: ' + JSON.stringify(out_msgs), 'info'); return out_msgs; - } catch (err: any) { log('error at function GenerateChartPage: ' + err.message, 'warn'); return []; From 1d3914ce86655ee79e2ead28564e5e8afb9ee05d Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Fri, 19 Jan 2024 12:37:30 +0100 Subject: [PATCH 98/99] let out_msgs: NSPanel.Payload[] = []; --- ioBroker/DEV/NSPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 5ecd0251..5c281749 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -6163,7 +6163,7 @@ function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { activePage = page; let id = page.items[0].id; - let out_msgs: Array = []; + let out_msgs: NSPanel.Payload[] = []; out_msgs.push({ payload: 'pageType~' + page.type }); let heading = page.heading !== undefined ? page.heading : "Chart..."; From 576176e1cc92979756e49e8c93265c8100cc51ef Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Fri, 19 Jan 2024 12:44:46 +0100 Subject: [PATCH 99/99] Change in cardLChart Change: yAxisTicks parameter is not required in cardLChart PageItem --- ioBroker/DEV/NSPanelTs.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 5c281749..9b62d627 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -103,6 +103,7 @@ ReleaseNotes: - 16.01.2024 - v4.3.3.38 Optimate: function SendTime() - 17.01.2024 - v4.3.3.38 Add: ScreensaverEntityIconSelect for MRIcons is like common.states for states. - 17.01.2024 - v4.3.3.38 Add: Changing the ScreensaverEntityValue value updates the screensaver. + - 19.01.2024 - v4.3.3.38 Change: yAxisTicks parameter is not required in cardLChart PageItem Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined