Hauptmenü

Stromverbrauch per DOIF?

Begonnen von gestein, 14 Februar 2022, 16:47:37

Vorheriges Thema - Nächstes Thema

gestein

Hallo,

ich bin auf der Suche nach einer eleganten Lösung um den Stromverbrauch festzustellen und zu visualisieren.

Dabei bin ich auf dieses DOIF gestossen:
https://forum.fhem.de/index.php/topic,125192.msg1200988.html#msg1200988

Allerdings erschließt sich mir die Funktionalität nicht ganz.
- Wann oder von wem wird die Funktion "reset_$2" aufgerufen.
   Mir ist klar, dass das dann eigentlich die Funktion z.B. "reset_<Reading>" ist.
- Das DOIF funktioniert nur, weil die <Reading> anders heißen.
  Bei mir wären das mehrere Shellys und die <Reading> wären bei jedem gleich.
  Daher überschreiben sich die Readings mit dem Prefix "$2" doch. Oder?

Mit diesen Templates bin ich immer noch nicht ganz auf Gleich. Vielleicht klappt das ja doch so wie es ist.

@Damian: Ich traue mich ja kaum mehr zu fragen, aber könntest Du das DOIF Deiner Visualisierung vielleicht posten?
https://forum.fhem.de/index.php/topic,125192.msg1198074.html#msg1198074
Vielen Dank im Voraus
lg, Gerhard

Damian

#1
Hier habe ich den Code bereits verfeinert: https://forum.fhem.de/index.php/topic,84969.msg1207068.html#msg1207068

Da jetzt das Device im Readingnamen steckt, ist es eindeutig.

reset-Block musste zuvor manuell ausgeführt werden. Jetzt gibt es init-Blöcke, die automatisch bei der Definition ausgeführt werden.

Ich werde bald einen Wiki-Beitrag dazu machen - ich warte nur bis sich die Grafiken etwas mehr gefüllt haben.
Hier mein aktueller Code für Stromertrag und Strombezug:

defmod di_counter DOIF DEF TPL_stat (midnight_$1_$2 { [00:01];;\
  set_Reading("$1_$2_counter",[?$1:$2]);;\
  set_Reading("$1_$2_last_day",get_Reading("$1_$2_day",0),1);;\
  set_Reading("$1_$2_day",0,1);;\
  set_Reading("$1_$2_month",get_Reading("$1_$2_month",0)+get_Reading("$1_$2_last_day",0),1);;\
  if ($mday == 1) {\
    set_Reading("$1_$2_last_month",get_Reading("$1_$2_month",0),1);;\
    set_Reading("$1_$2_month",0,1);;\
    set_Reading("$1_$2_year",get_Reading("$1_$2_year",0)+get_Reading("$1_$2_last_month",0),1);;\
  }\
  if ($yday == 1) {\
    set_Reading("$1_$2_last_year",get_Reading("$1_$2_year",0),1);;\
    set_Reading("$1_$2_year",0,1);;\
  }\
}\
\
day_count_$1_$2 {set_Reading ("$1_$2_day",int(([$1:$2,0]-get_Reading("$1_$2_counter",0))*1000)/1000,1);;}\
\
init_$1_$2 {\
  if (!get_Reading("$1_$2_counter","")) {\
    set_Reading("$1_$2_counter",[?$1:$2]);;\
    set_Reading ("$1_$2_day",0);;\
    set_Reading ("$1_$2_month",0);;\
    set_Reading ("$1_$2_year",0);;\
    set_Reading ("$1_$2_last_day",0);;\
    set_Reading ("$1_$2_last_month",0);;\
    set_Reading ("$1_$2_last_year",0);;\
  } \
}\
)\
TPL_stat (Stromzaehler,total_c)\
TPL_stat (Stromzaehler,total_f)
attr di_counter room CUL_EM
attr di_counter uiTable {package ui_Table}\
\
card([[$SELF:Stromzaehler_total_f_day:col1w],[$SELF:Stromzaehler_total_c_day:col1w]],"Energie in kWh pro Tag","fa_bolt\@silver",-20,20,0,90,["Ertrag","Bezug"],undef,"1","130,,1,0,1","0,0,0,0,2")|\
card([[$SELF:Stromzaehler_total_f_month:col365d],[$SELF:Stromzaehler_total_c_month:col365d]],"Energie in kWh pro Monat","fa_bolt\@silver",-300,600,0,90,["Ertrag","Bezug"],undef,"1","130,,1,0,1","0,0,0,0,2")


Dargestellt wird der tägliche und monatliche Verbrauch/Bezug, siehe Anhang. Da es erst zwei Tage lang läuft, sieht man den monatlichen Anstieg noch nicht besonders gut.

