mirror of
https://github.com/joBr99/nspanel-lovelace-ui.git
synced 2025-12-19 14:14:12 +01:00
Script vom Wiki nach Github schieben
This commit is contained in:
@@ -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);
|
||||
}
|
||||
});
|
||||
224
ioBroker/Blockly/Abfallkalender.ts
Normal file
224
ioBroker/Blockly/Abfallkalender.ts
Normal file
@@ -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, <iobJS.StateCommon>{ type: 'string', role: 'weather.title.short', name: { de: 'TITEL', en: 'TITLE' } });
|
||||
await createAliasAsync(idAliasPanelVerzeichnis + '.' + idAliasAbfallVerzeichnis + '.event' + String(i) + '.LEVEL', idUserdataAbfallVerzeichnis + '.' + String(i) + '.color', true, <iobJS.StateCommon>{ type: 'number', role: 'value.warning', name: { de: 'LEVEL', en: 'LEVEL' } });
|
||||
await createAliasAsync(idAliasPanelVerzeichnis + '.' + idAliasAbfallVerzeichnis + '.event' + String(i) + '.INFO', idUserdataAbfallVerzeichnis + '.' + String(i) + '.date', true, <iobJS.StateCommon>{ 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 --------------------------------------------------------------------------
|
||||
50
ioBroker/Blockly/CardChart_History.js
Normal file
50
ioBroker/Blockly/CardChart_History.js
Normal file
@@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
78
ioBroker/Blockly/CardLChart_History.js
Normal file
78
ioBroker/Blockly/CardLChart_History.js
Normal file
@@ -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 [~<time>:<value>]*',
|
||||
type: 'string',
|
||||
role: 'value',
|
||||
});
|
||||
|
||||
on({id: sourceDP, change: "any"}, async function (obj) {
|
||||
sendTo(historyInstance, 'getHistory', {
|
||||
id: sourceDP,
|
||||
options: {
|
||||
start: Date.now() - (numberOfHoursAgo * 60 * 60 * 1000 ), //Time in ms: hours * 60m * 60s * 1000ms
|
||||
end: Date.now(),
|
||||
count: limitMeasurements,
|
||||
limit: limitMeasurements,
|
||||
aggregate: 'average'
|
||||
}
|
||||
}, function (result) {
|
||||
var ticksAndLabels = ""
|
||||
var coordinates = "";
|
||||
var cardLChartString = "";
|
||||
|
||||
let ticksAndLabelsList = []
|
||||
var date = new Date();
|
||||
date.setMinutes(0, 0, 0);
|
||||
var ts = Math.round(date.getTime() / 1000);
|
||||
var tsYesterday = ts - (numberOfHoursAgo * 3600);
|
||||
|
||||
for (var x = tsYesterday, i = 0; x < ts; x += (xAxisTicksEveryM * 60), i += xAxisTicksEveryM)
|
||||
{
|
||||
if (i % xAxisLabelEveryM)
|
||||
{
|
||||
ticksAndLabelsList.push(i);
|
||||
} else
|
||||
{
|
||||
var currentDate = new Date(x * 1000);
|
||||
// Hours part from the timestamp
|
||||
var hours = "0" + currentDate.getHours();
|
||||
// Minutes part from the timestamp
|
||||
var minutes = "0" + currentDate.getMinutes();
|
||||
// Seconds part from the timestamp
|
||||
var seconds = "0" + currentDate.getSeconds();
|
||||
var formattedTime = hours.slice(-2) + ':' + minutes.slice(-2);
|
||||
ticksAndLabelsList.push(String(i) + "^" + formattedTime);
|
||||
}
|
||||
}
|
||||
ticksAndLabels = ticksAndLabelsList.join("+");
|
||||
|
||||
let list = [];
|
||||
let offSetTime = Math.round(result.result[0].ts / 1000);
|
||||
let counter = Math.round((result.result[result.result.length -1 ].ts / 1000 - offSetTime) / maxX);
|
||||
for (var i = 0; i < result.result.length; i++)
|
||||
{
|
||||
var time = Math.round(((result.result[i].ts / 1000) - offSetTime) / counter);
|
||||
var value = Math.round(result.result[i].val * 10);
|
||||
if ((value != null) && (value != 0)){
|
||||
list.push(time + ":" + value)
|
||||
}
|
||||
}
|
||||
|
||||
coordinates = list.join("~");
|
||||
cardLChartString = ticksAndLabels + '~' + coordinates
|
||||
setState(targetDP, cardLChartString, true);
|
||||
|
||||
if (Debug) console.log(cardLChartString);
|
||||
});
|
||||
});
|
||||
54
ioBroker/Blockly/CardPower.js
Normal file
54
ioBroker/Blockly/CardPower.js
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* generate an JSON for display Power-Card on NSPanel
|
||||
* Source: https://github.com/joBr99/nspanel-lovelace-ui/wiki/ioBroker-Card-Definitionen-(Seiten)#cardpower-ab-ts-script-v341
|
||||
* Version: 0.1 - L4rs
|
||||
*/
|
||||
schedule("* * * * *", function () {
|
||||
|
||||
// Definition der Datenpunkte für das JSON der POWER-Card und der anzuzeigenden Leistungswerte
|
||||
var powerCardJson = "0_userdata.0.NSPanel.Energie.PowerCard",
|
||||
pwr1 = "", // Batterie
|
||||
pwr2 = Math.round(getState("mqtt.0.SmartHome.Energie.PV.openDTU.114180710360.0.power").val), // Solar
|
||||
pwr3 = "", // Wind
|
||||
pwr4 = "", // Verbraucher
|
||||
pwr5 = Math.round(getState("hm-rpc.0.MEQ0706303.1.POWER").val), // Stromnetz
|
||||
pwr6 = 0, // Auto
|
||||
pwrHome = Math.round(pwr5 - pwr2); // Berechnung des Energiefluss anstelle eines Datenpunktes
|
||||
|
||||
// Definition der Keys im JSON
|
||||
var keys = ["id", "value", "unit", "icon", "iconColor", "speed"];
|
||||
|
||||
// Definition der "Kacheln", inkl. StandardIcon. Es können alle Icon aus dem Iconmapping genutzt werden.
|
||||
// Kacheln die nicht genutzt werden sollen, müssen wie z.b. item1 formatiert sein
|
||||
var home = [0, pwrHome, "W", "home-lightning-bolt-outline", 0]; // Icon home
|
||||
var item1 = [1, pwr1, "", "", 0, ""]; // Icon battery-charging-60
|
||||
var item2 = [2, pwr2, "W", "solar-power-variant-outline", 3, pwr2 > 0 ? -2 : 0]; // Icon solar-power-variant
|
||||
var item3 = [3, pwr3, "", "", 0, ""]; // Icon wind-turbine
|
||||
var item4 = [4, pwr4, "", "", 0, ""]; // Icon shape
|
||||
var item5 = [5, pwr5, "W", "transmission-tower", 10, 10]; // Icon transmission-tower
|
||||
var item6 = [6, pwr6, "kW", "car-electric-outline", 5, 0]; // Icon car
|
||||
|
||||
/**
|
||||
* JSON generieren und in den Datenpunkt schreiben,
|
||||
*
|
||||
* --- ab hier keine Änderungen mehr ---
|
||||
*/
|
||||
function func(tags, values) {
|
||||
return Object.assign(
|
||||
...tags.map((element, index) => ({ [element]: values[index] }))
|
||||
);
|
||||
}
|
||||
|
||||
setState(
|
||||
powerCardJson,
|
||||
JSON.stringify([
|
||||
func(keys, home),
|
||||
func(keys, item1),
|
||||
func(keys, item2),
|
||||
func(keys, item3),
|
||||
func(keys, item4),
|
||||
func(keys, item5),
|
||||
func(keys, item6),
|
||||
])
|
||||
);
|
||||
});
|
||||
109
ioBroker/Blockly/CradLChart_Influx2.js
Normal file
109
ioBroker/Blockly/CradLChart_Influx2.js
Normal file
@@ -0,0 +1,109 @@
|
||||
const Debug = false;
|
||||
|
||||
const NSPanel_Path = '0_userdata.0.NSPanel.1.';
|
||||
const Path = NSPanel_Path + 'Influx2NSPanel.cardLChart.';
|
||||
const InfluxInstance = 'influxdb.1';
|
||||
const influxDbBucket = 'iobroker';
|
||||
const numberOfHoursAgo = 24;
|
||||
const xAxisTicksEveryM = 60;
|
||||
const xAxisLabelEveryM = 240;
|
||||
|
||||
// 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<string, string> = {};
|
||||
/* ↓ 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';
|
||||
|
||||
// create data source for NsPanel on script startup
|
||||
Object.keys(sensors).forEach(async x => {
|
||||
await generateDateAsync(x, sensors[x]);
|
||||
});
|
||||
|
||||
// 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]);
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 [~<time>:<value>]*',
|
||||
type: 'string',
|
||||
role: 'value',
|
||||
});
|
||||
} else {
|
||||
await setStateAsync(id, value, ack);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user