Visualisierung von Verbräuchen

Begonnen von Damian, 16 Dezember 2024, 18:38:14

Vorheriges Thema - Nächstes Thema

Damian

Hier mal ein etwas größeres Codeschnipsel zum Visualisieren von Verbräuchen.

Voraussetzung ist jeweils ein Zähler, der, was auch immer, kontinuierlich hochzählt.

Es reicht die Angabe des Readings (push-Zeile am Anfang und TPL_Single-Zeile am Ende des Codes für die Visualisierung) und schon werden die Daten stündlich, täglich, monatlich, jährlich und in Dekaden gesammelt und visualisiert.

Layout meiner Definition siehe Screenshot.

defmod di_counter_new DOIF subs {\
##                     Device        Reading          hier die push-Zeilen löschen bzw. durch eigene Readings ersetzen\
  push (@{$_counter},["MQTT2_DVES_C58DCB","total_w"]);; ## Wasserzähler\
  push (@{$_counter},["MQTT2_DVES_C58DCB","total_pv"]);; ## Solarenergie\
  push (@{$_counter},["MQTT2_DVES_C58DCB","total_c"]);; ## Bezugszähler\
  push (@{$_counter},["MQTT2_DVES_C58DCB","total_f"]);; ## Einspeisezähler\
  push (@{$_counter},["MQTT2_DVES_C58DCB","total_gas"]);; ## Gaszähler  \
  push (@{$_counter},["di_tibber","costsSum"]);; ## Stromkosten \
  push (@{$_counter},["MQTT2_DVES_C58DCB","total_consum"]);; ## Stromverbrauch positiv\
  push (@{$_counter},["HM_Sw1_Pl_2_Pwr","energyCalc"]);; ## Server\
   \
## Die restliche Code-Definition muss nicht angepasst werden\
## Anpassung der Visualisierung wird im uiTable-Attribut weiter unten vorgenommen\
\
sub hour { ## Diese Funktion wird zur vollen Stunde ausgeführt\
  my ($device,$reading,$mday,$yday)=@_;;\
  set_Reading ("$device.$reading.hour_counter",ReadingsVal($device, $reading,0));;   \
  set_Reading ("$device.$reading.last_hour",get_Reading("$device.$reading.hour",0),1);;\
  set_Reading ("$device.$reading.hour",0,1);;\
  set_Reading ("$device.$reading.day",int((ReadingsVal($device, $reading,0)-(get_Reading("$device.$reading.day_counter",0)))*1000)/1000,1);;\
\
}\
\
sub midnight { ## Diese Funktion wird um Mitternacht ausgeführt\
  my ($device,$reading,$mday,$yday)=@_;;\
  set_Reading("$device.$reading.day_counter",ReadingsVal($device, $reading,0));;   \
  set_Reading("$device.$reading.last_day",get_Reading("$device.$reading.day",0),1);;\
  set_Reading("$device.$reading.day",0,1);;\
  set_Reading ("$device.$reading.month",int((ReadingsVal($device, $reading,0)-(get_Reading("$device.$reading.month_counter",0)))*1000)/1000,1);;\
  set_Reading ("$device.$reading.year",int((ReadingsVal($device, $reading,0)-(get_Reading("$device.$reading.year_counter",0)))*1000)/1000,1);;\
\
  if ($mday == 1) {\
    set_Reading("$device.$reading.month_counter",ReadingsVal($device, $reading,0));;\
    set_Reading("$device.$reading.last_month",get_Reading("$device.$reading.month",0),1);;\
    set_Reading("$device.$reading.month",0,1);;\
    if ($yday == 0) {\
      set_Reading("$device.$reading.year_counter",ReadingsVal($device, $reading,0));;\
      set_Reading("$device.$reading.last_year",get_Reading("$device.$reading.year",0),1);;\
      set_Reading("$device.$reading.year",0,1);;\
    }\
  }\
}\
\
sub init_readings {\
  my ($device,$reading)=@_;;\
  if (get_Reading("$device.$reading.day_counter","") eq "") {   ## Initialisierung der Readings\
    ## aktuellen Zählerstand initialisieren\
    set_Reading("$device.$reading.last_counter",ReadingsVal($device, $reading,0));;\
    set_Reading("$device.$reading.hour_counter",ReadingsVal($device, $reading,0));;\
    set_Reading("$device.$reading.day_counter",ReadingsVal($device, $reading,0));; \
    set_Reading("$device.$reading.month_counter",ReadingsVal($device, $reading,0));;\
    set_Reading("$device.$reading.year_counter",ReadingsVal($device, $reading,0));;\
  \
    set_Reading ("$device.$reading.hour",0);;          ## aktueller Stundenverbrauch\
    set_Reading ("$device.$reading.day",0);;           ## aktueller Tagesverbrauch\
    set_Reading ("$device.$reading.month",0);;         ## aktueller Monatsverbrauch\
    set_Reading ("$device.$reading.year",0);;          ## aktueller Jahresverbrauch\
    set_Reading ("$device.$reading.last_hour",0);;      ## Verbrauch der letzten Stunde\
    set_Reading ("$device.$reading.last_day",0);;      ## Verbrauch des letzten Tages\
    set_Reading ("$device.$reading.last_month",0);;    ## Verbrauch des letzten Monats\
    set_Reading ("$device.$reading.last_year",0);;     ## Verbrauch des letzten Jahres\
## Log definieren\
    fhem ("defmod log.counter.$device.$reading FileLog ./log/counter.$device.$reading.log $SELF:$device.$reading.last_.*");;\
    fhem ("attr log.counter.$device.$reading room Filelogs");;\
  }\
}\
\
} ## Ende subs-Block\
\
get_data {                             ## Optionale Übernahme bestehender Daten aus dem Log\
for (my $i=0;;$i<@{$_counter};;$i++) \
{ ## my $i=3;;\
      ::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_hour","bar2day",-10,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_hour"));;\
    ::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_day","bar2month",-300,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_day"));;\
    ::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_month","bar2year",-300,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_month"));;\
