FHEM Forum

FHEM => Frontends => TabletUI => Thema gestartet von: ulli am 28 Februar 2016, 19:13:54

Titel: Tabellendarstellung mit variabler Anzahl an Readings
Beitrag von: ulli am 28 Februar 2016, 19:13:54
Hallo,

ich habe ein Device, welches Readings mit einem Index anlegt, welche variabel lang sind. z.B.
Reading_Name_1
Reading_Name_2
Reading_Name_3
Reading_1_1
Reading_1_2
Reading_1_3
Reading_2_1
Reading_3_1
Reading_3_2


Wie kann ich denn diese in TabletUI als Tabellenform wie folgt anzeigen lassen, wenn die Anzahl an Readings variiert?
Reading_Name_1
Reading_1_1   
Reading_1_2   
Reading_1_3

Reading_Name_2
Reading_2_1

Reading_Name_3
Reading_3_1
Reading_3_2


Besten Dank im Voraus.
Titel: Antw:Tabellendarstellung mit variabler Anzahl an Readings
Beitrag von: setstate am 28 Februar 2016, 20:48:16
Ich würde eine Liste aller möglichen Readings anlegen und alle optionalen mit class="autohide" markieren. Dann werden diese Elemente unsichtbar, wenn es das Reading zur Zeit nicht gibt. Der Check passiert aber nur bei einem ShortPoll, also beim vollständigen Synchronisieren mit FHEM (aller 15min, wenn longpoll an ist, oder beim Aufwachen aus einer Ruheposition), da FHEM fürs Wegnehmen von Readings kein Notify schickt.
Titel: Antw:Tabellendarstellung mit variabler Anzahl an Readings
Beitrag von: ulli am 02 März 2016, 19:22:54
Hmm das ist irgendwie ungünstig.
Gibt es eine Möglichkeit das ich über das Modul d.h uber eine get Funktion in fhem den HTML code generiere und diesen dann einfach in Tabletui darstellen lassen kann?
Titel: Antw:Tabellendarstellung mit variabler Anzahl an Readings
Beitrag von: zap am 02 März 2016, 21:13:07
Ich habe mir eine Funktion für myUtils geschrieben, die nummerierte Readings als HTmL Tabelle formatiert zurückliefert. Diese nutze ich, um ein Userreading zu setzen.

Das lese ich dann per Label Widget aus.

Das Problem: seit dem letzen Update stellt das Label Widget diesen Code nicht mehr korrekt dar. Insbesondere wenn ein Punkt darin vorkommt (z.B. Datum).

Bei Interesse kann ich die Funktion bereitstellen. Sie lässt sich über ein Template konfigurieren, d.h. ist für verschiedene Devicetypen wie GDS und Calllist nutzbar
Titel: Antw:Tabellendarstellung mit variabler Anzahl an Readings
Beitrag von: ulli am 03 März 2016, 20:00:32
Das hört sich ziemlich gut an...insbesondere  die template Umsetzung.
Wäre spitze wenn du es share würdest.
Titel: Antw:Tabellendarstellung mit variabler Anzahl an Readings
Beitrag von: zap am 03 März 2016, 21:26:37
Also, die folgende Funktion zählt die Anzahl der Readings. Das ist nützlich, wenn ein Modul zwar nummerierte Readings anbietet, aber kein Reading mit der Anzahl. Das ist z.B. bei FB_CALLLIST so.

Der Aufruf sieht so aus: myUtils_CountReadings (Devicename, ReadExpr)


sub myUtils_CountReadings ($$)
{
  my ($d, $e) = @_;
  my $c = 0;

  foreach my $r (keys %{$defs{$d}{READINGS}}) {
    $c++ if ($r =~ /$e/);
  }

  return $c;
}


Die folgende Funktion liefert eine Tabelle zurück: Sie wird wie folgt aufgerufen:

myUtils_GenerateTable (Devicename, StartNum, EndNum, TemplateFile)

Beispiel nach dem Listing.


