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