::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_year","bar2decade",-300,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_year"));;\
}\
}\
\
\
hour {[:00];;                            ## Sicherung der Daten der letzten Stunde\
  for (my $i=0;;$i<@{$_counter};;$i++) { ## Für jeden Zähler wird die Funktion hour aufgerufen\
    hour($_counter[$i][0],$_counter[$i][1],$mday,$yday);;\
  }\
}\
\
\
\
midnight {[00:01];;                          ## Sicherung der Daten um Mitternacht\
  for (my $i=0;;$i<@{$_counter};;$i++) { ## Für jeden Zähler wird die Funktion midnight aufgerufen\
    midnight($_counter[$i][0],$_counter[$i][1],$mday,$yday);;\
  }\
}\
\
init {                                ## initialisierung aller Readings\
  for (my $i=0;;$i<@{$_counter};;$i++) {## Für jeden Zähler werden Readings über die Funktion init_readings initialisiert\
    init_readings($_counter[$i][0],$_counter[$i][1]);;\
  }\
}\
\
DEF TPL_stat (\
  day_count_$1_$2 { ## bei einem Event des Zählers, wird der Verbrauch der Stunde im jeweiligen Reading festgehalten\
                    ##  $1 Zählerdevice, $2 Zählerreading\
\
      set_Reading ("$1.$2.last_counter",[$1:$2,0]);;\
      set_Reading ("$1.$2.hour",int(([$1:$2,0]-(get_Reading("$1.$2.hour_counter",0)))*1000)/1000,1);;\
  }\
)\
\
## Pro Zähler wird über eine FOR-Schleife ein day_count_<Device>_<Reading>-Block generiert\
FOR(@{$_counter},TPL_stat($1$1,$1$2)) ## $1$1 entspricht dem Device, $1$2 entspricht dem Reading
attr di_counter_new room Verbrauch
attr di_counter_new uiTable {package ui_Table;;} ## Optionale Visualisierung der Energie-Verbräuche/-Produktion im DOIF-Device\
\
## Template für die Darstellung eines Wertes, einzelne card-Aufrufe können auskommentiert werden\
DEF TPL_single (\
##card([$SELF:$2.$3.day:col1w],"$1",undef,$4,$5,$10,$11,"$12",undef,"1","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")| Wochendarstellung\
card([[$SELF:$2.$3.last_hour:bar2day-10],[$SELF:$2.$3.hour]],"$1 in $12/h",undef,$4/12,$5/12,$10,$11,["letzte","aktuell"],undef,"2","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")|\
card([[$SELF:$2.$3.last_day:bar2month-300],[$SELF:$2.$3.day]],"$12/Tag",undef,$4,$5,$10,$11,["letzter","aktuell"],undef,"1","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")|\
card([[$SELF:$2.$3.last_month:bar2year-300],[$SELF:$2.$3.month]],"$12/Monat",undef,$6,$7,$10,$11,["letzter","aktuell"],undef,"0","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")|\
card([[$SELF:$2.$3.last_year:bar2decade-300],[$SELF:$2.$3.year]],"$12/Jahr",undef,$8,$9,$10,$11,["letzter","aktuell"],undef,"0","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")\
)\
\
## Template für die Darstellung von zwei Werten, einzelne card-Aufrufe können auskommentiert werden\
DEF TPL_double (\
##card([[$SELF:$3.$4.day:col1w],[$SELF:$6.$7.day:col1w]],"$1",undef,$8,$9,$14,$15,["$2","$5"],undef,"1","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")| Wochendarstellung\
card([[$SELF:$3.$4.last_hour:bar2day-10],[$SELF:$6.$7.last_hour:bar2day-10],[$SELF:$3.$4.hour],[$SELF:$6.$7.hour]],"$1/h",undef,$8/12,$9/12,$14,$15,["$2","$5","$2","$5"],undef,"2","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")|\
card([[$SELF:$3.$4.last_day:bar2month-300],[$SELF:$6.$7.last_day:bar2month-300],[$SELF:$3.$4.day],[$SELF:$6.$7.day]],"pro Tag",undef,$8,$9,$14,$15,["$2","$5","$2","$5"],undef,"1","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")|\
card([[$SELF:$3.$4.last_month:bar2year-300],[$SELF:$6.$7.last_month:bar2year-300],[$SELF:$3.$4.month],[$SELF:$6.$7.month]],"pro Monat",undef,$10,$11,$14,$15,["$2","$5","$2","$5"],undef,"0","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")|\
card([[$SELF:$3.$4.last_year:bar2decade-300],[$SELF:$6.$7.last_year:bar2year-300],[$SELF:$3.$4.year],[$SELF:$6.$7.year]],"pro Jahr",undef,$12,$13,$14,$15,["$2","$5","$2","$5"],undef,"0","130,fixedscaling,,footer,noycolor,noring,220","0,0,0,0,2")\
)\
\
\
## Die Visualisierung einer Tabellenzeile wird über die obigen beiden Templates vorgenommen, hier zeilenweise anpassen/löschen:\
\
## Über das Template TPL_single wird jeweils pro card ein Wert visualisiert\
##          Überschrift,Device,Reading,minTag,maxTag,minMonat,maxMonat,minJahr,maxJahr,minColor,maxColor,Einheit\
TPL_single (Frischwasser,MQTT2_DVES_C58DCB,total_w,0,500,0,10000,0,80000,90,0,Liter)\
TPL_single (Gas,MQTT2_DVES_C58DCB,total_gas,0,10,0,250,0,2000,90,0,m³)\
TPL_single (PV,MQTT2_DVES_C58DCB,total_pv,0,30,0,600,0,5000,0,90,kWh)\
TPL_single (Einspeisung,MQTT2_DVES_C58DCB,total_f,0,30,0,600,0,5000,0,90,kWh)\
TPL_single (Bezug,MQTT2_DVES_C58DCB,total_c,-10,0,-300,0,-3000,0,0,90,kWh)\
TPL_single (Verbrauch,MQTT2_DVES_C58DCB,total_consum,-10,0,-300,0,-3000,0,0,90,kWh)\
TPL_single (Stromkosten,di_tibber,costsSum,0,4,0,90,0,1200,90,0,€)\
TPL_single (Server,HM_Sw1_Pl_2_Pwr,energyCalc,0,500,0,15000,0,30000,90,0,Wh)\
\
## Über das Template TPL_double werden jeweils pro card zwei Werte visualisiert\
##       Überschrift,Bezeichnung1,Device1,Reading1,Bezeichnung2,Device2,Reading2,minTag,maxTag,minMonat,maxMonat,minJahr,maxJahr,minColor,maxColor,Einheit\
##TPL_double (Heizenergie,Gesamt,vaillant,total_h,Wasser,vaillant,total_hwc,0,100,0,2000,0,20000,90,0,kWh)\
##TPL_double (Stromeinspeisung/Strombezug,Bezug,MQTT2_DVES_C58DCB,total_c,Einsp.,MQTT2_DVES_C58DCB,total_f,-10,25,-300,600,-3000,5000,0,90,kWh)
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