sub myUtils_GenerateTable ($$$$)
{
  my ($t_device, $t_start, $t_end, $t_file) = @_;

  my @html;
  my $t_reading;
  my $t = '';
  my $dr;
  my %tdef;

  # Read template file
  if (open (TEMPLATE, "<$t_file")) {
    @html = <TEMPLATE>;
    close (TEMPLATE);
  }
  else {
    return "Can't open file $t_file";
  }

  # Parse template
  foreach my $line (@html) {
    chomp $line;
    my ($key, $h) = split /:/, $line, 2;
    next if (!defined ($h) || $key =~ /^#/);
    $tdef{$key} = $h;
  }

  # Set default values
  $tdef{'begin-html'} = '' if (!exists ($tdef{'begin-html'}));
  $tdef{'end-html'} = '' if (!exists ($tdef{'end-html'}));
  $tdef{'begin-table'} = "<table>" if (!exists ($tdef{'begin-table'}));
  $tdef{'end-table'} = "</table>" if (!exists ($tdef{'end-table'}));
  $tdef{'default'} = 'no data' if (!exists ($tdef{'default'}));;
  $tdef{'row-even'} = $tdef{'row-odd'} if (!exists ($tdef{'row-even'}));

  # Some syntax checks
  return "Missing definition in template file"  if (!exists ($tdef{'header'}) ||
    !exists ($tdef{'row-odd'}) || !exists ($tdef{'row-even'}));

  # Extract reading names from row definitions
  my @r_orows = ($tdef{'row-odd'} =~ m/\<r=\"(.*?)\"\/\>/g);
  my @r_erows = ($tdef{'row-even'} =~ m/\<r=\"(.*?)\"\/\>/g);

  # Start of table
  $t .= $tdef{'begin-html'}.$tdef{'begin-table'};

  # Table header
  $t .= $tdef{'header'};

  # Table rows
  my $i = $t_start;
  my $f;
  my $rn = 1;

  do {
    $f = 1;
    my $t_row = ($rn % 2) ? $tdef{'row-odd'} : $tdef{'row-even'};
    my $r_rows = ($rn % 2) ? \@r_orows : \@r_erows;

    foreach $t_reading (@$r_rows) {
      my $reading = sprintf ($t_reading, $i);
      my $v = ReadingsVal ($t_device, $reading, '');
      if ($v eq '') {
        $f = 0;
        last;
      }
      else {
        $t_row =~ s/\<r=\"$t_reading\"\/\>/$v/;
      }
    }

    if ($f > 0) {
      $t .= $t_row;
      $i++;
      $rn++;
    }
  } while ($f > 0 && $i <= $t_end);

  $t = $tdef{'default'} if ($rn == 1);

  # End of table
  $t .= $tdef{'end-table'}.$tdef{'end-html'};

  return $t;
}


Nun ein Beispiel für Wetteralarme aus dem Modul GDS:


attr mygds userReadings ftui_alerts {myUtils_GenerateTable($name, 0, 3, "/opt/fhem/www/tablet/gds.cfg")},ftui_alert_count {myUtils_CountReadings($name, '^a_[0-9]_event$')}


Die Datei gds.cfg sieht so aus:


begin-table:<table width="100%">
header:<tr><th>Zeitraum</th><th>Warnung</th></tr>
row-odd:<tr style="color: #<r="a_%d_eventCode_AREA_COLOR_hex"/>;"><td width="20%" valign="middle" class="border-t"><r="a_%d_onset_local"/><br><r="a_%d_expires_local"/></td><td width="80%" align="left" valign="middle" class="border-t"><r="a_%d_headline"/></td></tr>
end-table:</table>
default:Keine Warnungen vorhanden


Ein Reading wird so im Template eingebaut:

<r="Readingname"/>

In einem Readingname wird ein %d durch die laufende Reading-Nummer ersetzt.

Außer "row-odd" gibt es noch "row-even", d.h. gerade und ungerade Zeilen können unterschiedlich formatiert sein. Wenn "row-even" fehlt, wird "row-odd" verwendet.
Außerdem kann noch mit "begin-html" und "end-html" Code definiert werden, der am Anfang und am Ende eingefügt wird.

Nun noch ein Beispiel für eine FB_CALLLIST:

attr mycalls userReadings ftui-table {myUtils_GenerateTable($name, 1, 10, "/opt/fhem/www/tablet/phone_div.cfg")}, ftui-count {myUtils_CountReadings($name,'^[0-9]+-state$')}

Hier werden also 2 Readings generiert. Die Template-Datei sieht so aus, diesmal im div Layout:


# begin-html:<html>
begin-table:<div class="cell">
header:<div class="row"><div class="red"><div class="col-12">Uhrzeit</div><div class="col-12">Nummer</div></div></div>
row-odd:<div class="row"><div class="black"><div class="col-12"><r="%d-timestamp"/></div><div class="col-12"><r="%d-number"/></div></div></div>
row-even:<div class="row"><div class="gray"><div class="col-12"><r="%d-timestamp"/></div><div class="col-12"><r="%d-number"/></div></div></div>
end-table:</div>
default:Keine Eintr&auml;ge vorhanden
# end-html:</html>