[Mini-Chart-Card] Schätzeisen bzw. grobe Visualisierung von Daten

Begonnen von schwatter, 09 Juni 2025, 23:37:53

Vorheriges Thema - Nächstes Thema

schwatter

Deine Ringe nutze ich auch gerne. Zum Beispiel im devStateIcon.

{ui_Table::temp_hum_ring(ReadingsVal("THsensorBk","temperature",0),ReadingsVal("THsensorBk","humidity",0))}

Aber ich wollte mal ausbrechen und schauen.

Gruß schwatter

Damian

Zitat von: schwatter am 12 Juni 2025, 19:48:06Deine Ringe nutze ich auch gerne. Zum Beispiel im devStateIcon.

{ui_Table::temp_hum_ring(ReadingsVal("THsensorBk","temperature",0),ReadingsVal("THsensorBk","humidity",0))}

Aber ich wollte mal ausbrechen und schauen.

Gruß schwatter

Ja, es ist immer gut selber was zu machen, oft entwickelt sich ein größeres Projekt mit der Zeit.

P.S. Man kann übrigens im deviStateIcon eines Devices auch die ui_Table::card-Funktion verwenden, die solche Verläufe visualisiert

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

schwatter

#17
Das habe ich aufm Schirm. Wollte es aber absichtlich spartanischer und visuell flexibel.
Funktional is deine Card natürlich besser.

Gruß schwatter

schwatter

#18
Nabend,

hier ein Beispiel für stateFormat ohne Echarts. Nur Html, SVG und Perl. Dadurch viel effizienter.

{
  my @v = (split /,/, ReadingsVal('Smartmeter_2E1F50','chartArray',''))[-40..-1];  # letzte 40 Werte

  my ($min, $max) = (sort {$a <=> $b} @v)[0,-1];
  $max //= 0; $min //= 0;
  my $range = $max - $min || 1;

  # SVG-Zielgröße (angepasst!)
  my $width  = 160;
  my $height = 70;

  my $w = $width / (@v - 1 || 1);

  # y-Position der Null-Linie
  my $y0 = $height - ((0 - $min) / $range * $height);

  # Punkte vorbereiten
  my @points = map {
    [ $_ * $w, $height - (($v[$_] - $min)/$range * $height), $v[$_] ]
  } 0..$#v;

  my $bar_width = $w * 0.6;

  my $bars_svg = join "", map {
    my ($x, $y, $val) = @{$points[$_]};
    my $color = $val >= 0 ? 'red' : 'green';

    if ($val >= 0) {
      my $bar_height = $y0 - $y;
      sprintf(
        '<rect x="%.2f" y="%.2f" width="%.2f" height="%.2f" fill="%s" opacity="0.8" />',
        $x - $bar_width/2, $y, $bar_width, $bar_height, $color
      );
    } else {
      my $bar_height = $y - $y0;
      sprintf(
        '<rect x="%.2f" y="%.2f" width="%.2f" height="%.2f" fill="%s" opacity="0.8" />',
        $x - $bar_width/2, $y0, $bar_width, $bar_height, $color
      );
    }
  } 0..$#points;

  my $current_power = ReadingsVal('Smartmeter_2E1F50','APOX_Power', '--');
  my $todayIn       = ReadingsVal('Smartmeter_2E1F50','statAPOX_E_inDay', '--');
  my $todayOut      = ReadingsVal('Smartmeter_2E1F50','statAPOX_E_outDay', '--');

  return qq{
    <style>
      div#Smartmeter_2E1F50 { pointer-events:none; }
    </style>
    <div style="width:365px; padding:10px; border:1px solid #ddd; border-radius:6px; font-family:sans-serif; box-shadow:0 2px 4px rgba(0,0,0,0.1); box-sizing:border-box; height:90px; position:relative;">
      <div style="position:absolute; top:10px; left:10px; width:90px; font-size:14px; text-align:left; line-height:26px;">
        <div>Currently</div><div>Today in</div><div>Total out</div>
      </div>
      <div style="position:absolute; top:10px; left:80px; width:120px; font-size:14px; font-weight:bold; text-align:center; line-height:26px; display:flex; flex-direction:column; white-space:normal; word-wrap:break-word;">
        <div>${current_power} W</div><div>${todayIn} Wh</div><div>${todayOut} kWh</div>
      </div>
      <div style="position:absolute; top:10px; right:10px; width:160px; height:70px; overflow:hidden;">
        <svg style="width:160px!important; height:70px!important; display:block;" viewBox="0 0 160 70" preserveAspectRatio="none">
          $bars_svg
        </svg>
      </div>
    </div>
  };
}