privat58

Vielen Dank dafür, habe es als uiState genutzt um es im Floorplan darzustellen.
Eine Frage wäre nur, kann man die Farben rot und Grün vertauschen? Geringer Verbrauch grün, hoher Verbrauch rot.
Mit der Wiki tue ich mich etwas schwer, programmieren ist mehr "probieren" bei mir.
Dank erst einmal.

Damian

Zitat von: privat58 am 14 Januar 2025, 20:13:25Vielen Dank dafür, habe es als uiState genutzt um es im Floorplan darzustellen.
Eine Frage wäre nur, kann man die Farben rot und Grün vertauschen? Geringer Verbrauch grün, hoher Verbrauch rot.
Mit der Wiki tue ich mich etwas schwer, programmieren ist mehr "probieren" bei mir.
Dank erst einmal.

ja, das ist ja auch im Codeschnipsel vorgesehen:

##          Überschrift,Device,Reading,minTag,maxTag,minMonat,maxMonat,minJahr,maxJahr,minColor,maxColor,Einheit\
TPL_single (Frischwasser,MQTT2_DVES_C58DCB,total_w,0,500,0,10000,0,80000,90,0,Liter)

da musst du nur die beiden Zahlen vertauschen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

privat58

Vielen lieben Dank,
da sieht man es wieder mal: "Wer lesen kann ist klar im Vorteil" :-)
Ich hatte es nicht registriert.
mvh

