diff --git a/fhem/www/codemirror/01_FHEMWEB.pm b/fhem/www/codemirror/01_FHEMWEB.pm deleted file mode 100644 index e6c6ccf41..000000000 --- a/fhem/www/codemirror/01_FHEMWEB.pm +++ /dev/null @@ -1,3494 +0,0 @@ -### -### special version for testing codemirror integration -### derived from SVN 5080 -### -### modified by betateilchen, justme1968, papa and others -### -### see: http://forum.fhem.de/index.php/topic,20444.0.html -### -### - -############################################## -# $Id: 01_FHEMWEB.pm 5080 2014-03-01 08:02:45Z rudolfkoenig $ -package main; - -use strict; -use warnings; -use TcpServerUtils; -use HttpUtils; - -######################### -# Forward declaration -sub FW_IconURL($); -sub FW_iconName($); -sub FW_iconPath($); -sub FW_answerCall($); -sub FW_codemirrorLink($); -sub FW_codemirrorParams($); -sub FW_dev2image($;$); -sub FW_devState($$@); -sub FW_digestCgi($); -sub FW_doDetail($); -sub FW_fatal($); -sub FW_fileList($); -sub FW_parseColumns(); -sub FW_htmlEscape($); -sub FW_logWrapper($); -sub FW_makeEdit($$$); -sub FW_makeImage(@); -sub FW_makeTable($$$@); -sub FW_makeTableFromArray($$@); -sub FW_pF($@); -sub FW_pH(@); -sub FW_pHPlain(@); -sub FW_pO(@); -sub FW_readIcons($); -sub FW_readIconsFrom($$); -sub FW_returnFileAsStream($$$$$); -sub FW_roomOverview($); -sub FW_select($$$$$@); -sub FW_serveSpecial($$$$); -sub FW_showRoom(); -sub FW_style($$); -sub FW_submit($$@); -sub FW_textfield($$$); -sub FW_textfieldv($$$$); -sub FW_updateHashes(); -sub FW_visibleDevices(;$); - -use vars qw($FW_dir); # base directory for web server -use vars qw($FW_icondir); # icon base directory -use vars qw($FW_cssdir); # css directory -use vars qw($FW_gplotdir);# gplot directory -use vars qw($MW_dir); # moddir (./FHEM), needed by edit Files in new - # structure - -use vars qw($FW_ME); # webname (default is fhem), used by 97_GROUP/weblink -use vars qw($FW_ss); # is smallscreen, needed by 97_GROUP/95_VIEW -use vars qw($FW_tp); # is touchpad (iPad / etc) -use vars qw($FW_sp); # stylesheetPrefix - -# global variables, also used by 97_GROUP/95_VIEW/95_FLOORPLAN -use vars qw(%FW_types); # device types, -use vars qw($FW_RET); # Returned data (html) -use vars qw($FW_RETTYPE); # image/png or the like -use vars qw($FW_wname); # Web instance -use vars qw($FW_subdir); # Sub-path in URL, used by FLOORPLAN/weblink -use vars qw(%FW_pos); # scroll position -use vars qw($FW_cname); # Current connection name -use vars qw(%FW_hiddenroom); # hash of hidden rooms, used by weblink -use vars qw($FW_plotmode);# Global plot mode (WEB attribute), used by SVG -use vars qw($FW_plotsize);# Global plot size (WEB attribute), used by SVG -use vars qw(%FW_webArgs); # all arguments specified in the GET -use vars qw(@FW_fhemwebjs);# List of fhemweb*js scripts to load -use vars qw($FW_detail); # currently selected device for detail view -use vars qw($FW_cmdret); # Returned data by the fhem call -use vars qw($FW_room); # currently selected room -use vars qw($FW_formmethod); -use vars qw(%FW_visibleDeviceHash); - -$FW_formmethod = "post"; - -my $FW_zlib_checked; -my $FW_use_zlib = 1; -my $FW_activateInform = 0; - -######################### -# As we are _not_ multithreaded, it is safe to use global variables. -# Note: for delivering SVG plots we fork -my @FW_httpheader; # HTTP header, line by line -my @FW_enc; # Accepted encodings (browser header) -my $FW_data; # Filecontent from browser when editing a file -my %FW_icons; # List of icons -my @FW_iconDirs; # Directory search order for icons -my $FW_RETTYPE; # image/png or the like -my %FW_rooms; # hash of all rooms -my %FW_types; # device types, for sorting -my %FW_hiddengroup;# hash of hidden groups -my $FW_inform; -my $FW_XHR; # Data only answer, no HTML -my $FW_jsonp; # jasonp answer (sending function calls to the client) -my $FW_headercors; # -my $FW_chash; # client fhem hash -my $FW_encoding="UTF-8"; - - -##################################### -sub -FHEMWEB_Initialize($) -{ - my ($hash) = @_; - - $hash->{ReadFn} = "FW_Read"; - $hash->{GetFn} = "FW_Get"; - $hash->{SetFn} = "FW_Set"; - $hash->{AttrFn} = "FW_Attr"; - $hash->{DefFn} = "FW_Define"; - $hash->{UndefFn} = "FW_Undef"; - $hash->{NotifyFn}= "FW_SecurityCheck"; - $hash->{ActivateInformFn} = "FW_ActivateInform"; - no warnings 'qw'; - my @attrList = qw( - CORS:0,1 - HTTPS:1,0 - SVGcache:1,0 - allowedCommands - allowfrom - basicAuth - basicAuthMsg - column - defaultRoom - endPlotNow:1,0 - endPlotToday:1,0 - enhancedEditor:1,0 - enhancedEditorTheme - fwcompress:0,1 - hiddengroup - hiddenroom - iconPath - longpoll:0,1 - longpollSVG:1,0 - menuEntries - ploteditor:always,onClick,never - plotfork:1,0 - plotmode:gnuplot,gnuplot-scroll,SVG - plotsize - nrAxis - redirectCmds:0,1 - refresh - reverseLogs:0,1 - roomIcons - sortRooms - smallscreen:unused - stylesheetPrefix - touchpad:unused - webname - ); - use warnings 'qw'; - $hash->{AttrList} = join(" ", @attrList); - - - ############### - # Initialize internal structures - map { addToAttrList($_) } ( "webCmd", "icon", "devStateIcon", - "sortby", "devStateStyle"); - InternalTimer(time()+60, "FW_closeOldClients", 0, 0); - - $FW_dir = "$attr{global}{modpath}/www"; - $FW_icondir = "$FW_dir/images"; - $FW_cssdir = "$FW_dir/pgm2"; - $FW_gplotdir = "$FW_dir/gplot"; - if(opendir(DH, "$FW_dir/pgm2")) { - @FW_fhemwebjs = sort grep /^fhemweb.*js$/, readdir(DH); - closedir(DH); - } - - $data{webCmdFn}{slider} = "FW_sliderFn"; - $data{webCmdFn}{timepicker} = "FW_timepickerFn"; - $data{webCmdFn}{noArg} = "FW_noArgFn"; - $data{webCmdFn}{textField} = "FW_textFieldFn"; - $data{webCmdFn}{"~dropdown"}= "FW_dropdownFn"; # Should be the last -} - -##################################### -sub -FW_SecurityCheck($$) -{ - my ($ntfy, $dev) = @_; - return if($dev->{NAME} ne "global" || - !grep(m/^INITIALIZED$/, @{$dev->{CHANGED}})); - my $motd = AttrVal("global", "motd", ""); - if($motd =~ "^SecurityCheck") { - my @list = grep { !AttrVal($_, "basicAuth", undef) } - devspec2array("TYPE=FHEMWEB"); - $motd .= (join(",", sort @list)." has no basicAuth attribute.\n") - if(@list); - $attr{global}{motd} = $motd; - } - $modules{FHEMWEB}{NotifyFn}= "FW_Notify"; - return; -} - -##################################### -sub -FW_Define($$) -{ - my ($hash, $def) = @_; - my ($name, $type, $port, $global) = split("[ \t]+", $def); - return "Usage: define FHEMWEB [IPV6:] [global]" - if($port !~ m/^(IPV6:)?\d+$/ || ($global && $global ne "global")); - - foreach my $pe ("fhemSVG", "openautomation", "default") { - FW_readIcons($pe); - } - - my $ret = TcpServer_Open($hash, $port, $global); - - # Make sure that fhem only runs once - if($ret && !$init_done) { - Log3 $hash, 1, "$ret. Exiting."; - exit(1); - } - - return $ret; -} - -##################################### -sub -FW_Undef($$) -{ - my ($hash, $arg) = @_; - return TcpServer_Close($hash); -} - -##################################### -sub -FW_Read($) -{ - my ($hash) = @_; - my $name = $hash->{NAME}; - - if($hash->{SERVERSOCKET}) { # Accept and create a child - TcpServer_Accept($hash, "FHEMWEB"); - return; - } - - $FW_chash = $hash; - $FW_wname = $hash->{SNAME}; - $FW_cname = $name; - $FW_subdir = ""; - - my $c = $hash->{CD}; - if(!$FW_zlib_checked) { - $FW_zlib_checked = 1; - $FW_use_zlib = AttrVal($FW_wname, "fwcompress", 1); - if($FW_use_zlib) { - eval { require Compress::Zlib; }; - if($@) { - $FW_use_zlib = 0; - Log3 $FW_wname, 1, $@; - Log3 $FW_wname, 1, - "$FW_wname: Can't load Compress::Zlib, deactivating compression"; - $attr{$FW_wname}{fwcompress} = 0; - } - } - } - - - - # Data from HTTP Client - my $buf; - my $ret = sysread($c, $buf, 1024); - - if(!defined($ret) || $ret <= 0) { - CommandDelete(undef, $name); - Log3 $FW_wname, 4, "Connection closed for $name"; - return; - } - - $hash->{BUF} .= $buf; - if($defs{$FW_wname}{SSL}) { - while($c->pending()) { - sysread($c, $buf, 1024); - $hash->{BUF} .= $buf; - } - } - - if(!$hash->{HDR}) { - return if($hash->{BUF} !~ m/^(.*)(\n\n|\r\n\r\n)(.*)$/s); - $hash->{HDR} = $1; - $hash->{BUF} = $3; - if($hash->{HDR} =~ m/Content-Length: ([^\r\n]*)/s) { - $hash->{CONTENT_LENGTH} = $1; - } - } - return if($hash->{CONTENT_LENGTH} && - length($hash->{BUF})<$hash->{CONTENT_LENGTH}); - - @FW_httpheader = split("[\r\n]", $hash->{HDR}); - delete($hash->{HDR}); - - my @origin = grep /Origin/, @FW_httpheader; - $FW_headercors = (AttrVal($FW_wname, "CORS", 0) ? - "Access-Control-Allow-".$origin[0]."\r\n". - "Access-Control-Allow-Methods: GET OPTIONS\r\n". - "Access-Control-Allow-Headers: Origin, Authorization, Accept\r\n". - "Access-Control-Allow-Credentials: true\r\n". - "Access-Control-Max-Age:86400\r\n" : ""); - - - ############################# - # BASIC HTTP AUTH - my $basicAuth = AttrVal($FW_wname, "basicAuth", undef); - my @headerOptions = grep /OPTIONS/, @FW_httpheader; - if($basicAuth) { - my @authLine = grep /Authorization: Basic/, @FW_httpheader; - my $secret = $authLine[0]; - $secret =~ s/^Authorization: Basic // if($secret); - my $pwok = ($secret && $secret eq $basicAuth); - if($secret && $basicAuth =~ m/^{.*}$/ || $headerOptions[0]) { - eval "use MIME::Base64"; - if($@) { - Log3 $FW_wname, 1, $@; - - } else { - my ($user, $password) = split(":", decode_base64($secret)); - $pwok = eval $basicAuth; - Log3 $FW_wname, 1, "basicAuth expression: $@" if($@); - } - } - if($headerOptions[0]) { - print $c "HTTP/1.1 200 OK\r\n", - $FW_headercors, - "Content-Length: 0\r\n\r\n"; - delete $hash->{CONTENT_LENGTH}; - delete $hash->{BUF}; - return; - exit(1); - }; - if(!$pwok) { - my $msg = AttrVal($FW_wname, "basicAuthMsg", "Fhem: login required"); - print $c "HTTP/1.1 401 Authorization Required\r\n", - "WWW-Authenticate: Basic realm=\"$msg\"\r\n", - $FW_headercors, - "Content-Length: 0\r\n\r\n"; - delete $hash->{CONTENT_LENGTH}; - delete $hash->{BUF}; - return; - }; - } - ############################# - - my $now = time(); - @FW_enc = grep /Accept-Encoding/, @FW_httpheader; - my ($method, $arg, $httpvers) = split(" ", $FW_httpheader[0], 3); - $arg .= "&".$hash->{BUF} if($hash->{CONTENT_LENGTH}); - delete $hash->{CONTENT_LENGTH}; - delete $hash->{BUF}; - $hash->{LASTACCESS} = $now; - - $arg = "" if(!defined($arg)); - Log3 $FW_wname, 4, "HTTP $name GET $arg"; - my $pid; - if(AttrVal($FW_wname, "plotfork", undef)) { - # Process SVG rendering as a parallel process - return if(($arg =~ m+/SVG_showLog+) && ($pid = fork)); - } - - my $cacheable = FW_answerCall($arg); - return if($cacheable == -1); # Longpoll / inform request; - - my $compressed = ""; - if(($FW_RETTYPE =~ m/text/i || - $FW_RETTYPE =~ m/svg/i || - $FW_RETTYPE =~ m/script/i) && - (int(@FW_enc) == 1 && $FW_enc[0] =~ m/gzip/) && - $FW_use_zlib) { - $FW_RET = Compress::Zlib::memGzip($FW_RET); - $compressed = "Content-Encoding: gzip\r\n"; - } - - my $length = length($FW_RET); - my $expires = ($cacheable? - ("Expires: ".localtime($now+900)." GMT\r\n") : ""); - Log3 $FW_wname, 4, "$arg / RL:$length / $FW_RETTYPE / $compressed / $expires"; - print $c "HTTP/1.1 200 OK\r\n", - "Content-Length: $length\r\n", - $expires, $compressed, $FW_headercors, - "Content-Type: $FW_RETTYPE\r\n\r\n", - $FW_RET; - exit if(defined($pid)); -} - -########################### -sub -FW_serveSpecial($$$$) -{ - my ($file,$ext,$dir,$cacheable)= @_; - $file =~ s,\.\./,,g; # little bit of security - - $file = "$FW_sp$file" if($ext eq "css" && -f "$dir/$FW_sp$file.$ext"); - $FW_RETTYPE = ext2MIMEType($ext); - return FW_returnFileAsStream("$dir/$file.$ext", "", - $FW_RETTYPE, 0, $cacheable); -} - -sub -FW_answerCall($) -{ - my ($arg) = @_; - my $me=$defs{$FW_cname}; # cache, else rereadcfg will delete us - - $FW_RET = ""; - $FW_RETTYPE = "text/html; charset=$FW_encoding"; - $FW_ME = "/" . AttrVal($FW_wname, "webname", "fhem"); - - $MW_dir = "$attr{global}{modpath}/FHEM"; - $FW_sp = AttrVal($FW_wname, "stylesheetPrefix", ""); - $FW_ss = ($FW_sp =~ m/smallscreen/); - $FW_tp = ($FW_sp =~ m/smallscreen|touchpad/); - @FW_iconDirs = grep { $_ } split(":", AttrVal($FW_wname, "iconPath", - "$FW_sp:default:fhemSVG:openautomation")); - if($arg =~ m,$FW_ME/floorplan/([a-z0-9.:_]+),i) { # FLOORPLAN: special icondir - unshift @FW_iconDirs, $1; - FW_readIcons($1); - } - - # /icons/... => current state of ... - # also used for static images: unintended, but too late to change - if($arg =~ m,^$FW_ME/icons/(.*)$,) { - my ($icon,$cacheable) = (urlDecode($1), 1); - my $iconPath = FW_iconPath($icon); - - # if we do not have the icon, we convert the device state to the icon name - if(!$iconPath) { - ($icon, undef, undef) = FW_dev2image($icon); - $cacheable = 0; - return 0 if(!$icon); - $iconPath = FW_iconPath($icon); - } - $iconPath =~ m/(.*)\.([^.]*)/; - return FW_serveSpecial($1, $2, $FW_icondir, $cacheable); - - } elsif($arg =~ m,^$FW_ME/(.*)/([^/]*)$,) { # the "normal" case - my ($dir, $ofile, $ext) = ($1, $2, ""); - $dir =~ s/\.\.//g; - $dir =~ s,www/,,g; # Want commandref.html to work from file://... - - my $file = $ofile; - $file =~ s/\?.*//; # Remove timestamp of CSS reloader - if($file =~ m/^(.*)\.([^.]*)$/) { - $file = $1; $ext = $2; - } - my $ldir = "$FW_dir/$dir"; - $ldir = "$FW_dir/pgm2" if($dir eq "css" || $dir eq "js"); # FLOORPLAN compat - $ldir = "$attr{global}{modpath}/docs" if($dir eq "docs"); - - if(-r "$ldir/$file.$ext") { # no return for FLOORPLAN - return FW_serveSpecial($file, $ext, $ldir, ($arg =~ m/nocache/) ? 0 : 1); - } - $arg = "/$dir/$ofile"; - - } elsif($arg =~ m/^$FW_ME(.*)/) { - $arg = $1; # The stuff behind FW_ME, continue to check for commands/FWEXT - - } else { - my $c = $me->{CD}; - Log3 $FW_wname, 4, "$FW_wname: redirecting $arg to $FW_ME"; - print $c "HTTP/1.1 302 Found\r\n", - "Content-Length: 0\r\n", $FW_headercors, - "Location: $FW_ME\r\n\r\n"; - return -1; - - } - - - $FW_plotmode = AttrVal($FW_wname, "plotmode", "SVG"); - $FW_plotsize = AttrVal($FW_wname, "plotsize", $FW_ss ? "480,160" : - $FW_tp ? "640,160" : "800,160"); - my ($cmd, $cmddev) = FW_digestCgi($arg); - - - if($FW_inform) { # Longpoll header - if($FW_inform =~ /type=/) { - foreach my $kv (split(";", $FW_inform)) { - my ($key,$value) = split("=", $kv, 2); - $me->{inform}{$key} = $value; - } - - } else { # Compatibility mode - $me->{inform}{type} = ($FW_room ? "status" : "raw"); - $me->{inform}{filter} = ($FW_room ? $FW_room : ".*"); - } - my $filter = $me->{inform}{filter}; - $filter = "NAME=.*" if($filter eq "room=all"); - $filter = "room!=.*" if($filter eq "room=Unsorted"); - - my %h = map { $_ => 1 } devspec2array($filter); - $me->{inform}{devices} = \%h; - %FW_visibleDeviceHash = FW_visibleDevices(); - - # NTFY_ORDER is larger than the normal order (50-) - $me->{NTFY_ORDER} = $FW_cname; # else notifyfn won't be called - %ntfyHash = (); - - my $c = $me->{CD}; - print $c "HTTP/1.1 200 OK\r\n", - $FW_headercors, - "Content-Type: application/octet-stream; charset=$FW_encoding\r\n\r\n", - FW_roomStatesForInform($me); - return -1; - } - - my $docmd = 0; - $docmd = 1 if($cmd && - $cmd !~ /^showlog/ && - $cmd !~ /^style / && - $cmd !~ /^edit/); - - #If we are in XHR or json mode, execute the command directly - if($FW_XHR || $FW_jsonp) { - $FW_cmdret = $docmd ? FW_fC($cmd, $cmddev) : ""; - $FW_RETTYPE = "text/plain; charset=$FW_encoding"; - if($FW_jsonp) { - $FW_cmdret =~ s/'/\\'/g; - # Escape newlines in JavaScript string - $FW_cmdret =~ s/\n/\\\n/g; - FW_pO "$FW_jsonp('$FW_cmdret');"; - } else { - FW_pO $FW_cmdret; - } - return 0; - } - - ############################## - # FHEMWEB extensions (FLOORPLOAN, SVG_WriteGplot, etc) - my $FW_contentFunc; - if(defined($data{FWEXT})) { - foreach my $k (sort keys %{$data{FWEXT}}) { - my $h = $data{FWEXT}{$k}; - next if($arg !~ m/^$k/); - $FW_contentFunc = $h->{CONTENTFUNC}; - next if($h !~ m/HASH/ || !$h->{FUNC}); - #Returns undef as FW_RETTYPE if it already sent a HTTP header - no strict "refs"; - ($FW_RETTYPE, $FW_RET) = &{$h->{FUNC}}($arg); - use strict "refs"; - return defined($FW_RETTYPE) ? 0 : -1; - } - } - - - #Now execute the command - $FW_cmdret = ""; - if($docmd) { - $FW_cmdret = FW_fC($cmd, $cmddev); - if($cmd =~ m/^define +([^ ]+) /) { # "redirect" after define to details - $FW_detail = $1; - } - } - - # Redirect after a command, to clean the browser URL window - if($docmd && !$FW_cmdret && AttrVal($FW_wname, "redirectCmds", 1)) { - my $tgt = $FW_ME; - if($FW_detail) { $tgt .= "?detail=$FW_detail" } - elsif($FW_room) { $tgt .= "?room=$FW_room" } - my $c = $me->{CD}; - print $c "HTTP/1.1 302 Found\r\n", - "Content-Length: 0\r\n", $FW_headercors, - "Location: $tgt\r\n", - "\r\n"; - return -1; - } - - FW_updateHashes(); - - my $t = AttrVal("global", "title", "Home, Sweet Home"); - - FW_pO ''; - FW_pO ''; - FW_pO "\n$t"; - FW_pO ''; - - # Enable WebApps - if($FW_tp || $FW_ss) { - my $icon = $FW_ME."/images/default/fhemicon_ios.png"; - if($FW_ss) { - FW_pO ''; - } elsif($FW_tp) { - FW_pO ''; - } - FW_pO ''; - FW_pO ''; - FW_pO ''; - } - - # meta refresh in rooms only - if ($FW_room) { - my $rf = AttrVal($FW_wname, "refresh", ""); - FW_pO "" if($rf); - } - - FW_pO ""; - - ######################## - # FW Extensions - my $jsTemplate = ''; - if(defined($data{FWEXT})) { - foreach my $k (sort keys %{$data{FWEXT}}) { - my $h = $data{FWEXT}{$k}; - next if($h !~ m/HASH/ || !$h->{SCRIPT}); - my $script = $h->{SCRIPT}; - $script = ($script =~ m,^/,) ? "$FW_ME$script" : "$FW_ME/pgm2/$script"; - FW_pO sprintf($jsTemplate, $script); - } - } - - FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/svg.js") if($FW_plotmode eq "SVG"); - if($FW_plotmode eq"jsSVG") { - FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/jsSVG.js"); - FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/jquery.min.js"); - } - foreach my $js (@FW_fhemwebjs) { - FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/$js"); - } - - my $onload = AttrVal($FW_wname, "longpoll", 1) ? - "onload=\"FW_delayedStart()\"" : ""; - FW_pO "\n"; - - if($FW_activateInform) { - $FW_cmdret = $FW_activateInform = ""; - $cmd = "style eventMonitor"; - } - - if($FW_cmdret) { - $FW_detail = ""; - $FW_room = ""; - $FW_cmdret = FW_htmlEscape($FW_cmdret); - $FW_cmdret =~ s/>/>/g; - FW_pO "
"; - $FW_cmdret = "
$FW_cmdret
" if($FW_cmdret =~ m/\n/); - if($FW_ss) { - FW_pO "
$FW_cmdret
"; - } else { - FW_pO $FW_cmdret; - } - FW_pO "
"; - - } - - FW_roomOverview($cmd); - if($FW_contentFunc) { - no strict "refs"; - my $ret = &{$FW_contentFunc}($arg); - use strict "refs"; - return $ret if($ret); - } - - if($cmd =~ m/^style /) { FW_style($cmd,undef); } - elsif($FW_detail) { FW_doDetail($FW_detail); } - elsif($FW_room) { FW_showRoom(); } - elsif(!$FW_cmdret && - !$FW_contentFunc) { - - $FW_room = AttrVal($FW_wname, "defaultRoom", ''); - if($FW_room ne '') { - FW_showRoom(); - - } else { - my $motd = AttrVal("global","motd","none"); - if($motd ne "none") { - $motd =~ s/\n/
/g; - FW_pO "
$motd
"; - } - } - } - FW_pO ""; - return 0; -} - - -########################### -# Digest CGI parameters -sub -FW_digestCgi($) -{ - my ($arg) = @_; - my (%arg, %val, %dev); - my ($cmd, $c) = ("","",""); - - %FW_pos = (); - $FW_room = ""; - $FW_detail = ""; - $FW_XHR = undef; - $FW_jsonp = undef; - $FW_inform = undef; - - %FW_webArgs = (); - #Remove (nongreedy) everything including the first '?' - $arg =~ s,^.*?[?],,; - foreach my $pv (split("&", $arg)) { - next if($pv eq ""); # happens when post forgot to set FW_ME - $pv =~ s/\+/ /g; - $pv =~ s/%([\dA-F][\dA-F])/chr(hex($1))/ige; - my ($p,$v) = split("=",$pv, 2); - - # Multiline: escape the NL for fhem - $v =~ s/[\r]//g if($v && $p && $p ne "data"); - $FW_webArgs{$p} = $v; - - if($p eq "detail") { $FW_detail = $v; } - if($p eq "room") { $FW_room = $v; } - if($p eq "cmd") { $cmd = $v; } - if($p =~ m/^arg\.(.*)$/) { $arg{$1} = $v; } - if($p =~ m/^val\.(.*)$/) { $val{$1} = ($val{$1} ? $val{$1}.",$v" : $v) } - if($p =~ m/^dev\.(.*)$/) { $dev{$1} = $v; } - if($p =~ m/^cmd\.(.*)$/) { $cmd = $v; $c = $1; } - if($p eq "pos") { %FW_pos = split(/[=;]/, $v); } - if($p eq "data") { $FW_data = $v; } - if($p eq "XHR") { $FW_XHR = 1; } - if($p eq "jsonp") { $FW_jsonp = $v; } - if($p eq "inform") { $FW_inform = $v; } - - } - $cmd.=" $dev{$c}" if(defined($dev{$c})); - $cmd.=" $arg{$c}" if(defined($arg{$c}) && - ($arg{$c} ne "state" || $cmd !~ m/^set/)); - $cmd.=" $val{$c}" if(defined($val{$c})); - return ($cmd, $c); -} - -##################### -# create FW_rooms && FW_types -sub -FW_updateHashes() -{ - ################# - # Make a room hash - %FW_rooms = (); - foreach my $d (keys %defs ) { - next if(IsIgnored($d)); - foreach my $r (split(",", AttrVal($d, "room", "Unsorted"))) { - $FW_rooms{$r}{$d} = 1; - } - } - - ############### - # Needed for type sorting - %FW_types = (); - foreach my $d (sort keys %defs ) { - next if(IsIgnored($d)); - my $t = AttrVal($d, "subType", $defs{$d}{TYPE}); - $t = AttrVal($d, "model", $t) if($t && $t eq "unknown"); # RKO: ??? - $FW_types{$d} = $t; - } - - $FW_room = AttrVal($FW_detail, "room", "Unsorted") if($FW_detail); -} - -############################## -sub -FW_makeTable($$$@) -{ - my($title, $name, $hash, $cmd) = (@_); - - return if(!$hash || !int(keys %{$hash})); - my $class = lc($title); - $class =~ s/[^A-Za-z]/_/g; - FW_pO "
"; - FW_pO $title; - FW_pO ""; - my $si = AttrVal("global", "showInternalValues", 0); - - my $row = 1; - foreach my $n (sort keys %{$hash}) { - next if(!$si && $n =~ m/^\./); # Skip "hidden" Values - my $val = $hash->{$n}; - $val = "" if(!defined($val)); - - $val = $hash->{$n}{NAME} # Exception - if($n eq "IODev" && ref($val) eq "HASH" && defined($hash->{$n}{NAME})); - - my $r = ref($val); - next if($r && ($r ne "HASH" || !defined($hash->{$n}{VAL}))); - - FW_pF "", ($row&1)?"odd":"even"; - $row++; - - if($n eq "DEF" && !$FW_hiddenroom{input}) { - FW_makeEdit($name, $n, $val); - - } else { - if( $title eq "Attributes" ) { - FW_pO ""; - } else { - FW_pO ""; - } - - if(ref($val)) { #handle readings - my ($v, $t) = ($val->{VAL}, $val->{TIME}); - $v = FW_htmlEscape($v); - if($FW_ss) { - $t = ($t ? "
$t
" : ""); - FW_pO ""; - } else { - $t = "" if(!$t); - FW_pO ""; - FW_pO ""; - } - } else { - $val = FW_htmlEscape($val); - - # if possible provide som links - if ($n eq "room"){ - FW_pO ""; - - } elsif ($n eq "webCmd"){ - my $lc = "detail=$name&cmd.$name=set $name"; - FW_pO ""; - - } elsif ($n =~ m/^fp_(.*)/ && $defs{$1}){ #special for Floorplan - FW_pH "detail=$1", $val,1; - - } else { - FW_pO ""; - } - } - - } - - FW_pH "cmd.$name=$cmd $name $n&detail=$name", $cmd, 1 - if($cmd && !$FW_ss); - FW_pO ""; - } - FW_pO "
". - "". - "$n
$n
$v$t
$v
$t
". - join(",", map { FW_pH("room=$_",$_,0,"",1,1) } split(",",$val)). - "
". - join(":", map {FW_pH("$lc $_",$_,0,"",1,1)} split(":",$val) ). - "
". - join(",", map { ($_ ne $name && $defs{$_}) ? - FW_pH( "detail=$_", $_ ,0,"",1,1) : $_ } split(",",$val)). - "
"; - FW_pO "
"; - -} - -############################## -# Used only for set or attr lists. -sub -FW_makeSelect($$$$) -{ - my ($d, $cmd, $list,$class) = @_; - return if(!$list || $FW_hiddenroom{input}); - my @al = sort map { s/:.*//;$_ } split(" ", $list); - - my $selEl = (defined($al[0]) ? $al[0] : " "); - $selEl = $1 if($list =~ m/([^ ]*):slider,/); # promote a slider if available - $selEl = "room" if($list =~ m/room:/); - - FW_pO "
"; - FW_pO "
"; - FW_pO FW_hidden("detail", $d); - FW_pO FW_hidden("dev.$cmd$d", $d); - FW_pO FW_submit("cmd.$cmd$d", $cmd, $class); - FW_pO "
 $d 