Gruß schwatter

schwatter

#19
Tag,

und hier noch als Line mit Html,SVG und Perl + Farbschleier. Das Post vorher habe ich auch nochmal angepasst. Die Viewbox war falsch skaliert.

{
  my @v = (split /,/, ReadingsVal('OpenDTU','chartArray',''))[-40..-1];  # letzte 40 Werte

  my ($min, $max) = (sort {$a <=> $b} @v)[0,-1];
  $max //= 0; $min //= 0;
  my $range = $max - $min || 1;

  # Zielgröße der SVG
  my $width = 155;
  my $height = 65;

  my $w = $width / (@v - 1 || 1);  # Abstand zwischen Punkten

  # Punkte berechnen
  my @points = map {
    my $x = $_ * $w;
    my $y = $height - (($v[$_] - $min) / $range * $height);
    [$x, $y]
  } 0..$#v;

  # Linie (Pfade) erzeugen
  my $path_d = "M" . join(" L", map { sprintf("%.2f,%.2f", @$_) } @points);

  # Fläche unter der Linie
  my $area_path_d = $path_d . sprintf(" L%.2f,%.2f L0,%.2f Z", $width, $height, $height);

  # Werte auslesen
  my $current_power = ReadingsVal('OpenDTU','total.Power.v', '--');
  my $todayIn = ReadingsVal('OpenDTU','total.Power.v', '--');
  my $todayOut = ReadingsVal('OpenDTU','total.YieldTotal.v', '--');

  return qq{
    <style>
      div#OpenDTU { pointer-events:none; }
    </style>
    <div style="width:365px; padding:10px; border:1px solid #ddd; border-radius:6px; font-family:sans-serif; box-shadow:0 2px 4px rgba(0,0,0,0.1); box-sizing:border-box; height:90px; position:relative;">
     
      <!-- Labels -->
      <div style="position:absolute; top:10px; left:10px; width:90px; font-size:14px; text-align:left; line-height:26px;">
        <div>Currently</div><div>Today in</div><div>Total out</div>
      </div>

      <!-- Werte -->
      <div style="position:absolute; top:10px; left:80px; width:120px; font-size:14px; font-weight:bold; text-align:center; line-height:26px; display:flex; flex-direction:column; white-space:normal; word-wrap:break-word;">
        <div>${current_power} W</div><div>${todayIn} Wh</div><div>${todayOut} kWh</div>
      </div>

      <!-- SVG-Chart -->
      <div style="position:absolute; top:10px; right:10px; width:160px; height:70px; overflow:hidden;">
        <svg style="width:160px!important; height:70px!important; display:block;" viewBox="0 0 160 70" preserveAspectRatio="xMidYMid meet">
          <path d="$area_path_d" fill="rgba(59,130,246,0.2)" />
          <path d="$path_d" fill="none" stroke="#3b82f6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
        </svg>
      </div>
    </div>
  };
}


Gruß schwatter

schwatter

#20
Mahlzeit,

ich habe Post #1 überarbeitet. Es ist jetzt nach Perl und Echart gegliedert. Für Perl habe ich 2 Beispieldummys erstellt.
Das Board hat gemeckert beim Code einfügen, daher als Anhang.

Perlvariante.
- alle wichtigen Variablen am Anfang
- Bei chartCardLinePerl ist Moving Average enthalten. Wer das nicht braucht kann den Codeblock # Moving Average löschen.
- Bei chartCardLinePerl ist eine gepunktete Nulllinie enthalten. Wer das nicht braucht, einfach #<!-- Null-Linie --> löschen.

Gruß schwatter

schwatter

Morgen,

erstes Post überarbeitet.
- Unter 1.2 Ringbuffer hinzugefügt.
- Dadurch werden die letzten 50 Werte gespeichert. Kommt ein Neuer dazu, fliegt der letzte Alte raus.
- Ein Überlauf wird dadurch verhindert.
- Das at um Mitternacht fällt weg.
- Dadurch besser für Livevalues.

Gruß schwatter