From 1faa540a7059591eda27a5e0c3056ff8f3091ff5 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 23 Jan 2024 07:58:21 +0100 Subject: [PATCH 1/9] Add some optional types --- ioBroker/DEV/NSPanelTs.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 55642c3d..fc46cc4e 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -9037,7 +9037,7 @@ function HandleScreensaverStatusIcons() : void { } else { payloadString += '~'; } - + // statusUpdate~icon1~icon1Color~icon1font~icon2~icon2color~icon2font~icon2font SendToPanel({ payload: 'statusUpdate~' + payloadString }); } catch (err: any) { @@ -9891,6 +9891,7 @@ namespace NSPanel { export type PageBaseType = { type: PagetypeType, + uniqueName?: string, heading: string, items: PageItem[], useColor: boolean, @@ -10001,6 +10002,8 @@ namespace NSPanel { // mean string start with getState(' and end with ').val type getStateID = string; export type PageBaseItem = { + uniqueName?: string, + role?: string, id?: string | null, icon?: string, icon2?: string, From f7f853f05ea13b9d30df066a3af110966b58a7ec Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 23 Jan 2024 16:55:07 +0100 Subject: [PATCH 2/9] Add setOn / setOff --- ioBroker/DEV/NSPanelTs.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index fc46cc4e..ed6d01a0 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -1,5 +1,5 @@ /*----------------------------------------------------------------------- -TypeScript v4.3.3.38 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne +TypeScript v4.3.3.39 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,8 +103,9 @@ 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 - - 20.01.2024 - v4.3.3.38 Add: click on indicatorIcon navigate to Page + - 19.01.2024 - v4.3.3.38 Change: yAxisTicks parameter is not required in cardLChart PageItem + - 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' Todo: @@ -972,7 +973,7 @@ export const config: Config = { // _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________ // _________________________________ EN: No more configuration from here _____________________________________ -const scriptVersion: string = 'v4.3.3.38'; +const scriptVersion: string = 'v4.3.3.39'; const tft_version: string = 'v4.3.3'; const desired_display_firmware_version = 53; const berry_driver_version = 9; @@ -986,6 +987,8 @@ let weatherForecast: boolean; let pageCounter: number = 0; let alwaysOn: boolean = false; +let buttonToggleState: {[key: string]: boolean} = {}; + const axios = require('axios'); const dayjs = require('dayjs'); const moment = require('moment'); @@ -3242,7 +3245,13 @@ function HandleHardwareButton(method: NSPanel.EventMethod): void { break; case 'set': if (Debug) log('HandleHardwareButton -> Mode Set', 'info'); - if (buttonConfig.entity) { + if (buttonConfig.setOn && existsState(buttonConfig.setOn.dp) && !buttonToggleState[method]) { + setState(buttonConfig.setOn.dp, buttonConfig.setOn.val); + buttonToggleState[method] = true; + } else if (buttonConfig.setOff && existsState(buttonConfig.setOff.dp) && buttonToggleState[method]) { + setState(buttonConfig.setOff.dp, buttonConfig.setOff.val); + buttonToggleState[method] = false; + } else if (buttonConfig.entity && existsState(buttonConfig.entity)) { setState(buttonConfig.entity, buttonConfig.setValue); } screensaverEnabled = true; @@ -10061,6 +10070,8 @@ namespace NSPanel { page: (PageThermo | PageMedia | PageAlarm | PageQR | PageEntities | PageGrid | PageGrid2 | PagePower | PageChart | PageUnlock | null), entity: string | null, setValue: string | number | boolean | null + setOn?: {dp:string, val:iobJS.StateValue} + setOff?: {dp:string, val:iobJS.StateValue}; } export type Config = { From aa266da5ac8963f20eb1a606de156ba58ba8a062 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 23 Jan 2024 18:17:34 +0100 Subject: [PATCH 3/9] fix txt.matchall --- 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 ec950bf7..4818d27f 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -6188,7 +6188,7 @@ function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] { 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); + const sorted = [...String(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!`) } From 4aab72fb109fce104e391dbbeda439a2344c6671 Mon Sep 17 00:00:00 2001 From: ticaki Date: Tue, 23 Jan 2024 18:36:03 +0100 Subject: [PATCH 4/9] build nice objects --- ioBroker/DEV/NSPanelTs.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ioBroker/DEV/NSPanelTs.ts b/ioBroker/DEV/NSPanelTs.ts index 4818d27f..c7a9f5b8 100644 --- a/ioBroker/DEV/NSPanelTs.ts +++ b/ioBroker/DEV/NSPanelTs.ts @@ -6322,9 +6322,9 @@ function HandleButtonEvent(words: any): void { SendToPanel({ payload: 'timeout~' + getState(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver').val }); } - setOrCreate(NSPanel_Path + "Event.Button.Action", buttonAction ?? words[2]); - setOrCreate(NSPanel_Path + "Event.Button.Value", words[4] != undefined ? words[4] : null); - setOrCreate(NSPanel_Path + "Event.Button.Id", id); + setOrCreate(NSPanel_Path + "Event.Button.Action", buttonAction ?? words[2], false, {name: 'Incoming button acion', type: 'string', role: 'text', write: false, read: true}); + setOrCreate(NSPanel_Path + "Event.Button.Value", words[4] != undefined ? words[4] : '', false, {name: 'Incoming button value', type: 'string', role: 'text', write: false, read: true}); + setOrCreate(NSPanel_Path + "Event.Button.Id", id, false, {name: 'Incoming button id', type: 'string', role: 'text', write: false, read: true}); if (Debug) { log('HandleButtonEvent buttonAction: ' + buttonAction, 'info'); @@ -7374,9 +7374,11 @@ function HandleButtonEvent(words: any): void { function setOrCreate(id : string, value : any, forceCreation: boolean = true, common: Partial = { }, callback?: iobJS.SetStateCallback) { if (!existsState(id)) { - createState(id, value, forceCreation, common, callback); + extendObject(id.split('.').slice(0, -2).join('.'), {type: 'channel', common:{name: 'channel'}, native:{}}); + extendObject(id.split('.').slice(0, -1).join('.'), {type: 'channel', common:{name: 'channel'}, native:{}}); + createState(id, value, forceCreation, common, callback); } else { - setState(id, value); + setState(id, value, true); } } From a2feae891e9785c82b7d4d50bf9cf255d55d7e5c Mon Sep 17 00:00:00 2001 From: Thomas <101348966+tt-tom17@users.noreply.github.com> Date: Fri, 26 Jan 2024 18:50:47 +0100 Subject: [PATCH 5/9] Script vom Wiki nach Github schieben --- ioBroker/Blockly/Abfallkalender.js | 74 -------- ioBroker/Blockly/Abfallkalender.ts | 224 +++++++++++++++++++++++++ ioBroker/Blockly/CardChart_History.js | 50 ++++++ ioBroker/Blockly/CardLChart_History.js | 78 +++++++++ ioBroker/Blockly/CardPower.js | 54 ++++++ ioBroker/Blockly/CradLChart_Influx2.js | 109 ++++++++++++ 6 files changed, 515 insertions(+), 74 deletions(-) delete mode 100644 ioBroker/Blockly/Abfallkalender.js create mode 100644 ioBroker/Blockly/Abfallkalender.ts create mode 100644 ioBroker/Blockly/CardChart_History.js create mode 100644 ioBroker/Blockly/CardLChart_History.js create mode 100644 ioBroker/Blockly/CardPower.js create mode 100644 ioBroker/Blockly/CradLChart_Influx2.js diff --git a/ioBroker/Blockly/Abfallkalender.js b/ioBroker/Blockly/Abfallkalender.js deleted file mode 100644 index 71255bb9..00000000 --- a/ioBroker/Blockly/Abfallkalender.js +++ /dev/null @@ -1,74 +0,0 @@ -const idAbfalliCal = 'ical.1'; // iCal Instanz zum Abfallkalender -const idZeichenLoeschen = 14; // x Zeichen links vom String abziehen, wenn vor dem Eventname noch Text steht z.B. Strassenname; Standard = 0 -const idRestmuellName ='Hausmüll'; // Schwarze Tonne -const idWertstoffName = 'Gelber Sack'; // Gelbe Tonne / Sack -const idPappePapierName = 'Papier'; // Blaue Tonne -const idBioabfaelleName = 'Biomüll'; // Braune Tonne - - -var i, Muell_JSON, Event2, Color = 0; - -for (i = 1; i <= 4; i++) { - if (!existsState('0_userdata.0.Abfallkalender.' + parseFloat(i) + '.date')) { - log(i + '.date nicht vorhanden, wurde erstellt'); - createState('0_userdata.0.Abfallkalender.' + parseFloat(i) + '.date', '', - { - name: parseFloat(i) + '.date', - role: 'state', - type: 'string', - read: true, - write: true, - def: '' - }); - }; - if (!existsState('0_userdata.0.Abfallkalender.' + parseFloat(i) + '.event')) { - log(i + '.event nicht vorhanden, wurde erstellt'); - createState('0_userdata.0.Abfallkalender.' + parseFloat(i) + '.event', '', - { - name: parseFloat(i) + '.event', - role: 'state', - type: 'string', - read: true, - write: true, - def: '' - }); - }; - if (!existsState('0_userdata.0.Abfallkalender.' + parseFloat(i) + '.color')) { - log(i + '.color nicht vorhanden, wurde erstellt'); - createState('0_userdata.0.Abfallkalender.' + parseFloat(i) + '.color', 0, - { - name: parseFloat(i) + '.color', - role: 'state', - type: 'number', - read: true, - write: true, - def: 0 - }); - }; -} - -function subsequenceFromStartLast(sequence, at1) { - var start = at1; - var end = sequence.length; - return sequence.slice(start, end); -} - -on({ id: idAbfalliCal + '.data.table', change: "ne" }, async function () { - - for (i = 0; i <= 3; i++) { - Muell_JSON = getState(idAbfalliCal + '.data.table').val; - setStateDelayed((['0_userdata.0.Abfallkalender.', parseFloat(i) + 1, '.date'].join('')), getAttr(Muell_JSON, (String(i) + '.date')), false, parseInt(((0) || "").toString(), 10), false); - Event2 = subsequenceFromStartLast(getAttr(Muell_JSON, (String(i) + '.event')), idZeichenLoeschen); - setStateDelayed((['0_userdata.0.Abfallkalender.', parseFloat(i) + 1, '.event'].join('')), Event2, false, parseInt(((0) || "").toString(), 10), false); - if (Event2 == idRestmuellName) { - Color = 33840; - } else if (Event2 == idBioabfaelleName) { - Color = 2016; - } else if (Event2 == idPappePapierName) { - Color = 31; - } else if (Event2 == idWertstoffName) { - Color = 65504; - } - setStateDelayed((['0_userdata.0.Abfallkalender.', parseFloat(i) + 1, '.color'].join('')), Color, false, parseInt(((0) || "").toString(), 10), false); - } -}); diff --git a/ioBroker/Blockly/Abfallkalender.ts b/ioBroker/Blockly/Abfallkalender.ts new file mode 100644 index 00000000..9419574d --- /dev/null +++ b/ioBroker/Blockly/Abfallkalender.ts @@ -0,0 +1,224 @@ +/* + * @author 2023 @tt-tom + * + * Version 5.1.1 + * + * Das Script erstellt die Datenpunkte und Alias für den Abfallkalender im Sonoff NSPanel + * Es wird der iCal Adapter benötigt und eine URL mit Terminen vom Entsorger bzw. eine .ics-Datei mit den Terminen. + * Das Script triggert auf dem bereitgestellten JSON im iCal adapter und füllt die 0_userdata.0 Datenpunkte + * Weitere Informationen findest du in der FAQ auf Github https://github.com/joBr99/nspanel-lovelace-ui/wiki + * + * changelog + * - 06.12.2023 - v5.0.2 add custom name for trashtype + * - 06.12.2023 - v5.1.0 Refactoring + * - 22.01.2024 - v5.1.1 Add tow Events more + * + * +*/ + + +const idTrashData: string = 'ical.0.data.table'; // Datenpunkt mit Daten im JSON Format +const idUserdataAbfallVerzeichnis: string = '0_userdata.0.Abfallkalender'; // Name des Datenpunktverzeichnis unter 0_userdata.0 -> Strandard = 0_userdata.0.Abfallkalender +const idAliasPanelVerzeichnis: string = 'alias.0.NSPanel.allgemein'; //Name PanelVerzeichnis unter alias.0. Standard = alias.0.NSPanel.1 +const idAliasAbfallVerzeichnis: string = 'Abfall'; //Name Verzeichnis unterhalb der idPanelverzeichnis Standard = Abfall + +const anzahlZeichenLoeschen: number = 14; // x Zeichen links vom String abziehen, wenn vor dem Eventname noch Text steht z.B. Strassenname; Standard = 0 +const jsonEventName1: string = 'Hausmüll'; // Vergleichstring für Schwarze Tonne +const customEventName1: string = ''; // benutzerdefinierter Text für schwarze Tonne +const jsonEventName2: string = 'Gelber Sack'; // Vergleichstring für Gelbe Tonne / Sack +const customEventName2: string = ''; // benutzerdefinierter Text für gelbe Tonne +const jsonEventName3: string = 'Papier'; // Vergleichstring für Blaue Tonne +const customEventName3: string = ''; // benutzerdefinierter Text für blaue Tonne +const jsonEventName4: string = 'Biomüll'; // Vergleichstring für Braune Tonne +const customEventName4: string = ''; // benutzerdefinierter Text für braune Tonne +const jsonEventName5: string = 'Treppe'; // Vergleichstring für Event 5 +const customEventName5: string = 'Besen schwingen'; // benutzerdefinierter Text für Event 5 +const jsonEventName6: string = ''; // Vergleichstring für Event 6 +const customEventName6: string = ''; // benutzerdefinierter Text für Event 6 + +const Debug: boolean = false; + +// ------------------------- Trigger zum füllen der 0_userdata Datenpunkte aus dem json vom ical Adapter ------------------------------- + +// Trigger auf JSON Datenpunkt +on({ id: idTrashData, change: 'ne' }, async function () { + JSON_auswerten(); +}); + +// ------------------------------------- Ende Trigger ------------------------------------ + +// ------------------------------------- Funktion JSON auswerten und DP füllen ------------------------------- +async function JSON_auswerten() { + try { + + let trashJSON: any; + let instanzName: any; + let eventName: string; + let eventDatum: string; + let eventStartdatum: string; + let farbNummer: number = 0; + let farbString: string; + let abfallNummer: number = 1; + + trashJSON = getState(idTrashData).val; + instanzName = idTrashData.split('.'); + + if (Debug) log('Rohdaten von Instanz ' + instanzName[0] + ': ' + JSON.stringify(trashJSON), 'info') + + + if (Debug) log('Anzahl Trash - Daten: ' + trashJSON.length, 'info'); + + for (let i = 0; i < trashJSON.length; i++) { + if (abfallNummer === 7) { + if (Debug) log('Alle Abfall-Datenpunkte gefüllt', 'warn'); + break; + } + + log('Daten vom ical Adapter werden ausgewertet', 'info'); + eventName = getAttr(trashJSON, (String(i) + '.event')).slice(anzahlZeichenLoeschen, getAttr(trashJSON, (String(i) + '.event')).length); + // Leerzeichen vorne und hinten löschen + eventName = eventName.trimEnd(); + eventName = eventName.trimStart(); + eventDatum = getAttr(trashJSON, (String(i) + '.date')); + eventStartdatum = getAttr(trashJSON, (String(i) + '._date')); + + let d: Date = currentDate(); + let d1: Date = new Date(eventStartdatum); + + if (Debug) log('--------- Nächster Termin wird geprüft ---------', 'info'); + //if (Debug) log(d + ' ' + d1, 'info'); + if (Debug) log('Startdatum UTC: ' + eventStartdatum, 'info'); + if (Debug) log('Datum: ' + eventDatum, 'info'); + if (Debug) log('Event: ' + eventName, 'info'); + if (Debug) log('Kontrolle Leerzeichen %' + eventName + '%', 'info'); + + if (d.getTime() <= d1.getTime()) { + if ((eventName == jsonEventName1) || (eventName == jsonEventName2) || (eventName == jsonEventName3) || (eventName == jsonEventName4) || (eventName == jsonEventName5) || (eventName == jsonEventName6)) { + + switch (eventName) { + case jsonEventName1: + farbNummer = 33840; + if (customEventName1 != '') { + eventName = customEventName1; + if (Debug) log('Event customName: ' + eventName, 'info'); + }; + break; + case jsonEventName2: + farbNummer = 65504; + if (customEventName2 != '') { + eventName = customEventName2; + if (Debug) log('Event customName: ' + eventName, 'info'); + }; + break; + case jsonEventName3: + farbNummer = 31; + if (customEventName3 != '') { + eventName = customEventName3 + if (Debug) log('Event customName: ' + eventName, 'info'); + }; + break; + case jsonEventName4: + farbNummer = 2016; + if (customEventName4 != '') { + eventName = customEventName4; + if (Debug) log('Event customName: ' + eventName, 'info'); + }; + break; + case jsonEventName5: + farbNummer = 2016; + if (customEventName5 != '') { + eventName = customEventName5; + if (Debug) log('Event customName: ' + eventName, 'info'); + }; + break; + case jsonEventName6: + farbNummer = 2016; + if (customEventName6 != '') { + eventName = customEventName6 + if (Debug) log('Event customName: ' + eventName, 'info'); + }; + break; + } + + //if (farbString != undefined) farbNummer = rgb_dec565(hex_rgb(farbString)); + + + setState(idUserdataAbfallVerzeichnis + '.' + String(abfallNummer) + '.date', eventDatum); + setState(idUserdataAbfallVerzeichnis + '.' + String(abfallNummer) + '.event', eventName); + setState(idUserdataAbfallVerzeichnis + '.' + String(abfallNummer) + '.color', farbNummer); + + + //if (Debug) log('farbString: ' + farbString + ' farbNummer: ' + farbNummer, 'info'); + if (Debug) log('Abfallnummer: ' + abfallNummer, 'info'); + + abfallNummer += 1 + } else { + if (Debug) log('Kein Abfalltermin => Event passt mit keinem Abfallnamen überein.', 'warn'); + } + } else { + if (Debug) log('Termin liegt vor dem heutigen Tag', 'warn'); + } + } + } catch (err) { + log('error at subscrption: ' + err.message, 'warn'); + } +}; + +// ------------------------------------- Ende Funktion JSON ------------------------------ + +// ------------------------------------- Funktion zur Prüfung und Erstellung der Datenpunkte in 0_userdata.0 und alias.0 ----------------------- + +async function Init_Datenpunkte() { + try { + for (let i = 1; i <= 6; i++) { + if (existsObject(idUserdataAbfallVerzeichnis + '.' + String(i)) == false) { + log('Datenpunkt ' + idUserdataAbfallVerzeichnis + '.' + String(i) + ' werden angelegt', 'info') + await createStateAsync(idUserdataAbfallVerzeichnis + '.' + String(i) + '.date', '', { type: 'string' }); + await createStateAsync(idUserdataAbfallVerzeichnis + '.' + String(i) + '.event', '', { type: 'string' }); + await createStateAsync(idUserdataAbfallVerzeichnis + '.' + String(i) + '.color', 0, { type: 'number' }); + setObject(idAliasPanelVerzeichnis + '.' + idAliasAbfallVerzeichnis, { type: 'device', common: { name: { de: 'Abfall', en: 'Trash' } }, native: {} }); + setObject(idAliasPanelVerzeichnis + '.' + idAliasAbfallVerzeichnis + '.event' + String(i), { type: 'channel', common: { role: 'warning', name: { de: 'Ereignis ' + String(i), en: 'Event' + String(i) } }, native: {} }); + await createAliasAsync(idAliasPanelVerzeichnis + '.' + idAliasAbfallVerzeichnis + '.event' + String(i) + '.TITLE', idUserdataAbfallVerzeichnis + '.' + String(i) + '.event', true, { type: 'string', role: 'weather.title.short', name: { de: 'TITEL', en: 'TITLE' } }); + await createAliasAsync(idAliasPanelVerzeichnis + '.' + idAliasAbfallVerzeichnis + '.event' + String(i) + '.LEVEL', idUserdataAbfallVerzeichnis + '.' + String(i) + '.color', true, { type: 'number', role: 'value.warning', name: { de: 'LEVEL', en: 'LEVEL' } }); + await createAliasAsync(idAliasPanelVerzeichnis + '.' + idAliasAbfallVerzeichnis + '.event' + String(i) + '.INFO', idUserdataAbfallVerzeichnis + '.' + String(i) + '.date', true, { type: 'string', role: 'weather.title', name: { de: 'INFO', en: 'INFO' } }); + log('Fertig', 'info') + } else { + log('Datenpunkt ' + idUserdataAbfallVerzeichnis + '.' + String(i) + ' vorhanden', 'info') + } + } + log('Startabfrage der Daten', 'info'); + JSON_auswerten(); + } catch (err) { + log('error at function Init_Datenpunkte: ' + err.message, 'warn'); + } +} +Init_Datenpunkte(); + +// --------------------------- Ende Funktion Datenpunkte ------------------------------------------------ + + +// --------------------------- Zusatzfuktionen ------------------------------------------------------------- +function currentDate() { + let d: Date = new Date(); + return new Date(d.getFullYear(), d.getMonth(), d.getDate()); +} + +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); +} + +function hex_rgb(colorhex: string): RGB { + let r = parseInt(colorhex.substring(1, 3), 16); + let g = parseInt(colorhex.substring(3, 5), 16); + let b = parseInt(colorhex.substring(5, 7), 16); + return { red: r, green: g, blue: b }; +} + +type RGB = { + red: number, + green: number, + blue: number +}; + +// -------------------- Ende Zudatzfunktionen -------------------------------------------------------------------------- diff --git a/ioBroker/Blockly/CardChart_History.js b/ioBroker/Blockly/CardChart_History.js new file mode 100644 index 00000000..2cc66fc0 --- /dev/null +++ b/ioBroker/Blockly/CardChart_History.js @@ -0,0 +1,50 @@ +var sourceDP = 'alias.0.Wohnzimmer.Heizung.ACTUAL'; +var targetDP = '0_userdata.0.Test.chartTest'; +var rangeHours = 24; +var maxXAchsisTicks = 6; +var historyInstance = 'history.0'; + +on({id: sourceDP, change: "any"}, async function (obj) { + sendTo(historyInstance, 'getHistory', { + id: sourceDP, + options: { + start: Date.now() - (60 * 60 * 1000 * rangeHours), + end: Date.now(), + count: rangeHours, + limit: rangeHours, + aggregate: 'average' + } + }, function (result) { + var cardChartString = ""; + var stepXAchsis = rangeHours / maxXAchsisTicks; + + for (var i = 0; i < rangeHours; i++){ + var deltaHour = rangeHours - i; + var targetDate = new Date(Date.now() - (deltaHour * 60 * 60 * 1000)); + + //Check history items for requested hours + for (var j = 0, targetValue = 0; j < result.result.length; j++) { + var valueDate = new Date(result.result[j].ts); + var value = (Math.round(result.result[j].val * 10) / 10); + + if (valueDate > targetDate){ + if ((targetDate.getHours() % stepXAchsis) == 0){ + cardChartString += targetValue + '^' + targetDate.getHours() + ':00' + '~'; + } else { + cardChartString += targetValue + '~'; + } + break; + } else { + targetValue = value; + } + } + } + + cardChartString = cardChartString.substring(0,cardChartString.length-1); + if (existsState(targetDP) == false ) { + createState(targetDP, cardChartString, true, { type: 'string' }); + } else { + setState(targetDP, cardChartString, true); + } + }); +}); \ No newline at end of file diff --git a/ioBroker/Blockly/CardLChart_History.js b/ioBroker/Blockly/CardLChart_History.js new file mode 100644 index 00000000..9f3d0dc3 --- /dev/null +++ b/ioBroker/Blockly/CardLChart_History.js @@ -0,0 +1,78 @@ +const sourceDP = 'alias.0.Wohnzimmer.Heizung.ACTUAL'; +const targetDP = '0_userdata.0.Test.chartTest'; +const numberOfHoursAgo = 24; // Period of time in hours which shall be visualized +const xAxisTicksEveryM = 60; // Time after x axis gets a tick in minutes +const xAxisLabelEveryM = 240; // Time after x axis is labeled in minutes +const historyInstance = 'history.0'; + +const Debug = false; +const maxX = 1420; +const limitMeasurements = 35; + +createState(targetDP, "", { + name: 'SensorGrid', + desc: 'Sensor Values [~