From 2b54f742c5f7ed523fed4f270c181a4beb2bc334 Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Tue, 30 Jan 2024 08:50:21 +0100 Subject: [PATCH 01/16] v4.3.3.39 Update NSPanel.ts - Add: Optional setOn & setOff for HW button with mode 'set' - Fix: ack for read-only state --- ioBroker/DEV/NSPanelTs.ts | 8 ++++---- ioBroker/NsPanelTs.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 25f63f0b..17d0da34 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1241,13 +1241,13 @@ async function Init_Release() { if (existsObject(NSPanel_Path + 'Display_Firmware.desiredVersion') == false) { 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); + await setStateAsync(NSPanel_Path + 'Display_Firmware.desiredVersion', desired_display_firmware_version, true); } if (existsObject(NSPanel_Path + 'Config.Update.activ') == false) { await createStateAsync(NSPanel_Path + 'Config.Update.activ', 1, { type: 'number', write: false }); } else { - await setStateAsync(NSPanel_Path + 'Config.Update.activ', 0); + await setStateAsync(NSPanel_Path + 'Config.Update.activ', 0, true); } let currentFW = 0; @@ -1271,8 +1271,8 @@ async function Init_Release() { } } 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); + await setStateAsync(NSPanel_Path + 'Display_Firmware.TFT.currentVersion', currentFW + ' / v' + FWRelease[findFWIndex], true); + await setStateAsync(NSPanel_Path + 'Display_Firmware.TFT.desiredVersion', desired_display_firmware_version + ' / ' + tft_version, true); } } catch (err: any) { log('error at function Init_Release: ' + err.message, 'warn'); diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 25f63f0b..17d0da34 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1241,13 +1241,13 @@ async function Init_Release() { if (existsObject(NSPanel_Path + 'Display_Firmware.desiredVersion') == false) { 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); + await setStateAsync(NSPanel_Path + 'Display_Firmware.desiredVersion', desired_display_firmware_version, true); } if (existsObject(NSPanel_Path + 'Config.Update.activ') == false) { await createStateAsync(NSPanel_Path + 'Config.Update.activ', 1, { type: 'number', write: false }); } else { - await setStateAsync(NSPanel_Path + 'Config.Update.activ', 0); + await setStateAsync(NSPanel_Path + 'Config.Update.activ', 0, true); } let currentFW = 0; @@ -1271,8 +1271,8 @@ async function Init_Release() { } } 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); + await setStateAsync(NSPanel_Path + 'Display_Firmware.TFT.currentVersion', currentFW + ' / v' + FWRelease[findFWIndex], true); + await setStateAsync(NSPanel_Path + 'Display_Firmware.TFT.desiredVersion', desired_display_firmware_version + ' / ' + tft_version, true); } } catch (err: any) { log('error at function Init_Release: ' + err.message, 'warn'); From e7cc10692b6f2895d1be89320c5ebaa21ab91bbc Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Tue, 30 Jan 2024 10:23:19 +0100 Subject: [PATCH 02/16] Update and Rename CardLChart_Influx2 --- .../Blockly/{CradLChart_Influx2.js => CardLChart_Influx2.ts} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename ioBroker/Blockly/{CradLChart_Influx2.js => CardLChart_Influx2.ts} (99%) diff --git a/ioBroker/Blockly/CradLChart_Influx2.js b/ioBroker/Blockly/CardLChart_Influx2.ts similarity index 99% rename from ioBroker/Blockly/CradLChart_Influx2.js rename to ioBroker/Blockly/CardLChart_Influx2.ts index 2f48d31e..6eb4ef5d 100644 --- a/ioBroker/Blockly/CradLChart_Influx2.js +++ b/ioBroker/Blockly/CardLChart_Influx2.ts @@ -12,8 +12,8 @@ const xAxisLabelEveryM = 240; // add all sensors which are to be displayed in this script, there is no need to use multiple scripts const sensors : Record = {}; /* ↓ Id of the sensor ↓ Id of the data source for the charts */ -sensors['deconz.0.Sensors.65.temperature'] = Path + 'buero_temperature'; -sensors['deconz.0.Sensors.65.humidity'] = Path + 'buero_luftfeuchte'; +sensors['deconz.0.Sensors.65.temperature'] = Path + 'buero_temperature.ACTUAL'; +sensors['deconz.0.Sensors.65.humidity'] = Path + 'buero_luftfeuchte.ACTUAL'; // create data source for NsPanel on script startup Object.keys(sensors).forEach(async x => { From 6172b0c35f1870f60f3614b76eaceb481df77543 Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Tue, 30 Jan 2024 10:55:19 +0100 Subject: [PATCH 03/16] v4.3.3.39 Update NSPanel.ts - Add: Optional setOn & setOff for HW button with mode 'set' - Fix: ack for read-only state --- ioBroker/DEV/NSPanelTs.ts | 8 ++++---- ioBroker/NsPanelTs.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 17d0da34..df388ec8 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1087,8 +1087,8 @@ async function CheckConfigParameters() { let common = getObject(id).common; 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('.')); + setIfExists(NSPanel_Path + 'IoBroker.JavaScriptVersion', 'v' + javaScriptVersion, null, true); + setIfExists(NSPanel_Path + 'IoBroker.ScriptName', (name as unknown as string).split('.').slice(2).join('.'), null, true); 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'); @@ -1099,7 +1099,7 @@ async function CheckConfigParameters() { const hostList = $('system.host.*.nodeCurrent'); hostList.each(function(id, i) { nodeVersion = getState(id).val; - setIfExists(NSPanel_Path + 'IoBroker.NodeJSVersion', 'v' + nodeVersion); + setIfExists(NSPanel_Path + 'IoBroker.NodeJSVersion', 'v' + nodeVersion, null , true); 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', ); @@ -1146,7 +1146,7 @@ async function InitIoBrokerInfo() { 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); + setIfExists(NSPanel_Path + 'IoBroker.ScriptVersion', scriptVersion, null, true); } catch (err: any) { log('error at funktion InitIoBrokerInfo ' + err.message, 'warn'); } diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 17d0da34..df388ec8 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1087,8 +1087,8 @@ async function CheckConfigParameters() { let common = getObject(id).common; 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('.')); + setIfExists(NSPanel_Path + 'IoBroker.JavaScriptVersion', 'v' + javaScriptVersion, null, true); + setIfExists(NSPanel_Path + 'IoBroker.ScriptName', (name as unknown as string).split('.').slice(2).join('.'), null, true); 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'); @@ -1099,7 +1099,7 @@ async function CheckConfigParameters() { const hostList = $('system.host.*.nodeCurrent'); hostList.each(function(id, i) { nodeVersion = getState(id).val; - setIfExists(NSPanel_Path + 'IoBroker.NodeJSVersion', 'v' + nodeVersion); + setIfExists(NSPanel_Path + 'IoBroker.NodeJSVersion', 'v' + nodeVersion, null , true); 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', ); @@ -1146,7 +1146,7 @@ async function InitIoBrokerInfo() { 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); + setIfExists(NSPanel_Path + 'IoBroker.ScriptVersion', scriptVersion, null, true); } catch (err: any) { log('error at funktion InitIoBrokerInfo ' + err.message, 'warn'); } From 0a2461f4a584e28ad2bec61f3302d9eba8146612 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Sat, 3 Feb 2024 10:44:24 +0100 Subject: [PATCH 04/16] v4.3.3.39 - Update NsPanelTs.ts fix maxValueColorTemp --- ioBroker/NsPanelTs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index df388ec8..38a864bb 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -7722,7 +7722,7 @@ function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOpti if (existsState(id + '.TEMPERATURE')) { colorTemp = 0; if (getState(id + '.TEMPERATURE').val != null) { - if (pageItem.minValueColorTemp !== undefined && pageItem.minValueColorTemp !== undefined) { + 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; From 9c49a9c67d842d952de846ef68d831e597a251e0 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Sat, 3 Feb 2024 10:45:45 +0100 Subject: [PATCH 05/16] v4.3.3.39 - Update NSPanelTs.ts Fix: if (pageItem.minValueColorTemp !== undefined && pageItem.maxValueColorTemp !== undefined) { --- 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 df388ec8..38a864bb 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -7722,7 +7722,7 @@ function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOpti if (existsState(id + '.TEMPERATURE')) { colorTemp = 0; if (getState(id + '.TEMPERATURE').val != null) { - if (pageItem.minValueColorTemp !== undefined && pageItem.minValueColorTemp !== undefined) { + 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; From 9b5964a758a45a629ee7bec3e364fef0badd3f71 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Mon, 5 Feb 2024 17:06:01 +0100 Subject: [PATCH 06/16] v4.3.3.40 - Update NSPanelTs.ts - Fix maxColorTempValue for RGB - Fix SqueezeboxRPC-Media-Player and add some Functions --- ioBroker/DEV/NSPanelTs.ts | 146 +++++++++++++++++++++++++++----------- 1 file changed, 104 insertions(+), 42 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 38a864bb..5da8454f 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.39 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.40 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 @@ -107,7 +107,9 @@ ReleaseNotes: - 20.01.2024 - v4.3.3.38 Add: click on indicatorIcon navigate to Page - 23.01.2024 - v4.3.3.39 Add: Optional setOn & setOff for HW button with mode 'set' - 28.01.2024 - v4.3.3.39 Fix: ack for read-only state - + - 03.02.2024 - v4.3.3.40 Fix: RGB maxValueColorTemp + - 05.02.2024 - v4.3.3.40 Fix SqueezeboxRPC-Media-Player and add some Functions + Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -974,7 +976,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.39'; +const scriptVersion: string = 'v4.3.3.40'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -4754,12 +4756,12 @@ function unsubscribeMediaSubscriptions(): void { 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 () { + 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) { @@ -4774,8 +4776,8 @@ function subscribeMediaSubscriptions(id: string): void { function subscribeMediaSubscriptionsSonosAdd(id: string): void { on({id: [id + '.QUEUE', - id + '.DURATION', - id + '.ELAPSED'], change: "any"}, async function () { + id + '.DURATION', + id + '.ELAPSED'], change: "any"}, async function () { (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); timeoutMedia = setTimeout(async function () { if (useMediaEvents) { @@ -4790,7 +4792,7 @@ function subscribeMediaSubscriptionsSonosAdd(id: string): void { function subscribeMediaSubscriptionsAlexaAdd(id: string): void { on({id: [id + '.DURATION', - id + '.ELAPSED'], change: "any"}, async function () { + id + '.ELAPSED'], change: "any"}, async function () { (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); timeoutMedia = setTimeout(async function () { if (useMediaEvents) { @@ -4805,7 +4807,21 @@ function subscribeMediaSubscriptionsAlexaAdd(id: string): void { function subscribeMediaSubscriptionsBoseAdd(id: string): void { on({id: [id + '.DURATION', - id + '.ELAPSED'], change: "any"}, async function () { + 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 subscribeMediaSubscriptionsSqueezeboxAdd(id: string): void { + on({id: [id + '.ELAPSED'], change: "any"}, async function () { (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); timeoutMedia = setTimeout(async function () { if (useMediaEvents) { @@ -5010,13 +5026,14 @@ async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPla 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 + '.SHUFFLE', dpPath + '.PlaylistShuffle', true, {type: 'string', role: 'media.mode.shuffle', name: 'SHUFFLE'}); await createAliasAsync(id + '.REPEAT', dpPath + '.PlaylistRepeat', true, {type: 'number', role: 'media.mode.repeat', name: 'REPEAT'}); + await createAliasAsync(id + '.DURATION', dpPath + '.Duration', true, {type: 'string', role: 'media.duration', name: 'DURATION'}); + await createAliasAsync(id + '.ELAPSED', dpPath + '.Time', true, {type: 'string', role: 'media.elapsed', name: 'ELAPSED'}); } catch (err: any) { log('error at function createAutoMediaAlias Adapter Squeezebox: ' + err.message, 'warn'); } } - } break; case "bosesoundtouch.0.": @@ -5081,23 +5098,6 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { let vInstance = page.items[0].adapterPlayerInstance!; let v1Adapter = vInstance.split('.'); 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') { - 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 : ''; @@ -5105,7 +5105,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { 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' }); @@ -5122,6 +5122,8 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { subscribeMediaSubscriptionsAlexaAdd(page.items[0].id); } else if (v2Adapter == 'bosesoundtouch') { subscribeMediaSubscriptionsBoseAdd(page.items[0].id); + } else if (v2Adapter == 'squeezeboxrpc') { + subscribeMediaSubscriptionsSqueezeboxAdd(page.items[0].id); } } } @@ -5135,6 +5137,8 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { subscribeMediaSubscriptionsAlexaAdd(page.items[0].id); } else if (v2Adapter == 'bosesoundtouch') { subscribeMediaSubscriptionsBoseAdd(page.items[0].id); + } else if (v2Adapter == 'squeezeboxrpc') { + subscribeMediaSubscriptionsSqueezeboxAdd(page.items[0].id); } } else if (page.type == 'cardMedia' && pageCounter == -1) { //Do Nothing @@ -5197,7 +5201,33 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { title = title + ' (' + vElapsed + '|' + vDuration + ')'; } } + let author = getState(id + '.ARTIST').val; + + if (v2Adapter == 'squeezeboxrpc' && author.length == 0) { + if(existsObject(([page.items[0].adapterPlayerInstance, 'Players.', page.items[0].mediaDevice, '.Playlist'].join('')))) { + if(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); + let currentIndex: number = parseInt(getState([page.items[0].adapterPlayerInstance, 'Players.', page.items[0].mediaDevice, '.PlaylistCurrentIndex'].join('')).val); + author = lmstracklist[currentIndex].Artist + '|' + lmstracklist[currentIndex].Album; + if (author.length > 37) { + author = author.slice(0, 37) + '...'; + } + let elapsedTime: number = parseInt(getState([page.items[0].adapterPlayerInstance, 'Players.', page.items[0].mediaDevice, '.Time'].join('')).val); + let elapsedSeconds = elapsedTime%60 < 10 ? '0' : ''; + let vElapsed = Math.floor(elapsedTime/60) + ":" + elapsedSeconds + elapsedTime%60; + + let durationSeconds = parseInt(lmstracklist[currentIndex].Duration)%60 < 10 ? '0' : ''; + let vDuration = Math.floor(parseInt(lmstracklist[currentIndex].Duration)/60) + ":" + durationSeconds + parseInt(lmstracklist[currentIndex].Duration)%60; + title = lmstracklist[currentIndex].title; + if (title.length > 25) { + title = title.slice(0, 25) + '...'; + } + title = title + ' (' + vElapsed + '|' + vDuration + ')'; + } + } + } + let shuffle = getState(id + '.SHUFFLE').val; //New Adapter/Player @@ -5480,8 +5510,8 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { }, 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); + } 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; @@ -5576,9 +5606,11 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { 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'); @@ -5619,6 +5651,15 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { findLocale('media','crossfade') + '~' + 'media5~' } + } else if (v2Adapter == 'squeezeboxrpc') { + 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 = 'button' + '~' + id + '' + '~' + @@ -6813,8 +6854,8 @@ function HandleButtonEvent(words: any): void { 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 adapterPlayerInstanceStateSeceltor: string = pageItemTemp.adapterPlayerInstance + 'Players.' + pageItemTemp.mediaDevice + '.state'; + if (Debug) log('HandleButtonEvent media-pause Squeezebox-> adapterPlayerInstanceStateSeceltor: ' + adapterPlayerInstanceStateSeceltor, 'info'); let stateVal = getState(adapterPlayerInstanceStateSeceltor).val; if (stateVal == 0) { setState(adapterPlayerInstanceStateSeceltor, 1); @@ -6877,6 +6918,13 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.SHUFFLE', false); } } + if ((tempPage.adapterPlayerInstance).startsWith("squeezeboxrpc")) { + if (getState(tempPage.adapterPlayerInstance + 'Players.' + tempPage.mediaDevice + '.PlaylistShuffle').val == 1) { + setIfExists(tempPage.adapterPlayerInstance + 'Players.' + tempPage.mediaDevice + '.PlaylistShuffle', 0); + } else { + setIfExists(tempPage.adapterPlayerInstance + 'Players.' + tempPage.mediaDevice + '.PlaylistShuffle', 1); + } + } if ((tempPage.adapterPlayerInstance).startsWith("bosesoundtouch")) { if (Debug) log(tempPage.adapterPlayerInstance + 'nowPlaying.shuffle'); if (getState(tempPage.adapterPlayerInstance + 'nowPlaying.shuffle').val == 'false') { @@ -6992,7 +7040,7 @@ function HandleButtonEvent(words: any): void { }); break; case 'squeezeboxrpc': - setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'cmdPlayFavorite'].join('.'), words[4]); + setState([adapterInstancePL, 'Players.', pageItemPL.mediaDevice, '.cmdPlayFavorite'].join(''), words[4]); break; case "bosesoundtouch": if (Debug) log('bosesoundtouch - playlist ' + pageItemPL.adapterPlayerInstance + ' - ' + words[4]); @@ -7048,7 +7096,7 @@ 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]); + setState([adapterInstanceTL, 'Players.', pageItemTL.mediaDevice, '.PlaylistCurrentIndex'].join(''), words[4]); break; case "bosesoundtouch": break; @@ -7102,6 +7150,13 @@ function HandleButtonEvent(words: any): void { switch (deviceAdapterSK) { case 'spotify-premium': break; + case 'squeezeboxrpc': + const vDuration: number = getState(adapterInstanceSK + 'Players.' + pageItemSeek.mediaDevice + '.Duration').val; + const vSeekPercentage : number = words[4] * 10; + const setSeekSeconds: number = vSeekPercentage * vDuration / 100; + if (Debug) log(adapterInstanceSK + 'Players.' + pageItemSeek.mediaDevice + '.cmdGoTime' + ': ' + setSeekSeconds + ' sec.'); + setState(adapterInstanceSK + 'Players.' + pageItemSeek.mediaDevice + '.cmdGoTime', String(setSeekSeconds.toFixed(0))); + break; case 'sonos': if (Debug) log('HandleButtonEvent mode-seek -> id: ' + id, 'info'); setState(adapterInstanceSK + 'root.' + pageItemSeek.mediaDevice + '.seek', parseInt(words[4]) * 10); @@ -7160,7 +7215,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemTemp)) break; let adapterInstance = pageItemTemp.adapterPlayerInstance.split('.'); if (adapterInstance[0] == 'squeezeboxrpc') { - let adapterPlayerInstancePowerSelector: string = [pageItemTemp.adapterPlayerInstance, 'Players', pageItemTemp.mediaDevice, 'Power'].join('.'); + let adapterPlayerInstancePowerSelector: string = [pageItemTemp.adapterPlayerInstance, 'Players.', pageItemTemp.mediaDevice, '.Power'].join(''); let stateVal = getState(adapterPlayerInstancePowerSelector).val; if (stateVal === 0) { setState(adapterPlayerInstancePowerSelector, 1); @@ -8186,9 +8241,16 @@ function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOpti const vTempAdapter = (pageItem.adapterPlayerInstance!).split('.'); 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 + '%'; if (vAdapter == 'sonos') { + const actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; + actualState = Math.round(actualStateTemp / 10) * 10 + '%'; + optionalString = '0%?10%?20%?30%?40%?50%?60%?70%?80%?90%?100%'; + } + if (vAdapter == 'squeezeboxrpc') { + const actualStateTime: number = parseInt(getState(pageItem.adapterPlayerInstance + 'Players.' + pageItem.mediaDevice + '.Time').val); + const actualStateDuration: number = parseInt(getState(pageItem.adapterPlayerInstance + 'Players.' + pageItem.mediaDevice + '.Duration').val); + const actualStateTemp: number = actualStateTime * 100 / actualStateDuration; + actualState = Math.round(actualStateTemp / 10) * 10 + '%'; optionalString = '0%?10%?20%?30%?40%?50%?60%?70%?80%?90%?100%'; } mode = 'seek'; From 62e905f336c6e854ddd4b5038f25c089a509db92 Mon Sep 17 00:00:00 2001 From: Armilar <102996011+Armilar@users.noreply.github.com> Date: Mon, 5 Feb 2024 17:21:13 +0100 Subject: [PATCH 07/16] v4.3.3.40 - Update NsPanelTs.ts - Fix maxColorTempValue for RGB - Fix SqueezeboxRPC-Media-Player and add some Functions --- ioBroker/NsPanelTs.ts | 146 ++++++++++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 42 deletions(-) diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 38a864bb..5da8454f 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.39 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.40 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 @@ -107,7 +107,9 @@ ReleaseNotes: - 20.01.2024 - v4.3.3.38 Add: click on indicatorIcon navigate to Page - 23.01.2024 - v4.3.3.39 Add: Optional setOn & setOff for HW button with mode 'set' - 28.01.2024 - v4.3.3.39 Fix: ack for read-only state - + - 03.02.2024 - v4.3.3.40 Fix: RGB maxValueColorTemp + - 05.02.2024 - v4.3.3.40 Fix SqueezeboxRPC-Media-Player and add some Functions + Todo: - XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined @@ -974,7 +976,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.39'; +const scriptVersion: string = 'v4.3.3.40'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -4754,12 +4756,12 @@ function unsubscribeMediaSubscriptions(): void { 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 () { + 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) { @@ -4774,8 +4776,8 @@ function subscribeMediaSubscriptions(id: string): void { function subscribeMediaSubscriptionsSonosAdd(id: string): void { on({id: [id + '.QUEUE', - id + '.DURATION', - id + '.ELAPSED'], change: "any"}, async function () { + id + '.DURATION', + id + '.ELAPSED'], change: "any"}, async function () { (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); timeoutMedia = setTimeout(async function () { if (useMediaEvents) { @@ -4790,7 +4792,7 @@ function subscribeMediaSubscriptionsSonosAdd(id: string): void { function subscribeMediaSubscriptionsAlexaAdd(id: string): void { on({id: [id + '.DURATION', - id + '.ELAPSED'], change: "any"}, async function () { + id + '.ELAPSED'], change: "any"}, async function () { (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); timeoutMedia = setTimeout(async function () { if (useMediaEvents) { @@ -4805,7 +4807,21 @@ function subscribeMediaSubscriptionsAlexaAdd(id: string): void { function subscribeMediaSubscriptionsBoseAdd(id: string): void { on({id: [id + '.DURATION', - id + '.ELAPSED'], change: "any"}, async function () { + 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 subscribeMediaSubscriptionsSqueezeboxAdd(id: string): void { + on({id: [id + '.ELAPSED'], change: "any"}, async function () { (function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })(); timeoutMedia = setTimeout(async function () { if (useMediaEvents) { @@ -5010,13 +5026,14 @@ async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPla 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 + '.SHUFFLE', dpPath + '.PlaylistShuffle', true, {type: 'string', role: 'media.mode.shuffle', name: 'SHUFFLE'}); await createAliasAsync(id + '.REPEAT', dpPath + '.PlaylistRepeat', true, {type: 'number', role: 'media.mode.repeat', name: 'REPEAT'}); + await createAliasAsync(id + '.DURATION', dpPath + '.Duration', true, {type: 'string', role: 'media.duration', name: 'DURATION'}); + await createAliasAsync(id + '.ELAPSED', dpPath + '.Time', true, {type: 'string', role: 'media.elapsed', name: 'ELAPSED'}); } catch (err: any) { log('error at function createAutoMediaAlias Adapter Squeezebox: ' + err.message, 'warn'); } } - } break; case "bosesoundtouch.0.": @@ -5081,23 +5098,6 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { let vInstance = page.items[0].adapterPlayerInstance!; let v1Adapter = vInstance.split('.'); 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') { - 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 : ''; @@ -5105,7 +5105,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { 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' }); @@ -5122,6 +5122,8 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { subscribeMediaSubscriptionsAlexaAdd(page.items[0].id); } else if (v2Adapter == 'bosesoundtouch') { subscribeMediaSubscriptionsBoseAdd(page.items[0].id); + } else if (v2Adapter == 'squeezeboxrpc') { + subscribeMediaSubscriptionsSqueezeboxAdd(page.items[0].id); } } } @@ -5135,6 +5137,8 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { subscribeMediaSubscriptionsAlexaAdd(page.items[0].id); } else if (v2Adapter == 'bosesoundtouch') { subscribeMediaSubscriptionsBoseAdd(page.items[0].id); + } else if (v2Adapter == 'squeezeboxrpc') { + subscribeMediaSubscriptionsSqueezeboxAdd(page.items[0].id); } } else if (page.type == 'cardMedia' && pageCounter == -1) { //Do Nothing @@ -5197,7 +5201,33 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { title = title + ' (' + vElapsed + '|' + vDuration + ')'; } } + let author = getState(id + '.ARTIST').val; + + if (v2Adapter == 'squeezeboxrpc' && author.length == 0) { + if(existsObject(([page.items[0].adapterPlayerInstance, 'Players.', page.items[0].mediaDevice, '.Playlist'].join('')))) { + if(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); + let currentIndex: number = parseInt(getState([page.items[0].adapterPlayerInstance, 'Players.', page.items[0].mediaDevice, '.PlaylistCurrentIndex'].join('')).val); + author = lmstracklist[currentIndex].Artist + '|' + lmstracklist[currentIndex].Album; + if (author.length > 37) { + author = author.slice(0, 37) + '...'; + } + let elapsedTime: number = parseInt(getState([page.items[0].adapterPlayerInstance, 'Players.', page.items[0].mediaDevice, '.Time'].join('')).val); + let elapsedSeconds = elapsedTime%60 < 10 ? '0' : ''; + let vElapsed = Math.floor(elapsedTime/60) + ":" + elapsedSeconds + elapsedTime%60; + + let durationSeconds = parseInt(lmstracklist[currentIndex].Duration)%60 < 10 ? '0' : ''; + let vDuration = Math.floor(parseInt(lmstracklist[currentIndex].Duration)/60) + ":" + durationSeconds + parseInt(lmstracklist[currentIndex].Duration)%60; + title = lmstracklist[currentIndex].title; + if (title.length > 25) { + title = title.slice(0, 25) + '...'; + } + title = title + ' (' + vElapsed + '|' + vDuration + ')'; + } + } + } + let shuffle = getState(id + '.SHUFFLE').val; //New Adapter/Player @@ -5480,8 +5510,8 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { }, 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); + } 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; @@ -5576,9 +5606,11 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { 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'); @@ -5619,6 +5651,15 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] { findLocale('media','crossfade') + '~' + 'media5~' } + } else if (v2Adapter == 'squeezeboxrpc') { + 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 = 'button' + '~' + id + '' + '~' + @@ -6813,8 +6854,8 @@ function HandleButtonEvent(words: any): void { 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 adapterPlayerInstanceStateSeceltor: string = pageItemTemp.adapterPlayerInstance + 'Players.' + pageItemTemp.mediaDevice + '.state'; + if (Debug) log('HandleButtonEvent media-pause Squeezebox-> adapterPlayerInstanceStateSeceltor: ' + adapterPlayerInstanceStateSeceltor, 'info'); let stateVal = getState(adapterPlayerInstanceStateSeceltor).val; if (stateVal == 0) { setState(adapterPlayerInstanceStateSeceltor, 1); @@ -6877,6 +6918,13 @@ function HandleButtonEvent(words: any): void { setIfExists(id + '.SHUFFLE', false); } } + if ((tempPage.adapterPlayerInstance).startsWith("squeezeboxrpc")) { + if (getState(tempPage.adapterPlayerInstance + 'Players.' + tempPage.mediaDevice + '.PlaylistShuffle').val == 1) { + setIfExists(tempPage.adapterPlayerInstance + 'Players.' + tempPage.mediaDevice + '.PlaylistShuffle', 0); + } else { + setIfExists(tempPage.adapterPlayerInstance + 'Players.' + tempPage.mediaDevice + '.PlaylistShuffle', 1); + } + } if ((tempPage.adapterPlayerInstance).startsWith("bosesoundtouch")) { if (Debug) log(tempPage.adapterPlayerInstance + 'nowPlaying.shuffle'); if (getState(tempPage.adapterPlayerInstance + 'nowPlaying.shuffle').val == 'false') { @@ -6992,7 +7040,7 @@ function HandleButtonEvent(words: any): void { }); break; case 'squeezeboxrpc': - setState([pageItemPL.adapterPlayerInstance, 'Players', pageItemPL.mediaDevice, 'cmdPlayFavorite'].join('.'), words[4]); + setState([adapterInstancePL, 'Players.', pageItemPL.mediaDevice, '.cmdPlayFavorite'].join(''), words[4]); break; case "bosesoundtouch": if (Debug) log('bosesoundtouch - playlist ' + pageItemPL.adapterPlayerInstance + ' - ' + words[4]); @@ -7048,7 +7096,7 @@ 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]); + setState([adapterInstanceTL, 'Players.', pageItemTL.mediaDevice, '.PlaylistCurrentIndex'].join(''), words[4]); break; case "bosesoundtouch": break; @@ -7102,6 +7150,13 @@ function HandleButtonEvent(words: any): void { switch (deviceAdapterSK) { case 'spotify-premium': break; + case 'squeezeboxrpc': + const vDuration: number = getState(adapterInstanceSK + 'Players.' + pageItemSeek.mediaDevice + '.Duration').val; + const vSeekPercentage : number = words[4] * 10; + const setSeekSeconds: number = vSeekPercentage * vDuration / 100; + if (Debug) log(adapterInstanceSK + 'Players.' + pageItemSeek.mediaDevice + '.cmdGoTime' + ': ' + setSeekSeconds + ' sec.'); + setState(adapterInstanceSK + 'Players.' + pageItemSeek.mediaDevice + '.cmdGoTime', String(setSeekSeconds.toFixed(0))); + break; case 'sonos': if (Debug) log('HandleButtonEvent mode-seek -> id: ' + id, 'info'); setState(adapterInstanceSK + 'root.' + pageItemSeek.mediaDevice + '.seek', parseInt(words[4]) * 10); @@ -7160,7 +7215,7 @@ function HandleButtonEvent(words: any): void { if (!isPageMediaItem(pageItemTemp)) break; let adapterInstance = pageItemTemp.adapterPlayerInstance.split('.'); if (adapterInstance[0] == 'squeezeboxrpc') { - let adapterPlayerInstancePowerSelector: string = [pageItemTemp.adapterPlayerInstance, 'Players', pageItemTemp.mediaDevice, 'Power'].join('.'); + let adapterPlayerInstancePowerSelector: string = [pageItemTemp.adapterPlayerInstance, 'Players.', pageItemTemp.mediaDevice, '.Power'].join(''); let stateVal = getState(adapterPlayerInstancePowerSelector).val; if (stateVal === 0) { setState(adapterPlayerInstancePowerSelector, 1); @@ -8186,9 +8241,16 @@ function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOpti const vTempAdapter = (pageItem.adapterPlayerInstance!).split('.'); 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 + '%'; if (vAdapter == 'sonos') { + const actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'root.' + pageItem.mediaDevice + '.seek').val; + actualState = Math.round(actualStateTemp / 10) * 10 + '%'; + optionalString = '0%?10%?20%?30%?40%?50%?60%?70%?80%?90%?100%'; + } + if (vAdapter == 'squeezeboxrpc') { + const actualStateTime: number = parseInt(getState(pageItem.adapterPlayerInstance + 'Players.' + pageItem.mediaDevice + '.Time').val); + const actualStateDuration: number = parseInt(getState(pageItem.adapterPlayerInstance + 'Players.' + pageItem.mediaDevice + '.Duration').val); + const actualStateTemp: number = actualStateTime * 100 / actualStateDuration; + actualState = Math.round(actualStateTemp / 10) * 10 + '%'; optionalString = '0%?10%?20%?30%?40%?50%?60%?70%?80%?90%?100%'; } mode = 'seek'; From 12c99c6857e7360058f0953a69d9f2eb7cf1f3e8 Mon Sep 17 00:00:00 2001 From: ticaki Date: Mon, 5 Feb 2024 19:29:15 +0100 Subject: [PATCH 08/16] Handle null in active*Brightness --- ioBroker/DEV/NSPanelTs.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 5da8454f..f9e4908f 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1516,11 +1516,11 @@ InitActiveBrightness(); on({id: [NSPanel_Path + 'ScreensaverInfo.activeBrightness'], change: 'ne'}, async function (obj) { try { - let active = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val; + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val ?? -1; 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(); + 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'); @@ -1529,7 +1529,7 @@ on({id: [NSPanel_Path + 'ScreensaverInfo.activeBrightness'], change: 'ne'}, asyn on({id: [NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness'], change: "ne"}, async function (obj) { try { - let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val; + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val ?? 80; 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'); @@ -1559,7 +1559,7 @@ on({id: [NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness'], change: "ne" on({id: String(NSPanel_Path) + 'ScreensaverInfo.Trigger_Dimmode', change: "ne"}, async function (obj) { try { - let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val; + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val ?? 80; if (obj.state.val) { SendToPanel({ payload: 'dimmode~' + 100 + '~' + active + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); } else { @@ -1910,8 +1910,8 @@ on({id: [NSPanel_Path + 'PageNavi'], change: "any"}, async function (obj) { //----------------------Begin Dimmode function ScreensaverDimmode(timeDimMode:NSPanel.DimMode) { try { - let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val - let dimmode = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val ?? 80 + let dimmode = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val ?? -1 if (Debug) { log('function ScreensaverDimmode RGB-Wert HMIDark' + rgb_dec565(HMIDark), 'info'); } @@ -2018,12 +2018,12 @@ async function InitDimmode() { 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 }); + SendToPanel({ payload: 'dimmode~' + getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val + '~' + getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val ?? 80 + '~' + 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 }); + SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessDay + '~' + getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val?? 80 + '~' + 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 }); + SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessNight + '~' + getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val ?? 80 + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); } ScreensaverDimmode(timeDimMode); } @@ -9953,7 +9953,7 @@ namespace NSPanel { 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' + export type roles = 'light' |'socket'|'dimmer'| 'hue' | 'rgb' | 'rgbSingle' | 'ct' | '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' From 157d3e3e663c1502e5d9fa5f643f42a7ed6eae42 Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Tue, 6 Feb 2024 10:32:06 +0100 Subject: [PATCH 09/16] v4.3.3.41 Update NSPanel.ts - Fix: activeBrightness -> null - Fix: bHome -> corrected PageId --- ioBroker/DEV/NSPanelTs.ts | 34 +++++++++++++---------- ioBroker/NsPanelTs.ts | 58 +++++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index f9e4908f..b812a4a4 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.40 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.41 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 @@ -108,7 +108,9 @@ ReleaseNotes: - 23.01.2024 - v4.3.3.39 Add: Optional setOn & setOff for HW button with mode 'set' - 28.01.2024 - v4.3.3.39 Fix: ack for read-only state - 03.02.2024 - v4.3.3.40 Fix: RGB maxValueColorTemp - - 05.02.2024 - v4.3.3.40 Fix SqueezeboxRPC-Media-Player and add some Functions + - 05.02.2024 - v4.3.3.40 Fix: SqueezeboxRPC-Media-Player and add some Functions + - 06.02.2024 - v4.3.3.41 Fix: activeBrightness -> null + - 06.02.2024 - v4.3.3.41 Fix: bHome -> corrected PageId Todo: @@ -976,7 +978,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.40'; +const scriptVersion: string = 'v4.3.3.41'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -6485,17 +6487,21 @@ function HandleButtonEvent(words: any): void { 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 'bHome': + if (Debug) { + log('HandleButtonEvent -> bHome: ' + words[4] + ' - ' + pageId, 'info'); + } + UnsubscribeWatcher(); + const home = activePage!.home; + if (home !== undefined) { + pageId = config.pages.findIndex(a => a == eval(home)) + pageId = pageId === -1 ? 0 : pageId; + GeneratePage(eval(home)); + } else { + pageId = 0; + GeneratePage(config.pages[0]); + } + break; case 'notifyAction': if (words[4] == 'yes') { setState(popupNotifyInternalName, { val: words[2], ack: true }); diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 5da8454f..b812a4a4 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.40 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.41 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 @@ -108,7 +108,9 @@ ReleaseNotes: - 23.01.2024 - v4.3.3.39 Add: Optional setOn & setOff for HW button with mode 'set' - 28.01.2024 - v4.3.3.39 Fix: ack for read-only state - 03.02.2024 - v4.3.3.40 Fix: RGB maxValueColorTemp - - 05.02.2024 - v4.3.3.40 Fix SqueezeboxRPC-Media-Player and add some Functions + - 05.02.2024 - v4.3.3.40 Fix: SqueezeboxRPC-Media-Player and add some Functions + - 06.02.2024 - v4.3.3.41 Fix: activeBrightness -> null + - 06.02.2024 - v4.3.3.41 Fix: bHome -> corrected PageId Todo: @@ -976,7 +978,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.40'; +const scriptVersion: string = 'v4.3.3.41'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -1516,11 +1518,11 @@ InitActiveBrightness(); on({id: [NSPanel_Path + 'ScreensaverInfo.activeBrightness'], change: 'ne'}, async function (obj) { try { - let active = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val; + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val ?? -1; 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(); + 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'); @@ -1529,7 +1531,7 @@ on({id: [NSPanel_Path + 'ScreensaverInfo.activeBrightness'], change: 'ne'}, asyn on({id: [NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness'], change: "ne"}, async function (obj) { try { - let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val; + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val ?? 80; 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'); @@ -1559,7 +1561,7 @@ on({id: [NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness'], change: "ne" on({id: String(NSPanel_Path) + 'ScreensaverInfo.Trigger_Dimmode', change: "ne"}, async function (obj) { try { - let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val; + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val ?? 80; if (obj.state.val) { SendToPanel({ payload: 'dimmode~' + 100 + '~' + active + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); } else { @@ -1910,8 +1912,8 @@ on({id: [NSPanel_Path + 'PageNavi'], change: "any"}, async function (obj) { //----------------------Begin Dimmode function ScreensaverDimmode(timeDimMode:NSPanel.DimMode) { try { - let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val - let dimmode = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val + let active = getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val ?? 80 + let dimmode = getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val ?? -1 if (Debug) { log('function ScreensaverDimmode RGB-Wert HMIDark' + rgb_dec565(HMIDark), 'info'); } @@ -2018,12 +2020,12 @@ async function InitDimmode() { 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 }); + SendToPanel({ payload: 'dimmode~' + getState(NSPanel_Path + 'ScreensaverInfo.activeDimmodeBrightness').val + '~' + getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val ?? 80 + '~' + 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 }); + SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessDay + '~' + getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val?? 80 + '~' + 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 }); + SendToPanel({ payload: 'dimmode~' + timeDimMode.brightnessNight + '~' + getState(NSPanel_Path + 'ScreensaverInfo.activeBrightness').val ?? 80 + '~' + rgb_dec565(config.defaultBackgroundColor) + '~' + rgb_dec565(globalTextColor) + '~' + Sliders2 }); } ScreensaverDimmode(timeDimMode); } @@ -6485,17 +6487,21 @@ function HandleButtonEvent(words: any): void { 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 'bHome': + if (Debug) { + log('HandleButtonEvent -> bHome: ' + words[4] + ' - ' + pageId, 'info'); + } + UnsubscribeWatcher(); + const home = activePage!.home; + if (home !== undefined) { + pageId = config.pages.findIndex(a => a == eval(home)) + pageId = pageId === -1 ? 0 : pageId; + GeneratePage(eval(home)); + } else { + pageId = 0; + GeneratePage(config.pages[0]); + } + break; case 'notifyAction': if (words[4] == 'yes') { setState(popupNotifyInternalName, { val: words[2], ack: true }); @@ -9953,7 +9959,7 @@ namespace NSPanel { 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' + export type roles = 'light' |'socket'|'dimmer'| 'hue' | 'rgb' | 'rgbSingle' | 'ct' | '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' From d983c44db7f642f2c7c8debf033bd3b5a99bdb18 Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:04:13 +0100 Subject: [PATCH 10/16] update CardLChart_Influx2.ts - codeanpassungen --- ioBroker/Blockly/CardLChart_Influx2.ts | 211 ++++++++++++++----------- 1 file changed, 116 insertions(+), 95 deletions(-) diff --git a/ioBroker/Blockly/CardLChart_Influx2.ts b/ioBroker/Blockly/CardLChart_Influx2.ts index 6eb4ef5d..4840919a 100644 --- a/ioBroker/Blockly/CardLChart_Influx2.ts +++ b/ioBroker/Blockly/CardLChart_Influx2.ts @@ -1,109 +1,130 @@ -const Debug = false; +/** + * Dieses Script fragt eine influxDb ab, um Daten für die cardLcart (Liniendiagramm) zuberechnen und im richtigen Format bereitzustellen. + * Es erstellt automatisch einen Datenpunkt. + * Die Abfrage muss ggf. angepasst werden. Aktuell ermittelt sie Werte der letzten 24h, zu Stundenwerten zusammengefasst. + */ -const NSPanel_Path = '0_userdata.0.NSPanel.1.'; +const Debug = false; // true für erweiterte Ausgaben im Log + +const NSPanel_Path = '0_userdata.0.NSPanel.'; const Path = NSPanel_Path + 'Influx2NSPanel.cardLChart.'; -const InfluxInstance = 'influxdb.1'; -const influxDbBucket = 'iobroker'; +const InfluxInstance = 'influxdb.0'; +const influxDbBucket = 'storage_short'; const numberOfHoursAgo = 24; const xAxisTicksEveryM = 60; const xAxisLabelEveryM = 240; +// + +const sensors : Record> = {}; +/** + * Hier werden die Sensoren festgelegt nach flogendem Schema + * + * sensors[‘Datenpunkt(kompletter Pfad) des Messwertes'] = {'taget': 'Name des Datenpunkt für die Chartwerte', 'measurement': 'genutzter Alias in der Influxdb für den Messwert'}; + * + * Wenn der Wert in der Datenbank keinen Alias hat bleibt der Wert 'measurement': weg. + * Jeder Messwert bekommt einen eigenen sensors[...] = {'target':....} + */ -// this records holds all sensors and their corresponding states which act as the data source for the charts -// add all sensors which are to be displayed in this script, there is no need to use multiple scripts -const sensors : Record = {}; -/* ↓ Id of the sensor ↓ Id of the data source for the charts */ -sensors['deconz.0.Sensors.65.temperature'] = Path + 'buero_temperature.ACTUAL'; -sensors['deconz.0.Sensors.65.humidity'] = Path + 'buero_luftfeuchte.ACTUAL'; +sensors['netatmo-crawler.0.stationData.1.temperature'] = {'target':'AussenTemp', 'measurement':'wetter.temperatur'}; + +// ##### ab hier keine Änderungen mehr nötig ##### + // create data source for NsPanel on script startup -Object.keys(sensors).forEach(async x => { - await generateDateAsync(x, sensors[x]); +Object.keys(sensors).forEach(async id => { + await generateDateAsync(id); }); - + // then listen to the sensors and update the data source states accordingly on({ id: Object.keys(sensors), change: 'any' }, async function (obj) { - if (!obj.id) { - return; - } - - await generateDateAsync(obj.id, sensors[obj.id]); + if (!obj.id) { + return; + } + await generateDateAsync(obj.id); }); - -async function generateDateAsync(sensorId: string, dataPointId: string) { - const query =[ - 'from(bucket: "' + influxDbBucket + '")', - '|> range(start: -' + numberOfHoursAgo + 'h)', - '|> filter(fn: (r) => r["_measurement"] == "' + sensorId + '")', - '|> filter(fn: (r) => r["_field"] == "value")', - '|> drop(columns: ["from", "ack", "q"])', - '|> aggregateWindow(every: 1h, fn: last, createEmpty: false)', - '|> map(fn: (r) => ({ r with _rtime: int(v: r._time) - int(v: r._start)}))', - '|> yield(name: "_result")'].join(''); - - if (Debug) console.log('Query: ' + query); - - const result : any = await sendToAsync(InfluxInstance, 'query', query); - if (result.error) { - console.error(result.error); - return; - } - - if (Debug) console.log(result); - const numResults = result.result.length; - let coordinates : string = ''; - for (let r = 0; r < numResults; r++) - { - const list : string[] = [] - const numValues = result.result[r].length; - - for (let i = 0; i < numValues; i++) - { - const time = Math.round(result.result[r][i]._rtime/1000/1000/1000/60); - const value = Math.round(result.result[r][i]._value * 10); - list.push(time + ":" + value); - } - - coordinates = list.join("~"); - - if (Debug) console.log(coordinates); - } - - const ticksAndLabelsList : string[] = [] - const date = new Date(); - date.setMinutes(0, 0, 0); - const ts = Math.round(date.getTime() / 1000); - const tsYesterday = ts - (numberOfHoursAgo * 3600); - if (Debug) console.log('Iterate from ' + tsYesterday + ' to ' + ts + ' stepsize=' + (xAxisTicksEveryM * 60)); - for (let x = tsYesterday, i = 0; x < ts; x += (xAxisTicksEveryM * 60), i += xAxisTicksEveryM) - { - if ((i % xAxisLabelEveryM)) - ticksAndLabelsList.push('' + i); - else - { - const currentDate = new Date(x * 1000); - // Hours part from the timestamp - const hours = "0" + String(currentDate.getHours()); - // Minutes part from the timestamp - const minutes = "0" + String(currentDate.getMinutes()); - const formattedTime = hours.slice(-2) + ':' + minutes.slice(-2); - - ticksAndLabelsList.push(String(i) + "^" + formattedTime); - } - } - if (Debug) console.log('Ticks & Label: ' + ticksAndLabelsList); - if (Debug) console.log('Coordinates: ' + coordinates); - await setOrCreate(dataPointId, ticksAndLabelsList.join("+") + '~' + coordinates, true); + +//__________________________ +// Beschreibe diese Funktion: Daten generieren +async function generateDateAsync(sensorId: string) { + let idMeasurement = sensors[sensorId].measurement; + if (idMeasurement =='' ||idMeasurement == undefined) {idMeasurement = sensorId}; + const dataPointId:string = Path + sensors[sensorId].target +'.ACTUAL'; + if (Debug) log(`(f) generateDateAsync: ${sensorId} ${dataPointId} > ${idMeasurement}`); + + const query =[ + 'from(bucket: "' + influxDbBucket + '")', + '|> range(start: -' + numberOfHoursAgo + 'h)', + '|> filter(fn: (r) => r["_measurement"] == "' + idMeasurement + '")', + '|> filter(fn: (r) => r["_field"] == "value")', + '|> drop(columns: ["from", "ack", "q"])', + '|> aggregateWindow(every: 1h, fn: last, createEmpty: false)', + '|> map(fn: (r) => ({ r with _rtime: int(v: r._time) - int(v: r._start)}))', + '|> yield(name: "_result")'].join(''); + + if (Debug) console.log('Query: ' + query); + + const result : any = await sendToAsync(InfluxInstance, 'query', query); + if (result.error) { + console.error(result.error); + return; + } + if (Debug) console.log(JSON.stringify(result)); + const numResults = result.result.length; + let coordinates : string = ''; + for (let r = 0; r < numResults; r++) + { + const list : string[] = []; + const numValues = result.result[r].length; + + for (let i = 0; i < numValues; i++) + { + const time = Math.round(result.result[r][i]._rtime/1000/1000/1000/60); + const value = Math.round(result.result[r][i]._value * 10); + list.push(time + ":" + value); + } + + coordinates = list.join("~"); + if (Debug) console.log(coordinates); + } + + const ticksAndLabelsList : string[] = [] + const date = new Date(); + date.setMinutes(0, 0, 0); + const ts = Math.round(date.getTime() / 1000); + const tsYesterday = ts - (numberOfHoursAgo * 3600); + if (Debug) console.log('Iterate from ' + tsYesterday + ' to ' + ts + ' stepsize=' + (xAxisTicksEveryM * 60)); + for (let x = tsYesterday, i = 0; x < ts; x += (xAxisTicksEveryM * 60), i += xAxisTicksEveryM) + { + if ((i % xAxisLabelEveryM)) + ticksAndLabelsList.push('' + i); + else + { + const currentDate = new Date(x * 1000); + // Hours part from the timestamp + const hours = "0" + String(currentDate.getHours()); + // Minutes part from the timestamp + const minutes = "0" + String(currentDate.getMinutes()); + const formattedTime = hours.slice(-2) + ':' + minutes.slice(-2); + + ticksAndLabelsList.push(String(i) + "^" + formattedTime); + } + } + if (Debug) console.log('Ticks & Label: ' + ticksAndLabelsList); + if (Debug) console.log('Coordinates: ' + coordinates); + await setOrCreate(dataPointId, ticksAndLabelsList.join("+") + '~' + coordinates, true); } - + +//__________________________ +// Beschreibe diese Funktion: Datenpunkte anlegen bzw. schreiben async function setOrCreate(id : string, value : any, ack : boolean) { - if (!(await existsStateAsync(id))) { - await createStateAsync(id, value, { - name: id.split('.').reverse()[0], - desc: 'Sensor Values [~