"; - FW_pO FW_select("sel.$cmd$d","arg.$cmd$d",\@al, $selEl, $class, - "FW_selChange(this.options[selectedIndex].text,'$list','val.$cmd$d')"); - FW_pO FW_textfield("val.$cmd$d", 30, $class); - # Initial setting - FW_pO ""; - FW_pO "
"; -} - -############################## -sub -FW_doDetail($) -{ - my ($d) = @_; - - my $h = $defs{$d}; - my $t = $h->{TYPE}; - $t = "MISSING" if(!defined($t)); - FW_pO "
"; - - if($FW_ss) { # FS20MS2 special: on and off, is not the same as toggle - my $webCmd = AttrVal($d, "webCmd", undef); - if($webCmd) { - FW_pO ""; - foreach my $cmd (split(":", $webCmd)) { - FW_pO ""; - FW_pH "cmd.$d=set $d $cmd&detail=$d", $cmd, 1, "col1"; - FW_pO ""; - } - FW_pO "
"; - } - } - FW_pO "
"; - - if($modules{$t}{FW_detailFn}) { - no strict "refs"; - my $txt = &{$modules{$t}{FW_detailFn}}($FW_wname, $d, $FW_room); - FW_pO "$txt
" if(defined($txt)); - use strict "refs"; - } - - FW_pO "
"; - FW_pO FW_hidden("detail", $d); - - FW_makeSelect($d, "set", getAllSets($d), "set"); - FW_makeSelect($d, "get", getAllGets($d), "get"); - - FW_makeTable("Internals", $d, $h); - FW_makeTable("Readings", $d, $h->{READINGS}); - - my $attrList = getAllAttr($d); - my $roomList = "multiple,".join(",", sort map { $_ =~ s/ /#/g ;$_} keys %FW_rooms); - $attrList =~ s/room /room:$roomList /; - FW_makeSelect($d, "attr", $attrList,"attr"); - - FW_makeTable("Attributes", $d, $attr{$d}, "deleteattr"); - ## dependent objects - my @dob; # dependent objects - triggered by current device - foreach my $dn (sort keys %defs) { - next if(!$dn || $dn eq $d); - my $dh = $defs{$dn}; - if(($dh->{DEF} && $dh->{DEF} =~ m/\b$d\b/) || - ($h->{DEF} && $h->{DEF} =~ m/\b$dn\b/)) { - push(@dob, $dn); - } - } - FW_pO "
"; - FW_makeTableFromArray("Probably associated with", "assoc", @dob,); - - FW_pO "
"; - - FW_pH "cmd=style iconFor $d", "Select icon"; - FW_pH "cmd=style showDSI $d", "Extend devStateIcon"; - FW_pH "$FW_ME/docs/commandref.html#${t}", "Device specific help"; - FW_pO "

