NEWS
FlexCharts + Viessmann WP + COP + Energien
-
in Arbeit ..
Vorhaben
Die Viessmann Wärmepumpen liefern Monatsübersichten für primäre und erzeugte Energien getrennt für Warmwasser und Heizung. Aus diesen Daten werden zwei Diagramme erzeugt ..
- Energiediagramme für Warmwasser, Heizen, elektrisch (primär) und erzeugt (generiert)
- COP-Werte für Warmwasser, Heizen und gesamt
- Über zwei DropDown-Widgets können beliebige Jahre und Monate ausgewählt werden.
Es ergibt sich am Ende folgende Darstellung ..
Ressourcen
Die Monatswerte werden aus der Wärmepumpe entnommen und als JSON in den Objekt gespeichert. Die Datenpunkte genHeizen, genWasser, primHeizen, primWasser enthalten die Energiewerte für den gewählten Monat. Die auf diese Weise über die Jahre gesammelten Daten können jederzeit aufgerufen und eingesehen werden.
Die zuletzt aufgeführten Datenpunkte sind zur Steuerung notwendig. Im Einzelnen sind dies ..
- htmlChart : Aktualisierungszeit der iFrame-Widgets in ms.
- listMonth : Liste aller Monate des ausgewählten Jahres
- listYear : Liste der verfügbaren Jahre
- selMonth : ausgewählter Monat (s. DropDown-Widget für Monate)
- selYear : ausgewähltes Jahr (DropDown-Widget)
Widgets
DropDown-Widgets
Das Skript, welches zur Steuerung der Charts eingesetzt wird, besteht aus zwei Teilen: im ersten werden die Funktionen COPs (Diagramm mit COP-Werten) und Energies (Energiewerte) definiert, im zweiten die Steuerungselemente.
1. Teil ..
//COP-DIAGRAMM: COP-Werte berechnen und Datenreihen des Diagramms damit befüllen function COPs() { let selYear = getState('0_userdata.0.Heizung.MonatsTabellen.selYear').val let selMonth = getState('0_userdata.0.Heizung.MonatsTabellen.selMonth').val let Chart = JSON.parse(getState('0_userdata.0.FlexCharts.Test_Chart').val) let srcWP = JSON.parse(getState(`0_userdata.0.Heizung.MonatsTabellen.${selYear}.${selMonth}.primWasser`).val); let srcHP = JSON.parse(getState(`0_userdata.0.Heizung.MonatsTabellen.${selYear}.${selMonth}.primHeizen`).val); let srcWG = JSON.parse(getState(`0_userdata.0.Heizung.MonatsTabellen.${selYear}.${selMonth}.genWasser`).val); let srcHG = JSON.parse(getState(`0_userdata.0.Heizung.MonatsTabellen.${selYear}.${selMonth}.genHeizen`).val); //Titelzeile des Diagramms setzen Chart.title.text = `COP-Werte im ${selMonth} ${selYear}` //x-Achse mit den Tagen des laufenden Monats füllen Chart.xAxis[0].data = [] //new Array(srcWP.length).fill(0) for (let j=0; j<srcWP.length; j++) { Chart.xAxis[0].data.push(j+1) } //Datenreihen des Diagramms leeren for (let i=0; i<3; i++) { Chart.series[i].data = [] } //Datenreihen mit den Energiewerten befüllen for (let i=0; i<srcWP.length; i++) { //COP für Warmwasser if (srcWP[i] > 0) { Chart.series[0].data.push((srcWG[i] / srcWP[i]).toFixed(1)) } else { Chart.series[0].data.push(0) } //COP für Heizen if (srcHP[i] > 0) { Chart.series[1].data.push((srcHG[i] / srcHP[i]).toFixed(i)) } else { Chart.series[1].data.push(0) } //gesamter COP (Warmwasser und Heizen) if (srcWP[i] + srcHP[i] > 0) {c Chart.series[2].data.push(((srcWG[i] + srcHG[i]) / (srcWP[i] + srcHP[i])).toFixed(1)) } else { Chart.series[2].data.push(0) } } //COP-Chart im Objektbaum von ioBroker ablegen setState('0_userdata.0.FlexCharts.Test_Chart',JSON.stringify(Chart),true) } //ENERGIEDIAGRAMM: Energiewerte ermitteln und Datenreihen des Diagramms damit befüllen function Energies() { let selYear = getState('0_userdata.0.Heizung.MonatsTabellen.selYear').val let selMonth = getState('0_userdata.0.Heizung.MonatsTabellen.selMonth').val let Chart = JSON.parse(getState('0_userdata.0.FlexCharts.Test_Chart_2').val) Chart.title.text = `Energiewerte Wasser&Heizen im ${selMonth} ${selYear}` let srcWP = JSON.parse(getState(`0_userdata.0.Heizung.MonatsTabellen.${selYear}.${selMonth}.primWasser`).val); let srcHP = JSON.parse(getState(`0_userdata.0.Heizung.MonatsTabellen.${selYear}.${selMonth}.primHeizen`).val); let srcWG = JSON.parse(getState(`0_userdata.0.Heizung.MonatsTabellen.${selYear}.${selMonth}.genWasser`).val); let srcHG = JSON.parse(getState(`0_userdata.0.Heizung.MonatsTabellen.${selYear}.${selMonth}.genHeizen`).val); //x-Achse mit den Tagen des laufenden Monats füllen //Chart.xAxis[0].data = new Array(srcWP.length).fill(0) Chart.xAxis[0].data = [] for (let j=0; j<srcWP.length; j++) { Chart.xAxis[0].data.push(j+1) } Chart.series[0].data = srcWP //Warmwasser primär Chart.series[1].data = srcWG //Warmwasser erzeugt Chart.series[2].data = srcHP //Heizung primär Chart.series[3].data = srcHG //Heizung erzeugt for (let i=0; i<srcWP.length; i++) { Chart.series[5].data[i] = (srcWG[i] + srcHG[i]).toFixed(1) //generierte Gesamtenergie Chart.series[4].data[i] = (srcWP[i] + srcHP[i]).toFixed(1) //primäre Gesamtenergie } //Chart als JSON im Objektbaum von ioBroker ablegen setState('0_userdata.0.FlexCharts.Test_Chart_2',JSON.stringify(Chart),true) }
2. Teil ..
Zur Auswahl der Jahre bzw. Monate werden DropDown-Widgets verwendet. Hierbei werden deren Datenfelder nicht statisch eingetragen, sondern mittels Binding aus oben aufgeführten Datenpunkten entnommen. Die Werteliste für die Jahre und Monate werden per Skript aus den Objekten in ioBroker dynamisch ermittelt. Hierzu wird die function listEntries(..) verwendet, die alle Verzeichnisse im übergebenen Pfadverzeichnis (parentPath) liefert. Sie wird sowohl zum Auffinden der Jahre- als auch Monatsverzeichnisse verwendet.
Über zwei Trigger werden bei Änderungen der DropDown-Widgets deren Listeneinträge aus dem Objektbaum von ioBroker bzw. die darzustellenden Charts aktualisiert.
function listEntries(parentPath) { let Elemente = []; //Pfadlänge parentPath let maxSplit = parentPath.split('.').length + 1 $(`${parentPath}.*`).each(function(id) { let arr = id.split('.',maxSplit+1) let child = id.split('.',maxSplit).join('.') if (!Elemente.includes(arr[maxSplit-1]) && (getObject(child).type === 'folder')) { Elemente.push(arr[maxSplit-1]); } }); return Elemente; } //listMonth des zugehörigen DropDown-Widgets füllen function listMonthYear() { let year = getState('0_userdata.0.Heizung.MonatsTabellen.selYear').val let parentFolder = `0_userdata.0.Heizung.MonatsTabellen.${year}`; let entries = listEntries(parentFolder); //Monatsnamen in die richtige Reihenfolge bringen let Months = ['Januar', 'Februar', 'Maerz', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'] let listMonth = [] Months.forEach(function(eintrag) { if (entries.includes(eintrag)) { listMonth.push(eintrag) } }) //DropDown-Widget der Monate befüllen setState('0_userdata.0.Heizung.MonatsTabellen.listMonth',listMonth.join(';'),true) } //Beim Start des Skripts wird das DropDown-Widget für die Jahre gefüllt. let parentFolder = '0_userdata.0.Heizung.MonatsTabellen'; let entries = listEntries(parentFolder); entries.sort setState('0_userdata.0.Heizung.MonatsTabellen.listYear',entries.join(';'),true) //Bei Auswahl des Jahres muss das DropDown-Widget für die Monate aktualisiert werden on({id: '0_userdata.0.Heizung.MonatsTabellen.selYear', change: 'any'}, function() { listMonthYear() setState('0_userdata.0.Heizung.MonatsTabellen.selMonth','') }); //Bei Auswahl eines Monats im DropDown-Widget werden COP- und Energie-Diagramm neu aufgebaut on({id: '0_userdata.0.Heizung.MonatsTabellen.selMonth', change: 'any'}, function(obj) { COPs() Energies() setState('0_userdata.0.Heizung.MonatsTabellen.htmlChart',1000,true) setTimeout(() => {setState('0_userdata.0.Heizung.MonatsTabellen.htmlChart',300000,true),1000}) });
iFrame-Widgets
Zur Anzeige der Monatswerte werden iFrame-Widgets verwendet.
- Quelle : Hier wird der für FlexCharts überliche HTML-Aufruf eingetragen, der die Referenz zu dem Datenpunkt enthält, in dem das Chart als JSON abgelegt ist.
- Updatezeit(ms) : Diese wird nicht statisch eingetragen, sondern mittels Binding aus dem Objektbaum von ioBroker (s. oben: htmlChart) entnommen.
Anm.: Üblicherweise sollte sich ein Widget aktualisieren, wenn seine Quelle sich ändert. Dies funktioniert offenbar bei iFrames leider nicht. Daher wird sozusagen ein Kunstgriff verwendet: Immer dann, wenn sich das DropDown-Widget für den Monat ändert, wird in den iFrames die Updatezeit neu auf den gewünschten Wert gesetzt. Hierdurch aktualisiert sich das iFrame unmittelbar neu.
-
@legro Danke für den Tipp mit dem Refresh. Klappt super!
-
Es geht noch kürzer. Es reicht einfach die gewünschte Update-Zeit (htmlChart) neu zu schreiben.
on({ id: '0_userdata.0.FlexCharts.refresh', change: 'any' }, () => { setState('0_userdata.0.Heizung.MonatsTabellen.htmlChart', 3000000, true); });
Dieser Code sorgt dafür, dass das Diagramm unmittelbar neu aufgebaut werden.
-
@legro Also quasi bei jeder Änderung einfach nur den DP, wo das Intervall steht, neu schreiben? Cool! Danke!
-
Ja, so einfach geht‘s.