Man kann natürlich auch auf die Readings last_day, last_month oder last_year triggern und diese z. B. loggen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

gestein

#2
Hallo Damian,

unglaublich, was Du da alles mit Deinem DOIF anstellt.
Schaut so einfach aus  ;)
Wenn ich es so vor mir sehe, dann ist alles klar. Aber wenn ich es selbst angehen müsste, dann ...

Danke, lg, Gerhard

Damian

#3
Zitat von: gestein am 14 Februar 2022, 18:04:48
Hallo Damian,

unglaublich, was Du da alles mit Deinem DOIF anstellt.
Schaut so einfach aus  ;)
Wenn ich es so vor mir sehe, dann ist alles klar. Aber wenn ich es selbst angehen müsste, dann ...

Danke, lg, Gerhard

Die Grafik ist hier ein nicht ganz unwichtiges Nebenprodukt :) Der Schwerpunkt bei der Definition ist allerdings das Template TPL_stat, welches mit allen fortlaufenden Zählern funktioniert und in den Readings ...day,...month,...year,...last_day, ...last_month, ...last_year die jeweiligen Verbräuche zum Loggen bzw. Plotten bestimmt.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

gestein

Das stimmt.

Zwei Fragen bitte noch:
1) wie würdest Du das folgende lösen?
Ich habe mehrere Shelly's und würde gerne den Verbrauch z.B. pro Zimmer und/oder pro Gruppe (Licht, Steckdose, Haushaltsgeräte) sehen.
Und dann noch den Gesamtverbrauch dazu.
Heißt das, für jedes Zimmer, jede Gruppe ein so ein DOIF anlegen?

2) wenn fhem neu gestartet wird, sind dann die Werte weg?
    Wenn man die Definition ändert, sind dann die Werte weg?

Vielen Dank im Voraus
Lg, Gerhard

Damian

Zitat von: gestein am 14 Februar 2022, 20:14:37
Das stimmt.

Zwei Fragen bitte noch:
1) wie würdest Du das folgende lösen?
Ich habe mehrere Shelly's und würde gerne den Verbrauch z.B. pro Zimmer und/oder pro Gruppe (Licht, Steckdose, Haushaltsgeräte) sehen.
Und dann noch den Gesamtverbrauch dazu.
Heißt das, für jedes Zimmer, jede Gruppe ein so ein DOIF anlegen?

2) wenn fhem neu gestartet wird, sind dann die Werte weg?
    Wenn man die Definition ändert, sind dann die Werte weg?

Vielen Dank im Voraus
Lg, Gerhard

Du kannst in einem DOIF-Device mehrfach das TPL_stat-Template aufrufen. Ich habe in meinem Beispiel zwei Zähler definiert:

TPL_stat (Stromzaehler,total_c)
TPL_stat (Stromzaehler,total_f)


Eine Summation über mehrere Zähler (Gruppe) ist nicht programmiert.

card speichert die Werte in versteckten Readings des DOIFs, mit save werden sie in der FHEM-Config gesichert. Damit bleiben die Grafiken nach dem Neustart erhalten. Wird dagegen die Definition des DOIF geändert (defmod), so werden alle Daten gelöscht. Man kann aber ein DOIF mit TPL_state definieren zum Bestimmen der Verbräuche und ein DOIF mit der Definition der cards zum Visualisieren, solange nur uiTable angepasst wird, bleiben die Grafiken ebenfalls erhalten.

Will man auf Nummer sicher gehen, dann sollte man die Tages-, Monats- und Jahresverbräuche zusätzlich loggen.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Und hier die Definition für den momentanen Verbrauch/Produktion, also die aktuelle Leistung. Hier werden die entsprechenden Readings der Zähler direkt angegeben.

card([[CUL_WZ:current:144col1d],[Stromzaehler:power_neg:144col1d]],"Leistung in kW","fa_bolt\@silver",-3.6,3.6,0,90,["Solar","Netz"],[(-1,0,-0.01,30,1,60,3.6,90)],"2","130,,1,0,1,0","1,,1,0,1")





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

WW

Zitat von: Damian am 14 Februar 2022, 17:40:21
Hier habe ich den Code bereits verfeinert: https://forum.fhem.de/index.php/topic,84969.msg1207068.html#msg1207068
...

Erst einmal ein Dankeschön für die tolle Anregung.
Im Gegensatz zu Electricity/Gas/Water-Calculator werden hier deutlich weniger Daten erzeugt und die Beschränkung auf das wesentliche ist einfacher. Für mich habe ich die Template-Definition noch um die Parameter $3 (Erzeugung eines kürzeren und lesbareren Namens für die erstellten Readings) und $4 (Anzahl der zu betrachtenden Nachkommastellen) ergänzt, um die Universalität zu erhöhen.


