Edit:
Die aktuelle Version der Energie-Karte wurde ins Wiki übernommen:
https://wiki.fhem.de/wiki/DOIF/uiTable_Anwendung#Visualisierung:_Energiefluss_als_Energie-Karte
Hier der Link zu kompakten Energie-Karte:
https://wiki.fhem.de/wiki/DOIF/uiTable_Anwendung#Visualisierung:_Energiefluss_als_kompakte_Energie-Karte
Sehr schön das du dir jetzt die Zeit nimmst.
Sieht auch schon ansehnlich aus :)
Edit:
Und sofort kommen Wünsche. Wenn möglich Mobile und Desktop berücksichtigen. Bzw. wenn möglich,
min 2 Größen über Settings ermöglichen.
Gruß schwatter
Zitat von: schwatter am 02 April 2026, 08:40:44Und sofort kommen Wünsche. Wenn möglich Mobile und Desktop berücksichtigen. Bzw. wenn möglich,
min 2 Größen über Settings ermöglichen.
Es ist bisher nur über uitable definiert, also ein DOIF-Device. Die Berechnung der einzelnen Werte kommt von außerhalb. Eine Skalierbarkeit ist ein Muss, aber noch nicht realisiert. Ebenfalls müssen Animationen abschaltbar sein, sonst kostet es einfach zu viel Performance insb. über Remoteverbindung. Ebenfalls fehlt mir noch der Verlauf einzelner Werte mit statistischer Auswertung ala card. Ich denke, ich werde eine einfache Version machen und eine umfangreichere. Immerhin ist es recht effizient definiert/programmiert - es werden nur Sachen zum Browser übertragen, die sich ändern, also nicht bei jedem Trigger, und davon gibt es viele, die ganze Grafik.
Zweiter Entwurf mit Verlaufsdiagrammen
Screenshot 2026-04-04 125018.png
Hallo Damian
sieht mega aus, super das du weiter machst mit FHEM.
Als ungeduldiger Mensch kommt natürlich die Frage..... wann wird die Energy-Card zum testen verfügbar werden.
gruss Remo
Zitat von: appi am 05 April 2026, 17:41:54Hallo Damian
sieht mega aus, super das du weiter machst mit FHEM.
Als ungeduldiger Mensch kommt natürlich die Frage..... wann wird die Energy-Card zum testen verfügbar werden.
gruss Remo
Ich bin kurz vor der Vollendung. Problem bereitet mir noch die Animation. Diese wird unterbrochen und neu gestartet, wenn sich der Wert (hier: Leistung) ändert. Das sieht nicht gut aus, wenn die Werte sich in kurzen Abständen ändern. Da muss ich noch etwas rumexperimentieren. Bis dahin will ich noch nichts posten, solange es nicht rundläuft.
Was ich aber schon sagen kann:
-die komplette Definition steckt im uiTable-Attribut und kann beliebig angepasst werden, sie nutzt vorhandene uiTable-Funktionen
-die gesamte Karte lässt sich mit einem Zoomparameter beliebig skalieren
-alle dargestellten Werte müssen im FHEM-System vorhanden sein, sie werden nicht in der Karte erzeugt bzw. berechnet.
Sobald ich fertig bin, werde ich die Definition hier posten.
Meine 240x240-Pixel-Variante muss mit weniger Informationen auskommen, damit sie auf dem GIFTV lesbar bleibt.
Ist off-topic, aber vielleicht hat das schon jemand von den Mitlesern hinbekommen: automatisch Fotos nach Amazon Photos hochschieben (analog zu push2giftv). Dann könnte der alte Echo Show mal was anderes als Amateur Foodporn (https://de.wikipedia.org/wiki/Foodporn) anzeigen.
Ich habe nun die Energy_card fertiggestellt. Dafür wurde allerdings eine neue DOIF-Version erstellt. Diese erlaubt nun ohne Umwege Javascript auszuführen. Das war erforderlich damit ich per Änderung von CSS-Attributen den animierten Energiefluss abhängig von der Leistung dynamisch anpassen konnte.
Die Definition kann beliebig angepasst werden. Man könnte z. B. statt Haus sein E-Auto darstellen.
Im einfachsten Fall braucht man am Ende in der Tabellendefinition nur die Readings auf eigene anzupassen und jeweils die maximale Leistung entsprechend zu ändern.
Die Geschwindigkeit und die Richtung der Stromfluss-Animation wird abhängig der aktuellen Leistung visualisiert, siehe GIF-Animation im Anhang.
Aktuelle DOIF-Definition und weiter Features siehe erster Post: https://forum.fhem.de/index.php?topic=144357.msg1361012#msg1361012
Screenshot 2026-04-17 204832.png
Andere Frage: warum wird der Speicher bei 89% schon nicht mehr geladen?
Zitat von: Per am 17 April 2026, 22:02:15Andere Frage: warum wird der Speicher bei 89% schon nicht mehr geladen?
Weil ich ihn auf 90 % begrenzt habe.
sieht ja super aus, bereits am laufen, allerdings kämpfe ich noch mit den Werten. Wo soll ich am besten W in KW umrechnen?
Direkt in der uiTable Reading definition?
Zitat von: appi am 17 April 2026, 22:37:18sieht ja super aus, bereits am laufen, allerdings kämpfe ich noch mit den Werten. Wo soll ich am besten W in KW umrechnen?
Direkt in der uiTable Reading definition?
Entweder im ursprünglichen Device als userReading oder du definierst dir ein DOIF-Reading in der Energy_Card selbst, welches du in uiTable angibst.
Könntest bitte alle deine Readingsnamen nach Bedeutung aufschlüsseln ?
Bei quota_powGetBpCms handelt es sich vermutlich um den aktuellen Ladestrom der Batterie und bei quota_soc um den aktuellen Ladezustand.
Aber der Rest ist doch sehr kryptisch, zumal einige Readings wohl nicht von einem Gerät direkt stammen sondern in einem anderen DOIF erst gebildet werden bsp total_f.day
Zitat von: Wzut am 18 April 2026, 09:08:41Könntest bitte alle deine Readingsnamen nach Bedeutung aufschlüsseln ?
Bei quota_powGetBpCms handelt es sich vermutlich um den aktuellen Ladestrom der Batterie und bei quota_soc um den aktuellen Ladezustand.
Aber der Rest ist doch sehr kryptisch, zumal einige Readings wohl nicht von einem Gerät direkt stammen sondern in einem anderen DOIF erst gebildet werden bsp total_f.day
Ich habe die Readingnamen angepasst und die Definition in den ersten Post verlagert. Später wird es dazu eine Wiki-Beschreibung geben.
Hier mal eine kompakte mobile Version. Die Bedeutung der Readings kann man im ersten Post nachschauen.
Edit: kleine Code-Änderungen
defmod di_energy_card_min DOIF {}
attr di_energy_card_min uiTable {\
$ATTRIBUTESFIRST = 1;;\
\
## Energy_card kann über das Attribut zoom skalliert werden\
\
$TABLE = 'zoom: 1;; width: 212px;; height: 195px;; text-align: left;; vertical-align: top;; border-radius:0%;; position:relative;; background: linear-gradient(to bottom, rgb(40,40,40), rgb(60, 60, 60));; ';;\
\
package ui_Table;;\
\
sub move {\
my ($left, $top, $content) = @_;;\
my $value;;\
if (ref($content) eq "ARRAY") {\
$value = $content->[0];;\
} else {\
$value =$content;;\
}\
\
my $out = '<div style="position:absolute;; left:'\
. $left . 'px;; top:'\
. $top . 'px;;">'\
. $value .\
'</div>';;\
\
if (ref($content) eq "ARRAY") {\
return ([$out,$content->[1]]);;\
} else {\
return ($out);;\
}\
}## end of move\
\
sub flow {\
\
my ($d,$item,$power,$max,$direction)=@_;;\
my $dur;;\
if ($power == 0) {\
$dur=0;;\
} else {\
$power=$max if ($power>$max);;\
$dur=6-abs(int(5*$power/$max));;\
}\
\
\
my ($from, $to, $x1, $x2, $y1, $y2);;\
\
if ($direction==0) { # ↖ unten rechts -> oben links\
($from, $to, $x1, $x2, $y1, $y2)=("1 1","-1 -1",100,0,100,0);;\
} elsif ($direction==1) { # ↘ oben links -> unten rechts\
($from, $to, $x1, $x2, $y1, $y2)=("-1 -1","1 1",0,100,0,100);;\
} elsif ($direction==2) { # ↗ unten links -> oben rechts\
($from, $to, $x1, $x2, $y1, $y2)=("-1 1","1 -1",0,100,100,0);;\
} elsif ($direction==3) { # ↙ oben rechts -> unten links\
($from, $to, $x1, $x2, $y1, $y2)=("1 -1","-1 1",100,0,0,100);;\
}\
\
my $out='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 35" width="40" height="35" style="width:40px;; height:35px;;">';;\
\
$out .= '<defs>\
<linearGradient id="flowGradient_'.$item.'" \
x1="'.$x1.'%" y1="'.$y1.'%" \
x2="'.$x2.'%" y2="'.$y2.'%" \
>\
<stop offset="0%" stop-color="white" stop-opacity="0.2"/>\
<stop offset="80%" stop-color="white" stop-opacity="1"/>\
<stop offset="100%" stop-color="white" stop-opacity="0.2"/>\
<animateTransform \
id="flowAnim_'.$item.'" \
attributeName="gradientTransform" \
type="translate" \
from="'.$from.'" \
to="'.$to.'" \
dur="'.$dur.'s" \
repeatCount="indefinite" \
calcMode="linear"/>\
</linearGradient>\
</defs>\
<path d="'.$d.'" fill="none" stroke="url(#flowGradient_'.$item.')" stroke-width="5" />';;\
\
##$out .= '<defs> <linearGradient id="flowGradient_'.$item.'" x1="'.$x1.'%" y1="0%" x2="'.$x2.'%" y2="0%"> <stop offset="0%" stop-color="gray" stop-opacity="0.2"/> <stop offset="100%" stop-color="white" stop-opacity="1"/> <stop offset="0%" stop-color="gray" stop-opacity="0.2"/></defs><path d="'.$d.'" fill="none" stroke="gray" stroke-opacity="0.2" stroke-width="3"/><path d="'.$d.'" fill="none" stroke="url(#flowGradient_'.$item.')" stroke-width="2" stroke-dasharray="3 9"><animate id="flowAnim_'.$item.'" attributeName="stroke-dashoffset" from="'.$from.'" to="'.$to.'" dur="'.$dur.'s" repeatCount="indefinite"/></path>';;\
\
return ([$out,'var e=document.getElementById("flowAnim_'.$item.'");;if (e) {e.setAttribute("dur","'.$dur.'s");;e.setAttribute("from","'.$from.'");;e.setAttribute("to","'.$to.'");;};; var e=document.getElementById("flowGradient_'.$item.'");;if (e) {e.setAttribute("x1","'.$x1.'%");;e.setAttribute("x2","'.$x2.'%");;e.setAttribute("y1","'.$y1.'%");;e.setAttribute("y2","'.$y2.'%");;}'])\
} ## end of flow\
\
sub grid_power {\
my ($power,$max)=@_;;\
return (move(30,64,flow("M 5 0 A 30 30 0 0 0 35 30","grid",$power,$max,($power > 0 ? 0 : 1))));;\
} \
\
sub solar_power {\
my ($power,$max)=@_;;\
return move(138,64,flow("M 35 0 A 30 30 0 0 1 5 30 L 5 30","solar",$power,$max,3));;\
} \
\
sub home_power {\
my ($power,$max)=@_;; \
return move(30,94,flow("M 5 35 A 30 30 0 0 1 35 5","home",$power,$max,3));;\
}\
\
sub battery_power {\
my ($power,$max)=@_;;\
return move(138,94,flow("M 35 35 A 30 30 0 0 0 5 5 ","battery",$power,$max,($power < 0 ? 0:1)));;\
}\
\
sub grid {\
my ($power,$feed,$consum)=@_;;\
move(2,2,icon_ring2("scene_power_grid\@silver",$power,-5,5,0,90,"kW",110,undef,"2",$feed-$consum,-20,20,0,90,"kWh",undef,"1",undef,"nogradient,,innerring,nopointer,negzeropos"));;\
}\
\
sub self {\
my ($autark,$EVG)=@_;;\
move(64,60,ring2($autark,0,100,undef,undef,"Autarkie",130,[(33.3,40,66.6,65,100,85)],"0,,fill:silver, %",$EVG,0,100,190,170,"EVQ",undef,"0,,fill:silver, %",undef,undef,"nogradient,,innerring,nopointer")) # [(33.3,40,66.6,65,100,85)]\
}\
\
sub solar {\
my ($power,$energy)=@_;;\
move(140,2,icon_ring2("solar_icon\@silver",$power,0,3.6,30,90,"kW",110,undef,"2",$energy,0,30,30,90,"kWh",undef,"1",undef,"nogradient,,innerring,nopointer"));;\
}\
\
sub home {\
my ($power,$consum)=@_;;\
move(2,130,icon_ring2("fa_home\@silver",$power,0,3,60,10,"kW",110,undef,"2",$consum,0,10,60,10,"kWh",undef,"1",undef,"nogradient,,innerring,nopointer"));;\
}\
\
sub battery {\
my ($power,$cap)=@_;;\
move(140,130,icon_ring2("battery_100\@silver",$power/1000,-1,1,220,170,"kW",110,undef,"2",$cap,0,100,0,90,"%",undef,"0",undef,"nogradient,,noinnerring,nopointer,zeronegpos"));;\
}\
\
} ## end of perl area\
\
## Tabellendefinition\
## Hier eigene Readings anpassen\
\
grid([MQTT2_DVES_C58DCB:power_fc],[di_counter_new:MQTT2_DVES_C58DCB.total_f.day],[di_counter_new:MQTT2_DVES_C58DCB.total_c_positiv.day]).\
solar([MQTT2_DVES_C58DCB:power_pv],[di_counter_new:MQTT2_DVES_C58DCB.total_pv.day]).\
home ([MQTT2_DVES_C58DCB:power_home_c],[di_counter_new:MQTT2_DVES_C58DCB.total_home_c.day]).\
battery([ecoflowStreamACpro:quota_powGetBpCms],[ecoflowStreamACpro:quota_soc]).\
self(([di_counter_new:MQTT2_DVES_C58DCB.total_pv.day]-[di_counter_new:MQTT2_DVES_C58DCB.total_f.day])/[di_counter_new:MQTT2_DVES_C58DCB.total_consum.day]*100,(1-[di_counter_new:MQTT2_DVES_C58DCB.total_f.day]/[di_counter_new:MQTT2_DVES_C58DCB.total_pv.day])*100).\
grid_power([MQTT2_DVES_C58DCB:power_fc],3.6).\
solar_power([MQTT2_DVES_C58DCB:power_pv],3.6).\
battery_power([ecoflowStreamACpro:quota_powGetBpCms],1050).\
home_power([MQTT2_DVES_C58DCB:power_home_c],3.6)
Screenshot 2026-04-19 133239.png
Sorry für meine Ungeduld.
Habe den code energy_card_min übernommen.
Da ich nur ein Balkon-KW und keine Batterie habe, habe ich Anpassungen vorgenommen.
Der Überschuss wird in battery angezeigt, sowie in den rings aktuelle Verbräuche/Erträge.
Sieht eigentlich schon sehr gut aus, aber
bei grid-Bezug läuft die Animation von self -> grid also falsch (Bei Einspeisung gar nichts, aber bei Überschuss korrekt von self -> battery).
Den 3. Parameter von grid "total_c_positiv.day" habe ich auf Null gesetzt, weil nicht verstanden (andere Werte verändern den Tagesbezug).
Auf dem Bild unten ist meine derzeitige Visualisierung (Auszug) mit enthalten.
Wie kann ich die Animation bei Einspeisung auf grid-> self ändern?
Kann man evtl. die Animation self -> battery entfernen, falls grid <-> self in beide Richtungen möglich ist?
Die Aufrufe der jeweiligen Funktionen entsprechen denen aus dem ersten Post:
grid([Netz:Leistung_Einspeisung_Bezug],[Netz:Energie_des_Tages_Einspeisung],[Netz:Energie_des_Tages_Bezug]).\
solar([PV:Leistung],[PV:Energie_des_Tages]).\
home ([Haus:Leistung_Bezug],[Haus:Energie_des_Tages_Bezug]).\
battery([Speicher:Leistung_Laden_Entladen],[Speicher:Kapazität]).\
## Visualisierung von Autarkie und Eigenverbrauchsquote als Ring\
self([Energie:Autarkie],[Energie:Eigenverbrauchsquote]).\
## Visualisierung der Energieflüsse, der zweiter Parameter ist die maximale Leistung\
grid_power([Netz:Leistung_Einspeisung_Bezug],3.6).\
solar_power([PV:Leistung_PV],3.6).\
battery_power([Speicher:Leistung_Bat],1).\
home_power([Haus:Leistung_Bezug],3.6)
Jede Funktion bildet ein Element ab. Die mit "_power" am Ende sind für die Animation zuständig (zweiter Parameter ist die maximale Leistung). Die Animationen (bis auf home) sind für beide Richtungen ausgelegt, abhängig davon, ob der Leistungswert positiv oder negativ ist. Möchte man z. B. keine Batterie haben, löscht man die beiden Zeilen, die mit "battery" beginnen.
Ich bastle an eine Version, wo man nur seine Readings und seine maximalen Werte zentral definiert, ohne den Code anpacken zu müssen.
Vielen Dank für die schnelle Antwort, funktioniert bestens. Das Problem lag an der Einstellung max. Leistung (bei mir W)
Zitat von: Damian am 21 April 2026, 18:24:31Möchte man z. B. keine Batterie haben, löscht man die beiden Zeilen, die mit "battery" beginnen.
Du kannst ja "wenn max XXX=0 dann XXX disableld" machen
Ich habe einen Wiki-Beitrag mit neuem Code zu der kompakten Energie-Karte verfasst.
Ich habe jetzt die gesamte Definition der erforderlichen Perlfunktionen in den Definitionsbereich des DOIF-Devices gepackt (subs-Block). Dort sind zu Anfang aller erforderlichen Maximalwerte definiert und beschriftet. Alle erforderlichen Readings befinden sich jetzt im Attribut DOIF-Readings, haben selbsterklärende Namen und müssen nur noch dort angepasst werden. Das Attribut uiTable beinhaltet nur noch die Definition der Tabelle mit den Aufrufen der Perlfunktionen. Es muss nicht mehr angepasst werden, wenn man das Layout nicht verändern will.
Edit:
https://wiki.fhem.de/wiki/DOIF/uiTable_Schnelleinstieg#Visualisierung%3A_Energiefluss_als_kompakte_Energie-Karte
neue Seite: https://wiki.fhem.de/wiki/DOIF/uiTable_Anwendung#Visualisierung%3A_Energiefluss_als_kompakte_Energie-Karte
Aus irgendwelchen Gründen wird der Code nicht farblich hervorgehoben. Möglicherweise ist die Wiki-Seite inzwischen zu groß geworden. Vermutlich werde ich die Anwendungsbeispiele auf eine neue Wiki-Seite auslagern.
uiTable-Anwendungen wurde auf eine eigene Wiki-Seite ausgelagert, da die bisherige Wiki-Seite zu groß geworden war. Jetzt wird der Code wieder farblich hervorgehoben.
Auch die Energie-Karte mit Werteverlauf ist jetzt im Wiki:
https://wiki.fhem.de/wiki/DOIF/uiTable_Anwendung#Visualisierung:_Energiefluss_als_Energie-Karte
Falls jemand seine energy_card in einer anderen DOIF-Tabelle einbinden möchte siehe: https://forum.fhem.de/index.php?topic=144559.msg1362721#msg1362721