cotecmania

Hallo Damian,

Danke dafür !

2 Fragen :
- Wenn ich das DOIF "di_counter_new" mit "rename" umbenenne, wird nichts mehr dargestellt. Benenne ich es wieder zurück gehts wieder.
  Wie kann ich es umbenennen ?
- Wie kann ich die Werte skalieren ? Ich habe als Reading Wh und möchte aber KWh im Diagramm darstellen also Werte/1000.
  Geht das ?

Gruss
Joe
FHEM auf RaspberryPI B (buster)
2xCUL868 für MAX/Slow_RF, HM-LAN, JeeLink
MAX!/HM-Thermostate, FS20/HM-Rolladenschalter, FS20-EM, LevelJet-Ölstandsmessung, PCA301, IT, KM271, IPCAM, FireTAB10 FTUI

Damian

Ich würde das DOIF-Device auf ein neues kopieren, das alte deaktivieren, das neue mit gewünschten eigenen Readings anpassen und starten. Wenn es nicht funktioniert, dann sind möglicherweise noch irgendwelche interne Bezüge zum alten drin, dann FHEM durchstarten (das alte muss deaktiviert sein)

Wenn du Werte skalieren willst, dann würde ich mir im ursprünglichen Device ein user-Reading definieren und dieses dann im DOIF-Device angeben.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

cotecmania

Danke, werde ich testen ...

Das heisst ich darf/kann keine 2 oder mehr Devices dieser Art in FHEM anlegen ?
Dann habe ich ja die komplette Visualisierung in einem Device.
Dachte ich könnte eins anlegen für Solar, eins für die Steckdosen, etc ...
FHEM auf RaspberryPI B (buster)
2xCUL868 für MAX/Slow_RF, HM-LAN, JeeLink
MAX!/HM-Thermostate, FS20/HM-Rolladenschalter, FS20-EM, LevelJet-Ölstandsmessung, PCA301, IT, KM271, IPCAM, FireTAB10 FTUI

Damian

Das geht schon, du kannst in di_counter nur die Werte sammeln und in anderen DOIF-Devices die Darstellung über card vornehmen. Strom und Gas kommen aus di_counter, siehe Anhang.

Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

