mirror of
https://github.com/fhem/fhem-mirror.git
synced 2024-11-22 09:49:50 +00:00
1ba6839dd3
git-svn-id: https://svn.fhem.de/fhem/trunk@25942 2b470e98-0d58-463d-a4d8-8e2adae1ed80
1973 lines
76 KiB
Perl
1973 lines
76 KiB
Perl
# $Id: 95_Dashboard.pm 21180 2020-02-11 21:04:55Z DS_Starter $
|
||
########################################################################################
|
||
# 95_Dashboard.pm
|
||
#
|
||
# written and released by Sascha Hermann 2013
|
||
#
|
||
# maintained 2019-2022 by Heiko Maaz
|
||
# e-mail: Heiko dot Maaz at t-online dot de
|
||
#
|
||
# This script is part of fhem.
|
||
#
|
||
# Fhem is free software: you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation, either version 2 of the License, or
|
||
# (at your option) any later version.
|
||
#
|
||
# Fhem is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU General Public License for more details.
|
||
#
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
||
#
|
||
########################################################################################
|
||
# Known Bugs/Todos:
|
||
# BUG: Nicht alle Inhalte aller Tabs laden, bei Plots dauert die bedienung des Dashboards zu lange. -> elemente hidden? -> widgets aus js über XHR nachladen und dann anzeigen (jquery xml nachladen...)
|
||
# BUG: Variabler abstand wird nicht gesichert
|
||
# BUG: Überlappen Gruppen andere? ->Zindex oberer reihe > als darunter liegenden
|
||
#
|
||
# Helpfull Links:
|
||
# http://jquery.10927.n7.nabble.com/saving-portlet-state-td125831.html
|
||
# http://jsfiddle.net/w7ZvQ/
|
||
# http://jsfiddle.net/adamboduch/e6zdX/1/
|
||
# http://www.innovativephp.com/jquery-resizable-practical-examples-and-demos/
|
||
# http://jsfiddle.net/raulfernandez/mAuxn/
|
||
# http://jsfiddle.net/zeTP8/
|
||
#
|
||
########################################################################################
|
||
package main;
|
||
|
||
use strict;
|
||
use warnings;
|
||
eval "use FHEM::Meta;1" or my $modMetaAbsent = 1;
|
||
use Data::Dumper;
|
||
|
||
use vars qw(%FW_icons); # List of icons
|
||
use vars qw($FW_dir); # base directory for web server
|
||
use vars qw($FW_icondir); # icon base directory
|
||
use vars qw($FW_room); # currently selected room
|
||
use vars qw(%defs); # FHEM device/button definitions
|
||
#use vars qw(%FW_groups); # List of Groups
|
||
use vars qw($FW_wname); # Web instance
|
||
use vars qw(%FW_types); # device types
|
||
use vars qw($FW_ss); # is smallscreen, needed by 97_GROUP/95_VIEW
|
||
|
||
# Versions History intern
|
||
our %Dashboard_vNotesIntern = (
|
||
"3.17.2" => "10.04.2022 fix perl warnings, Forum: #127216 ",
|
||
"3.17.1" => "10.02.2020 fix perl warning, Forum: https://forum.fhem.de/index.php/topic,16503.msg1023004.html#msg1023004 ",
|
||
"3.17.0" => "06.10.2019 Path handling of backgroundimage changed ",
|
||
"3.16.0" => "04.10.2019 new attribute dashboard_hideGroupHeader, commandref revised ",
|
||
"3.15.2" => "29.09.2019 fix warnings, Forum: https://forum.fhem.de/index.php/topic,16503.msg978883.html#msg978883 ",
|
||
"3.15.1" => "25.09.2019 change initial attributes, commandref revised ",
|
||
"3.15.0" => "24.09.2019 set activateTab, rename dashboard_activetab to dashboard_homeTab, ".
|
||
"rename dashboard_activetabRefresh to dashboard_webRefresh, some bugfixes, comref revised ",
|
||
"3.14.0" => "22.09.2019 new attribute dashboard_activetabRefresh, activate the active tab in browser ",
|
||
"3.13.2" => "21.09.2019 new solution to eliminate links for all Devices ",
|
||
"3.13.1" => "21.09.2019 don't eliminate links for PageEnd-Devices ",
|
||
"3.13.0" => "20.09.2019 change attribute noLinks to dashboard_noLinks, eliminate links for PageEnd-Devices ",
|
||
"3.12.0" => "16.09.2019 new attribute noLinks, review comref and get-options ",
|
||
"3.11.0" => "16.09.2019 attr dashboard_activetab is now working properly, commandref revised, calculate attribute ".
|
||
"dashboard_activetab (is now a userattr) ",
|
||
"3.10.1" => "29.06.2018 added FW_hideDisplayName, Forum #88727 ",
|
||
"1.0.0" => "20.12.2013 initial version released to testers "
|
||
);
|
||
|
||
|
||
#########################
|
||
# Forward declaration
|
||
sub Dashboard_GetGroupList();
|
||
sub Dashboard_searchImage($$$$);
|
||
use vars qw($FW_dir); # base directory for web server
|
||
|
||
#########################
|
||
# Global variables
|
||
my %group;
|
||
my $dashboard_groupListfhem;
|
||
my $fwjquery = "jquery.min.js";
|
||
my $fwjqueryui = "jquery-ui.min.js";
|
||
|
||
#############################################################################################
|
||
sub Dashboard_Initialize ($) {
|
||
my ($hash) = @_;
|
||
|
||
$hash->{DefFn} = "Dashboard_define";
|
||
$hash->{SetFn} = "Dashboard_Set";
|
||
$hash->{GetFn} = "Dashboard_Get";
|
||
$hash->{UndefFn} = "Dashboard_undef";
|
||
$hash->{FW_detailFn} = "Dashboard_DetailFN";
|
||
$hash->{AttrFn} = "Dashboard_Attr";
|
||
$hash->{AttrList} = "disable:0,1 ".
|
||
"dashboard_backgroundimage ".
|
||
"dashboard_colcount:1,2,3,4,5 ".
|
||
"dashboard_customcss " .
|
||
"dashboard_debug:0,1 ".
|
||
"dashboard_flexible " .
|
||
"dashboard_hideGroupHeader:1,0 " .
|
||
"dashboard_rowtopheight ".
|
||
"dashboard_rowbottomheight ".
|
||
"dashboard_row:top,center,bottom,top-center,center-bottom,top-center-bottom ".
|
||
"dashboard_rowcenterheight ".
|
||
"dashboard_rowcentercolwidth ".
|
||
"dashboard_showfullsize:0,1 ".
|
||
"dashboard_showtabs:tabs-and-buttonbar-at-the-top,tabs-and-buttonbar-on-the-bottom,tabs-and-buttonbar-hidden ".
|
||
"dashboard_showtogglebuttons:0,1 ".
|
||
"dashboard_tab1name " .
|
||
"dashboard_tab1groups " .
|
||
"dashboard_tab1devices " .
|
||
"dashboard_tab1sorting " .
|
||
"dashboard_tab1icon " .
|
||
"dashboard_tab1colcount " .
|
||
"dashboard_tab1rowcentercolwidth " .
|
||
"dashboard_tab1backgroundimage " .
|
||
"dashboard_width ".
|
||
"dashboard_noLinks:1,0 ";
|
||
|
||
$data{FWEXT}{jquery}{SCRIPT} = "/pgm2/".$fwjquery if (!$data{FWEXT}{jquery}{SCRIPT});
|
||
$data{FWEXT}{jqueryui}{SCRIPT} = "/pgm2/".$fwjqueryui if (!$data{FWEXT}{jqueryui}{SCRIPT});
|
||
$data{FWEXT}{z_dashboard}{SCRIPT} = "/pgm2/dashboard.js" if (!$data{FWEXT}{z_dashboard});
|
||
$data{FWEXT}{x_dashboard}{SCRIPT} = "/pgm2/svg.js" if (!$data{FWEXT}{x_dashboard});
|
||
|
||
eval { FHEM::Meta::InitMod( __FILE__, $hash ) }; # für Meta.pm (https://forum.fhem.de/index.php/topic,97589.0.html)
|
||
|
||
return undef;
|
||
}
|
||
|
||
################################################################
|
||
# Definition
|
||
################################################################
|
||
sub Dashboard_define ($$) {
|
||
my ($hash, $def) = @_;
|
||
|
||
my @args = split (" ", $def);
|
||
my $now = time();
|
||
my $name = $hash->{NAME};
|
||
|
||
$hash->{HELPER}{MODMETAABSENT} = 1 if($modMetaAbsent); # Modul Meta.pm nicht vorhanden
|
||
|
||
# Versionsinformationen setzen
|
||
Dashboard_setVersionInfo($hash);
|
||
|
||
readingsSingleUpdate( $hash, "state", "Initialized", 0 );
|
||
|
||
RemoveInternalTimer($hash);
|
||
InternalTimer ($now+2, 'Dashboard_init', $hash, 0);
|
||
InternalTimer ($now+5, 'Dashboard_CheckDashboardAttributUssage', $hash, 0);
|
||
|
||
my $url = '/dashboard/'.$name;
|
||
|
||
$data{FWEXT}{$url}{CONTENTFUNC} = 'Dashboard_CGI'; # $data{FWEXT} = FHEMWEB Extension, siehe 01_FHEMWEB.pm
|
||
$data{FWEXT}{$url}{LINK} = 'dashboard/'.$name;
|
||
$data{FWEXT}{$url}{NAME} = $name;
|
||
|
||
return;
|
||
}
|
||
|
||
################################################################
|
||
# Set
|
||
################################################################
|
||
sub Dashboard_Set($@) {
|
||
my ($hash, $name, $cmd, @args) = @_;
|
||
|
||
my $setlist = "Unknown argument $cmd, choose one of ".
|
||
"lock:noArg ".
|
||
"unlock:noArg "
|
||
;
|
||
|
||
my $tl = Dashboard_possibleTabs ($name);
|
||
|
||
$setlist .= "activateTab:$tl " if($tl);
|
||
|
||
if ( $cmd eq "lock" ) {
|
||
readingsSingleUpdate ($hash, "lockstate", "lock", 0);
|
||
return;
|
||
}
|
||
elsif ( $cmd eq "unlock" ) {
|
||
readingsSingleUpdate ($hash, "lockstate", "unlock", 0);
|
||
return;
|
||
}
|
||
elsif ( $cmd eq "activateTab" ) {
|
||
Dashboard_activateTab ($name,$args[0]);
|
||
return;
|
||
}
|
||
else {
|
||
return $setlist;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
################################################################
|
||
# Get
|
||
################################################################
|
||
sub Dashboard_Get($@) {
|
||
my ($hash, @a) = @_;
|
||
my $res = "";
|
||
|
||
my $arg = (defined($a[1]) ? $a[1] : "");
|
||
my $arg2 = (defined($a[2]) ? $a[2] : "");
|
||
|
||
if ($arg eq "config") {
|
||
my $name = $hash->{NAME};
|
||
my $attrdata = $attr{$name};
|
||
if ($attrdata) {
|
||
my $x = keys %$attrdata;
|
||
my $i = 0;
|
||
my @splitattr;
|
||
$res .= "{\n";
|
||
$res .= " \"CONFIG\": {\n";
|
||
$res .= " \"name\": \"$name\",\n";
|
||
$res .= " \"lockstate\": \"".ReadingsVal($name,"lockstate","unlock")."\",\n";
|
||
|
||
my @iconFolders = split(":", AttrVal($FW_wname, "iconPath", "$FW_sp:default:fhemSVG:openautomation"));
|
||
my $iconDirs = "";
|
||
|
||
for my $idir (@iconFolders) {$iconDirs .= "$attr{global}{modpath}/www/images/".$idir.",";}
|
||
|
||
$res .= " \"icondirs\": \"$iconDirs\", \"dashboard_tabcount\": " . Dashboard_GetTabCount($hash, 0). ", \"dashboard_homeTab\": " . Dashboard_GetActiveTab($name);
|
||
$res .= ($i != $x) ? ",\n" : "\n";
|
||
|
||
for my $attr (sort keys %$attrdata) {
|
||
$i++;
|
||
@splitattr = split("@", $attrdata->{$attr});
|
||
|
||
if (@splitattr == 2) {
|
||
$res .= " \"".Dashboard_Escape($attr)."\": \"".$splitattr[0]."\",\n";
|
||
$res .= " \"".Dashboard_Escape($attr)."color\": \"".$splitattr[1]."\"";
|
||
}
|
||
elsif ($attr ne "dashboard_homeTab") {
|
||
$res .= " \"".Dashboard_Escape($attr)."\": \"".$attrdata->{$attr}."\"";
|
||
}
|
||
else {
|
||
next;
|
||
}
|
||
|
||
$res .= ($i != $x) ? ",\n" : "\n";
|
||
}
|
||
|
||
$res .= " }\n";
|
||
$res .= "}\n";
|
||
return $res;
|
||
}
|
||
}
|
||
elsif ($arg eq "groupWidget") {
|
||
#### Comming Soon ######
|
||
# For dynamic load of GroupWidgets from JavaScript
|
||
#my $dbgroup = "";
|
||
#for (my $p=2;$p<@a;$p++){$dbgroup .= @a[$p]." ";} #For Groupnames with Space
|
||
#for (my $p=2;$p<@a;$p++){$dbgroup .= $a[$p]." ";} #For Groupnames with Space
|
||
|
||
#$dashboard_groupListfhem = Dashboard_GetGroupList;
|
||
#%group = Dashboard_BuildGroupList($dashboard_groupListfhem);
|
||
#$res .= Dashboard_BuildGroupWidgets(1,1,1212,trim($dbgroup),"t1c1,".trim($dbgroup).",true,0,0:");
|
||
#return $res;
|
||
#For dynamic loading of tabs
|
||
}
|
||
elsif ($arg eq "tab" && $arg2 =~ /^\d+$/) {
|
||
return Dashboard_BuildDashboardTab($arg2, $hash->{NAME});
|
||
}
|
||
elsif ($arg eq "icon") {
|
||
shift @a;
|
||
shift @a;
|
||
return "Please provide only one icon whose path and full name is to show." if(!@a || $a[1]);
|
||
my $icon = join (' ', @a);
|
||
return FW_iconPath($icon);
|
||
}
|
||
else {
|
||
return "Unknown argument $arg choose one of config:noArg icon";
|
||
}
|
||
}
|
||
|
||
################################################################
|
||
# Attr
|
||
################################################################
|
||
sub Dashboard_Attr($$$) {
|
||
my ($cmd, $name, $aName, $aVal) = @_;
|
||
my $hash = $defs{$name};
|
||
|
||
if ($cmd eq "set") {
|
||
if ($aName =~ m/dashboard_tab([1-9][0-9]*)groups/ || $aName =~ m/dashboard_tab([1-9][0-9]*)devices/) {
|
||
# add dynamic attributes
|
||
addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "name");
|
||
addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "devices");
|
||
addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "groups");
|
||
addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "sorting");
|
||
addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "icon");
|
||
addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "colcount");
|
||
addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "rowcentercolwidth");
|
||
addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "backgroundimage");
|
||
}
|
||
|
||
if ($aName =~ m/alias/) {
|
||
# if an alias is set to the dashboard, replace the name shown in the left navigation by this alias
|
||
my $url = '/dashboard/'.$name;
|
||
$data{FWEXT}{$url}{NAME} = $aVal;
|
||
}
|
||
|
||
if ($aName =~ m/dashboard_homeTab/) {
|
||
Dashboard_activateTab ($name,$aVal);
|
||
}
|
||
}
|
||
|
||
if ($aName =~ m/dashboard_(.*)backgroundimage/) {
|
||
my $ct = "";
|
||
|
||
if (!$1) {
|
||
$ct = "MAIN";
|
||
}
|
||
else {
|
||
$ct = $1;
|
||
}
|
||
|
||
delete $hash->{HELPER}{BIMG}{$ct};
|
||
if($cmd eq "set") {
|
||
Dashboard_searchImage($name, "$FW_dir/images", $aVal,$ct);
|
||
if (!$hash->{HELPER}{BIMG}{$ct}) {
|
||
Log3 ($name, 2, "Dashboard $name - Background image file not found: $aVal");
|
||
return "Background image file not found: $aVal";
|
||
}
|
||
}
|
||
}
|
||
|
||
InternalTimer (time()+2, 'Dashboard_init', $hash, 0);
|
||
|
||
return;
|
||
}
|
||
|
||
################################################################
|
||
# Undefine
|
||
################################################################
|
||
sub Dashboard_undef ($$) {
|
||
my ($hash,$arg) = @_;
|
||
|
||
# remove dashboard links from left menu
|
||
my $url = '/dashboard/'.$hash->{NAME};
|
||
delete $data{FWEXT}{$url};
|
||
|
||
RemoveInternalTimer($hash);
|
||
|
||
return undef;
|
||
}
|
||
|
||
################################################################
|
||
# Routine für FHEMWEB Detailanzeige
|
||
################################################################
|
||
sub Dashboard_DetailFN() {
|
||
my ($name, $d, $room, $pageHash) = @_;
|
||
my $hash = $defs{$name};
|
||
|
||
my $ret = "";
|
||
$ret .= "<table class=\"block wide\" id=\"dashboardtoolbar\" style=\"width:100%\">\n";
|
||
$ret .= "<tr><td>Helper:\n<div>\n";
|
||
$ret .= "<a href=\"$FW_ME/dashboard/".$d."\"><button type=\"button\">Return to Dashboard</button></a>\n";
|
||
$ret .= "<a href=\"$FW_ME?cmd=shutdown restart\"><button type=\"button\">Restart FHEM</button></a>\n";
|
||
$ret .= "<a href=\"$FW_ME?cmd=save\"><button type=\"button\">Save config</button></a>\n";
|
||
$ret .= "</div>\n";
|
||
$ret .= "</td></tr>\n";
|
||
$ret .= "</table>\n";
|
||
|
||
return $ret;
|
||
}
|
||
|
||
#############################################################################################
|
||
# Common Start
|
||
#############################################################################################
|
||
sub Dashboard_CGI($) {
|
||
my $htmlarg = shift;
|
||
|
||
$htmlarg =~ s/^\///; # eliminate leading /
|
||
my @params = split(/\//,$htmlarg); # split URL by /
|
||
my $ret = '';
|
||
my $name = $params[1];
|
||
|
||
$ret = '<div id="content">';
|
||
|
||
if ($name && defined($defs{$name})) {
|
||
my $showfullsize = AttrVal($name, "dashboard_showfullsize", 0);
|
||
|
||
if ($showfullsize) {
|
||
if ($FW_RET =~ m/<body[^>]*class="([^"]+)"[^>]*>/) {
|
||
$FW_RET =~ s/class="$1"/class="$1 dashboard_fullsize"/;
|
||
}
|
||
else {
|
||
$FW_RET =~ s/<body/<body class="dashboard_fullsize"/;
|
||
}
|
||
}
|
||
$ret .= Dashboard_SummaryFN($FW_wname,$name,$FW_room,undef);
|
||
}
|
||
else {
|
||
$ret .= 'Dashboard "'.$name.'" not found';
|
||
}
|
||
|
||
$ret .= '</div>';
|
||
FW_pO $ret;
|
||
|
||
# empty room to make sure no room actions are taken by the framework
|
||
$FW_room = '';
|
||
|
||
return 0;
|
||
}
|
||
|
||
#############################################################################################
|
||
# Dashboard als HTML-Ausgabe
|
||
#############################################################################################
|
||
sub DashboardAsHtml($) {
|
||
my $d = shift;
|
||
Dashboard_SummaryFN($FW_wname,$d,$FW_room,undef);
|
||
}
|
||
|
||
#############################################################################################
|
||
# zentrale Dashboard Generierung
|
||
# (beachte $data{FWEXT} bzw. $data{FWEXT}{CONTENTFUNC} in 01_FHEMWEB.pm)
|
||
#############################################################################################
|
||
sub Dashboard_SummaryFN ($$$$) {
|
||
my ($FW_wname, $d, $room, $pageHash) = @_;
|
||
|
||
my $ret = "";
|
||
my $showbuttonbar = "hidden";
|
||
my $debugfield = "hidden";
|
||
my $hash = $defs{$d};
|
||
my $name = $d;
|
||
my $id = $defs{$d}{NR};
|
||
|
||
######################### Read Dashboard Attributes and set Default-Values ####################################
|
||
my $showtabs = AttrVal($name, "dashboard_showtabs", "tabs-and-buttonbar-at-the-top");
|
||
my $lockstate = ReadingsVal($name, "lockstate", "unlock");
|
||
my $showhelper = ($lockstate eq "unlock") ? 1 : 0;
|
||
my $disable = AttrVal($name, "disable", 0);
|
||
my $colcount = AttrVal($name, "dashboard_colcount", 1);
|
||
my $colwidth = AttrVal($name, "dashboard_rowcentercolwidth", 100);
|
||
my $colheight = AttrVal($name, "dashboard_rowcenterheight", 400);
|
||
my $rowtopheight = AttrVal($name, "dashboard_rowtopheight", 250);
|
||
my $rowbottomheight = AttrVal($name, "dashboard_rowbottomheight", 250);
|
||
my $showtogglebuttons = AttrVal($name, "dashboard_showtogglebuttons", 1);
|
||
my $showfullsize = AttrVal($name, "dashboard_showfullsize", 0);
|
||
my $flexible = AttrVal($name, "dashboard_flexible", 0);
|
||
my $customcss = AttrVal($name, "dashboard_customcss", "none");
|
||
# my $row = AttrVal($name, "dashboard_row", "center");
|
||
my $debug = AttrVal($name, "dashboard_debug", "0");
|
||
my ($activetab,$tabname) = Dashboard_GetActiveTab($name,1);
|
||
my $tabcount = Dashboard_GetTabCount($hash, 1);
|
||
my $dashboardversion = $hash->{HELPER}{VERSION};
|
||
my $dbwidth = AttrVal($name, "dashboard_width", "100%");
|
||
my @tabnames = ();
|
||
my @tabsortings = ();
|
||
|
||
for (my $i = 0; $i < $tabcount; $i++) {
|
||
$tabnames[$i] = AttrVal($name, "dashboard_tab" . ($i + 1) . "name", "Dashboard-Tab " . ($i + 1));
|
||
$tabsortings[$i] = AttrVal($name, "dashboard_tab" . ($i + 1) . "sorting", "");
|
||
}
|
||
|
||
if ($disable == 1) {
|
||
readingsSingleUpdate($hash, "state", "Disabled", 0 );
|
||
return "";
|
||
}
|
||
|
||
# Hintergrundbild bauen
|
||
my $bimg = $hash->{HELPER}{BIMG}{MAIN}?"url(/fhem/images/$hash->{HELPER}{BIMG}{MAIN})":"none";
|
||
|
||
if ($debug == 1) { $debugfield = "edit"; }
|
||
if ($showtabs eq "tabs-and-buttonbar-at-the-top") { $showbuttonbar = "top"; }
|
||
if ($showtabs eq "tabs-and-buttonbar-on-the-bottom") { $showbuttonbar = "bottom"; }
|
||
if ($showbuttonbar eq "hidden") { $lockstate = "lock"; }
|
||
if ($activetab > $tabcount) { $activetab = $tabcount; }
|
||
|
||
$colwidth =~ tr/,/:/;
|
||
if (not ($colheight =~ /^\d+$/)) { $colheight = 400; }
|
||
if (not ($rowtopheight =~ /^\d+$/)) { $rowtopheight = 50; }
|
||
if (not ($rowbottomheight =~ /^\d+$/)) { $rowbottomheight = 50; }
|
||
|
||
#------------------- Check dashboard_sorting on false content ------------------------------------
|
||
for (my $i=0;$i<@tabsortings;$i++){
|
||
if (($tabsortings[$i-1] !~ /[0-9]+/ || $tabsortings[$i-1] !~ /:/ || $tabsortings[$i-1] !~ /,/ ) && ($tabsortings[$i-1] ne "," && $tabsortings[$i-1] ne "")) {
|
||
Log3 ($name, 3, "Dashboard $name - Value of attribut dashboard_tab".$i."sorting is wrong. Saved sorting can not be set. Fix Value or delete the Attribute. [".$tabsortings[$i-1]."]");
|
||
}
|
||
else {
|
||
Log3 ($name, 5, "Dashboard $name - Sorting OK or Empty: dashboard_tab".$i."sorting");
|
||
}
|
||
}
|
||
#-------------------------------------------------------------------------------------------------
|
||
|
||
if ($room ne "all") {
|
||
############################ Set FHEM url to avoid hardcoding it in javascript ############################
|
||
$ret .= "<script type='text/javascript'>var fhemUrl = '".$FW_ME."';</script>";
|
||
|
||
## Dashboard-Tab Details Tabelle (Stift rechte Seite im Kopf)
|
||
$ret .= "<div id=\"tabEdit\" class=\"dashboard-dialog-content dashboard-widget-content\" title=\"Dashboard-Tab\" style=\"display:none;\">\n";
|
||
$ret .= "<div id=\"dashboard-dialog-tabs\" class=\"dashboard dashboard_tabs\">\n";
|
||
|
||
$ret .= "<ul class=\"dashboard dashboard_tabnav\">\n";
|
||
$ret .= "<li class=\"dashboard dashboard_tab\"><a href=\"#tabs-1\">Current Tab</a></li>\n";
|
||
$ret .= "<li class=\"dashboard dashboard_tab\"><a href=\"#tabs-2\">Common</a></li>\n";
|
||
$ret .= "</ul>\n";
|
||
|
||
$ret .= "<div id=\"tabs-1\" class=\"dashboard_tabcontent\">\n";
|
||
$ret .= "<table>\n";
|
||
$ret .= "<tr colspan=\"2\">";
|
||
$ret .= "<td><div id=\"tabID\"></div></td>";
|
||
$ret .= "</tr>\n";
|
||
$ret .= "<tr>";
|
||
$ret .= "<td>Tabtitle:</td><td colspan=\"2\"><input id=\"tabTitle\" type=\"text\" size=\"25\"></td>";
|
||
$ret .= "</tr>";
|
||
$ret .= "<tr>";
|
||
$ret .= "<td>Tabicon:</td><td><input id=\"tabIcon\" type=\"text\" size=\"10\"></td><td><input id=\"tabIconColor\" type=\"text\" size=\"7\"></td>";
|
||
$ret .= "</tr>";
|
||
# the method FW_multipleSelect seems not to be available any more in fhem
|
||
#$ret .= "<tr><td>Groups:</td><td colspan=\"2\"><input id=\"tabGroups\" type=\"text\" size=\"25\" onfocus=\"FW_multipleSelect(this)\" allvals=\"multiple,$dashboard_groupListfhem\" readonly=\"readonly\"></td></tr>";
|
||
$ret .= "<tr>";
|
||
$ret .= "<td>Groups:</td><td colspan=\"2\"><input id=\"tabGroups\" type=\"text\" size=\"25\"></td>";
|
||
$ret .= "</tr>";
|
||
$ret .= "<tr>";
|
||
$ret .= "<td></td><td colspan=\"2\"><input type=\"checkbox\" id=\"tabActiveTab\" value=\"\"><label for=\"tabActiveTab\">This Tab is currently selected</label></td>";
|
||
$ret .= "</tr>";
|
||
$ret .= "</table>\n";
|
||
$ret .= "</div>\n";
|
||
|
||
$ret .= "<div id=\"tabs-2\" class=\"dashboard_tabcontent\">\n";
|
||
$ret .= "Comming soon";
|
||
$ret .= "</div>\n";
|
||
|
||
$ret .= "</div>\n";
|
||
$ret .= "</div>\n";
|
||
## Ende Dashboard-Tab Details Tabelle
|
||
|
||
$ret .= "<div id=\"dashboard_define\" style=\"display: none;\">$name</div>\n";
|
||
$ret .= "<table class=\"roomoverview dashboard\" id=\"dashboard\">\n";
|
||
|
||
$ret .= "<tr style=\"height: 0px;\"><td><div class=\"dashboardhidden\">\n";
|
||
$ret .= "<input type=\"$debugfield\" size=\"100%\" id=\"dashboard_attr\" value=\"$name,$dbwidth,$showhelper,$lockstate,$showbuttonbar,$colheight,$showtogglebuttons,$colcount,$rowtopheight,$rowbottomheight,$tabcount,$activetab,$colwidth,$showfullsize,$customcss,$flexible\">\n";
|
||
$ret .= "<input type=\"$debugfield\" size=\"100%\" id=\"dashboard_jsdebug\" value=\"\">\n";
|
||
$ret .= "</div></td></tr>\n";
|
||
|
||
## Tab Content
|
||
$ret .= "<tr><td>\n";
|
||
$ret .= "<div id=\"dashboardtabs\" class=\"dashboard dashboard_tabs\" style=\"background: ".$bimg." no-repeat !important;\">";
|
||
|
||
########################### Dashboard Tab-Liste ##############################################
|
||
$ret .= " <ul id=\"dashboard_tabnav\" class=\"dashboard dashboard_tabnav dashboard_tabnav_".$showbuttonbar."\">\n";
|
||
for (my $i=0;$i<$tabcount;$i++) {
|
||
$ret .= "<li class=\"dashboard dashboard_tab dashboard_tab_".$showbuttonbar."\"><a href=\"#dashboard_tab".$i."\">".trim($tabnames[$i])."</a></li>";
|
||
}
|
||
$ret .= " </ul>\n";
|
||
########################################################################################
|
||
|
||
for (my $t=0;$t<$tabcount;$t++) {
|
||
if ($t == $activetab - 1) {
|
||
$ret .= Dashboard_BuildDashboardTab($t, $name);
|
||
}
|
||
}
|
||
$ret .= "</div>";
|
||
$ret .= "</td></tr>\n";
|
||
$ret .= "</table>\n";
|
||
}
|
||
else {
|
||
$ret .= "<table>";
|
||
$ret .= "<tr><td><div class=\"devType\">".$hash->{TYPE}."</div></td></tr>";
|
||
$ret .= "<tr><td><table id=\"TYPE_".$hash->{TYPE}."\" class=\"block wide\">";
|
||
$ret .= "<tbody><tr>";
|
||
$ret .= "<td><div><a href=\"$FW_ME?detail=$name\">$name</a></div></td>";
|
||
$ret .= "<td><div>".$hash->{STATE}."</div></td>";
|
||
$ret .= "</tr></tbody>";
|
||
$ret .= "</table></td></tr>";
|
||
$ret .= "</table>";
|
||
}
|
||
|
||
return $ret;
|
||
}
|
||
|
||
#############################################################################################
|
||
# Dashboard Tabs erstellen
|
||
#############################################################################################
|
||
sub Dashboard_BuildDashboardTab ($$) {
|
||
my ($t, $name) = @_;
|
||
my $hash = $defs{$name};
|
||
my $ret;
|
||
|
||
my $id = $hash->{NR};
|
||
my $colcount = AttrVal($name, 'dashboard_tab'.($t+1).'colcount', AttrVal($name, "dashboard_colcount", 1));
|
||
my $colwidths = AttrVal($name, 'dashboard_tab'.($t+1).'rowcentercolwidth', AttrVal($name, "dashboard_rowcentercolwidth", 100));
|
||
$colwidths =~ tr/,/:/;
|
||
my $row = AttrVal($name, "dashboard_row", "center");
|
||
my $tabgroups = AttrVal($name, "dashboard_tab".($t+1)."groups", "");
|
||
my $tabsortings = AttrVal($name, "dashboard_tab".($t+1)."sorting", "");
|
||
my $tabdevicegroups = AttrVal($name, "dashboard_tab".($t+1)."devices", "");
|
||
my $tabcount = Dashboard_GetTabCount($hash, 1);
|
||
|
||
unless ($tabgroups || $tabdevicegroups) {
|
||
readingsSingleUpdate($hash, "state", "No Groups or devices set", 0);
|
||
return "";
|
||
}
|
||
|
||
# Hintergrundbild bauen
|
||
my $ct = "tab".($t+1);
|
||
my $bimg = $hash->{HELPER}{BIMG}{$ct}?"url(/fhem/images/$hash->{HELPER}{BIMG}{$ct})":"none";
|
||
|
||
my @temptabdevicegroup = split(' ', $tabdevicegroups);
|
||
my @tabdevicegroups = ();
|
||
|
||
# make sure device groups without a group name are splitted into
|
||
# separate groups for every device they are containing
|
||
for my $devicegroup (@temptabdevicegroup) {
|
||
my @groupparts = split(':', $devicegroup);
|
||
|
||
if (@groupparts == 1) {
|
||
my @devices = map { $_ . '$$$' . $_ } devspec2array($groupparts[0]);
|
||
push(@tabdevicegroups, @devices);
|
||
}
|
||
else {
|
||
push(@tabdevicegroups, $devicegroup);
|
||
}
|
||
}
|
||
|
||
my $groups = Dashboard_GetGroupList();
|
||
$groups =~ s/#/ /g;
|
||
my @groups = split ',', $groups;
|
||
my @temptabgroup = split ',', $tabgroups;
|
||
|
||
# resolve group names from regular expressions
|
||
for (my $i=0;$i<@temptabgroup;$i++) {
|
||
my @stabgroup = split ":", trim($temptabgroup[$i]);
|
||
next if(!$stabgroup[0]);
|
||
my @index = grep { $groups[$_] eq $stabgroup[0] } (0 .. @groups-1);
|
||
|
||
if (@index == 0) {
|
||
my $matchGroup = '^'.$stabgroup[0] . '$';
|
||
@index = grep { $groups[$_] =~ m/$matchGroup/ } (0 .. @groups-1);
|
||
}
|
||
|
||
if (@index > 0) {
|
||
for (my $j=0; $j<@index;$j++) {
|
||
my $groupname = @groups[$index[$j]];
|
||
$groupname .= '$$$'.'a:group='.$groupname;
|
||
|
||
if (@stabgroup > 1) {
|
||
$groupname .= '$$$'.$stabgroup[1];
|
||
}
|
||
|
||
push(@tabdevicegroups,$groupname);
|
||
}
|
||
}
|
||
}
|
||
|
||
$tabgroups = join('§§§', @tabdevicegroups);
|
||
|
||
# add sortings for groups not already having a defined sorting
|
||
for (my $i=0;$i<@tabdevicegroups;$i++) {
|
||
my @stabgroup = split(/\$\$\$/, trim($tabdevicegroups[$i]));
|
||
my $matchGroup = ",".quotemeta(trim($stabgroup[0])).",";
|
||
|
||
if ($tabsortings !~ m/$matchGroup/) {
|
||
$tabsortings = $tabsortings."t".$t."c".Dashboard_GetMaxColumnId($row,$colcount).",".trim($stabgroup[0]).",true,0,0:";
|
||
}
|
||
}
|
||
|
||
$ret = "<div id=\"dashboard_tab".$t."\" data-tabwidgets=\"".$tabsortings."\" data-tabcolwidths=\"".$colwidths."\" class=\"dashboard dashboard_tabpanel\" style=\"background: ".$bimg." no-repeat !important;\">\n";
|
||
$ret .= "<ul class=\"dashboard_tabcontent\">\n";
|
||
$ret .= "<table class=\"dashboard_tabcontent\">\n";
|
||
|
||
##################### Top Row (only one Column) #############################################
|
||
if ($row eq "top-center-bottom" || $row eq "top-center" || $row eq "top"){
|
||
$ret .= Dashboard_BuildDashboardTopRow($name,$t,$id,$tabgroups,$tabsortings);
|
||
}
|
||
##################### Center Row (max. 5 Column) ############################################
|
||
if ($row eq "top-center-bottom" || $row eq "top-center" || $row eq "center-bottom" || $row eq "center") {
|
||
$ret .= Dashboard_BuildDashboardCenterRow($name,$t,$id,$tabgroups,$tabsortings,$colcount);
|
||
}
|
||
############################# Bottom Row (only one Column) ############################################
|
||
if ($row eq "top-center-bottom" || $row eq "center-bottom" || $row eq "bottom"){
|
||
$ret .= Dashboard_BuildDashboardBottomRow($name,$t,$id,$tabgroups,$tabsortings);
|
||
}
|
||
|
||
$ret .= "</table>\n";
|
||
$ret .= "</ul>\n";
|
||
$ret .= "</div>\n";
|
||
|
||
return $ret;
|
||
}
|
||
|
||
#############################################################################################
|
||
# Oberste Zeile erstellen
|
||
#############################################################################################
|
||
sub Dashboard_BuildDashboardTopRow ($$$$$) {
|
||
my ($name,$t,$id, $devicegroups, $groupsorting) = @_;
|
||
my $ret;
|
||
|
||
$ret .= "<tr><td class=\"dashboard_row\">\n";
|
||
$ret .= "<div id=\"dashboard_rowtop_tab".$t."\" class=\"dashboard dashboard_rowtop\">\n";
|
||
|
||
$ret .= "<div class=\"dashboard ui-row dashboard_row dashboard_column\" id=\"dashboard_tab".$t."column100\">\n";
|
||
$ret .= Dashboard_BuildGroupWidgets($name,$t,"100",$id,$devicegroups,$groupsorting);
|
||
$ret .= "</div>\n";
|
||
|
||
$ret .= "</div>\n";
|
||
$ret .= "</td></tr>\n";
|
||
|
||
return $ret;
|
||
}
|
||
|
||
#############################################################################################
|
||
#
|
||
#############################################################################################
|
||
sub Dashboard_BuildDashboardCenterRow ($$$$$$) {
|
||
my ($name,$t,$id, $devicegroups, $groupsorting, $colcount) = @_;
|
||
|
||
my $ret = "<tr><td class=\"dashboard_row\">\n";
|
||
$ret .= "<div id=\"dashboard_rowcenter_tab".$t."\" class=\"dashboard dashboard_rowcenter\">\n";
|
||
|
||
my $currentcol = $colcount;
|
||
my $maxcolindex = $colcount - 1;
|
||
my $replace = "t".$t."c".$maxcolindex.",";
|
||
|
||
# replace all sortings referencing not existing columns
|
||
# this does only work if there is no empty column inbetween
|
||
while (index($groupsorting, "t".$t."c".$currentcol.",") >= 0) {
|
||
my $search = "t" . $t . "c" . $currentcol . ",";
|
||
$groupsorting =~ s/$search/$replace/g;
|
||
$currentcol++;
|
||
}
|
||
|
||
for (my $i=0;$i<$colcount;$i++){
|
||
$ret .= "<div class=\"dashboard ui-row dashboard_row dashboard_column\" id=\"dashboard_tab".$t."column".$i."\">\n";
|
||
$ret .= Dashboard_BuildGroupWidgets($name,$t,$i,$id,$devicegroups,$groupsorting);
|
||
$ret .= "</div>\n";
|
||
}
|
||
$ret .= "</div>\n";
|
||
$ret .= "</td></tr>\n";
|
||
|
||
return $ret;
|
||
}
|
||
|
||
#############################################################################################
|
||
#
|
||
#############################################################################################
|
||
sub Dashboard_BuildDashboardBottomRow ($$$$$) {
|
||
my ($name,$t,$id, $devicegroups, $groupsorting) = @_;
|
||
my $ret;
|
||
$ret .= "<tr><td class=\"dashboard_row\">\n";
|
||
|
||
$ret .= "<div class=\"dashboard ui-row dashboard_row dashboard_column\" id=\"dashboard_tab".$t."column200\">\n";
|
||
$ret .= Dashboard_BuildGroupWidgets($name,$t,"200",$id,$devicegroups,$groupsorting);
|
||
$ret .= "</div>\n";
|
||
|
||
$ret .= "</div>\n";
|
||
$ret .= "</td></tr>\n";
|
||
|
||
return $ret;
|
||
}
|
||
|
||
#############################################################################################
|
||
#
|
||
#############################################################################################
|
||
sub Dashboard_BuildGroupWidgets ($$$$$$) {
|
||
my ($name,$tab,$column,$id,$devicegroups,$groupsorting) = @_;
|
||
my $ret = "";
|
||
|
||
my $counter = 0;
|
||
my %sorting = ();
|
||
my %groups = ();
|
||
my @groupnames = ();
|
||
|
||
for (split(":", $groupsorting)) {
|
||
my @parts = split (',', $_);
|
||
$sorting{$parts[1]} = $_;
|
||
# add group names to a list to have the correct order afterwards in the foreach loop
|
||
# store the group names in the right order to use them in the foreach loop
|
||
push(@groupnames, $parts[1]);
|
||
}
|
||
|
||
my @devicegroups = split('§§§', $devicegroups);
|
||
|
||
# sort the devices into a hash to be able to access them via group name
|
||
for my $singlegroup (@devicegroups) {
|
||
# make sure that splitting with colon is not destroying the devspec that might
|
||
# also contain a colon followed by a filter
|
||
my ($groupname, $groupdevices, $groupicon) = split(/\$\$\$/, $singlegroup);
|
||
|
||
my @values = ($groupdevices, $groupicon);
|
||
$groups{$groupname} = \@values;
|
||
}
|
||
|
||
my $groupicon = '';
|
||
|
||
for my $groupname (@groupnames) {
|
||
next if (!defined($groups{$groupname}));
|
||
my ($groupdevices, $groupicon) = @{$groups{$groupname}};
|
||
|
||
# if the device is not stored in the current column, skip it
|
||
next if (index($sorting{$groupname}, 't'.$tab.'c'.$column) < 0);
|
||
my $groupId = $id."t".$tab."c".$column."w".$counter;
|
||
|
||
$ret .= Dashboard_BuildGroup($name,$groupname,$groupdevices,$sorting{$groupname},$groupId,$groupicon);
|
||
$counter++;
|
||
}
|
||
|
||
return $ret;
|
||
}
|
||
|
||
#############################################################################################
|
||
#
|
||
#############################################################################################
|
||
sub Dashboard_BuildGroupList ($) {
|
||
my @dashboardgroups = split(",", $_[0]); #array for all groups to build an widget
|
||
my %group = ();
|
||
|
||
for my $d (sort keys %defs) {
|
||
for my $grp (split(",", AttrVal($d, "group", ""))) {
|
||
$grp = trim($grp);
|
||
for my $g (@dashboardgroups){
|
||
my ($gtitle, $iconName) = split(":", trim($g));
|
||
my $titleMatch = "^" . quotemeta($gtitle) . "\$";
|
||
$group{$grp}{$d} = 1 if($grp =~ $titleMatch);
|
||
}
|
||
}
|
||
}
|
||
|
||
return %group;
|
||
}
|
||
|
||
#############################################################################################
|
||
#
|
||
#############################################################################################
|
||
sub Dashboard_GetGroupList() {
|
||
my %allGroups = ();
|
||
|
||
for my $d (keys %defs ) {
|
||
next if(IsIgnored($d));
|
||
for my $g (split(",", AttrVal($d, "group", ""))) { $allGroups{$g}{$d} = 1; }
|
||
}
|
||
my $ret = join(",", sort map { $_ =~ s/ /#/g ;$_} keys %allGroups);
|
||
|
||
return $ret;
|
||
}
|
||
|
||
#############################################################################################
|
||
#
|
||
#############################################################################################
|
||
sub Dashboard_BuildGroup ($$$$$$) {
|
||
my ($name,$groupname,$devices,$sorting,$groupId,$icon) = @_;
|
||
my $row = 1;
|
||
my %extPage = ();
|
||
my $foundDevices = 0;
|
||
my $replaceGroup = "";
|
||
my $ret = "";
|
||
|
||
my $rf = ($FW_room ? "&room=$FW_room" : ""); # stay in the room
|
||
|
||
$ret .= "<div class=\"dashboard dashboard_widget ui-widget\" data-groupwidget=\"".$sorting."\" id=\"".$groupId."\">\n";
|
||
$ret .= "<div class=\"dashboard_widgetinner\">\n";
|
||
|
||
if ($groupname && $groupname ne $devices && !AttrVal($name,"dashboard_hideGroupHeader",0)) {
|
||
$ret .= "<div class=\"dashboard_widgetheader ui-widget-header dashboard_group_header\">";
|
||
if ($icon) {
|
||
$ret.= FW_makeImage($icon,$icon,"dashboard_group_icon");
|
||
}
|
||
$ret .= $groupname."</div>\n";
|
||
}
|
||
$ret .= "<div data-userheight=\"\" class=\"dashboard_content\">\n";
|
||
$ret .= "<table class=\"dashboard block wide\" id=\"TYPE_$groupname\">";
|
||
|
||
my %seen;
|
||
|
||
# make sure devices are not contained twice in the list
|
||
my @devices = grep { !$seen{$_}++ } devspec2array($devices);
|
||
|
||
# sort the devices in alphabetical order by sortby, alias, name
|
||
@devices = sort { lc(AttrVal($a,'sortby',AttrVal($a,'alias',$a))) cmp lc(AttrVal($b,'sortby',AttrVal($b,'alias',$b))) } @devices;
|
||
|
||
for my $d (@devices) {
|
||
next if (!defined($defs{$d}));
|
||
$foundDevices++;
|
||
|
||
$ret .= sprintf("<tr class=\"%s\">", ($row&1)?"odd":"even");
|
||
|
||
my $type = $defs{$d}{TYPE};
|
||
my $devName = AttrVal($d, "alias", $d);
|
||
my $icon = AttrVal($d, "icon", "");
|
||
$icon = FW_makeImage($icon,$icon,"icon dashboard_groupicon")." " if($icon);
|
||
$devName = "" if($modules{$defs{$d}{TYPE}}{FW_hideDisplayName}); # Forum 88667
|
||
|
||
if (!$modules{$defs{$d}{TYPE}}{FW_atPageEnd}) { # Don't show Link for "atEnd"-devices
|
||
if(AttrVal($name, "dashboard_noLinks", 0)) {
|
||
$ret .= "<td>$icon$devName</td>"; # keine Links zur Detailansicht des Devices
|
||
}
|
||
else {
|
||
$ret .= FW_pH ("detail=$d", "$icon$devName", 1, "col1", 1); # FW_pH = add href (<link>, <Text>, <?>, <class>, <Wert zurückgeben>, <?>)
|
||
}
|
||
}
|
||
|
||
$row++;
|
||
|
||
$extPage{group} = $groupname;
|
||
my ($allSets, $cmdlist, $txt) = FW_devState($d, $rf, \%extPage);
|
||
$allSets = FW_widgetOverride($d, $allSets);
|
||
|
||
############## Customize Result for Special Types #####################
|
||
my @txtarray = split(">", $txt);
|
||
if ($modules{$defs{$d}{TYPE}}{FW_atPageEnd}) {
|
||
no strict "refs";
|
||
my $devret = &{$modules{$defs{$d}{TYPE}}{FW_summaryFn}}($FW_wname, $d, $FW_room, \%extPage);
|
||
$ret .= "<td class=\"dashboard_dev_container\"";
|
||
|
||
if ($devret !~ /informId/i) {
|
||
$ret .= " informId=\"$d\"";
|
||
}
|
||
|
||
$ret .= ">$devret</td>";
|
||
use strict "refs";
|
||
|
||
}
|
||
else {
|
||
$ret .= "<td informId=\"$d\">$txt</td>";
|
||
}
|
||
|
||
############## Commands, slider, dropdown #####################
|
||
my $smallscreenCommands = AttrVal($FW_wname, "smallscreenCommands", "");
|
||
if((!$FW_ss || $smallscreenCommands) && $cmdlist) {
|
||
my @a = split("[: ]", AttrVal($d, "cmdIcon", ""));
|
||
my %cmdIcon = @a;
|
||
|
||
for my $cmd (split(":", $cmdlist)) {
|
||
my $htmlTxt;
|
||
my @c = split(' ', $cmd);
|
||
|
||
if(int(@c) && $allSets && $allSets =~ m/\b$c[0]:([^ ]*)/) {
|
||
my $values = $1;
|
||
for my $fn (sort keys %{$data{webCmdFn}}) {
|
||
no strict "refs";
|
||
$htmlTxt = &{$data{webCmdFn}{$fn}}($FW_wname, $d, $FW_room, $cmd, $values);
|
||
use strict "refs";
|
||
last if(defined($htmlTxt));
|
||
}
|
||
}
|
||
|
||
if($htmlTxt) {
|
||
# add colspan to avoid squeezed table cells
|
||
$htmlTxt =~ s/<td>/<td colspan="10">/;
|
||
$ret .= $htmlTxt;
|
||
}
|
||
else {
|
||
my $nCmd = $cmdIcon{$cmd} ?
|
||
FW_makeImage($cmdIcon{$cmd},$cmd,"webCmd") : $cmd;
|
||
$ret .= FW_pH "cmd.$d=set $d $cmd$rf", $nCmd, 1, "col3", 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
$ret .= "</tr>";
|
||
if(AttrVal($name, "dashboard_noLinks", 0)) {
|
||
$ret =~ s/(<a\s+href="\/fhem\?detail=$d">(.*)<\/a>)/$2/s; # keine Links zur Detailansicht des Devices
|
||
}
|
||
}
|
||
|
||
$ret .= "</table>";
|
||
$ret .= " </div>\n";
|
||
$ret .= " </div>\n";
|
||
$ret .= " </div>\n";
|
||
|
||
if (!$foundDevices) {
|
||
$ret .= "<table class=\"block wide\" id=\"TYPE_unknowngroup\">";
|
||
$ret .= "<tr class=\"odd\"><td class=\"changed\">Devices for group not found: $groupname</td></tr>";
|
||
$ret .= "<tr class=\"even\"><td class=\"changed\">Check if the device/group attribute is really set</td></tr>";
|
||
$ret .= "<tr class=\"odd\"><td class=\"changed\">Check if the device spec is correctly written</td></tr>";
|
||
$ret .= "</table>";
|
||
}
|
||
|
||
return $ret;
|
||
}
|
||
|
||
#############################################################################################
|
||
#
|
||
#############################################################################################
|
||
sub Dashboard_GetMaxColumnId ($$) {
|
||
my ($row, $colcount) = @_;
|
||
my $maxcolid = "0";
|
||
|
||
if (index($row,"bottom") > 0) { $maxcolid = "200"; }
|
||
elsif (index($row,"center") > 0) { $maxcolid = $colcount-1; }
|
||
elsif (index($row,"top") > 0) { $maxcolid = "100"; }
|
||
|
||
return $maxcolid;
|
||
}
|
||
|
||
#############################################################################################
|
||
#
|
||
#############################################################################################
|
||
sub Dashboard_CheckDashboardEntry ($) {
|
||
my $hash = shift;
|
||
my $now = time();
|
||
my $timeToExec = $now + 5;
|
||
|
||
RemoveInternalTimer($hash);
|
||
InternalTimer ($timeToExec, 'Dashboard_CheckDashboardAttributUssage', $hash, 0);
|
||
|
||
return;
|
||
}
|
||
|
||
#############################################################################################
|
||
# replaces old disused attributes and their values | set minimal attributes
|
||
#############################################################################################
|
||
sub Dashboard_CheckDashboardAttributUssage($) {
|
||
my $hash = shift;
|
||
my $d = $hash->{NAME};
|
||
my $dashboardversion = $hash->{HELPER}{VERSION};
|
||
my $detailnote = "";
|
||
|
||
# --------- Set minimal Attributes in the hope to make it easier for beginners --------------------
|
||
my $tab1groups = AttrVal($d, "dashboard_tab1groups", "<noGroup>");
|
||
if ($tab1groups eq "<noGroup>") {
|
||
FW_fC("attr ".$d." dashboard_tab1groups Set your FHEM groups here and arrange them on tab 1");
|
||
}
|
||
|
||
# ---------------- Delete empty Groups entries ----------------------------------------------------------
|
||
my $tabgroups = AttrVal($d, "dashboard_tab1groups", "999");
|
||
if ($tabgroups eq "1" ) { FW_fC("deleteattr ".$d." dashboard_tab1groups"); }
|
||
$tabgroups = AttrVal($d, "dashboard_tab2groups", "999");
|
||
if ($tabgroups eq "1" ) { FW_fC("deleteattr ".$d." dashboard_tab2groups"); }
|
||
$tabgroups = AttrVal($d, "dashboard_tab3groups", "999");
|
||
if ($tabgroups eq "1" ) { FW_fC("deleteattr ".$d." dashboard_tab3groups"); }
|
||
$tabgroups = AttrVal($d, "dashboard_tab4groups", "999");
|
||
if ($tabgroups eq "1" ) { FW_fC("deleteattr ".$d." dashboard_tab4groups"); }
|
||
$tabgroups = AttrVal($d, "dashboard_tab5groups", "999");
|
||
if ($tabgroups eq "1" ) { FW_fC("deleteattr ".$d." dashboard_tab5groups"); }
|
||
|
||
my $lockstate = AttrVal($d, "dashboard_lockstate", ""); # outdates 04.2014
|
||
if ($lockstate ne "") {
|
||
{ FW_fC("deleteattr ".$d." dashboard_lockstate"); }
|
||
Log3 ($d, 3, "Dashboard $d - Using an outdated no longer used Attribute or Value. This has been corrected. Don't forget to save config. [dashboard_lockstate]");
|
||
}
|
||
my $showhelper = AttrVal($d, "dashboard_showhelper", ""); # outdates 04.2014
|
||
if ($showhelper ne "") {
|
||
{ FW_fC("deleteattr ".$d." dashboard_showhelper"); }
|
||
Log3 $hash, 3, "[".$d. " V".$dashboardversion."]"." Using an outdated no longer used Attribute or Value. This has been corrected. Don't forget to save config. [dashboard_showhelper]";
|
||
}
|
||
my $showtabs = AttrVal($d, "dashboard_showtabs", ""); # delete values 04.2014
|
||
if ($showtabs eq "tabs-at-the-top-buttonbar-hidden") {
|
||
{ FW_fC("set ".$d." dashboard_showtabs tabs-and-buttonbar-at-the-top"); }
|
||
Log3 $hash, 3, "[".$d. " V".$dashboardversion."]"." Using an outdated no longer used Attribute or Value. This has been corrected. Don't forget to save config. [tabs-at-the-top-buttonbar-hidden]";
|
||
}
|
||
if ($showtabs eq "tabs-on-the-bottom-buttonbar-hidden") {
|
||
{ FW_fC("set ".$d." dashboard_showtabs tabs-and-buttonbar-on-the-bottom"); }
|
||
Log3 $hash, 3, "[".$d. " V".$dashboardversion."]"." Using an outdated no longer used Attribute or Value. This has been corrected. Don't forget to save config. [tabs-on-the-bottom-buttonbar-hidden]";
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
#############################################################################################
|
||
# Anzahl der vorhandenen Tabs ermitteln und zurück geben
|
||
#############################################################################################
|
||
sub Dashboard_GetTabCount ($$) {
|
||
my ($hash, $defaultTabCount) = @_;
|
||
my $tabCount = 0;
|
||
|
||
while (AttrVal($hash->{NAME}, 'dashboard_tab' . ($tabCount + 1) . 'groups', '') ne ""
|
||
|| AttrVal($hash->{NAME}, 'dashboard_tab' . ($tabCount + 1) . 'devices', '') ne "") {
|
||
$tabCount++;
|
||
}
|
||
|
||
return $tabCount ? $tabCount : $defaultTabCount;
|
||
}
|
||
|
||
#############################################################################################
|
||
# Aktives Tab selektieren
|
||
# $gtn setzen um Tabnamen mit abzurufen
|
||
#############################################################################################
|
||
sub Dashboard_GetActiveTab ($;$) {
|
||
my ($name,$gtn) = @_;
|
||
|
||
my $maxTab = Dashboard_GetTabCount($defs{$name}, 1);
|
||
my $activeTab = 1;
|
||
|
||
for my $key (%FW_httpheader) {
|
||
Log3 ($name, 5, "Dashboard $name - FW_httpheader $key: ".$FW_httpheader{$key}) if(defined $FW_httpheader{$key});
|
||
}
|
||
|
||
if (defined($FW_httpheader{Cookie})) {
|
||
Log3 ($name, 4, "Dashboard $name - Cookie delivered: ".$FW_httpheader{Cookie});
|
||
|
||
# my %cookie = map({ split('=', $_) } split(/; */, $FW_httpheader{Cookie}));
|
||
my %cookie; # 10.02.2020, Forum: https://forum.fhem.de/index.php/topic,16503.msg1023004.html#msg1023004
|
||
|
||
for (split(/; */, $FW_httpheader{Cookie})) {
|
||
my ($k,$v) = split('=', $_);
|
||
next if(!defined $v);
|
||
$cookie{$k} = $v;
|
||
}
|
||
|
||
Log3($name, 5, "Dashboard $name - Cookie Hash: ". Dumper %cookie);
|
||
|
||
if (defined($cookie{dashboard_activetab})) {
|
||
$activeTab = $cookie{dashboard_activetab};
|
||
$activeTab = ($activeTab <= $maxTab)?$activeTab:$maxTab;
|
||
}
|
||
}
|
||
|
||
my $tabno = AttrVal($name, 'dashboard_homeTab', $activeTab);
|
||
$tabno = ($tabno <= $maxTab)?$tabno:$maxTab;
|
||
my $tabname = AttrVal($name, "dashboard_tab".($tabno)."name", "");
|
||
|
||
Log3 ($name, 4, "Dashboard $name - Dashboard active tab: $tabno/$tabname");
|
||
|
||
if($gtn) {
|
||
return ($tabno,$tabname);
|
||
}
|
||
else {
|
||
return $tabno;
|
||
}
|
||
}
|
||
|
||
#############################################################################################
|
||
# Wertevorrat der möglichen Tabs ermitteln
|
||
#############################################################################################
|
||
sub Dashboard_possibleTabs ($) {
|
||
my ($name) = @_;
|
||
my $f;
|
||
|
||
my $maxTab = Dashboard_GetTabCount($defs{$name}, 1);
|
||
|
||
for my $i (1..$maxTab) {
|
||
$f .= "," if($f);
|
||
$f .= $i;
|
||
}
|
||
|
||
return $f;
|
||
}
|
||
|
||
################################################################
|
||
# Versionierungen des Moduls setzen
|
||
# Die Verwendung von Meta.pm und Packages wird berücksichtigt
|
||
################################################################
|
||
sub Dashboard_setVersionInfo($) {
|
||
my ($hash) = @_;
|
||
my $name = $hash->{NAME};
|
||
|
||
my $v = (sortTopicNum("desc",keys %Dashboard_vNotesIntern))[0];
|
||
my $type = $hash->{TYPE};
|
||
$hash->{HELPER}{PACKAGE} = __PACKAGE__;
|
||
$hash->{HELPER}{VERSION} = $v;
|
||
|
||
if($modules{$type}{META}{x_prereqs_src} && !$hash->{HELPER}{MODMETAABSENT}) { # META-Daten sind vorhanden
|
||
$modules{$type}{META}{version} = "v".$v; # Version aus META.json überschreiben, Anzeige mit {Dumper $modules{SMAPortal}{META}}
|
||
|
||
if($modules{$type}{META}{x_version}) { # {x_version} ( nur gesetzt wenn $Id: 95_Dashboard.pm 21180 2020-02-11 21:04:55Z DS_Starter $ im Kopf komplett! vorhanden )
|
||
$modules{$type}{META}{x_version} =~ s/1.1.1/$v/g;
|
||
}
|
||
else {
|
||
$modules{$type}{META}{x_version} = $v;
|
||
}
|
||
|
||
return $@ unless (FHEM::Meta::SetInternals($hash)); # FVERSION wird gesetzt ( nur gesetzt wenn $Id: 95_Dashboard.pm 21180 2020-02-11 21:04:55Z DS_Starter $ im Kopf komplett! vorhanden )
|
||
|
||
if(__PACKAGE__ eq "FHEM::$type" || __PACKAGE__ eq $type) { # es wird mit Packages gearbeitet -> Perl übliche Modulversion setzen
|
||
use version 0.77; our $VERSION = FHEM::Meta::Get( $hash, 'version' ); # mit {<Modul>->VERSION()} im FHEMWEB kann Modulversion abgefragt werden
|
||
}
|
||
}
|
||
else {
|
||
$hash->{VERSION} = $v; # herkömmliche Modulstruktur
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
#############################################################################################
|
||
# Tabumschaltung bei setzen Attribut dashboard_homeTab bzw. "set ... activeTab"
|
||
#############################################################################################
|
||
sub Dashboard_activateTab ($$) {
|
||
my ($name,$tab) = @_;
|
||
my $hash = $defs{$name};
|
||
|
||
my $url = '/dashboard/'.$name;
|
||
return if(!$data{FWEXT}{$url});
|
||
|
||
$tab--;
|
||
my $web = AttrVal($name, "dashboard_webRefresh", $hash->{HELPER}{FW});
|
||
return if(!$web);
|
||
|
||
my @wa = split ',', $web;
|
||
|
||
{ map { FW_directNotify("#FHEMWEB:$_", 'dashboard_load_tab('."$tab".');$("#dashboardtabs").tabs("option", "active", '."$tab".')', "") } @wa }
|
||
|
||
# Andere Triggermöglichkeiten:
|
||
#{ map { FW_directNotify("#FHEMWEB:$_", 'dashboard_load_tab('."$tab".')', "") } @wa }
|
||
#{ map { FW_directNotify("#FHEMWEB:$_", '$("#dashboardtabs").tabs("option", "active", '."$tab".')', "") } @wa }
|
||
# CommandTrigger(undef,'WEB JS:dashboard_load_tab('."$tab".');JS:$("#dashboardtabs").tabs("option", "active", '."$tab".')' );
|
||
|
||
return;
|
||
}
|
||
|
||
######################################################################################
|
||
# initiale Routinen für Dashboard
|
||
######################################################################################
|
||
sub Dashboard_init ($) {
|
||
my $hash = shift;
|
||
my $name = $hash->{NAME};
|
||
|
||
RemoveInternalTimer($hash, "Dashboard_init");
|
||
|
||
if ($init_done) { # die Argumente für das Attribut dashboard_webRefresh dynamisch ermitteln und setzen
|
||
my $fwd = join ",", devspec2array("TYPE=FHEMWEB:FILTER=STATE=Initialized");
|
||
$hash->{HELPER}{FW} = $fwd;
|
||
|
||
my $atr = AttrVal($name, "dashboard_webRefresh", "");
|
||
|
||
delFromDevAttrList($name, "dashboard_webRefresh");
|
||
addToDevAttrList ($name, "dashboard_webRefresh:multiple-strict,$fwd");
|
||
|
||
$attr{$name}{dashboard_webRefresh} = $atr if($atr);
|
||
|
||
my $f = Dashboard_possibleTabs ($name); # die Argumente für das Attribut dashboard_homeTab dynamisch ermitteln und setzen
|
||
my $at = AttrVal($name, "dashboard_homeTab", "");
|
||
delFromDevAttrList($name, "dashboard_homeTab");
|
||
addToDevAttrList ($name, "dashboard_homeTab:$f");
|
||
$attr{$name}{dashboard_homeTab} = $at if($at);
|
||
}
|
||
else {
|
||
InternalTimer(time()+3, "Dashboard_init", $hash, 0);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
######################################################################################
|
||
# Zeichen escapen
|
||
######################################################################################
|
||
sub Dashboard_Escape($) {
|
||
my $a = shift;
|
||
return "null" if(!defined($a));
|
||
my %esc = ("\n" => '\n', "\r" => '\r', "\t" => '\t', "\f" => '\f', "\b" => '\b', "\"" => '\"', "\\" => '\\\\', "\'" => '\\\'', );
|
||
$a =~ s/([\x22\x5c\n\r\t\f\b])/$esc{$1}/eg;
|
||
|
||
return $a;
|
||
}
|
||
|
||
######################################################################################
|
||
# angegebenes $file im $dir und Unterverzeichnissen suchen
|
||
# und mit Pfad ab ".../images/" in $ct speichern wenn gefunden
|
||
######################################################################################
|
||
sub Dashboard_searchImage($$$$) {
|
||
my ($name,$dir,$file,$ct) = @_;
|
||
my $hash = $defs{$name};
|
||
|
||
my ($t,$im);
|
||
opendir(DIR, $dir);
|
||
my(@files) = grep {!/^\.\.?$/ } readdir(DIR);
|
||
closedir(DIR);
|
||
|
||
for (@files) {
|
||
if (-d ($t = "$dir/$_")) { # -d returns true if the following string is a directory.
|
||
Dashboard_searchImage($name,$t,$file,$ct);
|
||
}
|
||
else {
|
||
next if ($_ ne $file);
|
||
$im = (split("images\/", $dir."/".$_))[1];
|
||
$hash->{HELPER}{BIMG}{$ct} = $im; # Ergebnisfile in Container speichern wenn gefunden
|
||
|
||
Log3 ($name, 5, "Dashboard $name - Background image file found in: $dir/$_");
|
||
}
|
||
}
|
||
}
|
||
|
||
1;
|
||
|
||
=pod
|
||
=encoding utf8
|
||
=item summary Dashboard for showing multiple devices sorted in tabs
|
||
=item summary_DE Dashboard zur Anzeige mehrerer Geräte in verschiedenen Tabs
|
||
=begin html
|
||
|
||
<a name="Dashboard"></a>
|
||
<h3>Dashboard</h3>
|
||
<ul>
|
||
Creates a Dashboard in any group and/or devices can be arranged. The positioning may depend the objects and column width are made
|
||
arbitrarily by drag'n drop. Also, the width and height of an object can be increased beyond the minimum size. <br><br>
|
||
|
||
<b>Note: </b><br>
|
||
A group name in the dashboard respectively the attribute "dashboard_tabXgroups" equates the group name in FHEM and depict the
|
||
devices which are contained in that group.
|
||
<br>
|
||
<br>
|
||
|
||
<a name="Dashboarddefine"></a>
|
||
<b>Define</b>
|
||
<br><br>
|
||
|
||
<ul>
|
||
<ul>
|
||
<li><b>define <name> Dashboard </b>
|
||
<br><br>
|
||
<b>Example: </b><br>
|
||
define anyViews Dashboard
|
||
<br><br>
|
||
|
||
<b>Bestpractice beginner configuration: </b>
|
||
<br>
|
||
define anyViews Dashboard<br>
|
||
attr anyViews dashboard_colcount 2<br>
|
||
attr anyviews dashboard_rowcentercolwidth 30,70<br>
|
||
attr anyViews dashboard_tab1groups <Group1>,<Group2>,<Group3><br>
|
||
</ul>
|
||
</ul>
|
||
</li>
|
||
<br>
|
||
|
||
<a name="Dashboardset"></a>
|
||
<b>Set</b>
|
||
<br><br>
|
||
|
||
<ul>
|
||
<ul>
|
||
|
||
<li><b>set <name> activateTab <TabNo> </b><br>
|
||
The Tab with the defined number will be activated.
|
||
If the attribute "dashboard_homeTab" is set, this defined tab will be reactivated at next
|
||
browser refresh. <br>
|
||
<br>
|
||
</li>
|
||
|
||
<li><b>set <name> lock </b><br>
|
||
Locks the Dashboard so that no position changes can be made.
|
||
</li><br>
|
||
|
||
<li><b>set <name> unlock </b><br>
|
||
Unlock the Dashboard,
|
||
<br>
|
||
</li>
|
||
</ul>
|
||
</ul>
|
||
<br>
|
||
|
||
<a name="Dashboardget"></a>
|
||
<b>Get</b>
|
||
<ul>
|
||
<ul>
|
||
|
||
<a name="config"></a>
|
||
<li><b>get <name> config </b><br>
|
||
Delivers the configuration of the dashboard back. <br>
|
||
<br>
|
||
</li>
|
||
|
||
<a name="icon"></a>
|
||
<li><b>get <name> icon <icon name> </b><br>
|
||
Delivers the path and full name of the denoted icon back. <br><br>
|
||
|
||
<b>Example: </b><br>
|
||
get <name> icon measure_power_meter
|
||
<br>
|
||
</li>
|
||
|
||
</ul>
|
||
</ul>
|
||
<br>
|
||
<br>
|
||
|
||
<a name="Dashboardattr"></a>
|
||
<b>Attributes</b>
|
||
<br>
|
||
<br>
|
||
|
||
<ul>
|
||
<ul>
|
||
|
||
<a name="dashboard_backgroundimage"></a>
|
||
<li><b>dashboard_backgroundimage </b><br>
|
||
Displays a background image for the complete dashboard. The image is not stretched in any way. So the size should
|
||
match/extend the dashboard height/width. The relative path to "./www/images" has to be used. <br><br>
|
||
|
||
<b>Example</b><br>
|
||
attr dashboard_backgroundimage dashboard/cam_video.PNG <br>
|
||
# File ./www/images/dashboard/cam_video.PNG is shown <br>
|
||
attr dashboard_backgroundimage cam_video.PNG <br>
|
||
# File ./www/images/cam_video.PNG is shown <br>
|
||
</li><br>
|
||
|
||
<a name="dashboard_backgroundimage"></a>
|
||
<li><b>dashboard_backgroundimage </b><br>
|
||
Displays a background image for the complete dashboard. The image is not stretched in any way. So the size should
|
||
match/extend the dashboard height/width. Only the filename has to be set. <br>
|
||
The file must be at any location below the directory "./www/images/". <br>
|
||
<b>Suggestion: </b> Create the directory "./www/images/dashboard" and put the image file into.
|
||
<br><br>
|
||
|
||
<b>Example</b><br>
|
||
attr dashboard_backgroundimage cam_video.PNG <br>
|
||
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_colcount"></a>
|
||
<li><b>dashboard_colcount </b><br>
|
||
Number of columns in which the groups can be displayed. Nevertheless, it is possible to have multiple groups <br>
|
||
to be positioned in a column next to each other. This is depend on the width of columns and groups. <br>
|
||
Default: 1
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_debug"></a>
|
||
<li><b>dashboard_debug </b><br>
|
||
Show Hiddenfields. Only for Maintainer's use. <br>
|
||
Default: 0
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_flexible"></a>
|
||
<li><b>dashboard_flexible </b><br>
|
||
If set to a value > 0, the widgets are not positioned in columns any more but can be moved freely to any position in
|
||
the tab.<br/>
|
||
The value for this parameter also defines the grid, in which the position "snaps in". <br>
|
||
Default: 0
|
||
</li><br>
|
||
|
||
<a name="dashboard_hideGroupHeader"></a>
|
||
<li><b>dashboard_hideGroupHeader </b><br>
|
||
If set, the header containing the group name and group icon above the pictured FHEM-group (see also dashboard_tab1groups) is hidden. <br>
|
||
Default: 0
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_homeTab"></a>
|
||
<li><b>dashboard_homeTab </b><br>
|
||
Specifies which tab is activated. If it isn't set, the last selected tab will also be the active tab. <br>
|
||
Default: 1
|
||
</li><br>
|
||
|
||
<a name="dashboard_row"></a>
|
||
<li><b>dashboard_row </b><br>
|
||
To select which rows are displayed. top only; center only; bottom only; top and center; center and bottom; top,center and bottom. <br>
|
||
Default: center
|
||
</li><br>
|
||
|
||
<a name="dashboard_rowbottomheight"></a>
|
||
<li><b>dashboard_rowbottomheight </b><br>
|
||
Height of the bottom row in which the groups may be positioned. <br>
|
||
Default: 250
|
||
</li><br>
|
||
|
||
<a name="dashboard_rowcenterheight"></a>
|
||
<li><b>dashboard_rowcenterheight </b><br>
|
||
Height of the center row in which the groups may be positioned. <br>
|
||
Default: 400
|
||
</li><br>
|
||
|
||
<a name="dashboard_rowcentercolwidth"></a>
|
||
<li><b>dashboard_rowcentercolwidth </b><br>
|
||
About this attribute, the width of each column of the middle Dashboardrow can be set. It can be stored for each column
|
||
a separate value.
|
||
The values must be separated by a comma (no spaces). Each value determines the column width in%! The first value
|
||
specifies the width of the first column, the second value of the width of the second column, etc. Is the sum of the
|
||
width greater than 100 it is reduced.
|
||
If more columns defined as widths the missing widths are determined by the difference to 100. However, are less
|
||
columns are defined as the values of ignores the excess values. <br>
|
||
Default: 100
|
||
</li><br>
|
||
|
||
<a name="dashboard_rowtopheight"></a>
|
||
<li><b>dashboard_rowtopheight </b><br>
|
||
Height of the top row in which the groups may be positioned. <br>
|
||
Default: 250
|
||
</li><br>
|
||
|
||
<a name="dashboard_showfullsize"></a>
|
||
<li><b>dashboard_showfullsize </b><br>
|
||
Hide FHEMWEB Roomliste (complete left side) and Page Header if Value is 1. <br>
|
||
Default: 0
|
||
</li><br>
|
||
|
||
<a name="dashboard_showtabs"></a>
|
||
<li><b>dashboard_showtabs </b><br>
|
||
Displays the Tabs/Buttonbar on top or bottom, or hides them. If the Buttonbar is hidden lockstate is "lock" is used. <br>
|
||
Default: tabs-and-buttonbar-at-the-top
|
||
</li><br>
|
||
|
||
<a name="dashboard_showtogglebuttons"></a>
|
||
<li><b>dashboard_showtogglebuttons </b><br>
|
||
Displays a Toogle Button on each Group do collapse. <br>
|
||
Default: 0
|
||
</li><br>
|
||
|
||
<a name="dashboard_tab1backgroundimage"></a>
|
||
<li><b>dashboard_tab1backgroundimage </b><br>
|
||
Shows a background image for the tab. (also valid for further dashboard_tabXbackgroundimage) <br>
|
||
The image is not stretched in any way, it should therefore match the tab size or extend it.
|
||
Only the filename has to be set. <br>
|
||
The file must be at any location below the directory "./www/images/". <br>
|
||
<b>Suggestion: </b> Create the directory "./www/images/dashboard" and put the image file into.
|
||
<br><br>
|
||
|
||
<b>Example</b><br>
|
||
attr dashboard_tab1backgroundimage cam_video.PNG <br>
|
||
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_tab1colcount"></a>
|
||
<li><b>dashboard_tab1colcount </b><br>
|
||
Number of columns for a specific tab in which the groups can be displayed. (also valid for further dashboard_tabXcolcount) <br>
|
||
Nevertheless, it is possible to have multiple groups to be positioned in a column next to each other.
|
||
This depends on the width of columns and groups. <br>
|
||
Default: <dashboard_colcount>
|
||
</li><br>
|
||
|
||
<a name="dashboard_tab1devices"></a>
|
||
<li><b>dashboard_tab1devices </b><br>
|
||
DevSpec list of devices that should appear in the tab. (also valid for further dashboard_tabXdevices) <br>
|
||
The format is: <br><br>
|
||
<ul>
|
||
GROUPNAME:devspec1,devspec2,...,devspecX:ICONNAME <br><br>
|
||
</ul>
|
||
ICONNAME is optional. Also GROUPNAME is optional. In case of missing GROUPNAME, the matching devices are
|
||
not grouped, but shown as separate widgets without titles.
|
||
For further details on the DevSpec format see <a href="#devspec">DevSpec</a>.
|
||
</li><br>
|
||
|
||
<a name="dashboard_tab1groups"></a>
|
||
<li><b>dashboard_tab1groups </b><br>
|
||
Comma separated list of FHEM groups (see attribute "group" in a device) to be displayed in Tab.
|
||
(also valid for further dashboard_tabXgroups) <br>
|
||
Each group can be given an icon for this purpose the group name, the following must be
|
||
completed ":<icon>@<color>" <br><br>
|
||
|
||
<b>Example: </b><br>
|
||
Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow <br><br>
|
||
|
||
Additionally a group can contain a regular expression to show all groups matching a criteria. <br><br>
|
||
|
||
<b>Example: </b><br>
|
||
.*Light.* to show all groups that contain the string "Light"
|
||
</li><br>
|
||
|
||
<a name="dashboard_tab1icon"></a>
|
||
<li><b>dashboard_tab1icon </b><br>
|
||
Set the icon for a Tab. (also valid for further dashboard_tabXicon) <br>
|
||
There must exist an icon with the name ico.(png|svg) in the modpath directory. If the image is
|
||
referencing an SVG icon, then you can use the @colorname suffix to color the image.
|
||
</li><br>
|
||
|
||
<a name="dashboard_tab1name"></a>
|
||
<li><b>dashboard_tab1name </b><br>
|
||
Title of Tab. (also valid for further dashboard_tabXname)
|
||
</li><br>
|
||
|
||
<a name="dashboard_tab1sorting"></a>
|
||
<li><b>dashboard_tab1sorting </b><br>
|
||
Contains the position of each group in Tab. (also valid for further dashboard_tabXsorting) <br>
|
||
Value is written by the "Set" button. It is not recommended to take manual changes.
|
||
</li><br>
|
||
|
||
<a name="dashboard_noLinks"></a>
|
||
<li><b>dashboard_noLinks</b><br>
|
||
No link generation to the detail view of the devices takes place. <br><br>
|
||
|
||
<b>Note: </b><br>
|
||
Some device types deliver the links to their detail view integrated in the device.
|
||
In such cases you have to deactivate the link generation inside of the device (for example in SMAPortalSPG).
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_webRefresh"></a>
|
||
<li><b>dashboard_webRefresh </b><br>
|
||
With this attribute the FHEMWEB-Devices are determined, which: <br><br>
|
||
<ul>
|
||
<li> are activating the tab of a dashboard when the attribute "dashboard_homeTab" will be set </li>
|
||
<li> are positioning to the tab specified by command "set <name> activateTab" </li>
|
||
</ul>
|
||
<br>
|
||
Default: all
|
||
<br>
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_width"></a>
|
||
<li><b>dashboard_width </b><br>
|
||
To determine the Dashboardwidth. The value can be specified, or an absolute width value (eg 1200) in pixels in% (eg 80%). <br>
|
||
Default: 100%
|
||
</li>
|
||
<br>
|
||
|
||
</ul>
|
||
</ul>
|
||
</ul>
|
||
|
||
=end html
|
||
=begin html_DE
|
||
|
||
<a name="Dashboard"></a>
|
||
<h3>Dashboard</h3>
|
||
<ul>
|
||
Erstellt eine Übersicht in der Gruppen und/oder Geräte angeordnet werden können. Dabei können die Objekte mit Drag'n Drop
|
||
frei positioniert und in mehreren Spalten angeordnet werden. Auch kann die Breite und Höhe eines Objektes über die
|
||
Mindestgröße hinaus gezogen werden. <br><br>
|
||
|
||
<b>Hinweis: </b><br>
|
||
Ein Gruppenname im Dashboard bzw. dem Attribut "dashboard_tabXgroups" entspricht der Gruppe in FHEM und stellt die darin enthaltenen
|
||
Geräte im Dashboard dar.
|
||
<br>
|
||
<br>
|
||
|
||
<a name="Dashboarddefine"></a>
|
||
<b>Define</b>
|
||
<ul>
|
||
<ul>
|
||
<li><b>define <name> Dashboard </b><br>
|
||
<br>
|
||
<b>Beispiel: </b><br>
|
||
define anyViews Dashboard
|
||
<br>
|
||
<br>
|
||
|
||
<b>Bestpractice Anfängerkonfiguration: </b><br>
|
||
define anyViews Dashboard<br>
|
||
attr anyViews dashboard_colcount 2<br>
|
||
attr anyViews dashboard_rowcentercolwidth 30,70<br>
|
||
attr anyViews dashboard_tab1groups <Group1>,<Group2>,<Group3><br>
|
||
</li>
|
||
</ul>
|
||
</ul>
|
||
<br>
|
||
|
||
<a name="Dashboardset"></a>
|
||
<b>Set</b>
|
||
<ul>
|
||
<ul>
|
||
|
||
<li><b>set <name> activateTab <TabNo> </b><br>
|
||
Das Tab mit der angegebenen Nummer wird im Dashboard aktiviert.
|
||
Ist das Attribut "dashboard_homeTab" gesetzt, wird das in diesem Attribut
|
||
definierte Tab beim nächsten Browser-Refresh reaktiviert. <br>
|
||
<br>
|
||
</li>
|
||
|
||
<li><b>set <name> lock </b><br>
|
||
Sperrt das Dashboard. Es können keine Positionsänderungen vorgenommen werden. <br>
|
||
<br>
|
||
</li>
|
||
|
||
<li><b>set <name> unlock </b><br>
|
||
Entsperrt das Dashboard.
|
||
</li>
|
||
<br>
|
||
</ul>
|
||
</ul>
|
||
<br>
|
||
|
||
<a name="Dashboardget"></a>
|
||
<b>Get</b>
|
||
<ul>
|
||
<ul>
|
||
|
||
<a name="config"></a>
|
||
<li><b>get <name> config </b><br>
|
||
Liefert die Konfiguration des Dashboards zurück. <br>
|
||
<br>
|
||
</li>
|
||
|
||
<a name="icon"></a>
|
||
<li><b>get <name> icon <icon name> </b><br>
|
||
Liefert den Pfad und vollen Namen des angegebenen Icons zurück. <br><br>
|
||
|
||
<b>Beispiel: </b><br>
|
||
get <name> icon measure_power_meter
|
||
<br>
|
||
</li>
|
||
|
||
</ul>
|
||
</ul>
|
||
<br>
|
||
|
||
<a name="Dashboardattr"></a>
|
||
<b>Attributes</b>
|
||
<br>
|
||
<br>
|
||
<ul>
|
||
<ul>
|
||
|
||
<a name="dashboard_backgroundimage"></a>
|
||
<li><b>dashboard_backgroundimage </b><br>
|
||
Zeigt ein Hintergrundbild im Dashboard an. Das Bild wird nicht gestreckt, es sollte daher auf die Größe des Dashboards
|
||
passen oder diese überschreiten. Es ist nur der Filename anzugeben. <br>
|
||
Das File muss sich an beliebiger Stelle unterhalb des Verzeichnisses "./www/images/" befinden. <br>
|
||
<b>Empfehlung: </b> Das Verzeichnis "./www/images/dashboard" anlegen und das Bildfile in diesem Verzeichnis ablegen.
|
||
<br><br>
|
||
|
||
<b>Beispiel</b><br>
|
||
attr dashboard_backgroundimage cam_video.PNG <br>
|
||
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_colcount"></a>
|
||
<li><b>dashboard_colcount </b><br>
|
||
Die Anzahl der Spalten in der Gruppen dargestellt werden können. Dennoch ist es möglich, mehrere Gruppen <br>
|
||
in einer Spalte nebeneinander zu positionieren. Dies ist abhängig von der Breite der Spalten und Gruppen. <br>
|
||
Gilt nur für die mittlere Spalte! <br>
|
||
Default: 1
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_debug"></a>
|
||
<li><b>dashboard_debug </b><br>
|
||
Zeigt Debug-Felder an. Sollte nicht gesetzt werden! <br>
|
||
Default: 0
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_flexible"></a>
|
||
<li><b>dashboard_flexible </b><br>
|
||
Hat dieser Parameter einen Wert > 0, dann können die Widgets in den Tabs frei positioniert werden und hängen nicht
|
||
mehr an den Spalten fest. Der Wert gibt ebenfalls das Raster an, in dem die Positionierung "zuschnappt". <br>
|
||
Default: 0
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_hideGroupHeader"></a>
|
||
<li><b>dashboard_hideGroupHeader </b><br>
|
||
Wenn gesetzt, wird der Kopf mit Gruppenname und -icon der dargestellten FHEM-Gruppe (siehe dashboard_tab1groups) verborgen. <br>
|
||
Default: 0
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_homeTab"></a>
|
||
<li><b>dashboard_homeTab </b><br>
|
||
Legt das aktuell aktivierte Tab fest. Wenn nicht gesetzt, wird das zuletzt gewählte Tab das aktive Tab. <br>
|
||
Default: 1
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_row"></a>
|
||
<li><b>dashboard_row </b><br>
|
||
Auswahl welche Zeilen angezeigt werden sollen. top (nur Oben), center (nur Mitte), bottom (nur Unten) und den
|
||
Kombinationen daraus. <br>
|
||
Default: center
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_rowcenterheight"></a>
|
||
<li><b>dashboard_rowcenterheight </b><br>
|
||
Höhe der mittleren Zeile, in der die Gruppen angeordnet werden. <br>
|
||
Default: 400
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_rowcentercolwidth"></a>
|
||
<li><b>dashboard_rowcentercolwidth </b><br>
|
||
Über dieses Attribut wird die Breite der einzelnen Spalten der mittleren Dashboardreihe festgelegt. Dabei kann je Spalte ein separater Wert hinterlegt werden.
|
||
Die Werte sind durch ein Komma (ohne Leerzeichen) zu trennen. Jeder Wert bestimmt die Spaltenbreite in %! Der erste Wert gibt die Breite der ersten Spalte an,
|
||
der zweite Wert die Breite der zweiten Spalte usw. Ist die Summe der Breite größer als 100 werden die Spaltenbreiten reduziert.
|
||
Sind mehr Spalten als Breiten definiert werden die fehlenden Breiten um die Differenz zu 100 festgelegt. Sind hingegen weniger Spalten als Werte definiert werden
|
||
die überschüssigen Werte ignoriert. <br>
|
||
Default: 100
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_rowtopheight"></a>
|
||
<li><b>dashboard_rowtopheight </b><br>
|
||
Höhe der oberen Zeile, in der die Gruppen angeordnet werden. <br>
|
||
Default: 250
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_rowbottomheight"></a>
|
||
<li><b>dashboard_rowbottomheight </b><br>
|
||
Höhe der unteren Zeile, in der die Gruppen angeordnet werden. <br>
|
||
Default: 250
|
||
</li><br>
|
||
|
||
<a name="dashboard_showfullsize"></a>
|
||
<li><b>dashboard_showfullsize </b><br>
|
||
Blendet die FHEMWEB Raumliste (kompleter linker Bereich der Seite) und den oberen Bereich von FHEMWEB aus wenn der
|
||
Wert auf 1 gesetzt ist. <br>
|
||
Default: 0
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_showtabs"></a>
|
||
<li><b>dashboard_showtabs </b><br>
|
||
Zeigt die Tabs/Schalterleiste des Dashboards oben oder unten an, oder blendet diese aus. Wenn die Schalterleiste
|
||
ausgeblendet wird ist das Dashboard gespert. <br>
|
||
Default: tabs-and-buttonbar-at-the-top
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_showtogglebuttons"></a>
|
||
<li><b>dashboard_showtogglebuttons </b><br>
|
||
Zeigt eine Schaltfläche in jeder Gruppe mit der man diese auf- und zuklappen kann. <br>
|
||
Default: 0
|
||
</li><br>
|
||
|
||
<a name="dashboard_tab1backgroundimage"></a>
|
||
<li><b>dashboard_tab1backgroundimage </b><br>
|
||
Zeigt ein Hintergrundbild für den Tab an. (gilt ebenfalls für weitere dashboard_tabXbackgroundimage) <br>
|
||
Das Bild wird nicht gestreckt, es sollte also auf die Größe des Tabs passen oder diese überschreiten. Es ist nur der
|
||
Filename anzugeben. <br>
|
||
Das File muss sich an beliebiger Stelle unterhalb des Verzeichnisses "./www/images/" befinden. <br>
|
||
<b>Empfehlung: </b> Das Verzeichnis "./www/images/dashboard" anlegen und das Bildfile in diesem Verzeichnis ablegen.
|
||
<br><br>
|
||
|
||
<b>Beispiel</b><br>
|
||
attr dashboard_tab1backgroundimage cam_video.PNG <br>
|
||
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_tab1colcount"></a>
|
||
<li><b>dashboard_tab1colcount </b><br>
|
||
Die Anzahl der Spalten im Tab in der Gruppen dargestellt werden können. (gilt ebenfalls für weitere dashboard_tabXcolcount) <br>
|
||
Dennoch ist es möglich, mehrere Gruppen in einer Spalte nebeneinander zu positionieren. Dies ist abhängig von der Breite
|
||
der Spalten und Gruppen. <br>
|
||
Gilt nur für die mittlere Spalte! <br>
|
||
Default: <dashboard_colcount>
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_tab1devices"></a>
|
||
<li><b>dashboard_tab1devices </b><br>
|
||
DevSpec Liste von Geräten, die im Tab angezeigt werden sollen. (gilt ebenfalls für weitere dashboard_tabXdevices) <br>
|
||
Das Format ist: <br><br>
|
||
<ul>
|
||
GROUPNAME:devspec1,devspec2,...,devspecX:ICONNAME <br><br>
|
||
</ul>
|
||
ICONNAME ist optional. Auch GROUPNAME muss nicht vorhanden sein. Fehlt GROUPNAME, werden die angegebenen
|
||
Geräte nicht gruppiert, sondern als einzelne Widgets im Tab angezeigt. Für weitere Details bezüglich DevSpec:
|
||
<a href="#devspec">DevSpec</a>
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_tab1groups"></a>
|
||
<li><b>dashboard_tab1groups </b><br>
|
||
Durch Komma getrennte Liste der FHEM-Gruppen (siehe Attribut "group" eines Devices), die im Tab angezeigt werden.
|
||
(gilt ebenfalls für weitere dashboard_tabXgroups)
|
||
Falsche Gruppennamen werden hervorgehoben. <br>
|
||
Jede Gruppe kann zusätzlich ein Icon anzeigen, dazu muss der Gruppen name um ":<icon>@<farbe>"ergänzt
|
||
werden. <br><br>
|
||
|
||
<b>Beispiel: </b><br>
|
||
Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow <br><br>
|
||
|
||
Der Gruppenname kann ebenfalls einen regulären Ausdruck beinhalten, um alle Gruppen anzuzeigen, die darauf passen. <br><br>
|
||
|
||
<b>Beispiel: </b><br>
|
||
.*Licht.* zeigt alle Gruppen an, die das Wort "Licht" im Namen haben.
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_tab1icon"></a>
|
||
<li><b>dashboard_tab1icon </b><br>
|
||
Zeigt am Tab ein Icon an (gilt ebenfalls für weitere dashboard_tabXicon).
|
||
Es muss sich dabei um ein exisitereindes Icon mit modpath Verzeichnis handeln. Handelt es
|
||
sich um ein SVG Icon kann der Suffix @colorname für die Farbe des Icons angegeben werden.
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_tab1name"></a>
|
||
<li><b>dashboard_tab1name </b><br>
|
||
Titel des Tab. (gilt ebenfalls für weitere dashboard_tabXname)
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_tab1sorting"></a>
|
||
<li><b>dashboard_tab1sorting </b><br>
|
||
Enthält die Positionierung jeder Gruppe im Tab (gilt ebenfalls für weitere dashboard_tabXsorting). <br>
|
||
Der Wert wird mit der Schaltfläche "Set" geschrieben. Es wird nicht
|
||
empfohlen dieses Attribut manuell zu ändern.
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_noLinks"></a>
|
||
<li><b>dashboard_noLinks</b><br>
|
||
Es erfolgt keine Linkerstellung zur Detailansicht von Devices. <br><br>
|
||
|
||
<b>Hinweis: </b><br>
|
||
Bei manchen Devicetypen wird der Link zur Detailansicht integriert im Device mitgeliefert.
|
||
In diesen Fällen muß die Linkgenerierung direkt im Device abgestellt werden (z.B. bei SMAPortalSPG).
|
||
</li>
|
||
<br>
|
||
|
||
|
||
<a name="dashboard_webRefresh"></a>
|
||
<li><b>dashboard_webRefresh </b><br>
|
||
Mit diesem Attribut werden FHEMWEB-Devices bestimmt, die: <br><br>
|
||
<ul>
|
||
<li> beim Setzen des Attributes "dashboard_homeTab" diesen Tab im Dashboard sofort aktivieren </li>
|
||
<li> beim Ausführen von "set <name> activateTab" auf diesen Tab im Dashboard positionieren </li>
|
||
</ul>
|
||
<br>
|
||
Default: alle
|
||
<br>
|
||
</li>
|
||
<br>
|
||
|
||
<a name="dashboard_width"></a>
|
||
<li><b>dashboard_width </b><br>
|
||
Zum bestimmen der Dashboardbreite. Der Wert kann in % (z.B. 80%) angegeben werden oder als absolute Breite (z.B. 1200)
|
||
in Pixel. <br>
|
||
Default: 100%
|
||
</li>
|
||
<br>
|
||
|
||
</ul>
|
||
</ul>
|
||
</ul>
|
||
|
||
=end html_DE
|
||
|
||
=for :application/json;q=META.json 95_Dashboard.pm
|
||
{
|
||
"abstract": "Dashboard for showing multiple devices sorted in tabs",
|
||
"x_lang": {
|
||
"de": {
|
||
"abstract": "Dashboard zur Anzeige mehrerer Geräte in verschiedenen Tabs"
|
||
}
|
||
},
|
||
"keywords": [
|
||
"Dashboard",
|
||
"Tablet",
|
||
"UI",
|
||
"Browser"
|
||
],
|
||
"version": "v1.1.1",
|
||
"release_status": "stable",
|
||
"author": [
|
||
"Heiko Maaz <heiko.maaz@t-online.de>"
|
||
],
|
||
"x_fhem_maintainer": [
|
||
"DS_Starter"
|
||
],
|
||
"x_fhem_maintainer_github": [
|
||
"nasseeder1"
|
||
],
|
||
"prereqs": {
|
||
"runtime": {
|
||
"requires": {
|
||
"FHEM": 5.00918799,
|
||
"perl": 5.014
|
||
},
|
||
"recommends": {
|
||
"FHEM::Meta": 0
|
||
},
|
||
"suggests": {
|
||
}
|
||
}
|
||
},
|
||
"resources": {
|
||
"x_wiki": {
|
||
"web": "https://wiki.fhem.de/wiki/Dashboard",
|
||
"title": "Dashboard"
|
||
},
|
||
"repository": {
|
||
"x_dev": {
|
||
"type": "svn",
|
||
"url": "https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter",
|
||
"web": "https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter/95_Dashboard.pm",
|
||
"x_branch": "dev",
|
||
"x_filepath": "fhem/contrib/",
|
||
"x_raw": "https://svn.fhem.de/fhem/trunk/fhem/contrib/DS_Starter/95_Dashboard.pm"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
=end :application/json;q=META.json
|
||
|
||
=cut
|