defmod myCounter DOIF DEF TPL_stat (\
midnight_$3 { [00:00:05];;\
  set_Reading ("$3_counter",sprintf("%.$4f", [?$1:$2]));;\
  set_Reading ("$3_last_day",get_Reading("$3_day",0),1);;\
  set_Reading ("$3_day",0,1);;\
  set_Reading ("$3_month",get_Reading("$3_month",0)+get_Reading("$3_last_day",0),1);;\
  if ($mday == 1) {\
    set_Reading ("$3_last_month",get_Reading("$3_month",0),1);;\
    set_Reading ("$3_month",0,1);;\
    set_Reading ("$3_year",get_Reading("$3_year",0)+get_Reading("$3_last_month",0),1);;\
  }\
  if ($yday == 1) {\
    set_Reading ("$3_last_year",get_Reading("$3_year",0),1);;\
    set_Reading ("$3_year",0,1);;\
  }\
}\
\
day_count_$3 {set_Reading ("$3_day",sprintf("%.$4f", [$1:$2,0]-get_Reading("$3_counter",0)),1);;}\
\
init_$3 {\
  if (!get_Reading("$3_counter","")) {\
    set_Reading ("$3_counter",sprintf("%.$4f", [$1:$2,0]));;\
    set_Reading ("$3_day",0);;\
    set_Reading ("$3_month",0);;\
    set_Reading ("$3_year",0);;\
    set_Reading ("$3_last_day",0);;\
    set_Reading ("$3_last_month",0);;\
    set_Reading ("$3_last_year",0);;\
  } \
}\
)\
TPL_stat (KgFlurStromzaehler,zaehler,Strom,4)\
TPL_stat (KgWsGasRaspi,zaehler,Gas,2)\
TPL_stat (KgFlurWasserzaehler,zaehlerstand,Wasser,4)\
TPL_stat (dummyDgBueroZbDwRegen,mm,Regen,1)

attr myCounter DbLogExclude .*
attr myCounter DbLogInclude Gas.*,Strom.*,Regen.*,Wasser.*
attr myCounter icon helper_doif


MfG
Willi
FHEM 6.0 im Docker-Container (OMV4 auf ASRock J3455-ITX), FHEM 6.0 auf Raspi, Fritzbox 7490, CUL433, CUL868, Jeelink868, SIGNALduino, LaCrosseGateway, SonoffZbBridge, Shelly, Sonoff, ESP8266, ESP32, ESP32-Cam, LaCrosse, Revolt, OneWire, Zigbee (Sonoff, Blitzwolf, IKEA, Lidl)

Damian

Schön, dass du mit dem Codeschnipsel etwas anfangen konntest. Wenn du es erweitern konntest, dann hast du offenbar die Funktionsweise des Schnipsels nachvollziehen können :)
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

jkriegl

Komisch, hatte das Schnipsel am Laufen, mit einem 2. TPL_ rumgebastelt und den shelly (der events liefert) an den Gefrirschrank gesteckt.
Nun kann ich beim set <device> nur noch "disable, enable" wählen.
Was muss ich löschen, restoren?
defmod myCounter DOIF DEF TPL_stat ( \
midnight_$3 { [00:05];;\
   set_Reading ("$3_counter",sprintf("%.$4f", [?$1:$2]));;\
   set_Reading ("$3_last_day",get_Reading("$3_day",0),1);;\
   set_Reading ("$3_day",0,1);;\
   set_Reading ("$3_month",get_Reading("$3_month",0)+get_Reading("$3_last_day",0),1);;\
   if ($mday == 1) {\
     set_Reading ("$3_last_month",get_Reading("$3_month",0),1);;\
     set_Reading ("$3_month",0,1);;\
     set_Reading ("$3_year",get_Reading("$3_year",0)+get_Reading("$3_last_month",0),1);;\
   }\
   if ($yday == 1) {\
     set_Reading ("$3_last_year",get_Reading("$3_year",0),1);;\
     set_Reading ("$3_year",0,1);;\
   }\
}\
day_count_$3 {set_Reading ("$3_day",sprintf("%.$4f", [$1:$2,0]-get_Reading("$3_counter",0)),1);;}\
init_$3 {\
   if (!get_Reading("$3_counter","")) {\
     set_Reading ("$3_counter",sprintf("%.$4f", [$1:$2,0]));;\
     set_Reading ("$3_day",0);;\
     set_Reading ("$3_month",0);;\
     set_Reading ("$3_year",0);;\
     set_Reading ("$3_last_day",0);;\
     set_Reading ("$3_last_month",0);;\
     set_Reading ("$3_last_year",0);;\
   } \
}\
)\
\
TPL_stat (shelly_s_2,energyTotal,Gefr-Schr,3)
attr myCounter room 2.5 Shelly
attr myCounter uiTable {package ui_Table}