satprofi

Frage zu den Images, kann man das in FTUI3 auch visualisieren?
Schaut schon toll aus.
gruss
-----------------------------------------------------------------------
beelink miniPC - Fhem 6.x CUL 868, FS20, NetIO230 CUL 433
HMLAN, HM-CC-RT-DN,Homematic Actoren,LD382A,Telegram

Damian

Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

rinaldos

Guten Morgen Damian,

ist es möglich im Bereich DEF_TPL_single die tägliche Visualisierung im Monat, so umzustellen, dass mir nicht mehr der vergangene Tag (1...31) angezeigt wird.

Ich vermute mal, es betrifft diese Zeile:
card([[$SELF:$2.$3.last_day:bar2month-300],[$SELF:$2.$3.day]],"$12/Tag",undef,$4,$5,$10,$11,["letzter","aktuell"],undef,"1","130,fixedscaling,,footer,noycolor,halfring,220","0,0,0,0,2")

Sobald ich bar2month auf bar1month setze, wird kein Balken mehr angezeigt. Ich bin auch schon durch dein WIKI vom uiTable gegangen und habe versucht alles möglich zu ändern. Nur irgendwie scheitere ich daran :-(

Bei der Codezeile darüber, bar2day habe ich es wie folgt abgeändert und es zeigt den gewünschten Effekt, immer nur den aktuellen Tag. So würde ich auch gerne die Monate (1...31) sowie das Jahr (Jan...Dez) haben.
card([[$SELF:$2.$3.last_hour:bar1day-10],[$SELF:$2.$3.hour]],"$1 in $12/h akt",undef,$4/12,$5/12,$10,$11,["letzte","aktuell"],undef,"2","150,fixedscaling,,footer,noycolor,halfring,320","0,0,0,0,2")|

Über einen Tip wäre ich sehr dankbar.


Lieben Gruß Ingo

P.S. Danke für den schönen Codeschnipsel der Visualisierung

Damian

bar1month sollte korrekt sein, allerdings musst du ggf. warten bis neue Werte eintrudeln oder diese mit https://wiki.fhem.de/wiki/DOIF/uiTable_Schnelleinstieg#Import,_%C3%84nderung_und_L%C3%B6schung_von_Diagrammdaten selber setzen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

rinaldos

Danke schön für den Hinweis. Ich habe nun ein "init" durchgeführt, im Abschnitt get_data in der Zeile
    ::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_day","bar2month",-300,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_day"));;\

bar2month nach bar1month geändert. Die Daten aus dem Logfile neu einlesen lassen und schon waren alle Balken (so wie ich es mir vorgestellt habe) direkt wieder da. Dankeschön für den Denkanstoß. Anscheinend war ich nur zu ungeduldig um auf die Daten zu warten :-)

Lieben Gruß Ingo

Damian

Zitat von: rinaldos am 09 April 2025, 14:38:21Danke schön für den Hinweis. Ich habe nun ein "init" durchgeführt, im Abschnitt get_data in der Zeile
    ::DOIF_set_card_data ("$SELF","$SELF","$_counter[$i][0].$_counter[$i][1].last_day","bar2month",-300,fhem("get log.counter.$_counter[$i][0].$_counter[$i][1] ./log/counter.$_counter[$i][0].$_counter[$i][1].log - 2000 3000 4:last_day"));;\

bar2month nach bar1month geändert. Die Daten aus dem Logfile neu einlesen lassen und schon waren alle Balken (so wie ich es mir vorgestellt habe) direkt wieder da. Dankeschön für den Denkanstoß. Anscheinend war ich nur zu ungeduldig um auf die Daten zu warten :-)

Lieben Gruß Ingo

Die Option zum Einlesen der Daten aus dem Log, die ich in diesem Device zusätzlich eingebaut hatte, habe ich inzwischen verdrängt. Du hast die Option aber gefunden - das ist gut. Die Daten für die Visualisierung werden von der Card-Funktion in versteckten Readings des Devices gespeichert. Solange man nichts ändert und das System nicht abstürzt, reicht diese Vorgehensweise. Das zusätzliche Loggen der Daten und die Option diese im Notfall zu rekonstruieren, kann allerdings sehr nützlich sein.

Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF