mirror of
https://github.com/joBr99/nspanel-lovelace-ui.git
synced 2026-01-02 12:54:19 +01:00
Merge branch 'joBr99:main' into main
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);
|
||||
}
|
||||
}
|
||||
@@ -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,10 @@ 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'
|
||||
- 28.01.2024 - v4.3.3.39 Fix: ack for read-only state
|
||||
|
||||
|
||||
Todo:
|
||||
@@ -972,7 +974,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 +988,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');
|
||||
@@ -3166,9 +3170,9 @@ function findPageItem(searching: String): PageItem {
|
||||
function GeneratePage(page: PageType): void {
|
||||
try {
|
||||
activePage = page;
|
||||
setIfExists(NSPanel_Path + 'ActivePage.type', activePage.type);
|
||||
setIfExists(NSPanel_Path + 'ActivePage.heading', activePage.heading);
|
||||
setIfExists(NSPanel_Path + 'ActivePage.id0', activePage.items[0] !== undefined ? activePage.items[0].id : '');
|
||||
setIfExists(NSPanel_Path + 'ActivePage.type', activePage.type, null, true);
|
||||
setIfExists(NSPanel_Path + 'ActivePage.heading', activePage.heading, null, true);
|
||||
setIfExists(NSPanel_Path + 'ActivePage.id0', activePage.items[0] !== undefined ? activePage.items[0].id : '', null, true);
|
||||
switch (page.type) {
|
||||
case 'cardEntities':
|
||||
SendToPanel(GenerateEntitiesPage(page));
|
||||
@@ -3242,7 +3246,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;
|
||||
@@ -6179,7 +6189,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!`)
|
||||
}
|
||||
@@ -6224,17 +6234,17 @@ function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] {
|
||||
}
|
||||
}
|
||||
|
||||
function setIfExists(id: string, value: any, type: string | null = null): boolean {
|
||||
function setIfExists(id: string, value: any, type: string | null = null, ack: boolean = false): boolean {
|
||||
try {
|
||||
if (type === null) {
|
||||
if (existsState(id)) {
|
||||
setState(id, value);
|
||||
setState(id, value, ack);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
const obj = getObject(id);
|
||||
if (existsState(id) && obj.common.type !== undefined && obj.common.type === type) {
|
||||
setState(id, value);
|
||||
setState(id, value, ack);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -6312,10 +6322,10 @@ function HandleButtonEvent(words: any): void {
|
||||
alwaysOn = false;
|
||||
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');
|
||||
@@ -6505,7 +6515,7 @@ function HandleButtonEvent(words: any): void {
|
||||
if (Debug) log('NaviToPage: ' + words[2]);
|
||||
GeneratePage(indicatorScreensaverEntity.ScreensaverEntityNaviToPage);
|
||||
} else {
|
||||
const value = ['event','buttonPress2','screensaver','bExit',2];
|
||||
const value = ['event','buttonPress2','screensaver','bExit','2'];
|
||||
HandleButtonEvent(value);
|
||||
}
|
||||
}
|
||||
@@ -6546,6 +6556,7 @@ function HandleButtonEvent(words: any): void {
|
||||
case 'rgbSingle':
|
||||
case 'hue':
|
||||
toggleState(id + '.ON_ACTUAL');
|
||||
break;
|
||||
case 'media':
|
||||
if (!activePage || activePage.type != 'cardMedia') {
|
||||
if (activePage) throw new Error(`Found channel role media for card: ${activePage.type} not allowed`)
|
||||
@@ -7365,9 +7376,11 @@ function HandleButtonEvent(words: any): void {
|
||||
|
||||
function setOrCreate(id : string, value : any, forceCreation: boolean = true, common: Partial<iobJS.StateCommon> = { }, 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8488,9 +8501,9 @@ function UnsubscribeWatcher(): void {
|
||||
}
|
||||
|
||||
function HandleScreensaver(): void {
|
||||
setIfExists(NSPanel_Path + 'ActivePage.type', 'screensaver');
|
||||
setIfExists(NSPanel_Path + 'ActivePage.id0', 'screensaver');
|
||||
setIfExists(NSPanel_Path + 'ActivePage.heading', 'Screensaver');
|
||||
setIfExists(NSPanel_Path + 'ActivePage.type', 'screensaver', null, true);
|
||||
setIfExists(NSPanel_Path + 'ActivePage.id0', 'screensaver', null, true);
|
||||
setIfExists(NSPanel_Path + 'ActivePage.heading', 'Screensaver', null, true);
|
||||
if (existsObject(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced')) {
|
||||
if (getState(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced').val) {
|
||||
SendToPanel({ payload: 'pageType~screensaver2' });
|
||||
@@ -9049,7 +9062,7 @@ function HandleScreensaverStatusIcons() : void {
|
||||
} else {
|
||||
payloadString += '~';
|
||||
}
|
||||
|
||||
// statusUpdate~icon1~icon1Color~icon1font~icon2~icon2color~icon2font~icon2font
|
||||
SendToPanel({ payload: 'statusUpdate~' + payloadString });
|
||||
|
||||
} catch (err: any) {
|
||||
@@ -9903,6 +9916,7 @@ namespace NSPanel {
|
||||
|
||||
export type PageBaseType = {
|
||||
type: PagetypeType,
|
||||
uniqueName?: string,
|
||||
heading: string,
|
||||
items: PageItem[],
|
||||
useColor: boolean,
|
||||
@@ -10013,6 +10027,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,
|
||||
@@ -10070,6 +10086,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 = {
|
||||
|
||||
@@ -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,11 @@ 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
|
||||
- 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'
|
||||
- 28.01.2024 - v4.3.3.39 Fix: ack for read-only state
|
||||
|
||||
|
||||
Todo:
|
||||
- XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined
|
||||
@@ -971,7 +974,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;
|
||||
@@ -985,6 +988,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');
|
||||
@@ -3165,9 +3170,9 @@ function findPageItem(searching: String): PageItem {
|
||||
function GeneratePage(page: PageType): void {
|
||||
try {
|
||||
activePage = page;
|
||||
setIfExists(NSPanel_Path + 'ActivePage.type', activePage.type);
|
||||
setIfExists(NSPanel_Path + 'ActivePage.heading', activePage.heading);
|
||||
setIfExists(NSPanel_Path + 'ActivePage.id0', activePage.items[0] !== undefined ? activePage.items[0].id : '');
|
||||
setIfExists(NSPanel_Path + 'ActivePage.type', activePage.type, null, true);
|
||||
setIfExists(NSPanel_Path + 'ActivePage.heading', activePage.heading, null, true);
|
||||
setIfExists(NSPanel_Path + 'ActivePage.id0', activePage.items[0] !== undefined ? activePage.items[0].id : '', null, true);
|
||||
switch (page.type) {
|
||||
case 'cardEntities':
|
||||
SendToPanel(GenerateEntitiesPage(page));
|
||||
@@ -3241,7 +3246,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;
|
||||
@@ -6178,7 +6189,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!`)
|
||||
}
|
||||
@@ -6223,17 +6234,17 @@ function GenerateChartPage(page: NSPanel.PageChart): NSPanel.Payload[] {
|
||||
}
|
||||
}
|
||||
|
||||
function setIfExists(id: string, value: any, type: string | null = null): boolean {
|
||||
function setIfExists(id: string, value: any, type: string | null = null, ack: boolean = false): boolean {
|
||||
try {
|
||||
if (type === null) {
|
||||
if (existsState(id)) {
|
||||
setState(id, value);
|
||||
setState(id, value, ack);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
const obj = getObject(id);
|
||||
if (existsState(id) && obj.common.type !== undefined && obj.common.type === type) {
|
||||
setState(id, value);
|
||||
setState(id, value, ack);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -6312,6 +6323,10 @@ function HandleButtonEvent(words: any): void {
|
||||
SendToPanel({ payload: 'timeout~' + getState(NSPanel_Path + 'Config.Screensaver.timeoutScreensaver').val });
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
@@ -6500,7 +6515,7 @@ function HandleButtonEvent(words: any): void {
|
||||
if (Debug) log('NaviToPage: ' + words[2]);
|
||||
GeneratePage(indicatorScreensaverEntity.ScreensaverEntityNaviToPage);
|
||||
} else {
|
||||
const value = ['event','buttonPress2','screensaver','bExit',2];
|
||||
const value = ['event','buttonPress2','screensaver','bExit','2'];
|
||||
HandleButtonEvent(value);
|
||||
}
|
||||
}
|
||||
@@ -6541,6 +6556,7 @@ function HandleButtonEvent(words: any): void {
|
||||
case 'rgbSingle':
|
||||
case 'hue':
|
||||
toggleState(id + '.ON_ACTUAL');
|
||||
break;
|
||||
case 'media':
|
||||
if (!activePage || activePage.type != 'cardMedia') {
|
||||
if (activePage) throw new Error(`Found channel role media for card: ${activePage.type} not allowed`)
|
||||
@@ -7358,6 +7374,16 @@ function HandleButtonEvent(words: any): void {
|
||||
}
|
||||
}
|
||||
|
||||
function setOrCreate(id : string, value : any, forceCreation: boolean = true, common: Partial<iobJS.StateCommon> = { }, callback?: iobJS.SetStateCallback) {
|
||||
if (!existsState(id)) {
|
||||
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, true);
|
||||
}
|
||||
}
|
||||
|
||||
//Determination of page navigation (CustomSend-Payload)
|
||||
function GetNavigationString(pageId: number): string {
|
||||
try {
|
||||
@@ -8475,9 +8501,9 @@ function UnsubscribeWatcher(): void {
|
||||
}
|
||||
|
||||
function HandleScreensaver(): void {
|
||||
setIfExists(NSPanel_Path + 'ActivePage.type', 'screensaver');
|
||||
setIfExists(NSPanel_Path + 'ActivePage.id0', 'screensaver');
|
||||
setIfExists(NSPanel_Path + 'ActivePage.heading', 'Screensaver');
|
||||
setIfExists(NSPanel_Path + 'ActivePage.type', 'screensaver', null, true);
|
||||
setIfExists(NSPanel_Path + 'ActivePage.id0', 'screensaver', null, true);
|
||||
setIfExists(NSPanel_Path + 'ActivePage.heading', 'Screensaver', null, true);
|
||||
if (existsObject(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced')) {
|
||||
if (getState(NSPanel_Path + 'Config.Screensaver.ScreensaverAdvanced').val) {
|
||||
SendToPanel({ payload: 'pageType~screensaver2' });
|
||||
@@ -9036,7 +9062,7 @@ function HandleScreensaverStatusIcons() : void {
|
||||
} else {
|
||||
payloadString += '~';
|
||||
}
|
||||
|
||||
// statusUpdate~icon1~icon1Color~icon1font~icon2~icon2color~icon2font~icon2font
|
||||
SendToPanel({ payload: 'statusUpdate~' + payloadString });
|
||||
|
||||
} catch (err: any) {
|
||||
@@ -9890,6 +9916,7 @@ namespace NSPanel {
|
||||
|
||||
export type PageBaseType = {
|
||||
type: PagetypeType,
|
||||
uniqueName?: string,
|
||||
heading: string,
|
||||
items: PageItem[],
|
||||
useColor: boolean,
|
||||
@@ -10000,6 +10027,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,
|
||||
@@ -10057,6 +10086,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 = {
|
||||
|
||||
Reference in New Issue
Block a user