"; - FW_pO "
"; - -} - -############################## -sub -FW_makeTableFromArray($$@) { - my ($txt,$class,@obj) = @_; - if (@obj>0) { - my $row=1; - FW_pO "
"; - FW_pO "$txt"; - FW_pO ""; - foreach (sort @obj) { - FW_pF ""; - FW_pO ""; - } - FW_pO "
", ($row&1)?"odd":"even"; - $row++; - FW_pH "detail=$_", $_; - FW_pO "$defs{$_}{TYPE}
"; - } -} - -sub -FW_roomIdx(\@$) -{ - my ($arr,$v) = @_; - my ($index) = grep { $v =~ /^$arr->[$_]$/ } 0..$#$arr; - - if( !defined($index) ) { - $index = 9999; - } else { - $index = sprintf( "%03i", $index ); - } - - return "$index-$v"; -} - - -############## -# Header, Zoom-Icons & list of rooms at the left. -sub -FW_roomOverview($) -{ - my ($cmd) = @_; - - %FW_hiddenroom = (); - foreach my $r (split(",",AttrVal($FW_wname, "hiddenroom", ""))) { - $FW_hiddenroom{$r} = 1; - } - - ############## - # LOGO - my $hasMenuScroll; - if($FW_detail && $FW_ss) { - $FW_room = AttrVal($FW_detail, "room", undef); - $FW_room = $1 if($FW_room && $FW_room =~ m/^([^,]*),/); - $FW_room = "" if(!$FW_room); - FW_pO(FW_pHPlain("room=$FW_room", - "
" . FW_makeImage("back") . "
")); - FW_pO "
$FW_detail details
"; - return; - - } else { - $hasMenuScroll = 1; - FW_pO '" if($hasMenuScroll); - - ############## - # HEADER - FW_pO "
"; - FW_pO '
'; - FW_pO "
"; - FW_pO FW_hidden("room", "$FW_room") if($FW_room); - FW_pO FW_textfield("cmd", $FW_ss ? 25 : 40, "maininput"); - FW_pO "
"; - FW_pO "
"; - FW_pO "
"; - -} - - -######################## -# Show the overview of devices in one room -# room can be a room, all or Unsorted -sub -FW_showRoom() -{ - return if(!$FW_room); - - %FW_hiddengroup = (); - foreach my $r (split(",",AttrVal($FW_wname, "hiddengroup", ""))) { - $FW_hiddengroup{$r} = 1; - } - - FW_pO "
"; - FW_pO "
"; - FW_pO ""; # Need for equal width of subtables - - my $rf = ($FW_room ? "&room=$FW_room" : ""); # stay in the room - - # array of all device names in the room (exception weblinks without group - # attribute) - my @devs= grep { ($FW_rooms{$FW_room}{$_}||$FW_room eq "all") && - !IsIgnored($_) } keys %defs; - my (%group, @atEnds, %usuallyAtEnd); - foreach my $dev (@devs) { - if($modules{$defs{$dev}{TYPE}}{FW_atPageEnd}) { - $usuallyAtEnd{$dev} = 1; - if(!AttrVal($dev, "group", undef)) { - push @atEnds, $dev; - next; - } - } - foreach my $grp (split(",", AttrVal($dev, "group", $FW_types{$dev}))) { - next if($FW_hiddengroup{$grp}); - $group{$grp}{$dev} = 1; - } - } - - # row counter - my $row=1; - my %extPage = (); - - my ($columns, $maxc) = FW_parseColumns(); - FW_pO "" if($maxc != -1); - for(my $col=1; $col < ($maxc==-1 ? 2 : $maxc); $col++) { - FW_pO "" if($maxc != -1); # Column - } - FW_pO ""; - - FW_pO "
" if($maxc != -1); - - # iterate over the distinct groups - foreach my $g (sort keys %group) { - - next if($maxc != -1 && (!$columns->{$g} || $columns->{$g} != $col)); - - ################# - # Check if there is a device of this type in the room - FW_pO "\n"; - FW_pO ""; - } - FW_pO "
$g
"; - FW_pO ""; - - foreach my $d (sort { lc(AttrVal($a,"sortby",AttrVal($a,"alias",$a))) cmp - lc(AttrVal($b,"sortby",AttrVal($b,"alias",$b))) } - keys %{$group{$g}}) { - my $type = $defs{$d}{TYPE}; - - FW_pF "\n", ($row&1)?"odd":"even"; - my $devName = AttrVal($d, "alias", $d); - my $icon = AttrVal($d, "icon", ""); - $icon = FW_makeImage($icon,$icon,"icon") . " " if($icon); - - if($FW_hiddenroom{detail}) { - FW_pO ""; - } else { - FW_pH "detail=$d", "$icon$devName", 1, "col1" if(!$usuallyAtEnd{$d}); - } - $row++; - - my ($allSets, $cmdlist, $txt) = FW_devState($d, $rf, \%extPage); - - my $colSpan = ($usuallyAtEnd{$d} ? ' colspan="2"' : ''); - FW_pO ""; - - ###### - # Commands, slider, dropdown - if(!$FW_ss && $cmdlist) { - foreach my $cmd (split(":", $cmdlist)) { - my $htmlTxt; - my @c = split(' ', $cmd); # @c==0 if $cmd==" "; - if(int(@c) && $allSets && $allSets =~ m/$c[0]:([^ ]*)/) { - my $values = $1; - foreach 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) { - FW_pO $htmlTxt; - - } else { - FW_pH "cmd.$d=set $d $cmd$rf", $cmd, 1, "col3"; - } - } - } - FW_pO ""; - } - FW_pO "
$icon$devName
$txt
"; - FW_pO "