setstate myCounter initialized
setstate myCounter 2022-02-17 17:56:20 mode enabled
setstate myCounter 2022-02-17 17:56:20 state initialized
Rpi 3, Fhem, Cul 868, HM-CC-RT-DN, HM-Sec-Sco, HM-ES-PMSw1-Pl, ebus (Vaillant), ECMD, Telegram, HTTPMOD, Xiaomi, Shelly

Damian

TPL_stat (shelly_s_2,energyTotal,Gefr-Schr,3)

Minus im Readingnamen ist keine gute Idee ;)
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

jkriegl

Rpi 3, Fhem, Cul 868, HM-CC-RT-DN, HM-Sec-Sco, HM-ES-PMSw1-Pl, ebus (Vaillant), ECMD, Telegram, HTTPMOD, Xiaomi, Shelly

jkriegl

Kann man aus Gründen der Übersichtlichkeit die Readings "block_.* executed" evtl. unterdrücken. loglevel ist wohl obsolet.
Rpi 3, Fhem, Cul 868, HM-CC-RT-DN, HM-Sec-Sco, HM-ES-PMSw1-Pl, ebus (Vaillant), ECMD, Telegram, HTTPMOD, Xiaomi, Shelly

Damian

Zitat von: jkriegl am 17 Februar 2022, 19:55:53
Kann man aus Gründen der Übersichtlichkeit die Readings "block_.* executed" evtl. unterdrücken. loglevel ist wohl obsolet.

Ist z. Zt. nicht möglich.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Ich habe mal eine neue Version des Stromzählers programmiert.

Hier gibt es nur noch einen Mitternachtsblock und nur einen Initialisierungsblock für alle Zähler. Dadurch reduziert sich die Anzahl der Blöcke erheblich. Die Zählerangaben werden jetzt direkt am Anfang im subs-Block definiert. Die Anzahl der Zähler ist weiterhin beliebig. Die Visualisierung über card-Funktion ist geblieben.

defmod di_counter_new DOIF subs {\
##                     device,        read       \
  push (@{$_counter},["Stromzaehler","total_c"]);; ## Angaben für den ersten Zähler\
  push (@{$_counter},["Stromzaehler","total_f"]);; ## Angaben für den zweiten Zähler\
\
sub midnight {\
  my ($device,$reading,$mday,$yday)=@_;;\
  set_Reading("$device.$reading.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",get_Reading("$device.$reading.month",0)+get_Reading("$device.$reading.last_day",0),1);;\
  if ($mday == 1) {\
    set_Reading("$device.$reading.last_month",get_Reading("$device.$reading.month",0),1);;\
    set_Reading("$device.$reading.month",0,1);;\
    set_Reading("$device.$reading.year",get_Reading("$device.$reading.year",0)+get_Reading("$device.$reading.last_month",0),1);;\
  }\
  if ($yday == 1) {\
    set_Reading("$device.$reading.last_year",get_Reading("$device.$reading.year",0),1);;\
    set_Reading("$device.$reading.year",0,1);;\
  }\
}\
\
sub init {\
  my ($device,$reading)=@_;;\
  if (!get_Reading("$device.$reading.counter","")) {   ## Initialisierung der Readings\
    set_Reading("$device.$reading.counter",ReadingsVal($device,$reading,0));; ## aktueller Zählerstand\
    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_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\
  } \
}\
}\
\
mid {[00:01];; ## Sicherung der Daten um Mitternacht\
  for (my $i=0;;$i<@{$_counter};;$i++) {\
    midnight($_counter[$i][0],$_counter[$i][1],$mday,$yday);;\
  }\
}\
\
init {        ## initialisierung aller Readings\
  for (my $i=0;;$i<@{$_counter};;$i++) {\
    init($_counter[$i][0],$_counter[$i][1]);;\
  }\
}\
\
DEF TPL_stat (\
  day_count_$1_$2 {set_Reading ("$1.$2.day",int(([$1:$2,0]-get_Reading("$1.$2.counter",0))*1000)/1000,1);;}\
)\
\
\
## Definition aller day_count-Blöcke zum Zählen des Tagesverbrauchs\
FOR(@{$_counter},TPL_stat($1$1,$1$2))
attr di_counter_new uiTable {package ui_Table} ## Optionale Visualisierung der Tageswerte im DOIF-Device\
card([[$SELF:Stromzaehler.total_f.day:col1w],[$SELF:Stromzaehler.total_c.day:col1w]],"Energie in kWh pro Tag","fa_bolt\@silver",-25,25,0,90,["Ertrag","Bezug"],undef,"1","130,,1,0,1","0,0,0,0,2")
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF