2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2024-11-22 16:09:49 +00:00

FHEMWEB_JS_UMBAU: integrate it with the trunk

git-svn-id: https://svn.fhem.de/fhem/trunk@7496 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig 2015-01-10 16:54:23 +00:00
parent 912b31ae50
commit 32f37c18fe
29 changed files with 1840 additions and 1290 deletions

View File

@ -1,24 +1,35 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
# Do not insert empty lines here, update check depends on it. # Do not insert empty lines here, update check depends on it.
- feature: fhemweb.js rewrite based on jQuery, single-widget-implementation
- feature: SVG: multiple sources allowed, Plot-Editor
- feature: textfield-long and knob widgets
- added: some new icons by Rampler - added: some new icons by Rampler
- feature: PRESENCE: new reading "presence" which contains the current (or last known) - feature: PRESENCE: new reading "presence" which contains the current (or
presence state (can be "absent" or "present") last known) presence state (can be "absent" or "present")
- bugfix: 70_Jabber.pm: hardening XML::Stream Process() call and fix of ssl_verify - bugfix: 70_Jabber.pm: hardening XML::Stream Process() call and fix of
- feature: readingsGroup: allow devspec :FILTER= expressions in device selection ssl_verify
- feature: readingsGroup: allow devspec :FILTER= expressions in device
selection
- added: 73_km200.pm for the Buderus KM200 heating controller (Sailor) - added: 73_km200.pm for the Buderus KM200 heating controller (Sailor)
- feature: 70_XBMC: added command 'connect' to connect instantly - feature: 70_XBMC: added command 'connect' to connect instantly
- change: FB_CALLMONITOR: use standard file read/write function to support use of configDb - change: FB_CALLMONITOR: use standard file read/write function to support
- bugfix: FB_CALLMONITOR: fix phonebook file read when using configDb (Forum #30244) use of configDb
- feature: 70_XBMC: added commands: openmovieid, openepisodeid, addon, jsonraw (thanks to siggi85) - bugfix: FB_CALLMONITOR: fix phonebook file read when using configDb (Forum
#30244)
- feature: 70_XBMC: added commands: openmovieid, openepisodeid, addon,
jsonraw (thanks to siggi85)
- fix: 70_XBMC: made fork attribute to close file handles correctly - fix: 70_XBMC: made fork attribute to close file handles correctly
- feature: 70_XBMC: added mechanism to detect disconnects (TCP) - feature: 70_XBMC: added mechanism to detect disconnects (TCP)
- fix: 66_ECMD: avoid reading from a closed connection in ECMD_READ - fix: 66_ECMD: avoid reading from a closed connection in ECMD_READ
- feature: 70_PIONEERAVR: readings for currentAlbum etc., more internals (network settings, moved some from readings to internals), new attributes volumeLimit & volumeLimitStraight - feature: 70_PIONEERAVR: readings for currentAlbum etc., more internals
(network settings, moved some from readings to internals), new attributes
volumeLimit & volumeLimitStraight
- added: some new icons (hourglass, frost, sani_heating_level_XX) - added: some new icons (hourglass, frost, sani_heating_level_XX)
- fix: sani_heating_boost (possibility to colorize) - fix: sani_heating_boost (possibility to colorize)
- feature: FB_CALLMONITOR: add remote phonebook lookup via telnet connection - feature: FB_CALLMONITOR: add remote phonebook lookup via telnet connection
to FritzBox (JoWiemann). to FritzBox (JoWiemann).
- bugfix: 70_PIONEERAVR & 71_PIONEERAVRZONE: fixed not working set-extensions (on-for-timer,...) - bugfix: 70_PIONEERAVR & 71_PIONEERAVRZONE: fixed not working set-extensions
(on-for-timer,...)
- feature: fheminfo: report third-party modules - feature: fheminfo: report third-party modules
- feature: 99_Utils.pm: add getUniqueID, getKeyValue, setKeyValue - feature: 99_Utils.pm: add getUniqueID, getKeyValue, setKeyValue
- feature: SMARTMON: additional parameters for smartctl - feature: SMARTMON: additional parameters for smartctl
@ -33,7 +44,8 @@
- feature: HUEDevice: allow ct presets in webCmd - feature: HUEDevice: allow ct presets in webCmd
new subTypes extcolordimer and ctdimer new subTypes extcolordimer and ctdimer
start support for Lightify bulbs start support for Lightify bulbs
- added: SONOS and SONOSPLAYER to support Sonos Multiroom Audiosystems (Reinerlein) - added: SONOS and SONOSPLAYER to support Sonos Multiroom Audiosystems
(Reinerlein)
- change: 64_ESA2000.pm: add batterystate - change: 64_ESA2000.pm: add batterystate
- added: 42_SMARTMON: Frontend to smartctl (maintainer: hexenmeister) - added: 42_SMARTMON: Frontend to smartctl (maintainer: hexenmeister)
- feature: 70_PushNotifier added line break in Messages (xusader) - feature: 70_PushNotifier added line break in Messages (xusader)
@ -43,7 +55,8 @@
- bugfix: FB_CALLMONITOR: fixing not working company numbers - bugfix: FB_CALLMONITOR: fixing not working company numbers
reverse search for search.ch reverse search for search.ch
- bugfix: 70_PushNotifier repair set function (xusader) - bugfix: 70_PushNotifier repair set function (xusader)
- bugfix: PRESENCE: fixing not working timer, when using set [...] statusRequest - bugfix: PRESENCE: fixing not working timer, when using set [...]
statusRequest
- bugfix: FB_CALLMONITOR: fixing reverse search for klicktel.de - bugfix: FB_CALLMONITOR: fixing reverse search for klicktel.de
- feature: new module 52_I2C_MCP342x.pm added (klausw) - feature: new module 52_I2C_MCP342x.pm added (klausw)
- feature: SYSMON: read cpu temp on FritzBox - feature: SYSMON: read cpu temp on FritzBox
@ -57,7 +70,8 @@
- feature: new module 98_logProxy.pm added (justme1968) - feature: new module 98_logProxy.pm added (justme1968)
- change: 66_ECMD: ReadyFn added (fixes issue under Windows) - change: 66_ECMD: ReadyFn added (fixes issue under Windows)
- change: 02_RSS: use a GUID in RSS; urlq source for img command - change: 02_RSS: use a GUID in RSS; urlq source for img command
- feature: 70_PushNotifier improve usebility, configuration without cURL (xusader) - feature: 70_PushNotifier improve usebility, configuration without cURL
(xusader)
- bugfix: SYSMON: prevent empty line im log by userReadings - bugfix: SYSMON: prevent empty line im log by userReadings
- feature: 10_IT empfang (by bjoernh) - feature: 10_IT empfang (by bjoernh)
- bugfix: PRESENCE: fix race condition, when delete disabled attribute and - bugfix: PRESENCE: fix race condition, when delete disabled attribute and

View File

@ -16,6 +16,7 @@ sub FW_answerCall($);
sub FW_dev2image($;$); sub FW_dev2image($;$);
sub FW_devState($$@); sub FW_devState($$@);
sub FW_digestCgi($); sub FW_digestCgi($);
sub FW_directNotify($$);
sub FW_doDetail($); sub FW_doDetail($);
sub FW_fatal($); sub FW_fatal($);
sub FW_fileList($); sub FW_fileList($);
@ -187,11 +188,7 @@ FHEMWEB_Initialize($)
closedir(DH); closedir(DH);
} }
$data{webCmdFn}{slider} = "FW_sliderFn"; $data{webCmdFn}{"~"} = "FW_widgetFallbackFn"; # Should be the last
$data{webCmdFn}{timepicker} = "FW_timepickerFn";
$data{webCmdFn}{noArg} = "FW_noArgFn";
$data{webCmdFn}{textField} = "FW_textFieldFn";
$data{webCmdFn}{"~dropdown"}= "FW_dropdownFn"; # Should be the last
if($init_done) { # reload workaround if($init_done) { # reload workaround
foreach my $pe ("fhemSVG", "openautomation", "default") { foreach my $pe ("fhemSVG", "openautomation", "default") {
@ -531,7 +528,9 @@ FW_answerCall($)
$ldir = "$FW_dir/pgm2" if($dir eq "css" || $dir eq "js"); # FLOORPLAN compat $ldir = "$FW_dir/pgm2" if($dir eq "css" || $dir eq "js"); # FLOORPLAN compat
$ldir = "$attr{global}{modpath}/docs" if($dir eq "docs"); $ldir = "$attr{global}{modpath}/docs" if($dir eq "docs");
if(-r "$ldir/$file.$ext") { # no return for FLOORPLAN # pgm2 check is for jquery-ui images
my $static = ($ext =~ m/(css|js|png|jpg)/i || $dir =~ m/^pgm2/);
if(-r "$ldir/$file.$ext" || $static) { # no return for FLOORPLAN
return FW_serveSpecial($file, $ext, $ldir, ($arg =~ m/nocache/) ? 0 : 1); return FW_serveSpecial($file, $ext, $ldir, ($arg =~ m/nocache/) ? 0 : 1);
} }
$arg = "/$dir/$ofile"; $arg = "/$dir/$ofile";
@ -617,7 +616,6 @@ FW_answerCall($)
} }
return 0; return 0;
} }
############################## ##############################
# FHEMWEB extensions (FLOORPLOAN, SVG_WriteGplot, etc) # FHEMWEB extensions (FLOORPLOAN, SVG_WriteGplot, etc)
my $FW_contentFunc; my $FW_contentFunc;
@ -696,18 +694,26 @@ FW_answerCall($)
FW_pO "<meta http-equiv=\"refresh\" content=\"$rf\">" if($rf); FW_pO "<meta http-equiv=\"refresh\" content=\"$rf\">" if($rf);
} }
########################
# CSS
my $cssTemplate = "<link href=\"$FW_ME/%s\" rel=\"stylesheet\"/>"; my $cssTemplate = "<link href=\"$FW_ME/%s\" rel=\"stylesheet\"/>";
FW_pO sprintf($cssTemplate, "pgm2/style.css"); FW_pO sprintf($cssTemplate, "pgm2/style.css");
my @cssFiles = split(" ", AttrVal($FW_wname, "CssFiles", "")); FW_pO sprintf($cssTemplate, "pgm2/jquery-ui.min.css");
map { FW_pO sprintf($cssTemplate, $_); } @cssFiles; map { FW_pO sprintf($cssTemplate, $_); }
split(" ", AttrVal($FW_wname, "CssFiles", ""));
########################
# JavaScripts
my $jsTemplate = '<script type="text/javascript" src="%s"></script>';
FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/jquery.min.js");
FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/jquery-ui.min.js");
######################## ########################
# FW Extensions # FW Extensions
my $jsTemplate = '<script type="text/javascript" src="%s"></script>';
if(defined($data{FWEXT})) { if(defined($data{FWEXT})) {
foreach my $k (sort keys %{$data{FWEXT}}) { foreach my $k (sort keys %{$data{FWEXT}}) {
my $h = $data{FWEXT}{$k}; my $h = $data{FWEXT}{$k};
next if($h !~ m/HASH/ || !$h->{SCRIPT}); next if($h !~ m/HASH/ || !$h->{SCRIPT} || $h->{SCRIPT} =~ m+pgm2/jquery+);
my $script = $h->{SCRIPT}; my $script = $h->{SCRIPT};
$script = ($script =~ m,^/,) ? "$FW_ME$script" : "$FW_ME/pgm2/$script"; $script = ($script =~ m,^/,) ? "$FW_ME$script" : "$FW_ME/pgm2/$script";
FW_pO sprintf($jsTemplate, $script); FW_pO sprintf($jsTemplate, $script);
@ -715,21 +721,18 @@ FW_answerCall($)
} }
####################### #######################
# Other JavaScripts # Other JavaScripts + their Attributes
FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/svg.js") if($FW_plotmode eq "SVG");
map { FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/$_") } @FW_fhemwebjs; map { FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/$_") } @FW_fhemwebjs;
$jsTemplate = '<script attr=\'%s\' type="text/javascript" src="%s"></script>'; $jsTemplate = '<script attr=\'%s\' type="text/javascript" src="%s"></script>';
map { map {
my $n = $_; $n =~ s+.*/++; $n =~ s/.js$//; $n =~ s/fhem_//; $n .= "Param"; my $n = $_; $n =~ s+.*/++; $n =~ s/.js$//; $n =~ s/fhem_//; $n .= "Param";
FW_pO sprintf($jsTemplate, AttrVal($FW_wname, $n, ""), "$FW_ME/$_"); FW_pO sprintf($jsTemplate, AttrVal($FW_wname, $n, ""), "$FW_ME/$_");
} split(" ", AttrVal($FW_wname, "JavaScripts", "")); } split(" ", AttrVal($FW_wname, "JavaScripts", ""));
my $onload = AttrVal($FW_wname, "longpoll", 1) ?
"onload=\"FW_delayedStart()\"" : "";
my $csrf= ($FW_CSRF ? "fwcsrf='$defs{$FW_wname}{CSRFTOKEN}'" : ""); my $csrf= ($FW_CSRF ? "fwcsrf='$defs{$FW_wname}{CSRFTOKEN}'" : "");
FW_pO "</head>\n<body generated=\"".(time()-1) my $gen = 'generated="'.(time()-1).'"';
."\" name=\"$t\" $csrf $onload>"; my $lp = 'longpoll="'.AttrVal($FW_wname,"longpoll",1).'"';
FW_pO "</head>\n<body name=\"$t\" $gen $lp $csrf>";
if($FW_activateInform) { if($FW_activateInform) {
$cmd = "style eventMonitor $FW_activateInform"; $cmd = "style eventMonitor $FW_activateInform";
@ -921,7 +924,7 @@ FW_makeTable($$$@)
} else { } else {
if( $title eq "Attributes" ) { if( $title eq "Attributes" ) {
FW_pO "<td><div class=\"dname\">". FW_pO "<td><div class=\"dname\">".
"<a onClick='FW_querySetSelected(\"sel.attr$name\",\"$n\")'>". "<a onClick='FW_querySetSelected(\"sel_attr$name\",\"$n\")'>".
"$n</a></div></td>"; "$n</a></div></td>";
} else { } else {
FW_pO "<td><div class=\"dname\">$n</div></td>"; FW_pO "<td><div class=\"dname\">$n</div></td>";
@ -978,7 +981,7 @@ FW_makeTable($$$@)
############################## ##############################
# Used only for set or attr lists. # Used only for set or attr lists.
sub sub
FW_makeSelect($$$$) FW_detailSelect($$$$)
{ {
my ($d, $cmd, $list,$class) = @_; my ($d, $cmd, $list,$class) = @_;
return if(!$list || $FW_hiddenroom{input}); return if(!$list || $FW_hiddenroom{input});
@ -987,8 +990,9 @@ FW_makeSelect($$$$)
my $selEl = (defined($al[0]) ? $al[0] : " "); my $selEl = (defined($al[0]) ? $al[0] : " ");
$selEl = $1 if($list =~ m/([^ ]*):slider,/); # promote a slider if available $selEl = $1 if($list =~ m/([^ ]*):slider,/); # promote a slider if available
$selEl = "room" if($list =~ m/room:/); $selEl = "room" if($list =~ m/room:/);
$list =~ s/"/&quot;/g;
FW_pO "<div class='makeSelect'>"; FW_pO "<div class='makeSelect' dev=\"$d\" cmd=\"$cmd\" list=\"$list\">";
FW_pO "<form method=\"$FW_formmethod\" ". FW_pO "<form method=\"$FW_formmethod\" ".
"action=\"$FW_ME$FW_subdir\" autocomplete=\"off\">"; "action=\"$FW_ME$FW_subdir\" autocomplete=\"off\">";
FW_pO FW_hidden("detail", $d); FW_pO FW_hidden("detail", $d);
@ -996,12 +1000,8 @@ FW_makeSelect($$$$)
FW_pO FW_hidden("dev.$cmd$d", $d); FW_pO FW_hidden("dev.$cmd$d", $d);
FW_pO FW_submit("cmd.$cmd$d", $cmd, $class); FW_pO FW_submit("cmd.$cmd$d", $cmd, $class);
FW_pO "<div class=\"$class downText\">&nbsp;$d&nbsp;</div>"; FW_pO "<div class=\"$class downText\">&nbsp;$d&nbsp;</div>";
FW_pO FW_select("sel.$cmd$d","arg.$cmd$d",\@al, $selEl, $class, 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); FW_pO FW_textfield("val.$cmd$d", 30, $class);
# Initial setting
FW_pO "<script type=\"text/javascript\">" .
"FW_selChange('$selEl','$list','val.$cmd$d')</script>";
FW_pO "</form></div>"; FW_pO "</form></div>";
} }
@ -1037,12 +1037,8 @@ FW_doDetail($)
use strict "refs"; use strict "refs";
} }
FW_pO "<form method=\"$FW_formmethod\" action=\"$FW_ME\">"; FW_detailSelect($d, "set", FW_widgetOverride($d, getAllSets($d)), "set");
FW_pO FW_hidden("detail", $d); FW_detailSelect($d, "get", FW_widgetOverride($d, getAllGets($d)), "get");
FW_pO FW_hidden("fwcsrf", $defs{$FW_wname}{CSRFTOKEN}) if($FW_CSRF);
FW_makeSelect($d, "set", FW_widgetOverride($d, getAllSets($d)), "set");
FW_makeSelect($d, "get", FW_widgetOverride($d, getAllGets($d)), "get");
FW_makeTable("Internals", $d, $h); FW_makeTable("Internals", $d, $h);
FW_makeTable("Readings", $d, $h->{READINGS}); FW_makeTable("Readings", $d, $h->{READINGS});
@ -1057,7 +1053,7 @@ FW_doDetail($)
$attrList = FW_widgetOverride($d, $attrList); $attrList = FW_widgetOverride($d, $attrList);
$attrList =~ s/\\/\\\\/g; $attrList =~ s/\\/\\\\/g;
$attrList =~ s/'/\\'/g; $attrList =~ s/'/\\'/g;
FW_makeSelect($d, "attr", $attrList,"attr"); FW_detailSelect($d, "attr", $attrList,"attr");
FW_makeTable("Attributes", $d, $attr{$d}, "deleteattr"); FW_makeTable("Attributes", $d, $attr{$d}, "deleteattr");
## dependent objects ## dependent objects
@ -1070,7 +1066,6 @@ FW_doDetail($)
push(@dob, $dn); push(@dob, $dn);
} }
} }
FW_pO "</form>";
FW_makeTableFromArray("Probably associated with", "assoc", @dob,); FW_makeTableFromArray("Probably associated with", "assoc", @dob,);
FW_pO "</td></tr></table>"; FW_pO "</td></tr></table>";
@ -1078,6 +1073,7 @@ FW_doDetail($)
FW_pH "cmd=style iconFor $d", "Select icon"; FW_pH "cmd=style iconFor $d", "Select icon";
FW_pH "cmd=style showDSI $d", "Extend devStateIcon"; FW_pH "cmd=style showDSI $d", "Extend devStateIcon";
FW_pH "$FW_ME/docs/commandref.html#${t}", "Device specific help"; FW_pH "$FW_ME/docs/commandref.html#${t}", "Device specific help";
FW_pH "cmd=delete $d", "Delete this device ($d)" if($d ne "global");
FW_pO "<br><br>"; FW_pO "<br><br>";
FW_pO "</div>"; FW_pO "</div>";
@ -1300,7 +1296,7 @@ FW_showRoom()
$FW_hiddengroup{$r} = 1; $FW_hiddengroup{$r} = 1;
} }
FW_pO "<form method=\"$FW_formmethod\" ". FW_pO "<form method=\"$FW_formmethod\" ". # Why do we need a form here?
"action=\"$FW_ME\" autocomplete=\"off\">"; "action=\"$FW_ME\" autocomplete=\"off\">";
FW_pO "<div id=\"content\" room=\"$FW_room\">"; FW_pO "<div id=\"content\" room=\"$FW_room\">";
FW_pO "<table class=\"roomoverview\">"; # Need for equal width of subtables FW_pO "<table class=\"roomoverview\">"; # Need for equal width of subtables
@ -1358,7 +1354,7 @@ FW_showRoom()
$icon = FW_makeImage($icon,$icon,"icon") . "&nbsp;" if($icon); $icon = FW_makeImage($icon,$icon,"icon") . "&nbsp;" if($icon);
if($FW_hiddenroom{detail}) { if($FW_hiddenroom{detail}) {
FW_pO "<td><div class=\"col1\">$icon$devName</div></td>"; FW_pO "<td><div class=\"col1\">$icon$devName</div></td>" if(!$usuallyAtEnd{$d});
} else { } else {
FW_pH "detail=$d", "$icon$devName", 1, "col1" if(!$usuallyAtEnd{$d}); FW_pH "detail=$d", "$icon$devName", 1, "col1" if(!$usuallyAtEnd{$d});
} }
@ -1506,8 +1502,10 @@ FW_returnFileAsStream($$$$$)
} }
if(!open(FH, $path)) { if(!open(FH, $path)) {
Log3 $FW_wname, 2, "FHEMWEB $FW_wname $path: $!"; Log3 $FW_wname, 4, "FHEMWEB $FW_wname $path: $!";
FW_pO "<div id=\"content\">$path: $!</div>"; TcpServer_WriteBlocking($FW_chash,
"HTTP/1.1 404 Not Found\r\n".
"Content-Length:0\r\n\r\n");
FW_closeConn($FW_chash); FW_closeConn($FW_chash);
return 0; return 0;
} }
@ -1569,12 +1567,12 @@ FW_hidden($$)
sub sub
FW_select($$$$$@) FW_select($$$$$@)
{ {
my ($id, $n, $va, $def, $class, $jSelFn) = @_; my ($id, $name, $valueArray, $selected, $class, $jSelFn) = @_;
$jSelFn = ($jSelFn ? "onchange=\"$jSelFn\"" : ""); $jSelFn = ($jSelFn ? "onchange=\"$jSelFn\"" : "");
$id = ($id ? "id=\"$id\" informId=\"$id\"" : ""); $id = ($id ? "id=\"$id\" informId=\"$id\"" : "");
my $s = "<select $jSelFn $id name=\"$n\" class=\"$class\">"; my $s = "<select $jSelFn $id name=\"$name\" class=\"$class\">";
foreach my $v (@{$va}) { foreach my $v (@{$valueArray}) {
if(defined($def) && $v eq $def) { if(defined($selected) && $v eq $selected) {
$s .= "<option selected=\"selected\" value='$v'>$v</option>\n"; $s .= "<option selected=\"selected\" value='$v'>$v</option>\n";
} else { } else {
$s .= "<option value='$v'>$v</option>\n"; $s .= "<option value='$v'>$v</option>\n";
@ -1750,14 +1748,16 @@ FW_style($$)
my $filePath = FW_fileNameToPath($fileName); my $filePath = FW_fileNameToPath($fileName);
$FW_data =~ s/\r//g; $FW_data =~ s/\r//g;
my $err = FileWrite({FileName=>$filePath, ForceType=>$forceType}, split("\n", $FW_data)); my $err = FileWrite({FileName=>$filePath, ForceType=>$forceType},
split("\n", $FW_data));
if($err) { if($err) {
FW_pO "<div id=\"content\">$filePath: $!</div>"; FW_pO "<div id=\"content\">$filePath: $!</div>";
return; return;
} }
my $ret = FW_fC("rereadcfg") if($filePath eq $attr{global}{configfile}); my $ret = FW_fC("rereadcfg") if($filePath eq $attr{global}{configfile});
$ret = FW_fC("reload $fileName") if($fileName =~ m,\.pm$,); $ret = FW_fC("reload $fileName") if($fileName =~ m,\.pm$,);
$ret = ($ret ? "<h3>ERROR:</h3><b>$ret</b>" : "Saved the file $fileName to $forceType"); $ret = ($ret ? "<h3>ERROR:</h3><b>$ret</b>" :
"Saved the file $fileName to $forceType");
FW_style("style list", $ret); FW_style("style list", $ret);
$ret = ""; $ret = "";
@ -2201,6 +2201,16 @@ FW_makeEdit($$$)
} }
sub
FW_longpollInfo($$$)
{
my ($dev, $state, $html) = @_;
$dev =~ s/([\\"])/\\$1/g;
$state =~ s/([\\"])/\\$1/g;
$html =~ s/([\\"])/\\$1/g;
return "[\"$dev\",\"$state\",\"$html\"]";
}
sub sub
FW_roomStatesForInform($$) FW_roomStatesForInform($$)
{ {
@ -2219,7 +2229,7 @@ FW_roomStatesForInform($$)
my ($allSet, $cmdlist, $txt) = FW_devState($dn, "", \%extPage); my ($allSet, $cmdlist, $txt) = FW_devState($dn, "", \%extPage);
if($defs{$dn} && $defs{$dn}{STATE} && $defs{$dn}{TYPE} ne "weblink") { if($defs{$dn} && $defs{$dn}{STATE} && $defs{$dn}{TYPE} ne "weblink") {
push @data, "$dn<<$defs{$dn}{STATE}<<$txt"; push @data, FW_longpollInfo($dn, $defs{$dn}{STATE}, $txt);
} }
} }
my $data = join("\n", map { s/\n/ /gm; $_ } @data)."\n"; my $data = join("\n", map { s/\n/ /gm; $_ } @data)."\n";
@ -2265,7 +2275,7 @@ FW_Notify($$)
if( !$modules{$defs{$dn}{TYPE}}{FW_atPageEnd} ) { if( !$modules{$defs{$dn}{TYPE}}{FW_atPageEnd} ) {
my ($allSet, $cmdlist, $txt) = FW_devState($dn, "", \%extPage); my ($allSet, $cmdlist, $txt) = FW_devState($dn, "", \%extPage);
($FW_wname, $FW_ME, $FW_ss, $FW_tp, $FW_subdir) = @old; ($FW_wname, $FW_ME, $FW_ss, $FW_tp, $FW_subdir) = @old;
push @data, "$dn<<$dev->{STATE}<<$txt"; push @data, FW_longpollInfo($dn, $dev->{STATE}, $txt);
} }
#Add READINGS #Add READINGS
@ -2277,8 +2287,8 @@ FW_Notify($$)
next; #ignore 'set' commands next; #ignore 'set' commands
} }
my ($readingName,$readingVal) = split(": ",$events->[$i],2); my ($readingName,$readingVal) = split(": ",$events->[$i],2);
push @data, "$dn-$readingName<<$readingVal<<$readingVal"; push @data, FW_longpollInfo("$dn-$readingName",$readingVal,$readingVal);
push @data, "$dn-$readingName-ts<<$tn<<$tn"; push @data, FW_longpollInfo("$dn-$readingName-ts", $tn, $tn);
} }
} }
} }
@ -2310,6 +2320,24 @@ FW_Notify($$)
return undef; return undef;
} }
sub
FW_directNotify($$) # Notify without the event overhead (Forum #31293)
{
my ($dev, $msg) = @_;
foreach my $ntfy (values(%defs)) {
next if(!$ntfy->{TYPE} ||
$ntfy->{TYPE} ne "FHEMWEB" ||
!$ntfy->{inform} ||
!$ntfy->{inform}{devices}{$dev});
if(!addToWritebuffer($ntfy, FW_longpollInfo($dev, $msg, "")."\n")){
my $name = $ntfy->{NAME};
Log3 $name, 4, "Closing connection $name due to full buffer in FW_Notify";
TcpServer_Close($ntfy);
delete($defs{$name});
}
}
}
################### ###################
# Compute the state (==second) column # Compute the state (==second) column
sub sub
@ -2371,16 +2399,7 @@ FW_devState($$@)
} }
$link .= "&room=$room"; $link .= "&room=$room";
} }
if(AttrVal($FW_wname, "longpoll", 1)) {
$txt = "<a onClick=\"FW_cmd('$FW_ME$FW_subdir?XHR=1&$link')\">$txt</a>";
} elsif($FW_ss || $FW_tp) {
$txt ="<a onClick=\"location.href='$FW_ME$FW_subdir?$link$rf$FW_CSRF'\">$txt</a>";
} else {
$txt = "<a href=\"$FW_ME$FW_subdir?$link$rf$FW_CSRF\">$txt</a>"; $txt = "<a href=\"$FW_ME$FW_subdir?$link$rf$FW_CSRF\">$txt</a>";
}
} }
my $style = AttrVal($d, "devStateStyle", ""); my $style = AttrVal($d, "devStateStyle", "");
@ -2488,124 +2507,31 @@ FW_htmlEscape($)
########################### ###########################
# Widgets START # Widgets START
sub sub
FW_sliderFn($$$$$) FW_widgetFallbackFn()
{ {
my ($FW_wname, $d, $FW_room, $cmd, $values) = @_; my ($FW_wname, $d, $FW_room, $cmd, $values) = @_;
return undef if($values !~ m/^slider,([-\d.]*),([-\d.]*),([-\d.]*)(,1)?$/); # webCmd "temp 30" should remain text
return "" if($cmd =~ m/ /); # webCmd pct 30 should generate a link # noArg is needed for fhem.cfg.demo / Cinema
my ($min,$stp, $max, $flt) = ($1, $2, $3, $4); return "" if(!$values || $values eq "noArg");
$flt = ($flt ? 1 : 0);
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 "<td colspan='2'>".
"<div class='slider' id='slider.$d$id' min='$min' stp='$stp' ".
"max='$max' cmd='$FW_ME?cmd=set $d $cmd %$srf' flt='$flt'>".
"<div class='handle'>$min</div>".
"</div>".
"<script type=\"text/javascript\">".
"FW_sliderCreate(document.getElementById('slider.$d$id'),'$cv');".
"</script>".
"</td>";
}
sub my($reading) = split( ' ', $cmd, 2 );
FW_noArgFn($$$$$) my $current;
{
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 "<td colspan='2'>".
"<input name='time.$d' value='$cv' type='text' readonly size='5'>".
"<input type='button' value='+' onclick='FW_timeCreate(this,$c)'>".
"</td>";
}
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") { if($cmd eq "desired-temp" || $cmd eq "desiredTemperature") {
$txt = ReadingsVal($d, $cmd, 20); $current = ReadingsVal($d, $cmd, 20);
$txt =~ s/ .*//; # Cut off Celsius $current =~ s/ .*//; # Cut off Celsius
$txt = sprintf("%2.1f", int(2*$txt)/2) if($txt =~ m/[0-9.-]/); $current = sprintf("%2.1f", int(2*$current)/2) if($current =~ m/[0-9.-]/);
} else { } else {
$txt = ReadingsVal($d, $cmd, Value($d)); $current = ReadingsVal($d, $reading, undef);
$txt =~ s/$cmd //; if( !defined($current) ) {
$reading = 'state';
$current = Value($d);
} }
$current =~ s/$cmd //;
my $fpname = $FW_wname;
$fpname =~ s/.*floorplan\/(\w+)$/$1/; #allow usage of attr fp_setbutton
my $readng = ($cmd eq "state" ? "" : "$cmd"." ");
# TODO in case of running in a floorplan split $FW_wname to get name of
# webInstance. Actually in floorplan the dropdown will refresh the page
# always independently from setting in corresponding web instance, cause
# statement if( AttrVal($FW_wname, "longpoll", 0) == 1) will always fail.
my $selFunct="";
if( AttrVal($FW_wname, "longpoll", 0) == 1) {
$selFunct = "FW_cmd('$FW_ME?XHR=1&cmd.$d=set $d $readng '+ ".
"this.options[this.selectedIndex].value+ ' &room=$FW_room')";
} else {
$selFunct = "window.location = addcsrf('$FW_ME?cmd.$d=set $d $readng '+".
"this.options[this.selectedIndex].value+ ' &room=$FW_room')";
} }
my $fwsel; return "<td><div class='fhemWidget' cmd='$cmd' reading='$reading' ".
$fwsel = ($cmd eq "state" ? "" : "$cmd&nbsp;") . "dev='$d' arg='$values' current='$current'></div></td>";
FW_select("$d-$cmd","val.$d", \@tv, $txt,"dropdown","$selFunct");
return "<td colspan='2'>$fwsel</td>";
}
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 '<td align="center">'.
"<div>$cmd:<input id='textField.$d$id' type='text' value='$cv' ".
"onChange='textField_setText(this,\"$c\")'></div>".
'</td>';
}
# Widgets END # Widgets END
########################### ###########################
@ -3148,18 +3074,23 @@ FW_widgetOverride($$)
<li>if the modifier is ":time", then a javascript driven timepicker is <li>if the modifier is ":time", then a javascript driven timepicker is
displayed.</li> displayed.</li>
<li>if the modifier is ":textField", an input field is displayed.</li> <li>if the modifier is ":textField", an input field is displayed.</li>
<li>if the modifier is ":textField-long", is like textField, but upon
clicking on the input field a textArea (60x25) will be opened.</li>
<li>if the modifier is of the form <li>if the modifier is of the form
":slider,&lt;min&gt;,&lt;step&gt;,&lt;max&gt;[,1]", then a ":slider,&lt;min&gt;,&lt;step&gt;,&lt;max&gt;[,1]", then a
javascript driven slider is displayed. The optional ,1 at the end javascript driven slider is displayed. The optional ,1 at the end
avoids the rounding of floating-point numbers.</li> avoids the rounding of floating-point numbers.</li>
<li>if the modifier is of the form ":multiple,val1,val2,...", then <li>if the modifier is of the form ":multiple,val1,val2,...", then
multiple values can be selected and own values can be written, the multiple values can be selected and own values can be written, the
result is comma separated.</li> result is comma separated.</li>
<li>if the modifier is of the form ":multiple-strict,val1,val2,...", then <li>if the modifier is of the form ":multiple-strict,val1,val2,...",
multiple values can be selected and no new values can be added, the then multiple values can be selected and no new values can be
result is comma separated.</li> added, the result is comma separated.</li>
<li>if the modifier is of the form ":knob,min:1,max:100,...", then
the jQuery knob widget will be displayed. The parameters are
specified as a comma separated list of key:value pairs, where key
does not have to contain the "data-" prefix.</li>
<li>else a dropdown with all the modifier values is displayed</li> <li>else a dropdown with all the modifier values is displayed</li>
</ul> </ul>
If this attribute is specified for a FHEMWEB instance, then it is If this attribute is specified for a FHEMWEB instance, then it is
@ -3167,6 +3098,7 @@ FW_widgetOverride($$)
<ul> <ul>
attr FS20dev widgetOverride on-till:time<br> attr FS20dev widgetOverride on-till:time<br>
attr WEB widgetOverride room:textField<br> attr WEB widgetOverride room:textField<br>
attr dimmer widgetOverride dim:knob,min:1,max:100,step:1,linecap:round<br>
</ul> </ul>
</li> </li>
<br> <br>
@ -3722,6 +3654,10 @@ FW_widgetOverride($$)
<li>Ist der Modifier ":textField", wird ein Eingabefeld <li>Ist der Modifier ":textField", wird ein Eingabefeld
angezeigt.</li> angezeigt.</li>
<li>Ist der Modified ":textField-long" ist wie textField, aber beim
Click im Eingabefeld ein Dialog mit einer HTML textarea
(60x25) wird ge&ouml;ffnet.</li>
<li>Ist der Modifier in der Form <li>Ist der Modifier in der Form
":slider,&lt;min&gt;,&lt;step&gt;,&lt;max&gt;[,1]", so wird ein in ":slider,&lt;min&gt;,&lt;step&gt;,&lt;max&gt;[,1]", so wird ein in
JavaScript programmierter Slider angezeigt. Das optionale 1 JavaScript programmierter Slider angezeigt. Das optionale 1
@ -3735,8 +3671,15 @@ FW_widgetOverride($$)
Mehrfachauswahl m&ouml;glich, es k&ouml;nnen jedoch keine neuen Mehrfachauswahl m&ouml;glich, es k&ouml;nnen jedoch keine neuen
Werte definiert werden. Das Ergebnis ist Komma-separiert.</li> Werte definiert werden. Das Ergebnis ist Komma-separiert.</li>
<li>In allen anderen F&auml;llen erscheint ein Dropdown mit allen <li>Ist der Modifier ":knob,min:1,max:100,...", dass ein
Modifier Werten.</li> jQuery knob Widget wird angezeigt. Die Parameter werden als eine
Komma separierte Liste von Key:Value Paaren spezifiziert, wobei das
data- Pr&auml;fix entf&auml;llt. </li>
<li>In allen anderen F&auml;llen (oder falls der Modified explizit
mit :select anfaegt) erscheint ein HTML select mit allen Modifier
Werten.</li>
</ul> </ul>
Falls das Attribut f&uuml;r eine WEB Instanz gesetzt wurde, dann wird Falls das Attribut f&uuml;r eine WEB Instanz gesetzt wurde, dann wird
es bei allen von diesem Web-Instan angezeigten Ger&auml;ten angewendet. es bei allen von diesem Web-Instan angezeigten Ger&auml;ten angewendet.
@ -3744,6 +3687,7 @@ FW_widgetOverride($$)
<ul> <ul>
attr FS20dev widgetOverride on-till:time<br> attr FS20dev widgetOverride on-till:time<br>
attr WEB widgetOverride room:textField<br> attr WEB widgetOverride room:textField<br>
attr dimmer widgetOverride dim:knob,min:1,max:100,step:1,linecap:round<br>
</ul> </ul>
</li><br> </li><br>

View File

@ -273,23 +273,18 @@ return "<br>Timespec wizard:".
</tr><tr class="even"><td>Timespec</td> </tr><tr class="even"><td>Timespec</td>
<td><input type="text" id="aw_pts"></td> <td><input type="text" id="aw_pts"></td>
</tr><tr class="even"><td>Timespec</td> </tr><tr class="even"><td>Timespec</td>
<td><input type="text" readonly id="aw_ts" size="5"> <td><input type="text" name="aw_ts" id="aw_ts" size="5"></td>
<input type='button' value='+' id="aw_tsb"></td>
</tr> </tr>
</tr><tr class="even"> </tr><tr class="even">
<td colspan="2"><input type="button" id="aw_md" value="Modify"></td> <td colspan="2"><input type="button" id="aw_md" value="Modify"></td>
</tr> </tr>
</table> </table>
<script type="text/javascript"> <script type="text/javascript">
loadScript("pgm2/jquery.min.js", atDetails);
function
atDetails()
{ {
var t=$("#atWizard"), ip=$(t).attr("ip"), ts=$(t).attr("ts"); var t=$("#atWizard"), ip=$(t).attr("ip"), ts=$(t).attr("ts");
FW_replaceWidget("#aw_ts", "aw_ts", ["time"], "12:00");
$("[informid=aw_ts] input[type=text]").attr("id", "aw_ts");
function tsClick() {
FW_timeCreate(this, function(val) { $("#aw_tsb").click(tsClick) })
}
function ipClick() { function ipClick() {
var c = $("#aw_ip").prop("checked"); var c = $("#aw_ip").prop("checked");
$("#aw_ts").closest("tr").css("display", !c ? "table-row" : "none"); $("#aw_ts").closest("tr").css("display", !c ? "table-row" : "none");
@ -300,7 +295,6 @@ return "<br>Timespec wizard:".
$("#aw_ip").prop("checked", ip); $("#aw_ip").prop("checked", ip);
$("#aw_ts").val(ip ? "12:00" : ts); $("#aw_ts").val(ip ? "12:00" : ts);
$("#aw_pts").val(ip ? ts : 'sunset()'); $("#aw_pts").val(ip ? ts : 'sunset()');
$("#aw_tsb").click(tsClick);
$("#aw_ip").change(ipClick); $("#aw_ip").change(ipClick);
ipClick(); ipClick();
$("#aw_md").click(function(){ $("#aw_md").click(function(){

View File

@ -951,8 +951,8 @@ FileLog_sampleDataFn($$$$$)
for(my $r=0; $r < $max; $r++) { for(my $r=0; $r < $max; $r++) {
my @f = split(":", ($flog->[$r] ? $flog->[$r] : ":::"), 4); my @f = split(":", ($flog->[$r] ? $flog->[$r] : ":::"), 4);
my $ret = ""; my $ret = "";
$ret .= SVG_sel("par_${r}_0", $colnums, $f[0]); $ret .= SVG_sel("par_${r}_0", $colnums, $f[0], undef, "svgColumn");
$ret .= SVG_sel("par_${r}_1", $colregs, $f[1]); $ret .= SVG_sel("par_${r}_1", $colregs, $f[1], undef, "svgRegexp");
$ret .= SVG_txt("par_${r}_2", "", $f[2], 1); $ret .= SVG_txt("par_${r}_2", "", $f[2], 1);
$ret .= SVG_txt("par_${r}_3", "", $f[3], 6); $ret .= SVG_txt("par_${r}_3", "", $f[3], 6);
push @htmlArr, $ret; push @htmlArr, $ret;

View File

@ -32,7 +32,7 @@ sub SVG_calcOffsets($$);
sub SVG_doround($$$); sub SVG_doround($$$);
sub SVG_fmtTime($$); sub SVG_fmtTime($$);
sub SVG_pO($); sub SVG_pO($);
sub SVG_readgplotfile($$); sub SVG_readgplotfile($$$);
sub SVG_render($$$$$$$$$;$$); sub SVG_render($$$$$$$$$;$$);
sub SVG_showLog($); sub SVG_showLog($);
sub SVG_substcfg($$$$$$); sub SVG_substcfg($$$$$$);
@ -40,8 +40,12 @@ sub SVG_time_align($$);
sub SVG_time_to_sec($); sub SVG_time_to_sec($);
sub SVG_openFile($$$); sub SVG_openFile($$$);
sub SVG_doShowLog($$$$;$$); sub SVG_doShowLog($$$$;$$);
sub SVG_getData($$$$$);
sub SVG_sel($$$;$$);
my %SVG_devs; # hash of from/to entries per device my %SVG_devs; # hash of from/to entries per device
my $SVG_id=0;
##################################### #####################################
sub sub
@ -50,7 +54,8 @@ SVG_Initialize($)
my ($hash) = @_; my ($hash) = @_;
$hash->{DefFn} = "SVG_Define"; $hash->{DefFn} = "SVG_Define";
$hash->{AttrList} = "fixedoffset fixedrange startDate plotsize nrAxis label title plotfunction"; $hash->{AttrList} = "fixedoffset fixedrange startDate plotsize nrAxis ".
"label title plotfunction";
$hash->{SetFn} = "SVG_Set"; $hash->{SetFn} = "SVG_Set";
$hash->{FW_summaryFn} = "SVG_FwFn"; $hash->{FW_summaryFn} = "SVG_FwFn";
$hash->{FW_detailFn} = "SVG_FwFn"; $hash->{FW_detailFn} = "SVG_FwFn";
@ -133,6 +138,21 @@ jsSVG_getAttrs($)
} keys %{$attr{$d}}); } keys %{$attr{$d}});
} }
sub
SVG_getplotsize($)
{
my ($d) = @_;
return $FW_webArgs{plotsize} ?
$FW_webArgs{plotsize} : AttrVal($d,"plotsize",$FW_plotsize);
}
sub
SVG_isEmbed($)
{
return (AttrVal($FW_wname, "plotEmbed",
$FW_userAgent !~ m/(iPhone|iPad|iPod).*OS (8|9)/));
}
################## ##################
sub sub
SVG_FwFn($$$$) SVG_FwFn($$$$)
@ -141,6 +161,11 @@ SVG_FwFn($$$$)
my $hash = $defs{$d}; my $hash = $defs{$d};
my $ret = ""; my $ret = "";
if(!$pageHash || !$pageHash->{jsLoaded}) {
$ret .= "<script type='text/javascript' src='$FW_ME/pgm2/svg.js'></script>";
$pageHash->{jsLoaded} = 1 if($pageHash);
}
if(AttrVal($FW_wname, "plotmode", "SVG") eq "jsSVG") { if(AttrVal($FW_wname, "plotmode", "SVG") eq "jsSVG") {
my @d=split(":",$defs{$d}{DEF}); my @d=split(":",$defs{$d}{DEF});
@ -182,11 +207,10 @@ SVG_FwFn($$$$)
"&amp;pos=" . join(";", map {"$_=$FW_pos{$_}"} keys %FW_pos); "&amp;pos=" . join(";", map {"$_=$FW_pos{$_}"} keys %FW_pos);
if(AttrVal($d,"plotmode",$FW_plotmode) eq "SVG") { if(AttrVal($d,"plotmode",$FW_plotmode) eq "SVG") {
my ($w, $h) = split(",", AttrVal($d,"plotsize",$FW_plotsize)); my ($w, $h) = split(",", SVG_getplotsize($d));
$ret .= "<div class=\"SVGplot SVG_$d\">"; $ret .= "<div class=\"SVGplot SVG_$d\">";
if(AttrVal($FW_wname, "plotEmbed", if(SVG_isEmbed($FW_wname)) {
$FW_userAgent !~ m/(iPhone|iPad|iPod).*OS (8|9)/)) {
$ret .= "<embed src=\"$arg\" type=\"image/svg+xml\" " . $ret .= "<embed src=\"$arg\" type=\"image/svg+xml\" " .
"width=\"$w\" height=\"$h\" name=\"$d\"/>\n"; "width=\"$w\" height=\"$h\" name=\"$d\"/>\n";
@ -236,12 +260,12 @@ SVG_txt($$$$)
} }
sub sub
SVG_sel($$$@) SVG_sel($$$;$$)
{ {
my ($v,$l,$c,$fnData) = @_; my ($v,$l,$c,$fnData,$class) = @_;
my @al = split(",",$l); my @al = split(",",$l);
$c =~ s/\\x3a/:/g if($c); $c =~ s/\\x3a/:/g if($c);
return FW_select($v,$v,\@al,$c, "set", $fnData); return FW_select(undef,$v,\@al,$c, $class?$class:"set", $fnData);
} }
############################ ############################
@ -255,12 +279,10 @@ SVG_PEdit($$$$)
return "" if( $pe eq 'never' ); return "" if( $pe eq 'never' );
my $ld = $defs{$d}{LOGDEVICE};
my $ldt = $defs{$ld}{TYPE};
my $gp = "$FW_gplotdir/$defs{$d}{GPLOTFILE}.gplot"; my $gp = "$FW_gplotdir/$defs{$d}{GPLOTFILE}.gplot";
my $pm = AttrVal($d,"plotmode",$FW_plotmode);
my ($err, $cfg, $plot, $flog) = SVG_readgplotfile($d, $gp); my ($err, $cfg, $plot, $srcDesc) = SVG_readgplotfile($d, $gp, $pm);
my %conf = SVG_digestConf($cfg, $plot); my %conf = SVG_digestConf($cfg, $plot);
my $ret = "<br>"; my $ret = "<br>";
@ -280,8 +302,6 @@ SVG_PEdit($$$$)
"action=\"$FW_ME/SVG_WriteGplot\">"; "action=\"$FW_ME/SVG_WriteGplot\">";
$ret .= "Plot Editor"; $ret .= "Plot Editor";
$ret .= FW_hidden("detail", $d); # go to detail after save $ret .= FW_hidden("detail", $d); # go to detail after save
$ret .= FW_hidden("gplotName", $gp);
$ret .= FW_hidden("logdevicetype", $ldt);
if(defined($FW_pos{zoom}) && defined($FW_pos{off})) { # for showData if(defined($FW_pos{zoom}) && defined($FW_pos{off})) { # for showData
$ret .= FW_hidden("pos", "zoom=$FW_pos{zoom};off=$FW_pos{off}"); $ret .= FW_hidden("pos", "zoom=$FW_pos{zoom};off=$FW_pos{off}");
} }
@ -314,22 +334,39 @@ SVG_PEdit($$$$)
$ret .= "</tr>"; $ret .= "</tr>";
my $max = @{$conf{lType}}+1; my $max = @{$conf{lType}}+1;
my ($desc, $htmlArr, $example) = ("Spec", undef, ""); my ($desc, $cnt) = ("Spec", 0);
if($modules{$ldt}{SVG_sampleDataFn}) { my (@srcHtml, @paramHtml, @exampleHtml, @revIdx);
my @srcNames = grep { $modules{$defs{$_}{TYPE}}{SVG_sampleDataFn} }
sort keys %defs;
foreach my $src (@{$srcDesc->{order}}) {
my $lmax = $srcDesc->{src}{$src}{idx}+1;
my $fn = $modules{$defs{$src}{TYPE}}{SVG_sampleDataFn};
my @argArr = split(" ", $srcDesc->{src}{$src}{arg});
if($fn) {
no strict "refs"; no strict "refs";
($desc, $htmlArr, $example) = my ($ldesc, $paramHtml, $example) =
&{$modules{$ldt}{SVG_sampleDataFn}}($ld, $flog, $max,\%conf, $FW_wname); &{$fn}($src, \@argArr, $lmax,\%conf, $FW_wname);
use strict "refs"; use strict "refs";
$desc = $ldesc;
push @paramHtml, @{$paramHtml};
map { push @exampleHtml, $example } (0..$lmax-1);
} else { } else {
my @htmlArr; push @paramHtml, map { SVG_txt("par_${_}_0","",$_,20) } @argArr;
@htmlArr = map { SVG_txt("par_${_}_0","",$flog->[$_] ? $flog->[$_]:"",20) } map { push @exampleHtml, "" } (0..$lmax-1);
(0..$max-1);
$htmlArr = \@htmlArr;
} }
$ret .= "<tr class=\"odd\"><td>Diagramm label</td>"; push @srcHtml,
$ret .= "<td>$desc</td>"; map { FW_select(undef,"src_$_",\@srcNames,$src,"svgSrc");} (0..$lmax-1);
$ret .=" <td>Y-Axis,Plot-Type,Style,Width</td></tr>"; map { push @revIdx,$srcDesc->{rev}{$cnt}{$_}; } (0..$lmax-1);
$cnt++;
}
# Last, empty line
push @revIdx,int(@revIdx);
push @srcHtml, $srcHtml[0];
push @paramHtml, $paramHtml[0];
push @exampleHtml, $exampleHtml[0];
my @lineStyles; my @lineStyles;
if(SVG_openFile($FW_cssdir, if(SVG_openFile($FW_cssdir,
@ -338,33 +375,46 @@ SVG_PEdit($$$$)
close(FH); close(FH);
} }
my $r = 0; $ret .= "<tr class=\"odd\"><td>Diagramm label, Source</td>";
$ret .= "<td>$desc</td>";
$ret .=" <td>Y-Axis,Plot-Type,Style,Width</td></tr>";
my ($r, $example, @output) = (0, "");
for($r=0; $r < $max; $r++) { for($r=0; $r < $max; $r++) {
$ret .= "<tr class=\"".(($r&1)?"odd":"even")."\"><td>"; my $idx = $revIdx[$r];
$ret .= SVG_txt("title_${r}", "", !$conf{lTitle}[$r]&&$r<($max-1) ? $example .= "<div class='ex ex_$idx' style='display:".($idx?"none":"block").
"notitle" : $conf{lTitle}[$r], 12); "'>$exampleHtml[$r]</div>";
$ret .= "</td><td>"; my $o = "<tr row='$idx' class=\"".(($r&1)?"odd":"even")."\"><td>";
$ret .= $htmlArr->[$r] if($htmlArr && @{$htmlArr} > $r); $o .= SVG_txt("title_$idx", "", !$conf{lTitle}[$idx]&&$idx<($max-1) ?
$ret .= "</td><td>"; "notitle" : $conf{lTitle}[$idx], 12);
my $v = $conf{lAxis}[$r]; my $sh = $srcHtml[$r]; $sh =~ s/src_\d+/src_$idx/g;
$ret .= SVG_sel("axes_${r}", "left,right", $o .= $sh;
$o .= "</td><td>";
my $ph = $paramHtml[$r]; $ph =~ s/par_\d+_/par_${idx}_/g;
$o .= $ph;
$o .= "</td><td>";
my $v = $conf{lAxis}[$idx];
$o .= SVG_sel("axes_${idx}", "left,right",
($v && $v eq "x1y1") ? "left" : "right"); ($v && $v eq "x1y1") ? "left" : "right");
$ret .= SVG_sel("type_${r}", "lines,points,steps,fsteps,histeps,bars", $o .= SVG_sel("type_${idx}", "lines,points,steps,fsteps,histeps,bars",
$conf{lType}[$r]); $conf{lType}[$idx]);
my $ls = $conf{lStyle}[$r]; my $ls = $conf{lStyle}[$idx];
if($ls) { if($ls) {
$ls =~ s/class=//g; $ls =~ s/class=//g;
$ls =~ s/"//g; $ls =~ s/"//g;
} }
$ret .= SVG_sel("style_${r}", join(",", @lineStyles), $ls); $o .= SVG_sel("style_$idx", join(",", @lineStyles), $ls);
my $lw = $conf{lWidth}[$r]; my $lw = $conf{lWidth}[$idx];
if($lw) { if($lw) {
$lw =~ s/.*stroke-width://g; $lw =~ s/.*stroke-width://g;
$lw =~ s/"//g; $lw =~ s/"//g;
} }
$ret .= SVG_sel("width_${r}", "0.2,0.5,1,1.5,2,3,4", ($lw ? $lw : 1)); $o .= SVG_sel("width_$idx", "0.2,0.5,1,1.5,2,3,4", ($lw ? $lw : 1));
$ret .= "</td></tr>"; $o .= "</td></tr>";
$output[$idx] = $o;
} }
$ret .= join("", @output);
$ret .= "<tr class=\"".(($r++&1)?"odd":"even")."\"><td colspan=\"3\">"; $ret .= "<tr class=\"".(($r++&1)?"odd":"even")."\"><td colspan=\"3\">";
$ret .= "Example lines for input:<br>$example</td></tr>"; $ret .= "Example lines for input:<br>$example</td></tr>";
@ -374,6 +424,32 @@ SVG_PEdit($$$$)
"</td></tr>"; "</td></tr>";
$ret .= "</table></form>"; $ret .= "</table></form>";
my $sl = "$FW_ME/SVG_WriteGplot?detail=$d&showFileLogData=1";
if(defined($FW_pos{zoom}) && defined($FW_pos{off})) {
$sl .= "&pos=zoom=$FW_pos{zoom};off=$FW_pos{off}";
}
$ret .= <<'EOF';
<script type="text/javascript">
var sel = "table.plotEditor tr[row] ";
$(sel+"input,"+sel+"select").focus(function(){
var row = $(this).closest("tr").attr("row");
$("table.plotEditor div.ex").css("display","none");
$("table.plotEditor div.ex_"+row).css("display","block");
});
$("table.plotEditor input[name=title_0]").focus();
$("table.plotEditor input[name=showFileLogData]").click(function(e){
e.preventDefault();
EOF
$ret .=
"FW_cmd('$sl', function(arg){" .<<'EOF';
FW_okDialog(arg);
});
});
</script>
EOF
return $ret;
} }
################## ##################
@ -439,6 +515,7 @@ SVG_zoomLink($$$)
} }
# Debugging: show the data received from GET
sub sub
SVG_showData() SVG_showData()
{ {
@ -446,17 +523,15 @@ SVG_showData()
my $hash = $defs{$wl}; my $hash = $defs{$wl};
my ($d, $gplotfile, $file) = split(":", $hash->{DEF}); my ($d, $gplotfile, $file) = split(":", $hash->{DEF});
$gplotfile = "$FW_gplotdir/$gplotfile.gplot"; $gplotfile = "$FW_gplotdir/$gplotfile.gplot";
my ($err, $cfg, $plot, $flog) = SVG_readgplotfile($wl, $gplotfile); my $pm = AttrVal($d,"plotmode",$FW_plotmode);
my ($err, $cfg, $plot, $srcDesc) = SVG_readgplotfile($wl, $gplotfile, $pm);
if($err) { if($err) {
$FW_RET=$err; $FW_RET=$err;
return 1; return 1;
} }
SVG_calcOffsets($d, $wl); SVG_calcOffsets($d, $wl);
my ($f,$t)=($SVG_devs{$d}{from}, $SVG_devs{$d}{to}); $FW_RET = SVG_getData($d, $SVG_devs{$d}{from}, $SVG_devs{$d}{to}, $srcDesc,1);
my $cmd = "get $d $file - $f $t " . join(" ", @{$flog}); $FW_RET =~ s/\n/<br>/gs;
my $ret = FW_fC($cmd, 1);
$ret =~ s/\n/<br>/gs;
$FW_RET = "$cmd<br><br>$ret";
return 1; return 1;
} }
@ -480,7 +555,8 @@ SVG_WriteGplot($)
} }
return 0 if(!$maxLines); return 0 if(!$maxLines);
my $fName = $FW_webArgs{gplotName}; my $wlName = $FW_webArgs{detail};
my $fName = "$FW_gplotdir/$defs{$wlName}{GPLOTFILE}.gplot";
return if(!$fName); return if(!$fName);
my @rows; my @rows;
@ -501,7 +577,6 @@ SVG_WriteGplot($)
push @rows, "set y2range $FW_webArgs{y2range}" if($FW_webArgs{y2range}); push @rows, "set y2range $FW_webArgs{y2range}" if($FW_webArgs{y2range});
push @rows, ""; push @rows, "";
my $ld = $FW_webArgs{logdevicetype};
my @plot; my @plot;
for(my $i=0; $i <= $maxLines; $i++) { for(my $i=0; $i <= $maxLines; $i++) {
next if(!$FW_webArgs{"title_$i"}); next if(!$FW_webArgs{"title_$i"});
@ -512,7 +587,8 @@ SVG_WriteGplot($)
join(":", map { $v[$_] =~ s/:/\\x3a/g if($_<$#v); $v[$_] } 0..$#v) : join(":", map { $v[$_] =~ s/:/\\x3a/g if($_<$#v); $v[$_] } 0..$#v) :
$v[0]; $v[0];
push @rows, "#$ld $r"; my $src = $FW_webArgs{"src_$i"};
push @rows, "#$src $r";
push @plot, "\"<IN>\" using 1:2 axes ". push @plot, "\"<IN>\" using 1:2 axes ".
($FW_webArgs{"axes_$i"} eq "right" ? "x1y2" : "x1y1"). ($FW_webArgs{"axes_$i"} eq "right" ? "x1y2" : "x1y1").
($FW_webArgs{"title_$i"} eq "notitle" ? " notitle" : ($FW_webArgs{"title_$i"} eq "notitle" ? " notitle" :
@ -536,31 +612,51 @@ SVG_WriteGplot($)
return 0; return 0;
} }
#######################################################
# srcDesc:
# - {all} : space separated plot arguments, in the file order, without devname
# - {order}: unique name of the devs (FileLog,etc) in the .gplot order
# - {src}{X}: hash (X is an order element), consisting of
# {arg}: plot arguments for one dev, space separated
# {idx}: number of lines requested from the same source
# {num}: number or this src in the order array
# - {rev}{orderIdx}{localIdx} = N: reverse lookup of the plot argument index,
# using {src}{X}{num} as orderIdx and {src}{X}{idx} as localIdx
sub sub
SVG_readgplotfile($$) SVG_readgplotfile($$$)
{ {
my ($wl, $gplot_pgm) = @_; my ($wl, $gplot_pgm, $plotmode) = @_;
############################ ############################
# Read in the template gnuplot file. Digest the #FileLog lines. Replace # Read in the template gnuplot file. Digest the #FileLog lines. Replace
# the plot directive with our own, as we offer a file for each line # the plot directive with our own, as we offer a file for each line
my (@filelog, @data, $plot); my (%srcDesc, @data, $plot);
my $ld = $defs{$wl}{LOGDEVICE}
if($defs{$wl} && $defs{$wl}{LOGDEVICE});
my $ldType = $defs{$defs{$wl}{LOGDEVICE}}{TYPE} my $ldType = $defs{$defs{$wl}{LOGDEVICE}}{TYPE}
if($defs{$wl} && $defs{$wl}{LOGDEVICE} && $defs{$defs{$wl}{LOGDEVICE}}); if($ld && $defs{$ld});
$ldType = $defs{$wl}{TYPE} if(!$ldType && $defs{$wl}) {
if(!$ldType && $defs{$wl}); $ldType = $defs{$wl}{TYPE};
$ld = $wl;
}
my ($err, @svgplotfile) = FileRead($gplot_pgm); my ($err, @svgplotfile) = FileRead($gplot_pgm);
return ("$err", undef) if($err); return ("$err", undef) if($err);
my ($plotfnCnt, $srcNum) = (0,0);
my @empty;
$srcDesc{all} = "";
$srcDesc{order} = \@empty;
foreach my $l (@svgplotfile) { foreach my $l (@svgplotfile) {
$l = "$l\n" unless $l =~ m/\n$/; $l = "$l\n" unless $l =~ m/\n$/;
my $plotfn = undef; my ($src, $plotfn) = (undef, undef);
if($l =~ m/^#$ldType (.*)$/) { if($l =~ m/^#([^ ]*) (.*)$/) {
$plotfn = $1; if($1 eq $ldType) {
Log 3, "$wl: space is not allowed in $ldType definition: $plotfn" $src = $ld; $plotfn = $2;
if($plotfn =~ m/\s/); } elsif($defs{$1}) {
$src = $1; $plotfn = $2;
}
} elsif($l =~ "^plot" || $plot) { } elsif($l =~ "^plot" || $plot) {
$plot .= $l; $plot .= $l;
} else { } else {
@ -568,6 +664,8 @@ SVG_readgplotfile($$)
} }
if($plotfn) { if($plotfn) {
Log 3, "$wl: space is not allowed in $ldType definition: $plotfn"
if($plotfn =~ m/\s/);
my $specval = AttrVal($wl, "plotfunction", undef); my $specval = AttrVal($wl, "plotfunction", undef);
if ($specval) { if ($specval) {
my @spec = split(" ",$specval); my @spec = split(" ",$specval);
@ -577,11 +675,22 @@ SVG_readgplotfile($$)
$spec_count++; $spec_count++;
} }
} }
push(@filelog, $plotfn);
my $p = $srcDesc{src}{$src};
if(!$p) {
$p = { arg => $plotfn, idx=>0, num=>$srcNum++ };
$srcDesc{src}{$src} = $p;
push(@{$srcDesc{order}}, $src);
} else {
$p->{arg} .= " $plotfn";
$p->{idx}++;
}
$srcDesc{rev}{$p->{num}}{$p->{idx}} = $plotfnCnt++;
$srcDesc{all} .= " $plotfn";
} }
} }
return (undef, \@data, $plot, \@filelog); return (undef, \@data, $plot, \%srcDesc);
} }
sub sub
@ -592,9 +701,6 @@ SVG_substcfg($$$$$$)
# interpret title and label as a perl command and make # interpret title and label as a perl command and make
# to all internal values e.g. $value. # to all internal values e.g. $value.
my $oll = $attr{global}{verbose};
$attr{global}{verbose} = 0; # Else the filenames will be Log'ged
my $ldt = $defs{$defs{$wl}{LOGDEVICE}}{TYPE} my $ldt = $defs{$defs{$wl}{LOGDEVICE}}{TYPE}
if($defs{$wl} && $defs{$wl}{LOGDEVICE}); if($defs{$wl} && $defs{$wl}{LOGDEVICE});
$ldt = "" if(!defined($ldt)); $ldt = "" if(!defined($ldt));
@ -605,17 +711,17 @@ SVG_substcfg($$$$$$)
my $fileesc = $file; my $fileesc = $file;
$fileesc =~ s/\\/\\\\/g; # For Windows, by MarkusRR $fileesc =~ s/\\/\\\\/g; # For Windows, by MarkusRR
my $title = AttrVal($wl, "title", "\"$fileesc\""); my $title = AttrVal($wl, "title", "\"$fileesc\"");
my $allowed = AttrVal($FW_wname,"allowedCommands",undef);
$title = AnalyzeCommand(undef, "{ $title }"); $title = AnalyzeCommand(undef, "{ $title }", $allowed);
my $label = AttrVal($wl, "label", undef); my $label = AttrVal($wl, "label", undef);
my @g_label; my @g_label;
if ($label) { if ($label) {
@g_label = split("::",$label); @g_label = split("::",$label);
foreach (@g_label) { foreach (@g_label) {
$_ = AnalyzeCommand(undef, "{ $_ }"); $_ = AnalyzeCommand(undef, "{ $_ }", $allowed);
} }
} }
$attr{global}{verbose} = $oll;
my $gplot_script = join("", @{$cfg}); my $gplot_script = join("", @{$cfg});
$gplot_script .= $plot if(!$splitret); $gplot_script .= $plot if(!$splitret);
@ -623,7 +729,7 @@ SVG_substcfg($$$$$$)
$gplot_script =~ s/<OUT>/$tmpfile/g; $gplot_script =~ s/<OUT>/$tmpfile/g;
$gplot_script =~ s/<IN>/$file/g; $gplot_script =~ s/<IN>/$file/g;
my $ps = AttrVal($wl,"plotsize",$FW_plotsize); my $ps = SVG_getplotsize($wl);
$gplot_script =~ s/<SIZE>/$ps/g; $gplot_script =~ s/<SIZE>/$ps/g;
$gplot_script =~ s/<TL>/$title/g; $gplot_script =~ s/<TL>/$title/g;
@ -816,10 +922,9 @@ SVG_doShowLog($$$$;$$)
{ {
my ($wl, $d, $type, $file, $styleW, $styleH) = @_; my ($wl, $d, $type, $file, $styleW, $styleH) = @_;
my $pm = AttrVal($wl,"plotmode",$FW_plotmode); my $pm = AttrVal($wl,"plotmode",$FW_plotmode);
my $gplot_pgm = "$FW_gplotdir/$type.gplot"; my $gplot_pgm = "$FW_gplotdir/$type.gplot";
my ($err, $cfg, $plot, $flog) = SVG_readgplotfile($wl, $gplot_pgm); my ($err, $cfg, $plot, $srcDesc) = SVG_readgplotfile($wl, $gplot_pgm, $pm);
if($err || !$defs{$d}) { if($err || !$defs{$d}) {
my $msg = ($defs{$d} ? "Cannot read $gplot_pgm" : "No Logdevice $d"); my $msg = ($defs{$d} ? "Cannot read $gplot_pgm" : "No Logdevice $d");
Log3 $FW_wname, 1, $msg; Log3 $FW_wname, 1, $msg;
@ -851,8 +956,8 @@ SVG_doShowLog($$$$;$$)
# Read the data from the filelog # Read the data from the filelog
my $oll = $attr{global}{verbose}; my $oll = $attr{global}{verbose};
$attr{global}{verbose} = 0; # Else the filenames will be Log'ged $attr{global}{verbose} = 0; # Else the filenames will be Log'ged
my @path = split(" ", FW_fC("get $d $file $tmpfile $f $t " . my @path = split(" ",
join(" ", @{$flog}))); FW_fC("get $d $file $tmpfile $f $t $srcDesc->{all}"));
$attr{global}{verbose} = $oll; $attr{global}{verbose} = $oll;
# replace the path with the temporary filenames of the filelog output # replace the path with the temporary filenames of the filelog output
@ -878,8 +983,8 @@ SVG_doShowLog($$$$;$$)
my ($f,$t)=($SVG_devs{$d}{from}, $SVG_devs{$d}{to}); my ($f,$t)=($SVG_devs{$d}{from}, $SVG_devs{$d}{to});
my $oll = $attr{global}{verbose}; my $oll = $attr{global}{verbose};
$attr{global}{verbose} = 0; # Else the filenames will be Log'ged $attr{global}{verbose} = 0; # Else the filenames will be Log'ged
my @path = split(" ", FW_fC("get $d $file $tmpfile $f $t " . my @path = split(" ",
join(" ", @{$flog}))); FW_fC("get $d $file $tmpfile $f $t $srcDesc->{all}"));
$attr{global}{verbose} = $oll; $attr{global}{verbose} = $oll;
# replace the path with the temporary filenames of the filelog output # replace the path with the temporary filenames of the filelog output
@ -915,8 +1020,7 @@ SVG_doShowLog($$$$;$$)
$f = 0 if(!$f); # From the beginning of time... $f = 0 if(!$f); # From the beginning of time...
$t = 9 if(!$t); # till the end $t = 9 if(!$t); # till the end
Log3 $FW_wname, 5, Log3 $FW_wname, 5, "plotcommand: get $d $file INT $f $t ".$srcDesc->{all};
"plotcommand: get $d $file INT $f $t " . join(" ", @{$flog});
$FW_RETTYPE = "image/svg+xml"; $FW_RETTYPE = "image/svg+xml";
@ -929,10 +1033,10 @@ SVG_doShowLog($$$$;$$)
close(CFH); close(CFH);
} else { } else {
FW_fC("get $d $file INT $f $t " . join(" ", @{$flog}), 1); my $da = SVG_getData($wl, $f, $t, $srcDesc, 0); # substcfg needs it(!)
($cfg, $plot) = SVG_substcfg(1, $wl, $cfg, $plot, $file, "<OuT>"); ($cfg, $plot) = SVG_substcfg(1, $wl, $cfg, $plot, $file, "<OuT>");
my $ret = SVG_render($wl, $f, $t, $cfg, my $ret = SVG_render($wl, $f, $t, $cfg, $da,
$internal_data, $plot, $FW_wname, $FW_cssdir, $flog, $plot, $FW_wname, $FW_cssdir, $srcDesc,
$styleW, $styleH); $styleW, $styleH);
$internal_data = ""; $internal_data = "";
FW_pO $ret; FW_pO $ret;
@ -950,6 +1054,58 @@ SVG_doShowLog($$$$;$$)
} }
sub
SVG_getData($$$$$)
{
my ($d, $f,$t,$srcDesc,$showData) = @_;
my (@da, $ret, @vals);
my @keys = ("min","max","avg","cnt","currval","mindate","maxdate","lastraw");
foreach my $src (@{$srcDesc->{order}}) {
my $s = $srcDesc->{src}{$src};
my $fname = ($src eq $defs{$d}{LOGDEVICE} ? $defs{$d}{LOGFILE} : "CURRENT");
my $cmd = "get $src $fname INT $f $t ".$s->{arg};
FW_fC($cmd);
if($showData) {
$ret .= "\n$cmd\n\n";
$ret .= $$internal_data;
} else {
push(@da, $internal_data);
for(my $i = 0; $i<=$s->{idx}; $i++) {
my %h;
foreach my $k (@keys) {
$h{$k} = $data{$k.($i+1)};
}
push @vals, \%h;
}
}
}
# Reorder the $data{maxX} stuff
my ($min, $max) = (999999, -999999);
my $no = int(keys %{$srcDesc->{rev}});
for(my $oi = 0; $oi < $no; $oi++) {
my $nl = int(keys %{$srcDesc->{rev}{$oi}});
for(my $li = 0; $li < $nl; $li++) {
my $r = $srcDesc->{rev}{$oi}{$li}+1;
my $val = shift @vals;
foreach my $k (@keys) {
$min = $val->{$k}
if($k eq "min" && defined($val->{$k}) && $val->{$k} < $min);
$max = $val->{$k}
if($k eq "max" && defined($val->{$k}) && $val->{$k} > $max);
$data{"$k$r"} = $val->{$k};
}
}
}
$data{maxAll} = $max;
$data{minAll} = $min;
return $ret if($showData);
return \@da;
}
###################### ######################
# Convert the configuration to a "readable" form -> array to hash # Convert the configuration to a "readable" form -> array to hash
@ -1051,17 +1207,16 @@ SVG_render($$$$$$$$$;$$)
my $from = shift; # e.g. 2008-01-01 my $from = shift; # e.g. 2008-01-01
my $to = shift; # e.g. 2009-01-01 my $to = shift; # e.g. 2009-01-01
my $confp = shift; # lines from the .gplot file, w/o FileLog and plot my $confp = shift; # lines from the .gplot file, w/o FileLog and plot
my $dp = shift; # pointer to data (one string) my $da = shift; # data pointer array
my $plot = shift; # Plot lines from the .gplot file my $plot = shift; # Plot lines from the .gplot file
my $parent_name = shift; # e.g. FHEMWEB instance name my $parent_name = shift; # e.g. FHEMWEB instance name
my $parent_dir = shift; # FW_dir my $parent_dir = shift; # FW_dir
my $flog = shift; # #FileLog lines, as array pointer my $srcDesc = shift; # #FileLog lines, as array pointer
my $styleW = shift; my $styleW = shift;
my $styleH = shift; my $styleH = shift;
$SVG_RET=""; $SVG_RET="";
my $SVG_ss = AttrVal($parent_name, "smallscreen", 0); my $SVG_ss = AttrVal($parent_name, "smallscreen", 0);
return $SVG_RET if(!defined($dp) || $dp eq "");
my $nr_axis = AttrVal($parent_name,"nrAxis","1,1"); my $nr_axis = AttrVal($parent_name,"nrAxis","1,1");
my ($nr_left_axis,$nr_right_axis,$use_left_axis,$use_right_axis) = my ($nr_left_axis,$nr_right_axis,$use_left_axis,$use_right_axis) =
@ -1084,23 +1239,24 @@ SVG_render($$$$$$$$$;$$)
my $w = $ow-$nr_left_axis*$axis_width-$nr_right_axis*$axis_width; my $w = $ow-$nr_left_axis*$axis_width-$nr_right_axis*$axis_width;
my $h = $oh-2*$y; # Rect size my $h = $oh-2*$y; # Rect size
# Keep only the Filter part of the #FileLog my $filter = $srcDesc->{all};
$flog = join(" ", map { my @a=split(":",$_); $filter =~ s/[^: ]*:([^: ]):[^ ]*/$1/g;
$a[1]=~s/\.[^\.]*$//; $a[1]; } @{$flog}); $filter = AttrVal($parent_name, "longpollSVG", 0) ? "flog=\" $filter \"" : "";
$flog = AttrVal($parent_name, "longpollSVG", 0) ? "flog=\" $flog \"" : "";
my %dataIdx; # Build a reverse Index for the dataSource
###################### ######################
# Html Header # SVG Header
my $svghdr = 'version="1.1" xmlns="http://www.w3.org/2000/svg" '.
'xmlns:xlink="http://www.w3.org/1999/xlink" '.
'id="SVGPLOT_'.(++$SVG_id).'"'.$filter;
if(!$styleW) { if(!$styleW) {
SVG_pO '<?xml version="1.0" encoding="UTF-8"?>'; SVG_pO '<?xml version="1.0" encoding="UTF-8"?>';
SVG_pO '<!DOCTYPE svg>'; SVG_pO '<!DOCTYPE svg>';
SVG_pO '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" '. SVG_pO "<svg $svghdr>";
'xmlns:xlink="http://www.w3.org/1999/xlink" '.$flog.'>';
} else { } else {
SVG_pO '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" '. SVG_pO "<svg $svghdr style='width:${styleW}px; height:${styleH}px;'>";
'xmlns:xlink="http://www.w3.org/1999/xlink" '.
"style='width:${styleW}px; height:${styleH}px;' ".
'>';
} }
my $prf = AttrVal($parent_name, "stylesheetPrefix", ""); my $prf = AttrVal($parent_name, "stylesheetPrefix", "");
@ -1134,17 +1290,6 @@ SVG_render($$$$$$$$$;$$)
SVG_pO "<text id=\"svg_title\" x=\"$off1\" y=\"$off2\" " . SVG_pO "<text id=\"svg_title\" x=\"$off1\" y=\"$off2\" " .
"class=\"title\" text-anchor=\"middle\">$title</text>"; "class=\"title\" text-anchor=\"middle\">$title</text>";
######################
# Copy and Paste labels, hidden by default
SVG_pO "<text id=\"svg_paste\" x=\"" .
($ow-$axis_width-$nr_right_axis*$axis_width) . "\" y=\"$off2\" " .
"onclick=\"parent.svg_paste(evt)\" " .
"class=\"paste\" text-anchor=\"end\"> </text>";
SVG_pO "<text id=\"svg_copy\" x=\"" .
($ow-$nr_right_axis*$axis_width) . "\" y=\"$off2\" " .
"onclick=\"parent.svg_copy(evt)\" " .
"class=\"copy\" text-anchor=\"end\"> </text>";
###################### ######################
# Left label = ylabel and right label = y2label # Left label = ylabel and right label = y2label
if(!$SVG_ss) { if(!$SVG_ss) {
@ -1198,7 +1343,10 @@ SVG_render($$$$$$$$$;$$)
my ($dxp, $dyp) = (\(), \()); my ($dxp, $dyp) = (\(), \());
my ($d, $v, $ld, $lv) = ("","","",""); my ($d, $v, $ld, $lv) = ("","","","");
for(my $dIdx=0; $dIdx<@{$da}; $dIdx++) {
my $lIdx = 0;
$idx = $srcDesc->{rev}{$dIdx}{$lIdx};
my $dp = $da->[$dIdx];
my ($dpl,$dpoff,$l) = (length($$dp), 0, ""); my ($dpl,$dpoff,$l) = (length($$dp), 0, "");
while($dpoff < $dpl) { # using split instead is memory hog while($dpoff < $dpl) { # using split instead is memory hog
my $ndpoff = index($$dp, "\n", $dpoff); my $ndpoff = index($$dp, "\n", $dpoff);
@ -1217,7 +1365,9 @@ SVG_render($$$$$$$$$;$$)
($min, $max) = (99999999, -99999999); ($min, $max) = (99999999, -99999999);
$hdx[$idx] = $dxp; $hdy[$idx] = $dyp; $hdx[$idx] = $dxp; $hdy[$idx] = $dyp;
($dxp, $dyp) = (\(), \()); ($dxp, $dyp) = (\(), \());
$idx++; $lIdx++;
$idx = $srcDesc->{rev}{$dIdx}{$lIdx};
last if(!$idx);
} elsif( $l =~ /^;/ ) { #allow ;special lines } elsif( $l =~ /^;/ ) { #allow ;special lines
if( $l =~ m/^;p (\S+)\s(\S+)/ ) {# point if( $l =~ m/^;p (\S+)\s(\S+)/ ) {# point
@ -1252,6 +1402,7 @@ SVG_render($$$$$$$$$;$$)
} }
last if($ndpoff == -1); last if($ndpoff == -1);
} }
}
$dxp = $hdx[0]; $dxp = $hdx[0];
if(($dxp && int(@{$dxp}) < 2 && !$tosec) || # not enough data and no range... if(($dxp && int(@{$dxp}) < 2 && !$tosec) || # not enough data and no range...
@ -1392,6 +1543,7 @@ SVG_render($$$$$$$$$;$$)
my (%hstep,%htics,%axdrawn); my (%hstep,%htics,%axdrawn);
my $allowed = AttrVal($FW_wname,"allowedCommands",undef);
#-- yrange handling for axes x1y1..x1y8 #-- yrange handling for axes x1y1..x1y8
for my $idx (0..7) { for my $idx (0..7) {
my $a = "x1y".($idx+1); my $a = "x1y".($idx+1);
@ -1399,10 +1551,15 @@ SVG_render($$$$$$$$$;$$)
my $yra="y".($idx+1)."range"; my $yra="y".($idx+1)."range";
$yra="yrange" if ($yra eq "y1range"); $yra="yrange" if ($yra eq "y1range");
#-- yrange is specified in plotfile #-- yrange is specified in plotfile
if($conf{$yra} && $conf{$yra} =~ /\[(.*):(.*)\]/) { if($conf{$yra}) {
$conf{$yra} = AnalyzeCommand(undef, $1, $allowed)
if($conf{$yra} =~ /^({.*})$/);
if($conf{$yra} =~ /\[(.*):(.*)\]/) {
$hmin{$a} = $1 if($1 ne ""); $hmin{$a} = $1 if($1 ne "");
$hmax{$a} = $2 if($2 ne ""); $hmax{$a} = $2 if($2 ne "");
} }
}
#-- tics handling #-- tics handling
my $yt="y".($idx+1)."tics"; my $yt="y".($idx+1)."tics";
$yt="ytics" if ($yt eq"y1tics"); $yt="ytics" if ($yt eq"y1tics");
@ -1732,13 +1889,15 @@ SVG_render($$$$$$$$$;$$)
} }
my $style = $conf{lStyle}[$i]; my $style = $conf{lStyle}[$i];
$style =~ s/class="/class="legend /; $style =~ s/class="/class="legend /;
SVG_pO "<text title=\"$desc\" ". SVG_pO "<text title=\"$desc\" line_id=\"line_$i\" " .
"onclick=\"parent.svg_labelselect(evt)\" line_id=\"line_$i\" " .
"x=\"$txtoff1\" y=\"$txtoff2\" text-anchor=\"end\" $style>$t</text>"; "x=\"$txtoff1\" y=\"$txtoff2\" text-anchor=\"end\" $style>$t</text>";
$txtoff2 += $th; $txtoff2 += $th;
} }
my $fnName = SVG_isEmbed($FW_wname) ? "parent.window.svg_init" : "svg_init";
SVG_pO "<script type='text/javascript'>if(typeof $fnName == 'function') ".
"$fnName('SVGPLOT_$SVG_id')</script>";
SVG_pO "</svg>"; SVG_pO "</svg>";
return $SVG_RET; return $SVG_RET;
} }
@ -1974,6 +2133,9 @@ plotAsPng(@)
set title &lt;L1&gt;<br></li> set title &lt;L1&gt;<br></li>
</ul></li> </ul></li>
</ul> </ul>
The value minAll and maxAll (representing the minimum/maximum over all
values) is also available from the data hash.
</li> </li>
<a name="title"></a> <a name="title"></a>
@ -2025,6 +2187,9 @@ plotAsPng(@)
regexp switch.on, and "0" for the regexp switch.off.<br> regexp switch.on, and "0" for the regexp switch.off.<br>
Write .gplot file again<br> Write .gplot file again<br>
</ul></li> </ul></li>
<li>If the range is of the form {...}, then it will be evaluated with perl.
The result is a string, and must have the form [min:max]
</li>
</ul> </ul>
The visibility of the ploteditor can be configured with the FHEMWEB attribute The visibility of the ploteditor can be configured with the FHEMWEB attribute
<a href="#ploteditor">ploteditor</a>. <a href="#ploteditor">ploteditor</a>.
@ -2142,7 +2307,7 @@ plotAsPng(@)
k&ouml;nnen ebenfalls die Werte der individuellen Kurve f&uuml;r min, k&ouml;nnen ebenfalls die Werte der individuellen Kurve f&uuml;r min,
max, mindate, maxdate, avg, cnt, sum, currval (letzter Wert) und currdate max, mindate, maxdate, avg, cnt, sum, currval (letzter Wert) und currdate
(letztes Datum) durch Zugriff der entsprechenden Werte &uuml;ber das (letztes Datum) durch Zugriff der entsprechenden Werte &uuml;ber das
DataHash verwendet werden. Siehe untenstehendes Beispiel:<br> data Hash verwendet werden. Siehe untenstehendes Beispiel:<br>
<ul> <ul>
<li>Beschriftunng der rechten und linken y-Achse:<br> <li>Beschriftunng der rechten und linken y-Achse:<br>
<ul> <ul>
@ -2164,6 +2329,8 @@ plotAsPng(@)
</ul> </ul>
</li> </li>
</ul> </ul>
Die Werte minAll und maxAll (die das Minimum/Maximum aller Werte
repr&auml;sentieren) sind ebenfals im data hash vorhanden.
</li> </li>
<a name="title"></a> <a name="title"></a>
@ -2229,6 +2396,9 @@ plotAsPng(@)
.gplot-Datei erneut speichern<br> .gplot-Datei erneut speichern<br>
</ul> </ul>
</li> </li>
<li>Falls Range der Form {...} entspricht, dann wird sie als Perl -
Expression ausgewertet. Das Ergebnis muss in der Form [min:max] sein.
</li>
</ul> </ul>
Die sichtbarkeit des Plot-Editors kann mit dem FHEMWEB Attribut <a Die sichtbarkeit des Plot-Editors kann mit dem FHEMWEB Attribut <a
href="#ploteditor">ploteditor</a> konfiguriert werden. href="#ploteditor">ploteditor</a> konfiguriert werden.

View File

@ -17,81 +17,9 @@ Color_Initialize()
sub sub
FHEM_colorpickerInit() FHEM_colorpickerInit()
{ {
$data{webCmdFn}{colorpicker} = "FHEM_colorpickerFn";
$data{FWEXT}{colorpicker}{SCRIPT} = "/jscolor/jscolor.js"; $data{FWEXT}{colorpicker}{SCRIPT} = "/jscolor/jscolor.js";
} }
sub
FHEM_colorpickerFn($$$$$)
{
#return undef;
my ($FW_wname, $d, $FW_room, $cmd, $values) = @_;
my @args = split("[ \t]+", $cmd);
my @value = split( ',', $values );
return undef if($values !~ m/^colorpicker,([^,]*)/);
my $mode = $1;
$mode = "RGB" if( !defined($mode) );
if( $mode eq "CT" ) {
if( !$args[1] && $data{webCmdFn}{slider} ) {
no strict "refs";
my $values = "slider,". join( ',', @value[2..4] );
my $htmlTxt = &{$data{webCmdFn}{slider}}($FW_wname, $d, $FW_room, $cmd, $values);
use strict "refs";
return $htmlTxt;
}
return undef if( !$args[1] );
}
my $trigger = $cmd; #default trigger is the event from the reading with the same name as the command
my $cv = ReadingsVal($d,$cmd,""); #get default value from this reading
if( !$cv ) { #if this reading does not exist ->
$trigger = "RGB"; # trigger name will be RGB
$cv = CommandGet("","$d $cmd"); # get default value from get command
}
$cmd = "" if($cmd eq "state");
my $srf = $FW_room ? "&room=$FW_room" : "";
if( $args[1] ) {
my $c = "cmd=set $d $cmd$srf";
if( $mode eq "CT" ) {
my $ct = $args[1];
my ($r, $g, $b) = Color::ct2rgb( $ct );
$args[1] = Color::rgb2hex( $r, $g, $b );
}
return '<td align="center">'.
"<div onClick=\"FW_cmd('$FW_ME?XHR=1&$c')\" style=\"width:32px;height:19px;".
'border:1px solid #fff;border-radius:8px;background-color:#'. $args[1] .';"></div>'.
'</td>' if( AttrVal($FW_wname, "longpoll", 1));
return '<td align="center">'.
"<a href=\"$FW_ME?$c\">".
'<div style="width:32px;height:19px;'.
'border:1px solid #fff;border-radius:8px;background-color:#'. $args[1] .';"></div>'.
'</a>'.
'</td>';
} elsif(AttrVal($d,"realtimePicker",0)) {
my $c = "$FW_ME?XHR=1&cmd=set $d $cmd %$srf";
my $ci = $c;
$ci = "$FW_ME?XHR=1&cmd=set $d $cmd % : transitiontime 0 : noUpdate$srf" if($defs{$d}->{TYPE} eq "HUEDevice");
return '<td align="center">'.
"<input maxlength='6' size='6' id='colorpicker.$d-$trigger' class=\"color {pickerMode:'$mode',pickerFaceColor:'transparent',pickerFace:3,pickerBorder:0,pickerInsetColor:'red',command:'$ci',onImmediateChange:'colorpicker_setColor(this)'}\" value='$cv' onChange='colorpicker_setColor(this,\"$mode\",\"$c\")'>".
'</td>';
} else {
my $c = "$FW_ME?XHR=1&cmd=set $d $cmd %$srf";
return '<td align="center">'.
"<input maxlength='6' size='6' id='colorpicker.$d-$trigger' class=\"color {pickerMode:'$mode',pickerFaceColor:'transparent',pickerFace:3,pickerBorder:0,pickerInsetColor:'red'}\" value='$cv' onChange='colorpicker_setColor(this,\"$mode\",\"$c\")'>".
'</td>';
}
}
my %dim_values = ( my %dim_values = (
0 => "dim06%", 0 => "dim06%",
1 => "dim12%", 1 => "dim12%",

View File

@ -1,4 +1,4 @@
#Mon Aug 26 16:36:31 2013 #Sun Jan 4 16:24:11 2015
{ {
'lcCinema' => { 'lcCinema' => {
'Break' => { 'Break' => {
@ -6,25 +6,25 @@
'ReadingLight' => 'dim37%' 'ReadingLight' => 'dim37%'
}, },
'Cinema' => { 'Cinema' => {
'Screen' => 'down',
'Projector' => 'on',
'CeilingLight' => 'off', 'CeilingLight' => 'off',
'Projector' => 'on',
'Screen' => 'down',
'ReadingLight' => 'off', 'ReadingLight' => 'off',
'TV' => 'off' 'TV' => 'off'
}, },
'WatchTV' => { 'WatchTV' => {
'Screen' => 'up',
'Projector' => 'off',
'CeilingLight' => 'off', 'CeilingLight' => 'off',
'Projector' => 'off',
'Screen' => 'up',
'ReadingLight' => 'dim12%', 'ReadingLight' => 'dim12%',
'TV' => 'on' 'TV' => 'on'
}, },
'AllOff' => { 'AllOff' => {
'Screen' => 'up',
'Projector' => 'off',
'CeilingLight' => 'off', 'CeilingLight' => 'off',
'Projector' => 'off',
'Screen' => 'up',
'ReadingLight' => 'off', 'ReadingLight' => 'off',
'TV' => 'off' 'TV' => 'off'
} }
} }
} }

View File

@ -1,13 +1,17 @@
#Mon Feb 17 20:54:16 2014 #Sun Jan 4 16:24:11 2015
setstate Alarm on setstate Alarm on
setstate Alarm 2013-08-23 07:42:48 state on setstate Alarm 2015-01-04 16:22:21 state on
setstate AllLights on setstate AllLights on
setstate AllLights 2013-08-25 14:23:20 LastDevice Office setstate AllLights 2015-01-04 16:22:04 LastDevice Alarm
setstate AllLights 2013-08-25 14:23:20 LastDevice_Abs Office setstate AllLights 2015-01-04 16:22:04 LastDevice_Abs Alarm
setstate AllLights 2013-08-25 14:23:20 state on setstate AllLights 2015-01-04 16:22:04 state undefined
setstate AllResidentsAway active setstate AllResidentsAway active
setstate CT off
setstate CT 2015-01-03 01:10:50 ct 3703
setstate CT 2015-01-04 13:30:52 lastCmd off
setstate CT 2015-01-04 16:22:04 state off
setstate CeilingLight dim0% setstate CeilingLight dim0%
setstate CeilingLight 2013-08-26 18:01:06 state off setstate CeilingLight 2015-01-04 16:22:40 state off
setstate Cellar T: 21.1 H: 54.6 setstate Cellar T: 21.1 H: 54.6
setstate Cellar 2013-08-13 08:00:48 DEVFAMILY WS300 setstate Cellar 2013-08-13 08:00:48 DEVFAMILY WS300
setstate Cellar 2013-08-13 08:00:48 DEVTYPE S300TH setstate Cellar 2013-08-13 08:00:48 DEVTYPE S300TH
@ -26,7 +30,7 @@ setstate Garden 2013-08-13 15:03:17 israining no
setstate Garden 2013-08-13 15:03:17 rain 81.9 setstate Garden 2013-08-13 15:03:17 rain 81.9
setstate Garden 2013-08-13 15:03:17 rain_raw 321 setstate Garden 2013-08-13 15:03:17 rain_raw 321
setstate Garden 2013-08-13 15:03:17 rain_raw_adj 321 setstate Garden 2013-08-13 15:03:17 rain_raw_adj 321
setstate Garden 2014-02-17 20:54:12 state defined setstate Garden 2015-01-04 16:19:04 state defined
setstate Garden 2013-08-13 15:03:17 temperature 18.3 setstate Garden 2013-08-13 15:03:17 temperature 18.3
setstate Garden 2013-08-13 15:03:17 tsecs 1376805797 setstate Garden 2013-08-13 15:03:17 tsecs 1376805797
setstate Garden 2013-08-13 15:03:17 unknown1 a setstate Garden 2013-08-13 15:03:17 unknown1 a
@ -34,36 +38,51 @@ setstate Garden 2013-08-13 15:03:17 unknown2 7
setstate Garden 2013-08-13 15:03:17 unknown3 1 setstate Garden 2013-08-13 15:03:17 unknown3 1
setstate Garden 2013-08-13 15:03:17 wind 0.5 setstate Garden 2013-08-13 15:03:17 wind 0.5
setstate Livingroom dim100% setstate Livingroom dim100%
setstate Livingroom 2013-08-23 07:57:21 state on setstate Livingroom 2015-01-04 16:22:21 state on
setstate Log.Cellar active setstate Log.Cellar active
setstate Log.Dewpoint active setstate Log.Dewpoint active
setstate Log.Garden active setstate Log.Garden active
setstate Logfile active setstate Logfile active
setstate Office on setstate Office on
setstate Office 2013-08-25 14:23:20 state on setstate Office 2015-01-04 16:22:21 state on
setstate Outdoor on setstate Outdoor on
setstate Outdoor 2013-08-25 14:23:20 state on setstate Outdoor 2015-01-04 16:22:21 state on
setstate Projector off setstate Projector off
setstate Projector 2013-08-26 18:01:06 state off setstate Projector 2015-01-04 16:22:40 state off
setstate ReadingLight dim12% setstate RGB off
setstate ReadingLight 2013-08-26 18:01:06 state dim12% setstate RGB 2015-01-04 12:55:47 hue 220
setstate RGB 2015-01-04 13:30:54 lastCmd off
setstate RGB 2015-01-04 12:55:47 rgb 0054FF
setstate RGB 2015-01-04 16:22:04 state off
setstate ReadingLight dim0%
setstate ReadingLight 2015-01-04 16:22:40 state off
setstate ResidentsComeHome active setstate ResidentsComeHome active
setstate SVG_01_Garden initialized setstate SVG_01_Garden initialized
setstate SVG_02_Cellar initialized setstate SVG_02_Cellar initialized
setstate SVG_03_Dewpoint initialized setstate SVG_03_Dewpoint initialized
setstate Screen up setstate Screen up
setstate Screen 2013-08-26 18:01:06 state up setstate Screen 2015-01-04 16:22:40 state up
setstate TV on setstate TV off
setstate TV 2013-08-26 18:01:06 state on setstate TV 2015-01-04 16:22:40 state off
setstate anyViews 2015-01-04 16:24:11 lockstate 0
setstate anyViews 2015-01-04 16:19:04 state Initialized
setstate anyViews_weblink initialized setstate anyViews_weblink initialized
setstate autocreate active setstate autocreate active
setstate colorInit 2015-01-04 16:19:04
setstate dew_all active setstate dew_all active
setstate eventTypes active
setstate global <no definition> setstate global <no definition>
setstate outdoorNotifier active setstate initialUsbCheck 2015-01-04 16:19:04
setstate lcCinema AllOff
setstate lcCinema 2015-01-04 16:22:40 state AllOff
setstate outdoorNotifier 2015-01-04 16:22:21
setstate rg_Guest1 none setstate rg_Guest1 none
setstate rg_Guest1 2014-02-16 13:59:50 durTimerAbsence 0 setstate rg_Guest1 2015-01-04 16:19:19 durTimerAbsence 00:00:00
setstate rg_Guest1 2014-02-16 13:34:06 durTimerPresence 0 setstate rg_Guest1 2015-01-04 16:19:19 durTimerAbsence_cr 0
setstate rg_Guest1 2014-02-15 16:15:34 durTimerSleep 0 setstate rg_Guest1 2015-01-04 16:19:19 durTimerPresence 00:00:00
setstate rg_Guest1 2015-01-04 16:19:19 durTimerPresence_cr 0
setstate rg_Guest1 2015-01-04 16:19:19 durTimerSleep 00:00:00
setstate rg_Guest1 2015-01-04 16:19:19 durTimerSleep_cr 0
setstate rg_Guest1 2014-02-16 14:09:20 lastArrival - setstate rg_Guest1 2014-02-16 14:09:20 lastArrival -
setstate rg_Guest1 2014-02-16 14:09:29 lastAwake 0 setstate rg_Guest1 2014-02-16 14:09:29 lastAwake 0
setstate rg_Guest1 2014-02-16 14:09:20 lastDeparture 2014-02-16 14:09:20 setstate rg_Guest1 2014-02-16 14:09:20 lastDeparture 2014-02-16 14:09:20
@ -80,9 +99,12 @@ setstate rg_Guest1 2014-02-16 14:09:20 presence absent
setstate rg_Guest1 2014-02-16 14:09:20 state none setstate rg_Guest1 2014-02-16 14:09:20 state none
setstate rg_Guest1 2014-02-15 16:16:27 wayhome 0 setstate rg_Guest1 2014-02-15 16:16:27 wayhome 0
setstate rg_Guest2 none setstate rg_Guest2 none
setstate rg_Guest2 2014-02-15 16:15:39 durTimerAbsence 0 setstate rg_Guest2 2015-01-04 16:19:19 durTimerAbsence 00:00:00
setstate rg_Guest2 2014-02-16 13:34:05 durTimerPresence 0 setstate rg_Guest2 2015-01-04 16:19:19 durTimerAbsence_cr 0
setstate rg_Guest2 2014-02-15 16:15:39 durTimerSleep 0 setstate rg_Guest2 2015-01-04 16:19:19 durTimerPresence 00:00:00
setstate rg_Guest2 2015-01-04 16:19:19 durTimerPresence_cr 0
setstate rg_Guest2 2015-01-04 16:19:19 durTimerSleep 00:00:00
setstate rg_Guest2 2015-01-04 16:19:19 durTimerSleep_cr 0
setstate rg_Guest2 2014-02-16 14:01:22 lastArrival - setstate rg_Guest2 2014-02-16 14:01:22 lastArrival -
setstate rg_Guest2 2014-02-16 14:09:29 lastAwake 0 setstate rg_Guest2 2014-02-16 14:09:29 lastAwake 0
setstate rg_Guest2 2014-02-16 14:00:46 lastDeparture 2014-02-16 14:00:45 setstate rg_Guest2 2014-02-16 14:00:46 lastDeparture 2014-02-16 14:00:45
@ -99,8 +121,8 @@ setstate rg_Guest2 2014-02-16 14:00:46 presence absent
setstate rg_Guest2 2014-02-16 14:01:22 state none setstate rg_Guest2 2014-02-16 14:01:22 state none
setstate rg_Guest2 2014-02-15 16:16:29 wayhome 0 setstate rg_Guest2 2014-02-15 16:16:29 wayhome 0
setstate rgr_Children home setstate rgr_Children home
setstate rgr_Children 2014-02-17 20:45:12 lastActivity home setstate rgr_Children 2015-01-04 16:19:19 lastActivity gone
setstate rgr_Children 2014-02-17 20:45:12 lastActivityBy Baby setstate rgr_Children 2015-01-04 16:19:19 lastActivityBy Son
setstate rgr_Children 2014-02-16 14:31:05 lastArrival 2014-02-16 14:31:05 setstate rgr_Children 2014-02-16 14:31:05 lastArrival 2014-02-16 14:31:05
setstate rgr_Children 2014-02-17 20:45:12 lastAwake 2014-02-17 20:45:12 setstate rgr_Children 2014-02-17 20:45:12 lastAwake 2014-02-17 20:45:12
setstate rgr_Children 2014-02-16 14:26:55 lastDeparture 2014-02-16 14:26:55 setstate rgr_Children 2014-02-16 14:26:55 lastDeparture 2014-02-16 14:26:55
@ -110,10 +132,10 @@ setstate rgr_Children 2014-02-17 20:45:12 lastDurSleep 29:47:11
setstate rgr_Children 2014-02-16 14:58:01 lastSleep 2014-02-16 14:58:01 setstate rgr_Children 2014-02-16 14:58:01 lastSleep 2014-02-16 14:58:01
setstate rgr_Children 2014-02-17 20:45:12 lastState asleep setstate rgr_Children 2014-02-17 20:45:12 lastState asleep
setstate rgr_Children 2014-02-16 14:31:05 presence present setstate rgr_Children 2014-02-16 14:31:05 presence present
setstate rgr_Children 2014-02-16 14:58:01 residentsAbsent 2 setstate rgr_Children 2015-01-04 16:19:19 residentsAbsent 0
setstate rgr_Children 2014-02-17 20:45:12 residentsAsleep 0 setstate rgr_Children 2014-02-17 20:45:12 residentsAsleep 0
setstate rgr_Children 2014-02-16 14:06:48 residentsAwoken 0 setstate rgr_Children 2014-02-16 14:06:48 residentsAwoken 0
setstate rgr_Children 2014-02-16 14:58:00 residentsGone 0 setstate rgr_Children 2015-01-04 16:19:19 residentsGone 2
setstate rgr_Children 2014-02-16 14:31:13 residentsGotosleep 0 setstate rgr_Children 2014-02-16 14:31:13 residentsGotosleep 0
setstate rgr_Children 2014-02-15 16:16:25 residentsGuests 0 setstate rgr_Children 2014-02-15 16:16:25 residentsGuests 0
setstate rgr_Children 2014-02-17 20:45:12 residentsHome 1 setstate rgr_Children 2014-02-17 20:45:12 residentsHome 1
@ -144,8 +166,8 @@ setstate rgr_Guests 2014-02-16 14:09:20 residentsTotalPresent 0
setstate rgr_Guests 2014-02-15 16:16:27 residentsTotalWayhome 0 setstate rgr_Guests 2014-02-15 16:16:27 residentsTotalWayhome 0
setstate rgr_Guests 2014-02-16 14:09:20 state none setstate rgr_Guests 2014-02-16 14:09:20 state none
setstate rgr_Parents home setstate rgr_Parents home
setstate rgr_Parents 2014-02-17 20:45:19 lastActivity absent setstate rgr_Parents 2015-01-04 16:19:19 lastActivity gone
setstate rgr_Parents 2014-02-17 20:45:19 lastActivityBy Father setstate rgr_Parents 2015-01-04 16:19:19 lastActivityBy Father
setstate rgr_Parents 2014-02-16 14:16:17 lastArrival 2014-02-16 14:16:17 setstate rgr_Parents 2014-02-16 14:16:17 lastArrival 2014-02-16 14:16:17
setstate rgr_Parents 2014-02-15 16:39:35 lastAwake 2014-02-15 16:39:35 setstate rgr_Parents 2014-02-15 16:39:35 lastAwake 2014-02-15 16:39:35
setstate rgr_Parents 2014-02-16 14:16:16 lastDeparture 2014-02-16 14:16:16 setstate rgr_Parents 2014-02-16 14:16:16 lastDeparture 2014-02-16 14:16:16
@ -155,10 +177,10 @@ setstate rgr_Parents 2014-02-15 16:39:35 lastDurSleep 00:02:44
setstate rgr_Parents 2014-02-15 16:36:51 lastSleep 2014-02-15 16:36:51 setstate rgr_Parents 2014-02-15 16:36:51 lastSleep 2014-02-15 16:36:51
setstate rgr_Parents 2014-02-16 14:16:17 lastState absent setstate rgr_Parents 2014-02-16 14:16:17 lastState absent
setstate rgr_Parents 2014-02-16 14:16:17 presence present setstate rgr_Parents 2014-02-16 14:16:17 presence present
setstate rgr_Parents 2014-02-17 20:45:19 residentsAbsent 1 setstate rgr_Parents 2015-01-04 16:19:19 residentsAbsent 0
setstate rgr_Parents 2014-02-16 13:31:53 residentsAsleep 0 setstate rgr_Parents 2014-02-16 13:31:53 residentsAsleep 0
setstate rgr_Parents 2014-02-16 13:31:53 residentsAwoken 0 setstate rgr_Parents 2014-02-16 13:31:53 residentsAwoken 0
setstate rgr_Parents 2014-02-17 20:45:19 residentsGone 0 setstate rgr_Parents 2015-01-04 16:19:19 residentsGone 1
setstate rgr_Parents 2014-02-15 16:36:51 residentsGotosleep 0 setstate rgr_Parents 2014-02-15 16:36:51 residentsGotosleep 0
setstate rgr_Parents 2014-02-15 16:13:39 residentsGuests 0 setstate rgr_Parents 2014-02-15 16:13:39 residentsGuests 0
setstate rgr_Parents 2014-02-16 14:26:52 residentsHome 1 setstate rgr_Parents 2014-02-16 14:26:52 residentsHome 1
@ -168,8 +190,8 @@ setstate rgr_Parents 2014-02-16 14:26:52 residentsTotalPresent 1
setstate rgr_Parents 2014-02-15 16:13:39 residentsTotalWayhome 0 setstate rgr_Parents 2014-02-15 16:13:39 residentsTotalWayhome 0
setstate rgr_Parents 2014-02-16 14:16:17 state home setstate rgr_Parents 2014-02-16 14:16:17 state home
setstate rgr_Residents home setstate rgr_Residents home
setstate rgr_Residents 2014-02-17 20:45:19 lastActivity absent setstate rgr_Residents 2015-01-04 16:19:19 lastActivity gone
setstate rgr_Residents 2014-02-17 20:45:19 lastActivityBy Father setstate rgr_Residents 2015-01-04 16:19:19 lastActivityBy Son
setstate rgr_Residents 2014-02-16 14:16:17 lastArrival 2014-02-16 14:16:17 setstate rgr_Residents 2014-02-16 14:16:17 lastArrival 2014-02-16 14:16:17
setstate rgr_Residents 2014-02-16 14:02:48 lastAwake 2014-02-16 14:02:48 setstate rgr_Residents 2014-02-16 14:02:48 lastAwake 2014-02-16 14:02:48
setstate rgr_Residents 2014-02-16 14:16:16 lastDeparture 2014-02-16 14:16:16 setstate rgr_Residents 2014-02-16 14:16:16 lastDeparture 2014-02-16 14:16:16
@ -179,10 +201,10 @@ setstate rgr_Residents 2014-02-16 14:02:48 lastDurSleep 00:00:00
setstate rgr_Residents 2014-02-16 14:02:48 lastSleep 2014-02-16 14:02:48 setstate rgr_Residents 2014-02-16 14:02:48 lastSleep 2014-02-16 14:02:48
setstate rgr_Residents 2014-02-16 14:16:17 lastState absent setstate rgr_Residents 2014-02-16 14:16:17 lastState absent
setstate rgr_Residents 2014-02-16 14:16:17 presence present setstate rgr_Residents 2014-02-16 14:16:17 presence present
setstate rgr_Residents 2014-02-17 20:45:19 residentsAbsent 3 setstate rgr_Residents 2015-01-04 16:19:19 residentsAbsent 0
setstate rgr_Residents 2014-02-17 20:45:12 residentsAsleep 0 setstate rgr_Residents 2014-02-17 20:45:12 residentsAsleep 0
setstate rgr_Residents 2014-02-16 14:06:49 residentsAwoken 0 setstate rgr_Residents 2014-02-16 14:06:49 residentsAwoken 0
setstate rgr_Residents 2014-02-17 20:45:19 residentsGone 0 setstate rgr_Residents 2015-01-04 16:19:19 residentsGone 3
setstate rgr_Residents 2014-02-16 14:31:13 residentsGotosleep 0 setstate rgr_Residents 2014-02-16 14:31:13 residentsGotosleep 0
setstate rgr_Residents 2014-02-16 14:09:20 residentsGuests 0 setstate rgr_Residents 2014-02-16 14:09:20 residentsGuests 0
setstate rgr_Residents 2014-02-17 20:45:12 residentsHome 2 setstate rgr_Residents 2014-02-17 20:45:12 residentsHome 2
@ -192,9 +214,12 @@ setstate rgr_Residents 2014-02-16 14:58:01 residentsTotalPresent 2
setstate rgr_Residents 2014-02-15 16:13:39 residentsTotalWayhome 0 setstate rgr_Residents 2014-02-15 16:13:39 residentsTotalWayhome 0
setstate rgr_Residents 2014-02-16 14:16:17 state home setstate rgr_Residents 2014-02-16 14:16:17 state home
setstate rr_Baby home setstate rr_Baby home
setstate rr_Baby 2014-02-16 14:30:21 durTimerAbsence 0 setstate rr_Baby 2015-01-04 16:19:19 durTimerAbsence 00:00:00
setstate rr_Baby 2014-02-17 20:44:42 durTimerPresence 1814 setstate rr_Baby 2015-01-04 16:19:19 durTimerAbsence_cr 0
setstate rr_Baby 2014-02-17 20:45:12 durTimerSleep 0 setstate rr_Baby 2015-01-04 16:23:19 durTimerPresence 7729:52:58
setstate rr_Baby 2015-01-04 16:23:19 durTimerPresence_cr 463793
setstate rr_Baby 2015-01-04 16:19:19 durTimerSleep 00:00:00
setstate rr_Baby 2015-01-04 16:19:19 durTimerSleep_cr 0
setstate rr_Baby 2014-02-16 14:30:21 lastArrival 2014-02-16 14:30:21 setstate rr_Baby 2014-02-16 14:30:21 lastArrival 2014-02-16 14:30:21
setstate rr_Baby 2014-02-17 20:45:12 lastAwake 2014-02-17 20:45:12 setstate rr_Baby 2014-02-17 20:45:12 lastAwake 2014-02-17 20:45:12
setstate rr_Baby 2014-02-16 14:32:38 lastDeparture 0 setstate rr_Baby 2014-02-16 14:32:38 lastDeparture 0
@ -208,10 +233,13 @@ setstate rr_Baby 2014-02-17 20:45:12 mood calm
setstate rr_Baby 2014-02-16 14:30:21 presence present setstate rr_Baby 2014-02-16 14:30:21 presence present
setstate rr_Baby 2014-02-17 20:45:12 state home setstate rr_Baby 2014-02-17 20:45:12 state home
setstate rr_Baby 2014-02-16 14:30:21 wayhome 0 setstate rr_Baby 2014-02-16 14:30:21 wayhome 0
setstate rr_Daughter absent setstate rr_Daughter gone
setstate rr_Daughter 2014-02-17 20:45:42 durTimerAbsence 1787 setstate rr_Daughter 2015-01-04 16:23:19 durTimerAbsence 7729:25:20
setstate rr_Daughter 2014-02-16 14:26:54 durTimerPresence 0 setstate rr_Daughter 2015-01-04 16:23:19 durTimerAbsence_cr 463765
setstate rr_Daughter 2014-02-16 14:02:48 durTimerSleep 0 setstate rr_Daughter 2015-01-04 16:19:19 durTimerPresence 00:00:00
setstate rr_Daughter 2015-01-04 16:19:19 durTimerPresence_cr 0
setstate rr_Daughter 2015-01-04 16:19:19 durTimerSleep 00:00:00
setstate rr_Daughter 2015-01-04 16:19:19 durTimerSleep_cr 0
setstate rr_Daughter 2014-02-16 14:57:58 lastArrival 2014-02-16 14:57:58 setstate rr_Daughter 2014-02-16 14:57:58 lastArrival 2014-02-16 14:57:58
setstate rr_Daughter 2014-02-16 14:02:48 lastAwake 2014-02-16 14:02:48 setstate rr_Daughter 2014-02-16 14:02:48 lastAwake 2014-02-16 14:02:48
setstate rr_Daughter 2014-02-16 14:57:59 lastDeparture 2014-02-16 14:57:59 setstate rr_Daughter 2014-02-16 14:57:59 lastDeparture 2014-02-16 14:57:59
@ -221,32 +249,38 @@ setstate rr_Daughter 2014-02-16 14:02:48 lastDurSleep 00:08:12
setstate rr_Daughter 2014-02-16 14:57:59 lastLocation home setstate rr_Daughter 2014-02-16 14:57:59 lastLocation home
setstate rr_Daughter 2014-02-16 14:57:59 lastMood calm setstate rr_Daughter 2014-02-16 14:57:59 lastMood calm
setstate rr_Daughter 2014-02-16 13:54:36 lastSleep 2014-02-16 13:54:36 setstate rr_Daughter 2014-02-16 13:54:36 lastSleep 2014-02-16 13:54:36
setstate rr_Daughter 2014-02-16 14:57:59 lastState home setstate rr_Daughter 2015-01-04 16:19:19 lastState absent
setstate rr_Daughter 2014-02-16 14:57:59 location underway setstate rr_Daughter 2014-02-16 14:57:59 location underway
setstate rr_Daughter 2014-02-16 14:57:59 mood - setstate rr_Daughter 2014-02-16 14:57:59 mood -
setstate rr_Daughter 2014-02-16 14:57:59 presence absent setstate rr_Daughter 2014-02-16 14:57:59 presence absent
setstate rr_Daughter 2014-02-16 14:57:59 state absent setstate rr_Daughter 2015-01-04 16:19:19 state gone
setstate rr_Daughter 2014-02-16 13:46:26 wayhome 0 setstate rr_Daughter 2014-02-16 13:46:26 wayhome 0
setstate rr_Father absent setstate rr_Father gone
setstate rr_Father 2014-02-17 20:45:19 durTimerAbsence 1818 setstate rr_Father 2015-01-04 16:23:19 durTimerAbsence 7729:56:27
setstate rr_Father 2014-02-16 14:26:52 durTimerPresence 0 setstate rr_Father 2015-01-04 16:23:19 durTimerAbsence_cr 463796
setstate rr_Father 2014-02-16 13:46:02 durTimerSleep 0 setstate rr_Father 2015-01-04 16:19:19 durTimerPresence 00:00:00
setstate rr_Father 2015-01-04 16:19:19 durTimerPresence_cr 0
setstate rr_Father 2015-01-04 16:19:19 durTimerSleep 00:00:00
setstate rr_Father 2015-01-04 16:19:19 durTimerSleep_cr 0
setstate rr_Father 2014-02-16 14:16:17 lastArrival 2014-02-16 14:16:17 setstate rr_Father 2014-02-16 14:16:17 lastArrival 2014-02-16 14:16:17
setstate rr_Father 2014-02-16 14:26:52 lastDeparture 2014-02-16 14:26:52 setstate rr_Father 2014-02-16 14:26:52 lastDeparture 2014-02-16 14:26:52
setstate rr_Father 2014-02-16 14:16:17 lastDurAbsence 00:00:01 setstate rr_Father 2014-02-16 14:16:17 lastDurAbsence 00:00:01
setstate rr_Father 2014-02-16 14:26:52 lastDurPresence 00:10:35 setstate rr_Father 2014-02-16 14:26:52 lastDurPresence 00:10:35
setstate rr_Father 2014-02-16 14:26:52 lastLocation home setstate rr_Father 2014-02-16 14:26:52 lastLocation home
setstate rr_Father 2014-02-16 14:26:52 lastMood calm setstate rr_Father 2014-02-16 14:26:52 lastMood calm
setstate rr_Father 2014-02-17 20:45:19 lastState gone setstate rr_Father 2015-01-04 16:19:19 lastState absent
setstate rr_Father 2014-02-16 14:26:52 location underway setstate rr_Father 2014-02-16 14:26:52 location underway
setstate rr_Father 2014-02-16 14:26:52 mood - setstate rr_Father 2014-02-16 14:26:52 mood -
setstate rr_Father 2014-02-16 14:26:52 presence absent setstate rr_Father 2014-02-16 14:26:52 presence absent
setstate rr_Father 2014-02-17 20:45:19 state absent setstate rr_Father 2015-01-04 16:19:19 state gone
setstate rr_Father 2014-02-16 13:46:02 wayhome 0 setstate rr_Father 2014-02-16 13:46:02 wayhome 0
setstate rr_Mother home setstate rr_Mother home
setstate rr_Mother 2014-02-16 14:04:26 durTimerAbsence 0 setstate rr_Mother 2015-01-04 16:19:19 durTimerAbsence 00:00:00
setstate rr_Mother 2014-02-17 20:45:42 durTimerPresence 1829 setstate rr_Mother 2015-01-04 16:19:19 durTimerAbsence_cr 0
setstate rr_Mother 2014-02-16 13:46:09 durTimerSleep 0 setstate rr_Mother 2015-01-04 16:23:19 durTimerPresence 7730:07:02
setstate rr_Mother 2015-01-04 16:23:19 durTimerPresence_cr 463807
setstate rr_Mother 2015-01-04 16:19:19 durTimerSleep 00:00:00
setstate rr_Mother 2015-01-04 16:19:19 durTimerSleep_cr 0
setstate rr_Mother 2014-02-16 14:16:17 lastArrival 2014-02-16 14:16:17 setstate rr_Mother 2014-02-16 14:16:17 lastArrival 2014-02-16 14:16:17
setstate rr_Mother 2014-02-16 14:16:16 lastDeparture 2014-02-16 14:16:16 setstate rr_Mother 2014-02-16 14:16:16 lastDeparture 2014-02-16 14:16:16
setstate rr_Mother 2014-02-16 14:16:17 lastDurAbsence 00:00:01 setstate rr_Mother 2014-02-16 14:16:17 lastDurAbsence 00:00:01
@ -259,10 +293,13 @@ setstate rr_Mother 2014-02-16 14:16:17 mood calm
setstate rr_Mother 2014-02-16 14:16:17 presence present setstate rr_Mother 2014-02-16 14:16:17 presence present
setstate rr_Mother 2014-02-16 14:16:17 state home setstate rr_Mother 2014-02-16 14:16:17 state home
setstate rr_Mother 2014-02-16 13:46:09 wayhome 0 setstate rr_Mother 2014-02-16 13:46:09 wayhome 0
setstate rr_Son absent setstate rr_Son gone
setstate rr_Son 2014-02-17 20:45:42 durTimerAbsence 1787 setstate rr_Son 2015-01-04 16:23:19 durTimerAbsence 7729:25:18
setstate rr_Son 2014-02-16 14:26:55 durTimerPresence 0 setstate rr_Son 2015-01-04 16:23:19 durTimerAbsence_cr 463765
setstate rr_Son 2014-02-16 14:00:53 durTimerSleep 0 setstate rr_Son 2015-01-04 16:19:19 durTimerPresence 00:00:00
setstate rr_Son 2015-01-04 16:19:19 durTimerPresence_cr 0
setstate rr_Son 2015-01-04 16:19:19 durTimerSleep 00:00:00
setstate rr_Son 2015-01-04 16:19:19 durTimerSleep_cr 0
setstate rr_Son 2014-02-16 14:58:00 lastArrival 2014-02-16 14:58:00 setstate rr_Son 2014-02-16 14:58:00 lastArrival 2014-02-16 14:58:00
setstate rr_Son 2014-02-16 14:06:44 lastAwake 2014-02-16 14:06:44 setstate rr_Son 2014-02-16 14:06:44 lastAwake 2014-02-16 14:06:44
setstate rr_Son 2014-02-16 14:58:01 lastDeparture 2014-02-16 14:58:01 setstate rr_Son 2014-02-16 14:58:01 lastDeparture 2014-02-16 14:58:01
@ -272,12 +309,12 @@ setstate rr_Son 2014-02-16 14:06:44 lastDurSleep 00:00:11
setstate rr_Son 2014-02-16 14:58:01 lastLocation home setstate rr_Son 2014-02-16 14:58:01 lastLocation home
setstate rr_Son 2014-02-16 14:58:01 lastMood calm setstate rr_Son 2014-02-16 14:58:01 lastMood calm
setstate rr_Son 2014-02-16 14:06:33 lastSleep 2014-02-16 14:06:33 setstate rr_Son 2014-02-16 14:06:33 lastSleep 2014-02-16 14:06:33
setstate rr_Son 2014-02-16 14:58:01 lastState home setstate rr_Son 2015-01-04 16:19:19 lastState absent
setstate rr_Son 2014-02-16 14:58:01 location underway setstate rr_Son 2014-02-16 14:58:01 location underway
setstate rr_Son 2014-02-16 14:58:01 mood - setstate rr_Son 2014-02-16 14:58:01 mood -
setstate rr_Son 2014-02-16 14:58:01 presence absent setstate rr_Son 2014-02-16 14:58:01 presence absent
setstate rr_Son 2014-02-16 14:58:01 state absent setstate rr_Son 2015-01-04 16:19:19 state gone
setstate rr_Son 2014-02-16 13:46:38 wayhome 0 setstate rr_Son 2014-02-16 13:46:38 wayhome 0
setstate sunRise Next: 06:58:34 setstate sunRise Next: 07:45:49
setstate sunSet Next: 18:20:46 setstate sunSet Next: 17:14:06
setstate wlCinema initialized setstate wlCinema initialized

View File

@ -73,7 +73,7 @@ attr Livingroom icon light_pendant_light
attr Livingroom model fs20di attr Livingroom model fs20di
attr Livingroom room Light attr Livingroom room Light
attr Livingroom webCmd dim attr Livingroom webCmd dim
define AllLights structure Light Alarm Livingroom Office Outdoor define AllLights structure Light Alarm Livingroom Office Outdoor CT RGB
attr AllLights devStateIcon undefined:light_question attr AllLights devStateIcon undefined:light_question
attr AllLights group Structure attr AllLights group Structure
attr AllLights icon light_light attr AllLights icon light_light
@ -164,7 +164,7 @@ attr ReadingLight eventMap off:dim0% on:dim100%
attr ReadingLight group Light attr ReadingLight group Light
attr ReadingLight icon light_floor_lamp attr ReadingLight icon light_floor_lamp
attr ReadingLight room Cinema attr ReadingLight room Cinema
attr ReadingLight webCmd on:off:dim attr ReadingLight webCmd on:off:dim:dim 50
define wlCinema weblink htmlCode {LightScene_2html("lcCinema")} define wlCinema weblink htmlCode {LightScene_2html("lcCinema")}
attr wlCinema room Cinema attr wlCinema room Cinema
define lcCinema LightScene Projector Screen TV CeilingLight ReadingLight define lcCinema LightScene Projector Screen TV CeilingLight ReadingLight
@ -185,6 +185,7 @@ attr anyViews dashboard_tab1name Dashboard Demo
attr anyViews dashboard_tab1sorting t0c100,Light,true,518,129:t0c100,Home State,true,496,204:t0c0,Single Lights,true,522,209:t0c0,AV,true,221,170: attr anyViews dashboard_tab1sorting t0c100,Light,true,518,129:t0c100,Home State,true,496,204:t0c0,Single Lights,true,522,209:t0c0,AV,true,221,170:
attr anyViews dashboard_tabcount 1 attr anyViews dashboard_tabcount 1
attr anyViews dashboard_width 80% attr anyViews dashboard_width 80%
attr anyViews room hidden
define anyViews_weblink weblink htmlCode {DashboardAsHtml("anyViews")} define anyViews_weblink weblink htmlCode {DashboardAsHtml("anyViews")}
attr anyViews_weblink room DashboardRoom attr anyViews_weblink room DashboardRoom
@ -288,3 +289,29 @@ attr rr_Baby icon status_available
attr rr_Baby room Residents attr rr_Baby room Residents
attr rr_Baby sortby 0 attr rr_Baby sortby 0
attr rr_Baby webCmd state attr rr_Baby webCmd state
define RGB readingsProxy RGB
attr RGB userattr Light Light_map structexclude
attr RGB Light AllLights
attr RGB alias RGB Light
attr RGB comment light with the ability to change RGB color
attr RGB devStateIcon {Color::devStateIcon("RGB","rgb","rgb","state")}
attr RGB group Color Lights
attr RGB room Light
attr RGB setFn {if( $CMD =~ m/on|off/ ) { $ARGS=$CMD;;$CMD = "state" } else {fhem ("setreading $DEVICE state on");;} if( $CMD =~ m/hue/ ) {my ($r,$g,$b) = Color::hsv2rgb($ARGS/360,1,1);; my $rgb = Color::rgb2hex( $r*255, $g*255, $b*255 );; fhem ("setreading $DEVICE rgb $rgb");;} if( $CMD =~ m/rgb/ && $ARGS =~ m/^(..)(..)(..)/ ) {my( $r, $g, $b ) = (hex($1)/255.0, hex($2)/255.0, hex($3)/255.0);; my ($h,$s,$v) = Color::rgb2hsv($r,$g,$b);; my $hue = int($h*359);; fhem ("setreading $DEVICE hue $hue");;} fhem ("setreading $DEVICE $CMD $ARGS");;return undef;;}
attr RGB setList on:noArg off:noArg rgb:colorpicker,RGB hue:colorpicker,HUE,0,1,359
attr RGB webCmd hue:rgb:rgb ff0000:rgb 00ff00:rgb 0000ff:rgb ffffff:on:off
define colorInit notify global:INITIALIZED {use Color;;Color_Initialize()}
attr colorInit room hidden
define CT readingsProxy CT
attr CT userattr Light Light_map structexclude
attr CT Light AllLights
attr CT alias CT Light
attr CT comment light with the ability to change the color temperature
attr CT devStateIcon {Color::devStateIcon("CT","rgb","rgb","state")}
attr CT getFn { my ($r,$g,$b) = Color::ct2rgb( ReadingsVal($DEVICE,"ct",333) );; return (Color::rgb2hex($r,$g,$b), 1);; }
attr CT getList rgb:noArg
attr CT group Color Lights
attr CT room Light
attr CT setFn {if( $CMD =~ m/on|off/ ) { $ARGS=$CMD;;$CMD = "state" } else {fhem ("setreading $DEVICE state on");;} fhem ("setreading $DEVICE $CMD $ARGS");;return undef;;}
attr CT setList on:noArg off:noArg ct:colorpicker,CT,2000,1,6500
attr CT webCmd ct::ct 2040:ct 2630:ct 3703:ct 6250:on:off

View File

@ -37,13 +37,18 @@ div.block { border:1px solid gray; background: #F8F8E0; padding:0.7em; }
.makeSelect { display:inline; float:left; clear:left; } .makeSelect { display:inline; float:left; clear:left; }
select { margin-left:5px; margin-right:5px; } select { margin-left:5px; margin-right:5px; }
.slider { float:left; width:250px; height:26px; } .slider { float:left; width:250px; height:26px; }
.colorpicker_ct .slider { background: url(../jscolor/ct_background.svg); }
.colorpicker_hue .slider { background: url(../jscolor/hue_background.svg); }
.get,.set,.attr { margin-bottom:5px; float:left; } .get,.set,.attr { margin-bottom:5px; float:left; }
select.svgSrc { width:100px; }
select.svgColumn { width:50px; }
select.svgRegexp { width:120px; }
.handle { position:relative; cursor:pointer; width:50px; .handle { position:relative; cursor:pointer; width:50px;
height:20px; line-height:20px; height:20px; line-height:20px;
-webkit-user-select:none; -moz-user-select:none; -user-select:none; -webkit-user-select:none; -moz-user-select:none; -user-select:none;
border:3px solid; color:#278727; text-align:center; } border:3px solid; color:#278727; text-align:center; }
.downText { margin-top:2px; } .downText { margin-top:2px; }
.makeSelect .slider {background:#F0F0D8; border-radius:8px;} /* detail only */
.set .set { margin-bottom:2px; margin-top:3px; } /* timepicker */ .set .set { margin-bottom:2px; margin-top:3px; } /* timepicker */
pre { white-space: pre-wrap; } pre { white-space: pre-wrap; }
@ -60,8 +65,23 @@ svg.on,svg.FS20_on { fill:orange; }
border-color:transparent; } border-color:transparent; }
.rc_button img:active { border-color: gray; } .rc_button img:active { border-color: gray; }
table#atWizard td:first-child { width: 240px; }
/* jQuery-UI mods */ /* jQuery-UI mods */
div.ui-dialog { border:3px solid #278727; padding: 0.2em; } div.ui-dialog { border:3px solid #278727; padding: 0.2em; }
div.ui-dialog div.ui-dialog-titlebar { display:none; } div.ui-dialog div.ui-dialog-titlebar { display:none; }
div.ui-widget-content { background:#FFFFE7; } div.ui-widget-content { background:#FFFFE7; }
#fwmenu {
position: absolute; z-index:1005;
text-align:left; max-width:600px;
font-weight: normal; font-size: 100%;
background:#FFFFE7; border:1px solid #278727;
}
#fwmenu li a { color:#278727; }
div#svgmarker {
position: absolute; z-index:1005; padding: 6px 10px;
text-align:left; max-width:600px;
color:#278727; background:#FFFFE7;
border:2px solid #278727; border-radius:4px;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,51 +1,143 @@
function //TODO: realtime picker
FW_colorpickerUpdateLine(d) //
{
var name = "colorpicker."+d[0];
el = document.getElementById(name);
if(el) {
if( d[1].length > 6 ) {
d[1] = d[1].slice(0,6);
}
el.color.fromString(d[1]);
}
}
function
colorpicker_setColor(el,mode,cmd)
{
var v = el.color;
if(mode==undefined) {
mode=el.pickerMode;
}
if(cmd==undefined) {
cmd=el.command;
}
if(v==undefined) {
v=el.toString();
}
if(mode=="HSV") {
v = (0x100 | Math.round(42*el.color.hsv[0])).toString(16).substr(1) +
(0x100 | Math.round(255*el.color.hsv[1])).toString(16).substr(1) +
(0x100 | Math.round(255*el.color.hsv[2])).toString(16).substr(1);
}
var req = new XMLHttpRequest();
var qcmd = addcsrf(cmd.replace('%',v));
req.open("GET", qcmd, true);
req.send(null);
if( 0 )
if(cmd)
document.location = cmd.replace('%',v);
}
FW_widgets['colorpicker'] = { FW_widgets['colorpicker'] = {
updateLine:FW_colorpickerUpdateLine createFn:FW_colorpickerCreate,
}; };
function
FW_colorpickerCreate(elName, devName, vArr, currVal, set, params, cmd)
{
if( 0 ) {
console.log( "elName: "+elName );
console.log( "devName: "+devName );
console.log( "vArr: "+vArr );
console.log( "currVal: "+currVal );
console.log( "set: "+set );
console.log( "params: "+params );
console.log( "cmd: "+cmd );
}
if(!vArr.length || vArr[0] != "colorpicker")
return undefined;
var mode = "RGB";
if( vArr.length >= 1 )
mode = vArr[1]
//console.log( "mode: "+mode );
if( params && params.length ) {
var color = params[0];
if( mode == "CT" )
color = colorpicker_ct2rgb(color);
var newEl = $('<div informID="###" style="width:32px;height:19px;border:1px solid #fff;border-radius:8px;background-color:#'+color+'" >').get(0);
$(newEl).click(function(arg) { cmd(params[0]) });
return newEl;
}
if( mode == "CT" ) {
var newEl = FW_createSlider(elName, devName, ["slider",vArr[2],vArr[3],vArr[4]], currVal, set, params, cmd);
$(newEl).addClass("colorpicker_ct");
return newEl;
} else if( mode == "HUE" ) {
var newEl = FW_createSlider(elName, devName, ["slider",vArr[2],vArr[3],vArr[4]], currVal, set, params, cmd);
$(newEl).addClass("colorpicker_hue");
return newEl;
}
if( currVal )
currVal = currVal.toUpperCase();
var newEl = $("<div style='display:inline-block'>").get(0);
$(newEl).append('<input type="text" id="colorpicker.'+ devName +'-'+set +'" maxlength="6" size="6">');
var inp = $(newEl).find("[type=text]");
var myPicker = new jscolor.color(inp.get(0),
{pickerMode:'RGB',pickerFaceColor:'transparent',pickerFace:3,pickerBorder:0,pickerInsetColor:'red'});
inp.get(0).color = myPicker;
if( currVal ) {
if( currVal.length > 6 ) currVal = currVal.slice(0,6);
myPicker.fromString(currVal);
}
if( elName )
$(inp).attr("name", elName);
if( cmd )
$(newEl).change(function(arg) { cmd( myPicker.toString() ) });
else
$(newEl).change(function(arg) { $(inp).attr("value", myPicker.toString() ) });
newEl.setValueFn = function(arg){ if( arg.length > 6 ) arg = arg.slice(0,6);
myPicker.fromString(arg); };
return newEl;
}
function
colorpicker_ct2rgb(ct)
{
// calculation from http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code
if( ct > 1000 ) // kelvin -> mired
ct = 1000000/ct;
// adjusted by 1000K
var temp = (1000000/ct)/100 + 10;
var r = 0;
var g = 0;
var b = 0;
r = 255;
if( temp > 66 )
r = 329.698727446 * Math.pow((temp - 60), -0.1332047592);
if( r < 0 )
r = 0;
else if( r > 255 )
r = 255;
if( temp <= 66 )
g = 99.4708025861 * Math.log(temp) - 161.1195681661;
else
g = 288.1221695283 * Math.pow((temp - 60), -0.0755148492);
if( g < 0 )
g = 0;
else if( g > 255 )
g = 255;
b = 255;
if( temp <= 19 )
b = 0;
if( temp < 66 )
b = 138.5177312231 * Math.log(temp-10) - 305.0447927307;
r = Math.round( r );
g = Math.round( g );
b = Math.round( b );
if( b < 0 )
b = 0;
else if( b > 255 )
b = 255;
return colorpicker_rgb2hex(r,g,b);
}
function
colorpicker_rgb2hex(r,g,b) {
if( g !== undefined )
return Number(0x1000000 + r*0x10000 + g*0x100 + b).toString(16).substring(1);
else
return Number(0x1000000 + r[0]*0x10000 + r[1]*0x100 + r[2]).toString(16).substring(1);
}

View File

@ -0,0 +1,38 @@
// Wrapper for the jquery knob widget.
FW_widgets['knob'] = { createFn:FW_knobCreate, };
function
FW_knobCreate(elName, devName, vArr, currVal, set, params, cmd)
{
if(!vArr.length || vArr[0] != "knob" || (params && params.length))
return undefined;
var conf = {};
for(var i1=0; i1<vArr.length; i1++) {
var kv = vArr[i1].split(":");
conf[kv[0]] = kv[1];
}
currVal = (currVal == undefined) ?
conf.min : parseFloat(currVal.replace(/[^\d.\-]/g, ""));
if(!conf.width) conf.width=conf.height=100;
if(!conf.fgColor) conf.fgColor="#278727";
var newEl = $("<div style='display:inline-block'>").get(0);
$(newEl).append('<input type="text" id="knob.'+devName+'-'+set +'" >');
var inp = $(newEl).find("input");
if(elName)
$(inp).attr("name", elName);
for(c in conf)
$(inp).attr("data-"+c, conf[c]);
loadScript("pgm2/jquery.knob.min.js",
function() {
inp.knob({ 'release' : function(v){ if(cmd) cmd(v) } });
newEl.setValueFn = function(arg){ inp.val(arg);
inp.trigger('change'); };
newEl.setValueFn(currVal);
});
return newEl;
}

View File

@ -1,90 +0,0 @@
function
FW_multipleSelChange(name, devName, vArr)
{
if(vArr.length < 2 || (vArr[0] != "multiple" && vArr[0] != "multiple-strict"))
return undefined;
var o = new Object();
o.newEl = document.createElement('input');
o.newEl.type='text';
o.newEl.size=30;
o.qFn = 'FW_multipleSetSelected(qArg, "%")';
o.qArg = o.newEl;
o.newEl.setAttribute('onFocus', vArr[0] == "multiple-strict" ?
'FW_multipleSelect(this, true)' : 'FW_multipleSelect(this, false)');
o.newEl.setAttribute('allVals', vArr);
o.newEl.setAttribute('readonly', 'readonly');
return o;
}
function
FW_multipleSelect(el, strict)
{
loadLink("pgm2/jquery-ui.min.css");
loadScript("pgm2/jquery.min.js", function(){
loadScript("pgm2/jquery-ui.min.js", function() {
var sel = $(el).val().split(","), selObj={};
for(var i1=0; i1<sel.length; i1++)
selObj[sel[i1]] = 1;
var vArr = $(el).attr("allVals").replace(/#/g, " ").split(",");
var table = "";
for(var i1=1; i1<vArr.length; i1++) {
var v = vArr[i1];
table += '<tr>'+ // funny stuff for ios6 style, forum #23561
'<td><div class="checkbox"><input name="'+v+'" type="checkbox"'+
(selObj[v] ? " checked" : "")+'/>'+
'<label for="'+v+'"><span></span></label></div></td>'+
'<td><label for="' +v+'">'+v+'</label></td></tr>';
delete(selObj[v]);
}
var selArr=[];
for(var i1 in selObj)
selArr.push(i1);
$('body').append(
'<div id="multidlg" style="display:none">'+
'<table>'+table+'</table>'+(!strict ? '<input id="md_freeText" '+
'value="'+selArr.join(',')+'"/>' : '')+
'</div>');
$('#multidlg').dialog(
{ modal:true, closeOnEscape:false, maxHeight:$(window).height()*3/4,
buttons:[
{ text:"Cancel", click:function(){ $('#multidlg').remove(); }},
{ text:"OK", click:function(){
var res=[];
if($("#md_freeText").val())
res.push($("#md_freeText").val());
$("#multidlg table input").each(function(){
if($(this).prop("checked"))
res.push($(this).attr("name"));
});
$(el).val(res.join(","));
$('#multidlg').remove();
}}]});
});
});
return false;
}
function
FW_multipleSetSelected(el, val)
{
if(typeof el == 'string')
el = document.getElementById(el);
el.value=val;
}
FW_widgets['multiple'] = {
selChange:FW_multipleSelChange
};
FW_widgets['multiple-strict'] = {
selChange:FW_multipleSelChange
};

View File

@ -1,14 +0,0 @@
function
FW_noArgSelChange(name, devName, vArr)
{
if(vArr.length != 1 || vArr[0] != "noArg")
return undefined;
var o = new Object();
o.newEl = document.createElement('div');
return o;
}
FW_widgets['noArg'] = {
selChange:FW_noArgSelChange
};

View File

@ -1,153 +0,0 @@
/*************** SLIDER **************/
function
FW_sliderUpdateLine(d)
{
for(var k=0; k<2; k++) {
var name = "slider."+d[0];
if(k == 1)
name = name+"-"+d[1].replace(/[ \d].*$/,'');
el = document.getElementById(name);
if(el) {
var doSet = 1; // Only set the "state" slider in the detail view
if(el.parentNode.getAttribute("name") == "val.set"+d[0]) {
var el2 = document.getElementsByName("arg.set"+d[0])[0];
if(el2.nodeName.toLowerCase() == "select" &&
el2.options[el2.selectedIndex].value != "state")
doSet = 0;
}
if(doSet) {
var val = d[1].replace(/^.*?([.\-\d]+).*/g, "$1"); // get first number
if(!val.match(/[.\-\d]+/))
val = 0;
FW_sliderCreate(el, val);
}
}
}
}
function
FW_sliderCreate(slider, curr)
{
var sh = slider.firstChild;
var lastX=-1, offX=0, maxX=0, val;
var min = parseFloat(slider.getAttribute("min"));
var stp = parseFloat(slider.getAttribute("stp"));
var max = parseFloat(slider.getAttribute("max"));
var flt = parseFloat(slider.getAttribute("flt"));
var cmd = slider.getAttribute("cmd");
function
init()
{
maxX = slider.offsetWidth-sh.offsetWidth;
if(curr) {
offX += (curr-min)*maxX/(max-min);
sh.innerHTML = curr;
sh.setAttribute('style', 'left:'+offX+'px;');
}
}
init();
function
touchFn(e, fn)
{
e.preventDefault(); // Prevents Safari from scrolling!
if(e.touches == null || e.touches.length == 0)
return;
e.clientX = e.touches[0].clientX;
fn(e);
}
function
mouseDown(e)
{
var oldFn1 = document.onmousemove, oldFn2 = document.onmouseup,
oldFn3 = document.ontouchmove, oldFn4 = document.ontouchend;
if(maxX == 0)
init();
lastX = e.clientX;
function
mouseMove(e)
{
var diff = e.clientX-lastX; lastX = e.clientX;
offX += diff;
if(offX < 0) offX = 0;
if(offX > maxX) offX = maxX;
val = min+(offX/maxX * (max-min));
val = (flt ? Math.floor(val/stp)*stp :
Math.floor(Math.floor(val/stp)*stp));
sh.innerHTML = val;
sh.setAttribute('style', 'left:'+offX+'px;');
if(cmd && cmd.substring(0,3) == "js:") {
eval(cmd.substring(3).replace('%',val));
}
}
document.onmousemove = mouseMove;
document.ontouchmove = function(e) { touchFn(e, mouseMove); }
document.onmouseup = document.ontouchend = function(e)
{
document.onmousemove = oldFn1; document.onmouseup = oldFn2;
document.ontouchmove = oldFn3; document.ontouchend = oldFn4;
if(cmd) {
if(cmd.substring(0,3) != "js:")
if(typeof val != "undefined") {
if(typeof FW_pollConn != "undefined")
FW_cmd(cmd.replace('%',val)+"&XHR=1");
else
window.location = addcsrf(cmd.replace('%',val));
}
} else {
if(typeof val != "undefined")
slider.nextSibling.setAttribute('value', val);
}
};
};
sh.onselectstart = function() { return false; }
sh.onmousedown = mouseDown;
sh.ontouchstart = function(e) { touchFn(e, mouseDown); }
}
function
FW_sliderSelChange(name, devName, vArr)
{
if(vArr.length < 4 || vArr.length > 5 || vArr[0] != "slider")
return undefined;
var o = new Object();
var min=parseFloat(vArr[1]),
stp=parseFloat(vArr[2]),
max=parseFloat(vArr[3]),
flt=parseFloat(vArr[4]);
if(!flt) flt=0;
o.newEl = document.createElement('div');
o.newEl.innerHTML =
'<div class="slider" id="slider.'+devName+
'" min="'+min+'" stp="'+stp+'" max="'+max+'" flt="'+flt+
'"><div class="handle">'+min+'</div></div>'+
'<input type="hidden" name="'+name+'" value="'+min+'">';
FW_sliderCreate(o.newEl.firstChild, undefined);
o.qFn = 'FW_querySetSlider(qArg, "%")';
o.qArg = o.newEl.firstChild;
return o;
}
function
FW_querySetSlider(el, val)
{
val = val.replace(/[^\d.\-]/g, ""); // remove non numbers
FW_sliderCreate(el, val);
}
FW_widgets['slider'] = {
updateLine:FW_sliderUpdateLine,
selChange:FW_sliderSelChange
};

View File

@ -1,27 +0,0 @@
function
FW_svgUpdateDevs(devs)
{
// if matches, refresh the SVG by removing and readding the embed tag
var embArr = document.getElementsByTagName("embed");
for(var i = 0; i < embArr.length; i++) {
var svg = embArr[i].getSVGDocument();
if(!svg || !svg.firstChild || !svg.firstChild.nextSibling)
continue;
var flog = svg.firstChild.nextSibling.getAttribute("flog");
for(var j=0; j < devs.length; j++) {
if(flog !== null && flog.match(" "+devs[j]+" ")) {
var e = embArr[i];
var newE = document.createElement("embed");
for(var k=0; k<e.attributes.length; k++)
newE.setAttribute(e.attributes[k].name, e.attributes[k].value);
e.parentNode.insertBefore(newE, e);
e.parentNode.removeChild(e);
break;
}
}
}
}
FW_widgets['SVG'] = {
updateDevs:FW_svgUpdateDevs,
};

View File

@ -1,46 +0,0 @@
function
FW_textFieldUpdateLine(d)
{
var name = "textField."+d[0];
el = document.getElementById(name);
if(el)
el.value = d[1];
}
function
FW_textFieldSelChange(name, devName, vArr)
{
if(vArr.length != 1 || vArr[0] != "textField")
return undefined;
var o = new Object();
o.newEl = document.createElement('input');
o.newEl.type='text';
o.newEl.size=30;
o.qFn = 'FW_textFieldSetSelected(qArg, "%")';
o.qArg = o.newEl;
return o;
}
function
FW_textFieldSetSelected(el, val)
{
if(typeof el == 'string')
el = document.getElementById(el);
el.value=val;
}
function
textField_setText(el,cmd)
{
var v = el.value;
var req = new XMLHttpRequest();
var qcmd = addcsrf(cmd.replace('%',v));
req.open("GET", qcmd, true);
req.send(null);
}
FW_widgets['textField'] = {
updateLine:FW_textFieldUpdateLine,
selChange:FW_textFieldSelChange
};

View File

@ -1,69 +0,0 @@
function
FW_timeSet(el,name,val)
{
var el = el.parentNode.parentNode.firstChild;
var v = el.value.split(":");
v[name] = ''+val;
if(v[0].length < 2) v[0] = '0'+v[0];
if(v[1].length < 2) v[1] = '0'+v[1];
el.value = v[0]+":"+v[1];
el.setAttribute('value', el.value);
}
function
FW_timeCreate(el,cmd)
{
var par = el.parentNode;
var v = par.firstChild.value;
var brOff = par.innerHTML.indexOf("<br>");
if(brOff > 0) {
par.innerHTML = par.innerHTML.substring(0, brOff).replace('"-"','"+"');
if(cmd) {
if(typeof cmd == "function")
cmd(v);
else if(typeof FW_pollConn != "undefined")
FW_cmd(cmd.replace('%',v)+"&XHR=1");
else
window.location = addcsrf(cmd.replace('%',v));
}
return;
}
el.setAttribute('value', '-');
if(v.indexOf(":") < 0)
par.firstChild.value = v = "12:00";
var val = v.split(":");
for(var i = 0; i < 2; i++) {
par.appendChild(document.createElement('br'));
var sl = document.createElement('div');
sl.innerHTML = '<div class="slider" min="0" stp='+(i==0?1:5)+
' max='+(i==0?23:55)+
' cmd="js:FW_timeSet(slider,'+i+',%)"'+
'><div class="handle">'+val[i]+
'</div></div>';
par.appendChild(sl);
sl.setAttribute('class', par.getAttribute('class'));
FW_sliderCreate(sl.firstChild, val[i]);
}
}
function
FW_timeSelChange(name, devName, vArr)
{
if(vArr.length != 1 || vArr[0] != "time")
return undefined;
var o = new Object();
o.newEl = document.createElement('div');
o.newEl.innerHTML='<input name="'+name+'" type="text" size="5">'+
'<input type="button" value="+" onclick="FW_timeCreate(this)">';
return o;
}
FW_widgets['time'] = {
selChange:FW_timeSelChange
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

23
fhem/www/pgm2/jquery.knob.min.js vendored Executable file

File diff suppressed because one or more lines are too long

View File

@ -1,13 +1,12 @@
var xmlns="http://www.w3.org/2000/svg"; "use strict";
var old_title; var svgNS = "http://www.w3.org/2000/svg";
var old_sel; var svg_b64 ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var svgdoc; var svg_initialized={};
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var to;
// Base64 encode the xy points (12 bit x, 12 bit y). // Base64 encode the xy points (12 bit x, 12 bit y).
function function
compressPoints(pointList) svg_compressPoints(pointList)
{ {
var i, x, y, lx = -1, ly, ret = ""; var i, x, y, lx = -1, ly, ret = "";
var pl_arr = pointList.replace(/^ */,'').split(/[, ]/); var pl_arr = pointList.replace(/^ */,'').split(/[, ]/);
@ -17,24 +16,24 @@ compressPoints(pointList)
if(pl_arr.length > 500 && lx != -1 && x-lx < 2) // Filter the data. if(pl_arr.length > 500 && lx != -1 && x-lx < 2) // Filter the data.
continue; continue;
ret = ret+ ret = ret+
b64.charAt((x&0xfc0)>>6)+ svg_b64.charAt((x&0xfc0)>>6)+
b64.charAt((x&0x3f))+ svg_b64.charAt((x&0x3f))+
b64.charAt((y&0xfc0)>>6)+ svg_b64.charAt((y&0xfc0)>>6)+
b64.charAt((y&0x3f)); svg_b64.charAt((y&0x3f));
lx = x; ly = y; lx = x; ly = y;
} }
return ret; return ret;
} }
function function
uncompressPoints(cmpData) svg_uncompressPoints(cmpData)
{ {
var i = 0, ret = ""; var i = 0, ret = "";
while(i < cmpData.length) { while(i < cmpData.length) {
var x = (b64.indexOf(cmpData.charAt(i++))<<6)+ var x = (svg_b64.indexOf(cmpData.charAt(i++))<<6)+
b64.indexOf(cmpData.charAt(i++)); svg_b64.indexOf(cmpData.charAt(i++));
var y = (b64.indexOf(cmpData.charAt(i++))<<6)+ var y = (svg_b64.indexOf(cmpData.charAt(i++))<<6)+
b64.indexOf(cmpData.charAt(i++)); svg_b64.indexOf(cmpData.charAt(i++));
ret += " "+x+","+y; ret += " "+x+","+y;
} }
return ret; return ret;
@ -42,130 +41,245 @@ uncompressPoints(cmpData)
function function
get_cookie() svg_getcookie()
{ {
var c = parent.document.cookie; var c = document.cookie;
if(c == null) if(c == null)
return ""; return [];
var results = c.match('fhemweb=(.*?)(;|$)' ); var results = c.match('fhemweb=(.*?)(;|$)' );
return (results ? unescape(results[1]) : ""); return (results ? unescape(results[1]).split(":") : []);
} }
function function
set_cookie(value) svg_prepareHash(el)
{ {
parent.document.cookie="fhemweb="+escape(value); var obj = { y_mul:0,y_h:0,y_min:0, decimals:0, x_mul:0,x_off:0,x_min:0 };
} for(var name in obj)
obj[name] = parseFloat($(el).attr(name));
return obj;
function
svg_copy(evt)
{
var d = evt.target.ownerDocument;
var cp = d.getElementById("svg_copy");
cp.firstChild.nodeValue = " ";
set_cookie(old_sel.getAttribute("y_min")+":"+
old_sel.getAttribute("y_mul")+":"+
compressPoints(old_sel.getAttribute("points")));
}
function
svg_paste(evt)
{
var d = evt.target.ownerDocument;
var ps = d.getElementById("svg_paste");
ps.firstChild.nodeValue = " ";
var o=d.createElementNS(xmlns, "polyline");
o.setAttribute("class", "pasted");
var data = get_cookie().split(":", 3);
o.setAttribute("points", uncompressPoints(data[2]));
var h = parseFloat(old_sel.getAttribute("y_h"));
var ny_mul = parseFloat(data[1]);
var ny_min = parseInt(data[0]);
var y_mul = parseFloat(old_sel.getAttribute("y_mul"));
var y_min = parseInt(old_sel.getAttribute("y_min"));
var tr =
"translate(0,"+ (h/y_mul+y_min-h/ny_mul-ny_min)*y_mul +") "+
"scale(1, "+ (y_mul/ny_mul) +") ";
o.setAttribute("transform", tr);
d.documentElement.appendChild(o);
}
function
showOtherLines(d, lid, currval, maxval)
{
for(var i=0; i < 9; i++) {
var id="line_"+i;
var el = d.getElementById(id);
if(el && id != lid) {
var h = parseFloat(el.getAttribute("y_h"));
el.setAttribute("transform", "translate(0,"+h*(1-currval)+") "+
"scale(1,"+currval+")");
}
}
if(currval != maxval) {
currval += (currval<maxval ? 0.02 : -0.02);
currval = Math.round(currval*100)/100;
to=setTimeout(function(){showOtherLines(d,lid,currval,maxval)},10);
}
}
function
svg_labelselect(evt)
{
var d = evt.target.ownerDocument;
var lid = evt.target.getAttribute("line_id");
var sel = d.getElementById(lid);
var tl = d.getElementById("svg_title");
var cp = d.getElementById("svg_copy");
var ps = d.getElementById("svg_paste");
clearTimeout(to);
if(old_sel == sel) {
sel.setAttribute("stroke-width", 1);
old_sel = null;
tl.firstChild.nodeValue = old_title;
cp.firstChild.nodeValue = " ";
ps.firstChild.nodeValue = " ";
showOtherLines(d, lid, 0, 1);
} else {
if(old_sel == null)
old_title = tl.firstChild.nodeValue;
else
old_sel.setAttribute("stroke-width", 1);
sel.setAttribute("stroke-width", 3);
old_sel = sel;
if(sel.getAttribute("points") != null) {
tl.firstChild.nodeValue = evt.target.getAttribute("title");
cp.firstChild.nodeValue = "Copy";
ps.firstChild.nodeValue = (get_cookie()==""?" ":"Paste");
}
showOtherLines(d, lid, 1, 0);
}
} }
function function
svg_click(evt) svg_click(evt)
{ {
var t=evt.target; var t = evt.target;
var y_mul = parseFloat(t.getAttribute("y_mul")); var o = svg_prepareHash(t);
var y_h = parseFloat(t.getAttribute("y_h"));
var y_min = parseFloat(t.getAttribute("y_min"));
var y_fx = parseFloat(t.getAttribute("decimals"));
var y_org = (((y_h-evt.clientY)/y_mul)+y_min).toFixed(y_fx);
var x_mul = parseFloat(t.getAttribute("x_mul")); var y_org = (((o.y_h-evt.clientY)/o.y_mul)+o.y_min).toFixed(o.decimals);
var x_off = parseFloat(t.getAttribute("x_off")); var d = new Date((((evt.clientX-o.x_min)/o.x_mul)+o.x_off) * 1000);
var x_min = parseFloat(t.getAttribute("x_min"));
var d = new Date((((evt.clientX-x_min)/x_mul)+x_off) * 1000);
var ts = (d.getHours() < 10 ? '0' : '') + d.getHours() + ":"+ var ts = (d.getHours() < 10 ? '0' : '') + d.getHours() + ":"+
(d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); (d.getMinutes() < 10 ? '0' : '') + d.getMinutes();
var tl = evt.target.ownerDocument.getElementById('svg_title'); var tl = t.ownerDocument.getElementById('svg_title');
tl.firstChild.nodeValue = t.getAttribute("title")+": "+y_org+" ("+ts+")"; tl.firstChild.nodeValue = t.getAttribute("title")+": "+y_org+" ("+ts+")";
} }
function
sv_menu(evt, embed)
{
var label = evt.target;
var svg = $(label).closest("svg");
var svgNode = $(svg).get(0);
var lid = $(label).attr("line_id");
var data = svg_getcookie();
var sel = $(svg).find("#"+lid);
var selNode = $(sel).get(0);
var tl = $(svg).find("#svg_title");
var par = svgNode.par;
FW_menu(evt, label,
["Copy", "Paste",
svgNode.isSingle ? "Show all lines":"Hide other lines",
selNode.showVal ? "Stop displaying values" : "Display plot values" ],
[undefined, data.length==0, undefined, selNode.nodeName!="polyline"],
function(arg) {
//////////////////////////////////// copy
if(arg == 0) {
document.cookie="fhemweb="+
$(sel).attr("y_min")+":"+$(sel).attr("y_mul")+":"+
svg_compressPoints($(sel).attr("points"));
}
//////////////////////////////////// paste
if(arg == 1) {
var doc = $(svg).get(0).ownerDocument;
var o=doc.createElementNS(svgNS, "polyline");
o.setAttribute("class", "pasted");
o.setAttribute("points", svg_uncompressPoints(data[2]));
var h = parseFloat($(sel).attr("y_h"));
var ny_mul = parseFloat(data[1]);
var ny_min = parseInt(data[0]);
var y_mul = parseFloat($(sel).attr("y_mul"));
var y_min = parseInt($(sel).attr("y_min"));
var tr =
"translate(0,"+ (h/y_mul+y_min-h/ny_mul-ny_min)*y_mul +") "+
"scale(1, "+ (y_mul/ny_mul) +") ";
o.setAttribute("transform", tr);
doc.documentElement.appendChild(o);
}
//////////////////////////////////// hide/show lines
if(arg == 2) {
if(svgNode.isSingle) {
delete(svgNode.isSingle);
$(sel).attr("stroke-width", 1);
$(tl).html($(tl).attr("hiddentitle"));
showOtherLines(0, 1);
} else {
svgNode.isSingle = 1;
$(sel).attr("stroke-width", 3);
$(tl).attr("hiddentitle", $(tl).html());
if($(sel).attr("points") != null)
$(tl).html($(label).attr("title"));
showOtherLines(1, 0);
}
}
//////////////////////////////////// value display
if(arg == 3) {
var hadShowVal = selNode.showVal;
$(svg).find("[id]").each(function(){delete($(this).get(0).showVal)});
$(svg).off("mousemove");
if(par && par.circle) {
$(par.circle).remove();
$(par.div).remove();
}
if(!hadShowVal) {
selNode.showVal = true;
$(svg).mousemove(mousemove);
svgNode.par = par = svg_prepareHash(selNode);
par.circle =
$(svg).get(0).ownerDocument.createElementNS(svgNS, "circle");
$(par.circle).attr("id", "svgmarker").attr("r", "8");
$(svg).append(par.circle);
par.div = $('<div id="svgmarker">');
par.divoffY = $(embed ? embed : svg).offset().top -
$("#content").offset().top-50;
$("#content").append(par.div);
var pl = selNode.points;
if(pl.length > 2)
mousemove({pageX:pl[pl.length-2].x});
}
}
}, embed);
function
mousemove(e)
{
var xRaw = e.pageX, pl = selNode.points, l = pl.length, i1;
if(!embed)
xRaw -= $(svg).offset().left;
for(i1=0; i1<l; i1++)
if(pl[i1].x > xRaw)
break;
if(i1==l || i1==0)
return;
var pp=pl[i1-1], pn=pl[i1];
var xR = (xRaw-pp.x)/(pn.x-pp.x); // Compute interim values
var yRaw = pp.y+xR*(pn.y-pp.y);
var y = (((par.y_h-yRaw)/par.y_mul)+par.y_min).toFixed(par.decimals);
var d = new Date((((xRaw-par.x_min)/par.x_mul)+par.x_off) * 1000);
var ts = (d.getHours() < 10 ? '0' : '') + d.getHours() + ":"+
(d.getMinutes() < 10 ? '0' : '') + d.getMinutes();
$(par.circle).attr("cx", xRaw).attr("cy", yRaw);
var yd = Math.floor((yRaw+par.divoffY) / 20)*20;
$(par.div).html(ts+" "+y)
.css({ left:xRaw-20, top:yd });
}
function
showOtherLines(currval, maxval)
{
$(svg).find("[id]").each(function(){
var id = $(this).attr("id");
if(id.indexOf("line_") != 0 || id == lid)
return;
var h = parseFloat($(this).attr("y_h"));
$(this).attr("transform", "translate(0,"+h*(1-currval)+") "+
"scale(1,"+currval+")");
});
if(currval != maxval) {
currval += (currval<maxval ? 0.02 : -0.02);
currval = Math.round(currval*100)/100;
setTimeout(function(){ showOtherLines(currval,maxval) }, 10);
}
}
}
function
svg_init_one(embed, svg)
{
var sid = $(svg).attr("id");
if(svg_initialized[sid])
return;
svg_initialized[sid] = true;
$("text.legend", svg).click(function(e){sv_menu(e, embed)});
}
function
svg_init(par) // also called directly from perl, in race condition
{
$("embed").each(function(){
var e = this;
var src = $(e).attr("src");
var ed = e.getSVGDocument();
if(src.indexOf("SVG_showLog") < 0 || !ed)
return;
var sTag = $("svg", ed)[0];
if((par && $(sTag).attr("id") != par))
return;
svg_init_one(e, sTag);
});
}
$(document).ready(function(){
svg_init(); // <embed><svg>
$("svg[id]").each(function(){ // <svg> (direct)
if($(this).attr("id").indexOf("SVGPLOT") == 0)
svg_init_one(undefined, this);
});
});
// longpollSVG code below
function
FW_svgUpdateDevs(devs)
{
// if matches, refresh the SVG by removing and readding the embed tag
var embArr = document.getElementsByTagName("embed");
for(var i = 0; i < embArr.length; i++) {
var svg = embArr[i].getSVGDocument();
if(!svg || !svg.firstChild || !svg.firstChild.nextSibling)
continue;
var flog = svg.firstChild.nextSibling.getAttribute("flog");
for(var j=0; j < devs.length; j++) {
if(flog !== null && flog.match(" "+devs[j]+" ")) {
var e = embArr[i];
var newE = document.createElement("embed");
for(var k=0; k<e.attributes.length; k++)
newE.setAttribute(e.attributes[k].name, e.attributes[k].value);
e.parentNode.insertBefore(newE, e);
e.parentNode.removeChild(e);
break;
}
}
}
}
FW_widgets.SVG = { updateDevs:FW_svgUpdateDevs };

View File

@ -35,3 +35,5 @@ polyline { stroke:black; fill:none; }
.l1fill_stripe {stroke:green; fill:url(#gr1_stripe);} text.l1fill_stripe {stroke:none; fill:green;} .l1fill_stripe {stroke:green; fill:url(#gr1_stripe);} text.l1fill_stripe {stroke:none; fill:green;}
.l0fill_gyr {stroke:red; fill:url(#gr0_gyr);} text.l0fill_gyr {stroke:none; fill:red;} .l0fill_gyr {stroke:red; fill:url(#gr0_gyr);} text.l0fill_gyr {stroke:none; fill:red;}
circle#svgmarker { fill:#278727; opacity:0.5; }