"; - - # Now the "atEnds" - foreach my $d (sort { lc(AttrVal($a, "sortby", AttrVal($a,"alias",$a))) cmp - lc(AttrVal($b, "sortby", AttrVal($b,"alias",$b))) } - @atEnds) { - no strict "refs"; - FW_pO &{$modules{$defs{$d}{TYPE}}{FW_summaryFn}}($FW_wname, $d, - $FW_room, \%extPage); - use strict "refs"; - } - FW_pO "
"; - FW_pO "
"; -} - -sub -FW_parseColumns() -{ - my %columns; - my $colNo = -1; - - foreach my $roomgroup (split("[ \t\r\n]+", AttrVal($FW_wname,"column",""))) { - my ($room, $groupcolumn)=split(":",$roomgroup); - last if(!defined($room) || !defined($groupcolumn)); - next if($room ne $FW_room); - $colNo = 1; - foreach my $groups (split(/\|/,$groupcolumn)) { - foreach my $group (split(",",$groups)) { - $columns{$group} = $colNo; - } - $colNo++; - } - } - return (\%columns, $colNo); -} - - -################# -# return a sorted list of actual files for a given regexp -sub -FW_fileList($) -{ - my ($fname) = @_; - $fname =~ m,^(.*)/([^/]*)$,; # Split into dir and file - my ($dir,$re) = ($1, $2); - return if(!$re); - $dir =~ s/%L/$attr{global}{logdir}/g if($dir =~ m/%/ && $attr{global}{logdir}); # %L present and log directory defined - $re =~ s/%./[A-Za-z0-9]*/g; # logfile magic (%Y, etc) - my @ret; - return @ret if(!opendir(DH, $dir)); - while(my $f = readdir(DH)) { - next if($f !~ m,^$re$,); - push(@ret, $f); - } - closedir(DH); - return sort @ret; -} - - -################################### -# Stream big files in chunks, to avoid bloating ourselves. -# This is a "terminal" function, no data can be appended after it is called. -sub -FW_outputChunk($$$) -{ - my ($c, $buf, $d) = @_; - $buf = $d->deflate($buf) if($d); - print $c sprintf("%x\r\n", length($buf)), $buf, "\r\n" if(length($buf)); -} - -sub -FW_returnFileAsStream($$$$$) -{ - my ($path, $suffix, $type, $doEsc, $cacheable) = @_; - - my $etag; - my $c = $FW_chash->{CD}; - - if($cacheable) { - #Check for If-None-Match header (ETag) - my @if_none_match_lines = grep /If-None-Match/, @FW_httpheader; - my $if_none_match = undef; - if(@if_none_match_lines) { - $if_none_match = $if_none_match_lines[0]; - $if_none_match =~ s/If-None-Match: \"(.*)\"/$1/; - } - - $etag = (stat($path))[9]; #mtime - if(defined($etag) && defined($if_none_match) && $etag eq $if_none_match) { - print $c "HTTP/1.1 304 Not Modified\r\n", - $FW_headercors, "\r\n"; - return -1; - } - } - - if(!open(FH, $path)) { - Log3 $FW_wname, 2, "FHEMWEB $FW_wname $path: $!"; - FW_pO "
$path: $!
"; - return 0; - } - binmode(FH) if($type !~ m/text/); # necessary for Windows - - $etag = defined($etag) ? "ETag: \"$etag\"\r\n" : ""; - my $expires = $cacheable ? ("Expires: ".gmtime(time()+900)." GMT\r\n"): ""; - my $compr = ((int(@FW_enc) == 1 && $FW_enc[0] =~ m/gzip/) && $FW_use_zlib) ? - "Content-Encoding: gzip\r\n" : ""; - print $c "HTTP/1.1 200 OK\r\n", - $compr, $expires, $FW_headercors, $etag, - "Transfer-Encoding: chunked\r\n", - "Content-Type: $type; charset=$FW_encoding\r\n\r\n"; - - my $d = Compress::Zlib::deflateInit(-WindowBits=>31) if($compr); - FW_outputChunk($c, $FW_RET, $d); - my $buf; - while(sysread(FH, $buf, 2048)) { - if($doEsc) { # FileLog special - $buf =~ s//>/g; - } - FW_outputChunk($c, $buf, $d); - } - close(FH); - FW_outputChunk($c, $suffix, $d); - - if($compr) { - $buf = $d->flush(); - print $c sprintf("%x\r\n", length($buf)), $buf, "\r\n" if($buf); - } - print $c "0\r\n\r\n"; - return -1; -} - - -################## -sub -FW_fatal($) -{ - my ($msg) = @_; - FW_pO "$msg"; -} - -################## -sub -FW_hidden($$) -{ - my ($n, $v) = @_; - return ""; -} - -################## -# Generate a select field with option list -sub -FW_select($$$$$@) -{ - my ($id, $n, $va, $def, $class, $jSelFn) = @_; - $jSelFn = ($jSelFn ? "onchange=\"$jSelFn\"" : ""); - $id = ($id ? "id=\"$id\" informId=\"$id\"" : ""); - my $s = ""; - return $s; -} - -################## -sub -FW_textfieldv($$$$) -{ - my ($n, $z, $class, $value) = @_; - my $v; - $v=" value=\"$value\"" if(defined($value)); - return if($FW_hiddenroom{input}); - my $s = ""; - return $s; -} - -sub -FW_textfield($$$) -{ - return FW_textfieldv($_[0], $_[1], $_[2], ""); -} - -################## -sub -FW_submit($$@) -{ - my ($n, $v, $class) = @_; - $class = ($class ? "class=\"$class\"" : ""); - my $s =""; - return $s; -} - -################## -sub -FW_displayFileList($@) -{ - my ($heading,@files)= @_; - my $hid = lc($heading); - $hid =~ s/[^A-Za-z]/_/g; - FW_pO "
$heading
"; - FW_pO ""; - my $row = 0; - foreach my $f (@files) { - FW_pO ""; - FW_pH "cmd=style edit $f", $f, 1; - FW_pO ""; - $row = ($row+1)%2; - } - FW_pO "
"; - FW_pO "
"; -} - -################## -sub -FW_fileNameToPath($) -{ - my $name = shift; - - $attr{global}{configfile} =~ m,([^/]*)$,; - my $cfgFileName = $1; - if($name eq $cfgFileName) { - return $attr{global}{configfile}; - } elsif($name =~ m/.*(css|svg)$/) { - return "$FW_cssdir/$name"; - } elsif($name =~ m/.*gplot$/) { - return "$FW_gplotdir/$name"; - } else { - return "$MW_dir/$name"; - } -} - -################## -# List/Edit/Save css and gnuplot files -sub -FW_style($$) -{ - my ($cmd, $msg) = @_; - my @a = split(" ", $cmd); - - my $ac = AttrVal($FW_wname,"allowedCommands",""); - return if($ac && $ac !~ m/\b$a[0]\b/); - - my $start = "
"; - my $end = "
"; - - if($a[1] eq "list") { - FW_pO $start; - FW_pO "$msg

" if($msg); - - $attr{global}{configfile} =~ m,([^/]*)$,; - my $cfgFileName = $1; - FW_displayFileList("config file", $cfgFileName) - if($attr{global}{configfile} ne 'configDB'); - FW_displayFileList("Own modules and helper files", - FW_fileList("$MW_dir/^(.*sh|[0-9][0-9].*Util.*pm|.*cfg|.*holiday". - "|.*layout)\$")); - FW_displayFileList("styles", - FW_fileList("$FW_cssdir/^.*(css|svg)\$")); - FW_displayFileList("gplot files", - FW_fileList("$FW_gplotdir/^.*gplot\$")); - FW_pO $end; - - } elsif($a[1] eq "select") { - my @fl = grep { $_ !~ m/(floorplan|dashboard)/ } FW_fileList("$FW_cssdir/.*style.css"); - FW_pO "$start"; - my $row = 0; - foreach my $file (@fl) { - next if($file =~ m/svg_/); - $file =~ s/style.css//; - $file = "default" if($file eq ""); - FW_pO ""; - FW_pH "cmd=style set $file", "$file", 1; - FW_pO ""; - $row = ($row+1)%2; - } - FW_pO "
$end"; - - } elsif($a[1] eq "set") { - if($a[2] eq "default") { - CommandDeleteAttr(undef, "$FW_wname stylesheetPrefix"); - } else { - CommandAttr(undef, "$FW_wname stylesheetPrefix $a[2]"); - } - FW_pO "${start}Reload the page in the browser.$end"; - - } elsif($a[1] eq "edit") { - my $fileName = $a[2]; - $fileName =~ s,.*/,,g; # Little bit of security - my $filePath = FW_fileNameToPath($fileName); - if(!open(FH, $filePath)) { - FW_pO "
$filePath: $!
"; - return; - } - my $data = join("", ); - close(FH); - - $data =~ s/&/&/g; - - my $ncols = $FW_ss ? 40 : 80; - FW_pO "
"; - FW_pO "
"; - FW_pO FW_submit("save", "Save $fileName"); - FW_pO "  "; - FW_pO FW_submit("saveAs", "Save as"); - FW_pO FW_textfieldv("saveName", 30, "saveName", $fileName); - FW_pO "

"; - FW_pO FW_hidden("cmd", "style save $fileName"); - FW_pO ""; - FW_pO "
"; - - if( AttrVal($FW_wname,'enhancedEditor',0) ) { - my $ext = ($fileName =~ m/\.(.*)$/)[0]; - FW_codemirrorLink($ext); - FW_pO "". - ""; - } - - FW_pO "
"; - - } elsif($a[1] eq "save") { - my $fileName = $a[2]; - $fileName = $FW_webArgs{saveName} - if($FW_webArgs{saveAs} && $FW_webArgs{saveName}); - $fileName =~ s,.*/,,g; # Little bit of security - my $filePath = FW_fileNameToPath($fileName); - - if(!open(FH, ">$filePath")) { - FW_pO "
$filePath: $!
"; - return; - } - $FW_data =~ s/\r//g if($^O !~ m/Win/); - binmode (FH); - print FH $FW_data; - close(FH); - - my $ret = FW_fC("rereadcfg") if($filePath eq $attr{global}{configfile}); - $ret = FW_fC("reload $fileName") if($fileName =~ m,\.pm$,); - $ret = ($ret ? "

ERROR:

$ret" : "Saved the file $fileName"); - FW_style("style list", $ret); - $ret = ""; - - } elsif($a[1] eq "iconFor") { - FW_iconTable("iconFor", "icon", "style setIF $a[2] %s", undef); - - } elsif($a[1] eq "setIF") { - FW_fC("attr $a[2] icon $a[3]"); - FW_doDetail($a[2]); - - } elsif($a[1] eq "showDSI") { - FW_iconTable("devStateIcon", "", - "style addDSI $a[2] %s", "Enter value/regexp for STATE"); - - } elsif($a[1] eq "addDSI") { - my $dsi = AttrVal($a[2], "devStateIcon", ""); - $dsi .= " " if($dsi); - FW_fC("attr $a[2] devStateIcon $dsi$FW_data:$a[3]"); - FW_doDetail($a[2]); - - } elsif($a[1] eq "eventMonitor") { - FW_pO ""; - FW_pO "
"; - FW_pO "
"; - FW_pO "Events:
\n"; - FW_pO "
"; - FW_pO "
"; - - } - -} - -sub -FW_iconTable($$$$) -{ - my ($name, $class, $cmdFmt, $textfield) = @_; - - my %icoList = (); - foreach my $style (@FW_iconDirs) { - foreach my $imgName (sort keys %{$FW_icons{$style}}) { - $imgName =~ s/\.[^.]*$//; # Cut extension - next if(!$FW_icons{$style}{$imgName}); # Dont cut it twice: FS20.on.png - next if($FW_icons{$style}{$imgName} !~ m/$imgName/); # Skip alias - next if($imgName=~m+^(weather/|shutter.*big|fhemicon|favicon|ws_.*_kl)+); - next if($imgName=~m+^(dashboardicons)+); - $icoList{$imgName} = 1; - } - } - - FW_pO "
"; - FW_pO "
"; - if($textfield) { - FW_pO "$textfield: ".FW_textfieldv("data",20,"iconTable",".*")."
"; - } - foreach my $i (sort keys %icoList) { - FW_pF "", $i, $i, FW_makeImage($i,$i,$class); - } - FW_pO "
"; - FW_pO "
"; -} - -################## -# print (append) to output -sub -FW_pO(@) -{ - my $arg = shift; - return if(!defined($arg)); - $FW_RET .= $arg; - $FW_RET .= "\n"; -} - -################# -# add href -sub -FW_pH(@) -{ - my ($link, $txt, $td, $class, $doRet,$nonl) = @_; - my $ret; - - $link = ($link =~ m,^/,) ? $link : "$FW_ME$FW_subdir?$link"; - - # Using onclick, as href starts safari in a webapp. - # Known issue: the pointer won't change - if($FW_ss || $FW_tp) { - $ret = "$txt"; - } else { - $ret = "$txt"; - } - - #actually 'div' should be removed if no class is defined - # as I can't check all code for consistancy I add nonl instead - $class = ($class)?" class=\"$class\"":""; - $ret = "$ret" if (!$nonl); - - $ret = "$ret" if($td); - return $ret if($doRet); - FW_pO $ret; -} - -################# -# href without class/div, returned as a string -sub -FW_pHPlain(@) -{ - my ($link, $txt, $td) = @_; - - $link = "?$link" if($link !~ m+^/+); - my $ret = ""; - $ret .= "" if($td); - if($FW_ss || $FW_tp) { - $ret .= "$txt"; - } else { - $ret .= "$txt"; - } - $ret .= "" if($td); - return $ret; -} - - -############################## -sub -FW_makeImage(@) -{ - my ($name, $txt, $class)= @_; - - $txt = $name if(!defined($txt)); - $class = "" if(!$class); - $class = "$class $name"; - $class =~ s/\./_/g; - $class =~ s/@/ /g; - - my $p = FW_iconPath($name); - return $name if(!$p); - if($p =~ m/\.svg$/i) { - if(open(FH, "$FW_icondir/$p")) { - ; ; ; # Skip the first 3 lines; - my $data = join("", ); - close(FH); - $data =~ s/[\r\n]/ /g; - $data =~ s/ *$//g; - $data =~ s/"; - } -} - -#### -sub -FW_IconURL($) -{ - my ($name)= @_; - return "$FW_ME/icons/$name"; -} - -################## -# print formatted -sub -FW_pF($@) -{ - my $fmt = shift; - $FW_RET .= sprintf $fmt, @_; -} - -################## -# fhem command -sub -FW_fC($@) -{ - my ($cmd, $unique) = @_; - my $ret; - if($unique) { - $ret = AnalyzeCommand($FW_chash, $cmd, - AttrVal($FW_wname,"allowedCommands",undef)); - } else { - $ret = AnalyzeCommandChain($FW_chash, $cmd, - AttrVal($FW_wname,"allowedCommands",undef)); - } - return $ret; -} - -sub -FW_Attr(@) -{ - my @a = @_; - my $hash = $defs{$a[1]}; - my $name = $hash->{NAME}; - my $sP = "stylesheetPrefix"; - my $retMsg; - - if($a[0] eq "set" && $a[2] eq "HTTPS") { - TcpServer_SetSSL($hash); - } - - if($a[0] eq "set") { # Converting styles - if($a[2] eq "smallscreen" || $a[2] eq "touchpad") { - $attr{$name}{$sP} = $a[2]; - $retMsg="$name: attribute $a[2] deprecated, converted to $sP"; - $a[3] = $a[2]; $a[2] = $sP; - } - } - if($a[2] eq $sP) { - # AttrFn is called too early, we have to set/del the attr here - if($a[0] eq "set") { - $attr{$name}{$sP} = (defined($a[3]) ? $a[3] : "default"); - FW_readIcons($attr{$name}{$sP}); - } else { - delete $attr{$name}{$sP}; - } - } - - if($a[2] eq "iconPath" && $a[0] eq "set") { - foreach my $pe (split(":", $a[3])) { - $pe =~ s+\.\.++g; - FW_readIcons($pe); - } - } - - return $retMsg; -} - - -# recursion starts at $FW_icondir/$dir -# filenames are relative to $FW_icondir -sub -FW_readIconsFrom($$) -{ - my ($dir,$subdir)= @_; - - my $ldir = ($subdir ? "$dir/$subdir" : $dir); - my @entries; - if(opendir(DH, "$FW_icondir/$ldir")) { - @entries= sort readdir(DH); # assures order: .gif .ico .jpg .png .svg - closedir(DH); - } - - foreach my $entry (@entries) { - if( -d "$FW_icondir/$ldir/$entry" ) { # directory -> recurse - FW_readIconsFrom($dir, $subdir ? "$subdir/$entry" : $entry) - unless($entry eq "." || $entry eq ".." || $entry eq ".svn"); - - } else { - if($entry =~ m/^iconalias.txt$/i && open(FH, "$FW_icondir/$ldir/$entry")){ - while(my $l = ) { - chomp($l); - my @a = split(" ", $l); - next if($l =~ m/^#/ || @a < 2); - $FW_icons{$dir}{$a[0]} = $a[1]; - } - close(FH); - } elsif($entry =~ m/(gif|ico|jpg|png|jpeg|svg)$/i) { - my $filename = $subdir ? "$subdir/$entry" : $entry; - $FW_icons{$dir}{$filename} = $filename; - - my $tag = $filename; # Add it without extension too - $tag =~ s/\.[^.]*$//; - $FW_icons{$dir}{$tag} = $filename; - } - } - } - $FW_icons{$dir}{""} = 1; # Do not check empty directories again. -} - -sub -FW_readIcons($) -{ - my ($dir)= @_; - return if($FW_icons{$dir}); - FW_readIconsFrom($dir, ""); -} - - -# check if the icon exists, and if yes, returns its "logical" name; -sub -FW_iconName($) -{ - my ($name)= @_; - $name =~ s/@.*//; - foreach my $pe (@FW_iconDirs) { - return $name if($pe && $FW_icons{$pe} && $FW_icons{$pe}{$name}); - } - return undef; -} - -# returns the physical absolute path relative for the logical path -# examples: -# FS20.on -> dark/FS20.on.png -# weather/sunny -> default/weather/sunny.gif -sub -FW_iconPath($) -{ - my ($name) = @_; - $name =~ s/@.*//; - foreach my $pe (@FW_iconDirs) { - return "$pe/$FW_icons{$pe}{$name}" - if($pe && $FW_icons{$pe} && $FW_icons{$pe}{$name}); - } - return undef; -} - -sub -FW_dev2image($;$) -{ - my ($name, $state) = @_; - my $d = $defs{$name}; - return "" if(!$name || !$d); - - my $type = $d->{TYPE}; - $state = $d->{STATE} if(!defined($state)); - return "" if(!$type || !defined($state)); - - my $model = $attr{$name}{model} if(defined($attr{$name}{model})); - - my (undef, $rstate) = ReplaceEventMap($name, [undef, $state], 0); - - my ($icon, $rlink); - my $devStateIcon = AttrVal($name, "devStateIcon", undef); - if(defined($devStateIcon) && $devStateIcon =~ m/^{.*}$/) { - my ($html, $link) = eval $devStateIcon; - Log3 $FW_wname, 1, "devStateIcon $name: $@" if($@); - return ($html, $link, 1) if(defined($html) && $html =~ m/^<.*>$/s); - $devStateIcon = $html; - } - - if(defined($devStateIcon)) { - my @list = split(" ", $devStateIcon); - foreach my $l (@list) { - my ($re, $iconName, $link) = split(":", $l, 3); - if(defined($re) && $state =~ m/^$re$/) { - if($iconName eq "") { - $rlink = $link; - last; - } - if(defined(FW_iconName($iconName))) { - return ($iconName, $link, 0); - } else { - return ($state, $link, 1); - } - } - } - } - - $state =~ s/ .*//; # Want to be able to have icons for "on-for-timer xxx" - - $icon = FW_iconName("$name.$state") if(!$icon); # lamp.Aus.png - $icon = FW_iconName("$name.$rstate") if(!$icon); # lamp.on.png - $icon = FW_iconName($name) if(!$icon); # lamp.png - $icon = FW_iconName("$model.$state") if(!$icon && $model); # fs20st.off.png - $icon = FW_iconName($model) if(!$icon && $model); # fs20st.png - $icon = FW_iconName("$type.$state") if(!$icon); # FS20.Aus.png - $icon = FW_iconName("$type.$rstate") if(!$icon); # FS20.on.png - $icon = FW_iconName($type) if(!$icon); # FS20.png - $icon = FW_iconName($state) if(!$icon); # Aus.png - $icon = FW_iconName($rstate) if(!$icon); # on.png - return ($icon, $rlink, 0); -} - -sub -FW_makeEdit($$$) -{ - my ($name, $n, $val) = @_; - - # Toggle Edit-Window visibility script. - my $pgm = "Javascript:" . - "s=document.getElementById('edit').style;". - "s.display = s.display=='none' ? 'block' : 'none';". - "s=document.getElementById('disp').style;". - "s.display = s.display=='none' ? 'block' : 'none';"; - $pgm .= "s=document.getElementById('editarea');". - "s.editor ? s.editor: s.editor = CodeMirror.fromTextArea(s,". FW_codemirrorParams("pm") .");" - if AttrVal($FW_wname,'enhancedEditor',0); - - FW_pO ""; - FW_pO "$n"; - FW_pO ""; - - $val =~ s,\\\n,\n,g; - my $eval = $val; - $eval = "
$eval
" if($eval =~ m/\n/); - FW_pO ""; - FW_pO "
$eval
"; - FW_pO ""; - - FW_pO ""; - FW_pO "
"; - FW_pO "
"; - FW_pO FW_hidden("detail", $name); - my $cmd = "modify"; - my $ncols = $FW_ss ? 30 : 60; - FW_pO ""; - FW_pO "
" . FW_submit("cmd.${cmd}$name", "$cmd $name"); - FW_pO "
"; - FW_codemirrorLink("pm") if( AttrVal($FW_wname,'enhancedEditor',0) ); - FW_pO ""; -} - - -sub -FW_roomStatesForInform($) -{ - my ($me) = @_; - return "" if($me->{inform}{type} !~ m/status/); - - my %extPage = (); - my @data; - foreach my $dn (keys %{$me->{inform}{devices}}) { - next if(!defined($defs{$dn})); - my $t = $defs{$dn}{TYPE}; - next if(!$t || $modules{$t}{FW_atPageEnd}); - my ($allSet, $cmdlist, $txt) = FW_devState($dn, "", \%extPage); - if($defs{$dn} && $defs{$dn}{STATE} && $defs{$dn}{TYPE} ne "weblink") { - push @data, "$dn<<$defs{$dn}{STATE}<<$txt"; - } - } - my $data = join("\n", map { s/\n/ /gm; $_ } @data)."\n"; - return $data; -} - -sub -FW_Notify($$) -{ - my ($ntfy, $dev) = @_; - - my $h = $ntfy->{inform}; - return undef if(!$h); - - my $dn = $dev->{NAME}; - return undef if(!$h->{devices}{$dn}); - - my @data; - my %extPage; - - if($h->{type} =~ m/status/) { - # Why is saving this stuff needed? FLOORPLAN? - my @old = ($FW_wname, $FW_ME, $FW_ss, $FW_tp, $FW_subdir); - $FW_wname = $ntfy->{SNAME}; - $FW_ME = "/" . AttrVal($FW_wname, "webname", "fhem"); - $FW_subdir = ""; - $FW_sp = AttrVal($FW_wname, "stylesheetPrefix", 0); - $FW_ss = ($FW_sp =~ m/smallscreen/); - $FW_tp = ($FW_sp =~ m/smallscreen|touchpad/); - @FW_iconDirs = grep { $_ } split(":", AttrVal($FW_wname, "iconPath", - "$FW_sp:default:fhemSVG:openautomation")); - if($h->{iconPath}) { - unshift @FW_iconDirs, $h->{iconPath}; - FW_readIcons($h->{iconPath}); - } - - my ($allSet, $cmdlist, $txt) = FW_devState($dn, "", \%extPage); - ($FW_wname, $FW_ME, $FW_ss, $FW_tp, $FW_subdir) = @old; - push @data, "$dn<<$dev->{STATE}<<$txt"; - - #Add READINGS - if($dev->{CHANGED}) { # It gets deleted sometimes (?) - my $tn = TimeNow(); - my $max = int(@{$dev->{CHANGED}}); - for(my $i = 0; $i < $max; $i++) { - if( $dev->{CHANGED}[$i] !~ /: /) { - next; #ignore 'set' commands - } - my ($readingName,$readingVal) = split(": ",$dev->{CHANGED}[$i],2); - push @data, "$dn-$readingName<<$readingVal<<$readingVal"; - push @data, "$dn-$readingName-ts<<$tn<<$tn"; - } - } - } - - if($h->{type} =~ m/raw/) { - if($dev->{CHANGED}) { # It gets deleted sometimes (?) - my $tn = TimeNow(); - if($attr{global}{mseclog}) { - my ($seconds, $microseconds) = gettimeofday(); - $tn .= sprintf(".%03d", $microseconds/1000); - } - my $max = int(@{$dev->{CHANGED}}); - my $dt = $dev->{TYPE}; - for(my $i = 0; $i < $max; $i++) { - push @data,("$tn $dt $dn ".$dev->{CHANGED}[$i]."
"); - } - } - } - - addToWritebuffer($ntfy, join("\n", map { s/\n/ /gm; $_ } @data)."\n") - if(@data); - return undef; -} - -################### -# Compute the state (==second) column -sub -FW_devState($$@) -{ - my ($d, $rf, $extPage) = @_; - - my ($hasOnOff, $link); - - my $cmdList = AttrVal($d, "webCmd", ""); - my $allSets = getAllSets($d); - my $state = $defs{$d}{STATE}; - $state = "" if(!defined($state)); - - $hasOnOff = ($allSets =~ m/(^| )on(:[^ ]*)?( |$)/ && - $allSets =~ m/(^| )off(:[^ ]*)?( |$)/); - my $txt = $state; - my $dsi = AttrVal($d, "devStateIcon", undef); - - if(defined(AttrVal($d, "showtime", undef))) { - my $v = $defs{$d}{READINGS}{state}{TIME}; - $txt = $v if(defined($v)); - - } elsif(!$dsi && $allSets =~ m/\bdesired-temp:/) { - $txt = "$1 °C" if($txt =~ m/^measured-temp: (.*)/); # FHT fix - $cmdList = "desired-temp" if(!$cmdList); - - } elsif(!$dsi && $allSets =~ m/\bdesiredTemperature:/) { - $txt = ReadingsVal($d, "temperature", ""); # ignores stateFormat!!! - $txt =~ s/ .*//; - $txt .= "°C"; - $cmdList = "desiredTemperature" if(!$cmdList); - - } else { - my ($icon, $isHtml); - ($icon, $link, $isHtml) = FW_dev2image($d); - $txt = ($isHtml ? $icon : FW_makeImage($icon, $state)) if($icon); - $link = "cmd.$d=set $d $link" if($link); - - } - - - if($hasOnOff) { - # Have to cover: "on:An off:Aus", "A0:Aus AI:An Aus:off An:on" - my $on = ReplaceEventMap($d, "on", 1); - my $off = ReplaceEventMap($d, "off", 1); - $link = "cmd.$d=set $d " . ($state eq $on ? $off : $on) if(!$link); - $cmdList = "$on:$off" if(!$cmdList); - - } - - if($link) { # Have command to execute - my $room = AttrVal($d, "room", undef); - if($room) { - if($FW_room && $room =~ m/\b$FW_room\b/) { - $room = $FW_room; - } else { - $room =~ s/,.*//; - } - $link .= "&room=$room"; - } - if(AttrVal($FW_wname, "longpoll", 1)) { - $txt = "$txt"; - - } elsif($FW_ss || $FW_tp) { - $txt ="$txt"; - - } else { - $txt = "$txt"; - - } - } - - my $style = AttrVal($d, "devStateStyle", ""); - $txt = "
$txt
"; - - my $type = $defs{$d}{TYPE}; - my $sfn = $modules{$type}{FW_summaryFn}; - if($sfn) { - if(!defined($extPage)) { - my %hash; - $extPage = \%hash; - } - no strict "refs"; - my $newtxt = &{$sfn}($FW_wname, $d, $FW_room, $extPage); - use strict "refs"; - $txt = $newtxt if(defined($newtxt)); # As specified - } - - return ($allSets, $cmdList, $txt); -} - - -sub -FW_Get($@) -{ - my ($hash, @a) = @_; - $FW_wname= $hash->{NAME}; - - my $arg = (defined($a[1]) ? $a[1] : ""); - if($arg eq "icon") { - return "need one icon as argument" if(int(@a) != 3); - my $icon = FW_iconPath($a[2]); - return defined($icon) ? "$FW_icondir/$icon" : "no such icon"; - - } elsif($arg eq "pathlist") { - return "web server root: $FW_dir\n". - "icon directory: $FW_icondir\n". - "css directory: $FW_cssdir\n". - "gplot directory: $FW_gplotdir"; - - } else { - return "Unknown argument $arg choose one of icon pathlist:noArg"; - - } -} - - -##################################### -sub -FW_Set($@) -{ - my ($hash, @a) = @_; - my %cmd = ("rereadicons" => 1, "clearSvgCache" => 1); - - return "no set value specified" if(@a < 2); - return ("Unknown argument $a[1], choose one of ". - join(" ", map { "$_:noArg" } sort keys %cmd)) - if(!$cmd{$a[1]}); - - if($a[1] eq "rereadicons") { - my @dirs = keys %FW_icons; - %FW_icons = (); - foreach my $d (@dirs) { - FW_readIcons($d); - } - } - if($a[1] eq "clearSvgCache") { - my $cDir = "$FW_dir/SVGcache"; - if(opendir(DH, $cDir)) { - map { my $n="$cDir/$_"; unlink($n) if(-f $n); } readdir(DH);; - closedir(DH); - } else { - return "Can't open $cDir: $!"; - } - } - return undef; -} - -##################################### -sub -FW_closeOldClients() -{ - my $now = time(); - foreach my $dev (keys %defs) { - next if(!$defs{$dev}{TYPE} || $defs{$dev}{TYPE} ne "FHEMWEB" || - !$defs{$dev}{LASTACCESS} || $defs{$dev}{inform} || - ($now - $defs{$dev}{LASTACCESS}) < 60); - Log3 $FW_wname, 4, "Closing connection $dev"; - FW_Undef($defs{$dev}, ""); - delete $defs{$dev}; - } - InternalTimer($now+60, "FW_closeOldClients", 0, 0); -} - -sub -FW_htmlEscape($) -{ - my ($txt) = @_; - $txt =~ s//>/g; - return $txt; -} - -########################### -# Widgets START -sub -FW_sliderFn($$$$$) -{ - my ($FW_wname, $d, $FW_room, $cmd, $values) = @_; - - return undef if($values !~ m/^slider,(.*),(.*),(.*)$/); - return "" if($cmd =~ m/ /); # webCmd pct 30 should generate a link - my ($min,$stp, $max) = ($1, $2, $3); - my $srf = $FW_room ? "&room=$FW_room" : ""; - my $cv = ReadingsVal($d, $cmd, Value($d)); - my $id = ($cmd eq "state") ? "" : "-$cmd"; - $cmd = "" if($cmd eq "state"); - $cv =~ s/.*?([.\-\d]+).*/$1/; # get first number - $cv = 0 if($cv !~ m/\d/); - return "". - "
". - "
$min
". - "
". - "". - ""; -} - -sub -FW_noArgFn($$$$$) -{ - my ($FW_wname, $d, $FW_room, $cmd, $values) = @_; - - return undef if($values !~ m/^noArg$/); - return ""; -} - -sub -FW_timepickerFn() -{ - my ($FW_wname, $d, $FW_room, $cmd, $values) = @_; - - return undef if($values ne "time"); - return "" if($cmd =~ m/ /); # webCmd on-for-timer 30 should generate a link - my $srf = $FW_room ? "&room=$FW_room" : ""; - my $cv = ReadingsVal($d, $cmd, Value($d)); - $cmd = "" if($cmd eq "state"); - my $c = "\"$FW_ME?cmd=set $d $cmd %$srf\""; - return "". - "". - "". - ""; -} - -sub -FW_dropdownFn() -{ - my ($FW_wname, $d, $FW_room, $cmd, $values) = @_; - - return "" if($cmd =~ m/ /); # webCmd temp 30 should generate a link - my @tv = split(",", $values); - # Hack: eventmap (translation only) should not result in a - # dropdown. eventMap/webCmd/etc handling must be cleaned up. - if(@tv > 1) { - my $txt; - if($cmd eq "desired-temp" || $cmd eq "desiredTemperature") { - $txt = ReadingsVal($d, $cmd, 20); - $txt =~ s/ .*//; # Cut off Celsius - $txt = sprintf("%2.1f", int(2*$txt)/2) if($txt =~ m/[0-9.-]/); - } else { - $txt = ReadingsVal($d, $cmd, Value($d)); - $txt =~ s/$cmd //; - } - - my $fpname = $FW_wname; - $fpname =~ s/.*floorplan\/(\w+)$/$1/; #allow usage of attr fp_setbutton - my $fwsel; - $fwsel = ($cmd eq "state" ? "" : "$cmd ") . - FW_select("$d-$cmd","val.$d", \@tv, $txt,"dropdown","submit()"). - FW_hidden("cmd.$d", "set"); - - return "
". - FW_hidden("arg.$d", $cmd) . - FW_hidden("dev.$d", $d) . - ($FW_room ? FW_hidden("room", $FW_room) : "") . - "$fwsel
"; - } - return undef; -} - -sub -FW_textFieldFn($$$$) -{ - my ($FW_wname, $d, $FW_room, $cmd, $values) = @_; - - my @args = split("[ \t]+", $cmd); - - return undef if($values !~ m/^textField$/); - return "" if($cmd =~ m/ /); - my $srf = $FW_room ? "&room=$FW_room" : ""; - my $cv = ReadingsVal($d, $cmd, ""); - my $id = ($cmd eq "state") ? "" : "-$cmd"; - - my $c = "$FW_ME?XHR=1&cmd=setreading $d $cmd %$srf"; - return ''. - "
$cmd:
". - ''; -} - -# Widgets END -########################### - -sub -FW_visibleDevices(;$) -{ - my($FW_wname) = @_; - - my %devices = (); - foreach my $d (sort keys %defs) { - next if(!defined($defs{$d})); - my $h = $defs{$d}; - next if(!$h->{TEMPORARY}); - next if($h->{TYPE} ne "FHEMWEB"); - next if(defined($FW_wname) && $h->{SNAME} ne $FW_wname); - - next if(!defined($h->{inform})); - - @devices{ keys %{$h->{inform}->{devices}} } = - values %{$h->{inform}->{devices}}; - } - return %devices; -} - -sub -FW_ActivateInform() -{ - $FW_activateInform = 1; -} - -my %codemirrorMapping = ( pm => "fhem", - cfg => "fhem", - layout => "fhem", - css => "css", - svg => "xml", -); - -sub FW_codemirrorLink($) -{ - my ($ext) = @_; - - my $lang = $codemirrorMapping{$ext}; - my $theme = AttrVal($FW_wname,'enhancedEditorTheme','blackboard'); - - $lang = "perl" if( !$lang ); - - FW_pO ""; - FW_pO ""; - FW_pO ""; - FW_pO ""; - FW_pO ""; - FW_pO ""; - FW_pO ""; - FW_pO ""; - FW_pO "" if( $lang ); - return; -} - -sub FW_codemirrorParams($) -{ - my ($ext) = @_; - - my $theme = AttrVal($FW_wname,'enhancedEditorTheme','blackboard'); - return "{theme: '". $theme. "', lineNumbers: true, matchBrackets: true, autoCloseBrackets: true, ". - "extraKeys: {'Ctrl-Space': 'autocomplete'} }"; -} - -1; - -=pod -=begin html - - -

FHEMWEB

-
    - FHEMWEB is the builtin web-frontend, it also implements a simple web - server (optionally with Basic-Auth and HTTPS). -

    - - - Define -
      - define <name> FHEMWEB <tcp-portnr> [global] -

      - Enable the webfrontend on port <tcp-portnr>. If global is specified, - then requests from all interfaces (not only localhost / 127.0.0.1) are - serviced.
      - To enable listening on IPV6 see the comments here. -
      -
    -
    - - - Set -
      -
    • rereadicons
      - reads the names of the icons from the icon path. Use after adding or - deleting icons. -
    • -
    • clearSvgCache
      - delete all files found in the www/SVGcache directory, which is used to - cache SVG data, if the SVGcache attribute is set. -
    • -
    -
    - - - Get -
      -
    • icon <logical icon>
      - returns the absolute path to the logical icon. Example: -
        - get myFHEMWEB icon FS20.on
        - /data/Homeautomation/fhem/FHEM/FS20.on.png -
        -
      -
    • -
    • pathlist
      - return FHEMWEB specific directories, where files for given types are - located -

      - -
    - - - Attributes -
      - -
    • webname
      - Path after the http://hostname:port/ specification. Defaults to fhem, - i.e the default http address is http://localhost:8083/fhem -

    • - - -
    • refresh
      - If set, a http-equiv="refresh" entry will be genererated with the given - argument (i.e. the browser will reload the page after the given - seconds). -

    • - - -
    • plotmode
      - Specifies how to generate the plots: -
        -
      • SVG
        - The plots are created with the SVG module. - This is the default.
      • - -
      • gnuplot
        - The plots are created with the gnuplot program. Note: this mode - ist only available due to historic reasons.
      • - -
      • gnuplot-scroll
        - Like the gnuplot-mode, but scrolling to historical values is alos - possible, just like with SVG.
      • -
      -

    • - - -
    • plotsize
      - the default size of the plot, in pixels, separated by comma: - width,height. You can set individual sizes by setting the plotsize of - the SVG. Default is 800,160 for desktop, and 480,160 for - smallscreen. -

    • - - -
    • nrAxis
      - the number of axis for which space should be reserved on the left and - right sides of a plot and optionaly how many axes should realy be used - on each side, separated by comma: left,right[,useLeft,useRight]. You - can set individual numbers by setting the nrAxis of the SVG. Default is - 1,1. -

    • - - -
    • SVGcache
      - if set, cache plots which won't change any more (the end-date is prior - to the current timestamp). The files are written to the www/SVGcache - directory. Default is off.
      - See also the clearSvgCache command for clearing the cache. -

    • - - -
    • endPlotToday
      - If this FHEMWEB attribute is set to 1, then week and month plots will - end today. Else the current week (starting at Sunday) or the current - month will be shown.
      -

    • - - -
    • endPlotNow
      - If this FHEMWEB attribute is set to 1, then day and hour plots will - end at current time. Else the whole day, the 6 hour period starting at - 0, 6, 12 or 18 hour or the whole hour will be shown. This attribute - is not used if the SVG has the attribute startDate defined.
      -

    • - - -
    • ploteditor
      - Configures if the Plot editor should be shown - in the SVG detail view. - Can be set to always, onClick or never. Default is always. -

    • - - -
    • plotfork
      - If set, generate the logs in a parallel process. Note: do not use it - on Windows and on systems with small memory foorprint. -

    • - - -
    • basicAuth, basicAuthMsg
      - request a username/password authentication for access. You have to set - the basicAuth attribute to the Base64 encoded value of - <user>:<password>, e.g.:
        - # Calculate first the encoded string with the commandline program
        - $ echo -n fhemuser:secret | base64
        - ZmhlbXVzZXI6c2VjcmV0
        - fhem.cfg:
        - attr WEB basicAuth ZmhlbXVzZXI6c2VjcmV0 -
      - You can of course use other means of base64 encoding, e.g. online - Base64 encoders. If basicAuthMsg is set, it will be displayed in the - popup window when requesting the username/password.
      -
      - If the argument of basicAuth is enclosed in {}, then it will be - evaluated, and the $user and $password variable will be set to the - values entered. If the return value is true, then the password will be - accepted. - Example:
      - - attr WEB basicAuth { "$user:$password" eq "admin:secret" }
      -
      -

    • - - -
    • HTTPS
      - Enable HTTPS connections. This feature requires the perl module - IO::Socket::SSL, to be installed with cpan -i IO::Socket::SSL or - apt-get install libio-socket-ssl-perl; OSX and the FritzBox-7390 - already have this module.
      - - A local certificate has to be generated into a directory called certs, - this directory must be in the modpath - directory, at the same level as the FHEM directory. -
        - mkdir certs
        - cd certs
        - openssl req -new -x509 -nodes -out server-cert.pem -days 3650 -keyout server-key.pem -
      -
      -
    • - - -
    • allowedCommands
      - A comma separated list of commands allowed from this FHEMWEB - instance.
      If set to an empty list , (i.e. comma only) - then this FHEMWEB instance will be read-only.
      If set to - get,set, then this FHEMWEB instance will only allow - regular usage of the frontend by clicking the icons/buttons/sliders but - not changing any configuration.
      - - - This attribute intended to be used together with hiddenroom/hiddengroup -
      - - Note:allowedCommands should work as intended, but no guarantee - can be given that there is no way to circumvent it. If a command is - allowed it can be issued by URL manipulation also for devices that are - hidden.

    • - -
    • allowfrom
    • -
      - - -
    • stylesheetPrefix
      - prefix for the files style.css, svg_style.css and svg_defs.svg. If the - file with the prefix is missing, the default file (without prefix) will - be used. These files have to be placed into the FHEM directory, and can - be selected directly from the "Select style" FHEMWEB menu entry. Example: -
        - attr WEB stylesheetPrefix dark
        -
        - Referenced files:
        -
          - darksvg_defs.svg
          - darksvg_style.css
          - darkstyle.css
          -
        -
        -
      - Note:if the argument contains the string smallscreen or touchpad, - then FHEMWEB will optimize the layout/access for small screen size (i.e. - smartphones) or touchpad devices (i.e. tablets)
      - - The default configuration installs 3 FHEMWEB instances: port 8083 for - desktop browsers, port 8084 for smallscreen, and 8085 for touchpad.
      - - If touchpad or smallscreen is specified, then WebApp support is - activated: After viewing the site on the iPhone or iPad in Safari, you - can add a link to the home-screen to get full-screen support. Links are - rendered differently in this mode to avoid switching back to the "normal" - browser. -
    • -
      - - -
    • iconPath
      - colon separated list of directories where the icons are read from. - The directories start in the fhem/www/images directory. The default is - $styleSheetPrefix:default:fhemSVG:openautomation
      - Set it to fhemSVG:openautomation to get only SVG images. -
    • -
      - - -
    • hiddenroom
      - Comma separated list of rooms to "hide", i.e. not to show. Special - values are input, detail and save, in which case the input areas, link - to the detailed views or save button is hidden (although each aspect - still can be addressed through URL manipulation).
      - The list can also contain values from the additional "Howto/Wiki/FAQ" - block. -
    • -
      - - -
    • hiddengroup
      - Comma separated list of groups to "hide", i.e. not to show in any room - of this FHEMWEB instance.
      - Example: attr WEBtablet hiddengroup FileLog,dummy,at,notify -
    • -
      - - -
    • menuEntries
      - Comma separated list of name,html-link pairs to display in the - left-side list. Example:
      - attr WEB menuEntries fhem.de,http://fhem.de,culfw.de,http://culfw.de
      - attr WEB menuEntries AlarmOn,http://fhemhost:8083/fhem?cmd=set%20alarm%20on
      -
    • -
      - - -
    • longpoll
      - Affects devices states in the room overview only.
      - In this mode status update is refreshed more or less instantaneously, - and state change (on/off only) is done without requesting a complete - refresh from the server. - Default is on. -
    • -
      - - -
    • longpollSVG
      - Reloads an SVG weblink, if an event should modify its content. Since - an exact determination of the affected events is too complicated, we - need some help from the #FileLog definition in the .gplot file: the - filter used there (second parameter) must either contain only the - deviceName or have the form deviceName.event or deviceName.*. This is - always the case when using the Plot - editor. The SVG will be reloaded for any event triggered by - this deviceName. - Default is off. -
    • -
      - - - -
    • redirectCmds
      - Clear the browser URL window after issuing the command by redirecting - the browser, as a reload for the same site might have unintended - side-effects. Default is 1 (enabled). Disable it by setting this - attribute to 0 if you want to study the command syntax, in order to - communicate with FHEMWEB. -
    • -
      - - -
    • fwcompress
      - Enable compressing the HTML data (default is 1, i.e. yes, use 0 to switch it off). -
    • -
      - - -
    • reverseLogs
      - Display the lines from the logfile in a reversed order, newest on the - top, so that you dont have to scroll down to look at the latest entries. - Note: enabling this attribute will prevent FHEMWEB from streaming - logfiles, resulting in a considerably increased memory consumption - (about 6 times the size of the file on the disk). -
    • -
      - - -
    • CORS
      - If set to 1, FHEMWEB will supply a "Cross origin resource sharing" - header, see the wikipedia for details. -
    • -
      - - -
    • icon
      - Set the icon for a device in the room overview. There is an - icon-chooser in FHEMWEB to ease this task. Setting icons for the room - itself is indirect: there must exist an icon with the name - ico.png in the iconPath. -
    • -
      - - -
    • roomIcons
      - Space separated list of room:icon pairs, to override the default - behaviour of showing an icon, if there is one with the name of - "icoRoomName". This is the correct way to remove the icon for the room - Everything, or to set one for rooms with / in the name (e.g. - Anlagen/EDV). The first part is treated as regexp, so space is - represented by a dot. Example:
      - attr WEB roomIcons Anlagen.EDV:icoEverything -
    • -
      - - -
    • sortRooms
      - Space separated list of rooms to override the default - sort order of the room links. Example:
      - attr WEB sortRooms DG OG EG Keller -
    • -
      - - -
    • defaultRoom
      - show the specified room if no room selected, e.g. on execution of some - commands. If set hides the motd. Example:
      - attr WEB defaultRoom Zentrale -
    • -
      - - -
    • sortby
      - Take the value of this attribute when sorting the devices in the room - overview instead of the alias, or if that is missing the devicename - itself. -
    • -
      - - -
    • devStateIcon
      - First form:
      -
        - Space separated list of regexp:icon-name:cmd triples, icon-name and cmd - may be empty.
        - If the state of the device matches regexp, then icon-name will be - displayed as the status icon in the room, and (if specified) clicking - on the icon executes cmd. If fhem cannot find icon-name, then the - status text will be displayed. - Example:
        -
          - attr lamp devStateIcon on:closed off:open
          - attr lamp devStateIcon on::A0 off::AI
          - attr lamp devStateIcon .*:noIcon
          -
        - Note: if the image is referencing an SVG icon, then you can use the - @colorname suffix to color the image. E.g.:
        -
          - attr Fax devStateIcon on:control_building_empty@red off:control_building_filled:278727 -
        - -
      - Second form:
      -
        - Perl regexp enclosed in {}. If the code returns undef, then the default - icon is used, if it retuns a string enclosed in <>, then it is - interpreted as an html string. Else the string is interpreted as a - devStateIcon of the first fom, see above. - Example:
        - {'<div style="width:32px;height:32px;background-color:green"></div>'} -
      -
    • -
      - - -
    • devStateStyle
      - Specify an HTML style for the given device, e.g.:
      -
        - attr sensor devStateStyle style="text-align:left;;font-weight:bold;;"
        -
      -
    • -
      - - -
    • webCmd
      - Colon separated list of commands to be shown in the room overview for a - certain device. Has no effect on smallscreen devices, see the - devStateIcon command for an alternative.
      - Example: -
        - attr lamp webCmd on:off:on-for-timer 10
        -
      -
      - - The first specified command is looked up in the "set device ?" list - (see the setList attribute for dummy devices). - If there it contains some known modifiers (colon, followed - by a comma separated list), then a different widget will be displayed: -
        -
      • if the modifier is ":noArg", then no further input field is - displayed
      • -
      • if the modifier is ":time", then a javascript driven timepicker is - displayed.
      • -
      • if the modifier is ":textField", an input field is displayed.
      • -
      • if the modifier is of the form - ":slider,<min>,<step>,<max>", then a javascript - driven slider is displayed
      • -
      • if the modifier is of the form ":multiple,val1,val2,...", then - multiple values can be selected, the result is comma separated.
      • -
      • else a dropdown with all the modifier values is displayed
      • -
      - If the command is state, then the value will be used as a command.
      - Examples for the modifier: -
        - define d1 dummy
        - attr d1 webCmd state
        - attr d1 setList state:on,off
        - define d2 dummy
        - attr d2 webCmd state
        - attr d2 setList state:slider,0,1,10
        - define d3 dummy
        - attr d3 webCmd state
        - attr d3 setList state:time
        -
      - Note: this is an attribute for the displayed device, not for the FHEMWEB - instance. -
    • -
      - - -
    • column
      - Allows to display more than one column per room overview, by specifying - the groups for the columns. Example:
      -
        - attr WEB column LivingRoom:FS20,notify|FHZ,notify DiningRoom:FS20|FHZ -
      - In this example in the LivingRoom the FS20 and the notify group is in - the first column, the FHZ and the notify in the second.
      - Note: some elements like SVG plots and readingsGroup can only be part of - a column if they are part of a group. -
    • -
      - -
    • enhancedEditor
      - Activates enhanced editor codemirror to edit files and DEFs. Example:
      -
      -
        attr WEB enhancedEditor <1|0>
      -
      - Set to 1 to activate, 0 to deactivate the enhanced editor.
      - Defaults to 0 if not set and internal editing will be used.
      -
    • -
      - -
    • enhancedEditorTheme
      - Select theme to be used in enhanced editor. Example:
      -
      -
        attr WEB enhancedEditorTheme blackboard
      -
      - Default theme is "blackboard".
      - Check directory ./www/codemirror/theme for available themes.
      -
    • -
    -
    - - Enhanced editor codemirror -
      -
      - Enhanced editor codemirror can be used for editing files and DEFs in fhem frontend.
      - Includes: syntax highlighting, bracket control, auto-complete and much more.
      - See codemirror website for more informations about editor's functionality and features.
      -
    -
- -=end html - -=begin html_DE - - -

FHEMWEB

-
    - FHEMWEB ist das default WEB-Frontend, es implementiert auch einen einfachen - Webserver (optional mit Basic-Auth und HTTPS). -

    - - - Define -
      - define <name> FHEMWEB <tcp-portnr> [global] -

      - Aktiviert das Webfrontend auf dem Port <tcp-portnr>. Mit dem - Parameter global werden Anfragen von allen Netzwerkschnittstellen - akzeptiert (nicht nur vom localhost / 127.0.0.1) .
      - - Informationen für den Betrieb mit IPv6 finden Sie hier.
      -
    -
    - - - Set -
      -
    • rereadicons
      - Damit wird die Liste der Icons neu eingelesen, für den Fall, dass - Sie Icons löschen oder hinzufügen. -
    • -
    • clearSvgCache
      - Im Verzeichnis www/SVGcache werden SVG Daten zwischengespeichert, wenn - das Attribut SVGcache gesetzt ist. Mit diesem Befehl leeren Sie diesen - Zwischenspeicher. -
    • -
    -
    - - - Get -
      -
    • icon <logical icon>
      - Liefert den absoluten Pfad des (logischen) Icons zurück. Beispiel: -
        - get myFHEMWEB icon FS20.on
        - /data/Homeautomation/fhem/FHEM/FS20.on.png -
        -
    • -
    • pathlist
      - Zeigt diejenigen Verzeichnisse an, in welchen die verschiedenen Dateien - für FHEMWEB liegen. -
    • -

      - -
    - - - Attributes -
      - -
    • webname
      - Der Pfad nach http://hostname:port/ . Standard ist fhem, - so ist die Standard HTTP Adresse http://localhost:8083/fhem -

    • - - -
    • refresh
      - Damit erzeugen Sie auf den ausgegebenen Webseiten einen automatischen - Refresh, z.B. nach 5 Sekunden. -

    • - - -
    • plotmode
      - Spezifiziert, wie Plots erzeugt werden sollen: -
        -
      • SVG
        - Die Plots werden mit Hilfe des SVG Moduls als SVG - Grafik gerendert. Das ist die Standardeinstellung.
      • - -
      • gnuplot
        - Die Plots werden mit Hilfe des gnuplot Programmes erzeugt. Diese - Option ist aus historischen Gründen vorhanden. -
      • - -
      • gnuplot-scroll
        - Wie gnuplot, der einfache Zugriff auf historische Daten ist aber - genauso möglich wie mit dem SVG Modul.
      • - -
      -

    • - - -
    • plotsize
      - gibt die Standardbildgröße aller erzeugten Plots an als - Breite,Höhe an. Um einem individuellen Plot die Größe zu - ändern muss dieses Attribut bei der entsprechenden SVG Instanz - gesetzt werden. Default sind 800,160 für Desktop und 480,160 - für Smallscreen -

    • - - -
    • nrAxis
      - (bei mehrfach-Y-Achsen im SVG-Plot) Die Darstellung der Y Achsen - benötigt Platz. Hierdurch geben Sie an wie viele Achsen Sie - links,rechts [useLeft,useRight] benötigen. Default ist 1,1 (also 1 - Achse links, 1 Achse rechts). -

    • - - -
    • SVGcache
      - Plots die sich nicht mehr ändern, werden im SVGCache Verzeichnis - (www/SVGcache) gespeichert, um die erneute, rechenintensive - Berechnung der Grafiken zu vermeiden. Default ist 0, d.h. aus.
      - Siehe den clearSvgCache Befehl um diese Daten zu löschen. -

    • - - -
    • endPlotToday
      - Wird dieses FHEMWEB Attribut gesetzt, so enden Wochen- bzw. Monatsplots - am aktuellen Tag, sonst wird die aktuelle Woche/Monat angezeigt. -

    • - - -
    • endPlotNow
      - Wenn Sie dieses FHEMWEB Attribut auf 1 setzen, werden Tages und - Stunden-Plots zur aktuellen Zeit beendet. (Ähnlich wie - endPlotToday, nur eben minütlich). - Ansonsten wird der gesamte Tag oder eine 6 Stunden Periode (0, 6, 12, - 18 Stunde) gezeigt. Dieses Attribut wird nicht verwendet, wenn das SVG - Attribut startDate benutzt wird.
      -

    • - - -
    • ploteditor
      - Gibt an ob der Plot Editor in der SVG detail - ansicht angezeigt werden soll. Kann auf always, onClick oder never - gesetzt werden. Der Default ist always. -

    • - - -
    • plotfork
      - Normalerweise wird die Ploterstellung im Hauptprozess ausgeführt, - FHEM wird wärend dieser Zeit nicht auf andere Ereignisse - reagieren. Auf Rechnern mit sehr wenig Speicher (z.Bsp. FRITZ!Box 7170) - kann das zum automatischen Abschuss des FHEM Prozesses durch das OS - führen. -

    • - - -
    • basicAuth, basicAuthMsg
      - Fragt username/password zur Autentifizierung ab. Es gibt mehrere - Varianten: -
        -
      • falls das Argument nicht in {} eingeschlossen ist, dann wird - es als base64 kodiertes benutzername:passwort interpretiert. - Um sowas zu erzeugen kann man entweder einen der zahlreichen - Webdienste verwenden, oder das base64 Programm. Beispiel: -
          - $ echo -n fhemuser:secret | base64
          - ZmhlbXVzZXI6c2VjcmV0
          - fhem.cfg:
          - attr WEB basicAuth ZmhlbXVzZXI6c2VjcmV0 -
        -
      • -
      • Werden die Argumente in {} angegeben, wird es als perl-Ausdruck - ausgewertet, die Variablen $user and $password werden auf die - eingegebenen Werte gesetzt. Falls der Rückgabewert wahr ist, - wird die Anmeldung akzeptiert. - - Beispiel:
        - - attr WEB basicAuth { "$user:$password" eq "admin:secret" }
        -
        -
      • -
      -

    • - - -
    • HTTPS
      - Ermöglicht HTTPS Verbindungen. Es werden die Perl Module - IO::Socket::SSL benötigt, installierbar mit cpan -i - IO::Socket::SSL oder apt-get install libio-socket-ssl-perl; (OSX und - die FritzBox-7390 haben dieses Modul schon installiert.)
      - - Ein lokales Zertifikat muss im Verzeichis certs erzeugt werden. - Dieses Verzeichnis muss im modpath - angegeben werden, also auf der gleichen Ebene wie das FHEM Verzeichnis. - Beispiel: -
        - mkdir certs
        - cd certs
        - openssl req -new -x509 -nodes -out server-cert.pem -days 3650 -keyout server-key.pem -
      - -
      -
    • - - -
    • allowedCommands
      - Eine Komma getrennte Liste der erlaubten Befehle. Bei einer leeren - Liste (, dh. nur ein Komma) wird dieser FHEMWEB-Instanz "read-only". -
      Falls es auf get,set gesetzt ist, dann sind in dieser - FHEMWEB Instanz keine Konfigurationsänderungen möglich, nur - "normale" Bedienung der Schalter/etc.
      - - Dieses Attribut sollte zusammen mit dem hiddenroom/hiddengroup - Attributen verwendet werden.
      - - Achtung: allowedCommands sollte wie hier beschrieben - funktionieren, allerdings können wir keine Garantie geben, - daß man sie nicht überlisten, und Schaden anrichten kann. -

    • - -
    • allowfrom -

    • - - -
    • stylesheetPrefix
      - Präfix für die Dateien style.css, svg_style.css und - svg_defs.svg. Wenn die Datei mit dem Präfix fehlt, wird die Default - Datei (ohne Präfix) verwendet. Diese Dateien müssen im FHEM - Ordner liegen und können direkt mit "Select style" im FHEMWEB - Menüeintrag ausgewählt werden. Beispiel: -
        - attr WEB stylesheetPrefix dark
        -
        - Referenzdateien:
        -
          - darksvg_defs.svg
          - darksvg_style.css
          - darkstyle.css
          -
        -
        -
      - Anmerkung:Wenn der Parametername smallscreen oder touchpad - enthält, wird FHEMWEB das Layout/den Zugriff für entsprechende - Geräte (Smartphones oder Touchpads) optimieren
      - - Standardmäßig werden 3 FHEMWEB Instanzen aktiviert: Port 8083 - für Desktop Browser, Port 8084 für Smallscreen, und 8085 - für Touchpad.
      - - Wenn touchpad oder smallscreen benutzt werden, wird WebApp support - aktiviert: Nachdem Sie eine Seite am iPhone oder iPad mit Safari - angesehen haben, können Sie einen Link auf den Homescreen anlegen um - die Seite im Fullscreen Modus zu sehen. Links werden in diesem Modus - anders gerendert, um ein "Zurückfallen" in den "normalen" Browser zu - verhindern. -

    • - - -
    • iconPath
      - Durch Doppelpunkt getrennte Aufzählung der Verzeichnisse, in - welchen nach Icons gesucht wird. Die Verzeichnisse müssen unter - fhem/www/images angelegt sein. Standardeinstellung ist: - $styleSheetPrefix:default:fhemSVG:openautomation
      - Setzen Sie den Wert auf fhemSVG:openautomation um nur SVG Bilder zu - benutzen. -

    • - - -
    • hiddenroom
      - Eine Komma getrennte Liste, um Räume zu verstecken, d.h. nicht - anzuzeigen. Besondere Werte sind input, detail und save. In diesem - Fall werden diverse Eingabefelder ausgeblendent. Durch direktes Aufrufen - der URL sind diese Räume weiterhin erreichbar!
      - Ebenso können Einträge in den Logfile/Commandref/etc Block - versteckt werden.

    • - - -
    • hiddengroup
      - Wie hiddenroom (siehe oben), jedoch auf Gerätegruppen bezogen. -
      - Beispiel: attr WEBtablet hiddengroup FileLog,dummy,at,notify -

    • - - -
    • menuEntries
      - Komma getrennte Liste; diese Links werden im linken Menü angezeigt. - Beispiel:
      - attr WEB menuEntries fhem.de,http://fhem.de,culfw.de,http://culfw.de
      - attr WEB menuEntries AlarmOn,http://fhemhost:8083/fhem?cmd=set%20alarm%20on
      -

    • - - -
    • longpoll
      - Dies betrifft die Aktualisierung der Gerätestati in der - Weboberfläche. Ist longpoll aktiviert, werden - Statusänderungen sofort im Browser dargestellt. ohne die Seite - manuell neu laden zu müssen. Standard ist aktiviert. -

    • - - - -
    • longpollSVG
      - Lädt SVG Instanzen erneut, falls ein Ereignis dessen Inhalt - ändert. Funktioniert nur, falls der dazugehörige #FileLog - Definition in der .gplot Datei folgenden Form hat: deviceName.Event - bzw. deviceName.*. Wenn man den Plot - Editor benutzt, ist das übrigens immer der Fall. Die SVG Datei - wird bei jedem auslösenden Event dieses Gerätes neu - geladen. Standard ist aus. -

    • - - -
    • redirectCmds
      - Damit wird das URL Eingabefeld des Browser nach einem Befehl geleert. - Standard ist eingeschaltet (1), ausschalten kann man es durch - setzen des Attributs auf 0, z.Bsp. um den Syntax der Kommunikation mit - FHEMWEB zu untersuchen. -

    • - - -
    • fwcompress
      - Aktiviert die HTML Datenkompression (Standard ist 1, also ja, 0 stellt - die Kompression aus). -

    • - - -
    • reverseLogs
      - Damit wird das Logfile umsortiert, die neuesten Einträge stehen - oben. Der Vorteil ist, dass man nicht runterscrollen muss um den - neuesten Eintrag zu sehen, der Nachteil dass FHEM damit deutlich mehr - Hauptspeicher benötigt, etwa 6 mal so viel, wie das Logfile auf - dem Datenträger groß ist. Das kann auf Systemen mit wenig - Speicher (FRITZ!Box) zum Terminieren des FHEM Prozesses durch das - Betriebssystem führen. -

    • - - -
    • CORS
      - Wenn auf 1 gestellt, wird FHEMWEB einen "Cross origin resource sharing" - Header bereitstellen, näheres siehe Wikipedia. -

    • - - -
    • icon
      - Damit definiert man ein Icon für die einzelnen Geräte in der - Raumübersicht. Es gibt einen passenden Link in der Detailansicht - um das zu vereinfachen. Um ein Bild für die Räume selbst zu - definieren muss ein Icon mit dem Namen ico<Raumname>.png im - iconPath existieren (oder man verwendet roomIcons, s.u.) -

    • - - -
    • roomIcons
      - Leerzeichen getrennte Liste von room:icon Zuordnungen - Der erste Teil wird als regexp interpretiert, daher muss ein - Leerzeichen als Punkt geschrieben werden. Beispiel:
      - attr WEB roomIcons Anlagen.EDV:icoEverything -

    • - - -
    • sortRooms
      - Durch Leerzeichen getrennte Liste von Räumen, um deren Reihenfolge - zu definieren. Beispiel:
      - attr WEB sortRooms DG OG EG Keller -

    • - - -
    • defaultRoom
      - Zeigt den angegebenen Raum an falls kein Raum explizit ausgewählt - wurde. Achtung: falls gesetzt, wird motd nicht mehr angezeigt. - Beispiel:
      - attr WEB defaultRoom Zentrale -

    • - - -
    • sortby
      - Der Wert dieses Attributs wird zum sortieren von Geräten in - Räumen verwendet, sonst wäre es der Alias oder, wenn keiner - da ist, der Gerätename selbst. -

    • - - -
    • devStateIcon
      - Erste Variante:
      -
        - Leerzeichen getrennte Auflistung von regexp:icon-name:cmd - Dreierpärchen, icon-name und cmd dürfen leer sein.
        - - Wenn der Zustand des Gerätes mit der regexp übereinstimmt, - wird als icon-name das entsprechende Status Icon angezeigt, und (falls - definiert), löst ein Klick auf das Icon das entsprechende cmd aus. - Wenn fhem icon-name nicht finden kann, wird der Status als Text - angezeigt. - Beispiel:
        -
          - attr lamp devStateIcon on:closed off:open
          - attr lamp devStateIcon on::A0 off::AI
          - attr lamp devStateIcon .*:noIcon
          -
        - Anmerkung: Wenn das Icon ein SVG Bild ist, kann das @colorname Suffix - verwendet werden um das Icon einzufärben. Z.B.:
        -
          - attr Fax devStateIcon on:control_building_empty@red off:control_building_filled:278727 -
        - -
      - Zweite Variante:
      -
        - Perl regexp eingeschlossen in {}. Wenn der Code undef - zurückliefert, wird das Standard Icon verwendet; wird ein String - in <> zurück geliefert, wird dieser als HTML String interpretiert. - Andernfalls wird der String als devStateIcon gemäß der - ersten Variante interpretiert, siehe oben. Beispiel:
        - - {'<div style="width:32px;height:32px;background-color:green"></div>'} -
      -

    • - - -
    • devStateStyle
      - Für ein best. Gerät einen best. HTML-Style benutzen. - Beispiel:
      -
        - attr sensor devStateStyle style="text-align:left;;font-weight:bold;;"
        -
      -

    • - - -
    • webCmd
      - Durch Doppelpunkte getrennte Auflistung von Befehlen, die für ein - bestimmtes Gerät gelten sollen. Funktioniert nicht mit - smallscreen, ein Ersatz dafür ist der devStateIcon Befehl.
      - Beispiel: -
        - attr lamp webCmd on:off:on-for-timer 10
        -
      -
      - - Der erste angegebene Befehl wird in der "set device ?" list - nachgeschlagen (Siehe das setList Attrib - für Dummy Geräte). Wenn dort bekannte Modifier sind, - wird ein anderes Widget angezeigt: -
        -
      • Ist der Modifier ":noArg", wird kein weiteres Eingabefeld - angezeigt.
      • - -
      • Ist der Modifier ":time", wird ein in Javaskript geschreibenes - Zeitauswahlmenü angezeigt.
      • - -
      • Ist der Modifier ":textField", wird ein Eingabefeld - angezeigt.
      • - -
      • Ist der Modifier in der Form - ":slider,<min>,<step>,<max>", so wird ein in - JavaScript programmierter Slider angezeigt
      • - -
      • Ist der Modifier ":multiple,val1,val2,...", dann ein - Mehrfachauswahl ist möglich, das Ergebnis ist Komma-separiert.
      • - -
      • In allen anderen Fällen erscheint ein Dropdown mit allen - Modifier Werten.
      • -
      - - Wenn der Befehl state ist, wird der Wert als Kommando interpretiert.
      - Beispiele für modifier: -
        - define d1 dummy
        - attr d1 webCmd state
        - attr d1 setList state:on,off
        - define d2 dummy
        - attr d2 webCmd state
        - attr d2 setList state:slider,0,1,10
        - define d3 dummy
        - attr d3 webCmd state
        - attr d3 setList state:time
        -
      - - Anmerkung: dies ist ein Attribut für das anzuzeigende Gerät, - nicht für die FHEMWEBInstanz. -

    • - - -
    • column
      - Damit werden mehrere Spalten für einen Raum angezeigt, indem - sie verschiedene Gruppen Spalten zuordnen. Beispiel:
      -
        - attr WEB column LivingRoom:FS20,notify|FHZ,notify DiningRoom:FS20|FHZ -
      - - In diesem Beispiel werden im Raum LivingRoom die FS20 sowie die notify - Gruppe in der ersten Spalte, die FHZ und das notify in der zweiten - Spalte angezeigt.
      - - Anmerkung: einige Elemente, wie SVG Plots und readingsGroup können - nur Teil einer Spalte sein wenn sie in group - stehen. -

    • - -
    -
- -=end html_DE - -=cut