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.
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.
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?
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
Das hört sich ziemlich gut an...insbesondere die template Umsetzung.
Wäre spitze wenn du es share würdest.
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äge vorhanden
# end-html:</html>