FHEMWEB_JS_UMBAU: integrate it with the trunk
git-svn-id: https://svn.fhem.de/fhem/trunk@7496 2b470e98-0d58-463d-a4d8-8e2adae1ed80
38
fhem/CHANGED
@ -1,24 +1,35 @@
|
||||
# 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.
|
||||
- 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
|
||||
- feature: PRESENCE: new reading "presence" which contains the current (or last known)
|
||||
presence state (can be "absent" or "present")
|
||||
- bugfix: 70_Jabber.pm: hardening XML::Stream Process() call and fix of ssl_verify
|
||||
- feature: readingsGroup: allow devspec :FILTER= expressions in device selection
|
||||
- feature: PRESENCE: new reading "presence" which contains the current (or
|
||||
last known) presence state (can be "absent" or "present")
|
||||
- bugfix: 70_Jabber.pm: hardening XML::Stream Process() call and fix of
|
||||
ssl_verify
|
||||
- feature: readingsGroup: allow devspec :FILTER= expressions in device
|
||||
selection
|
||||
- added: 73_km200.pm for the Buderus KM200 heating controller (Sailor)
|
||||
- feature: 70_XBMC: added command 'connect' to connect instantly
|
||||
- change: FB_CALLMONITOR: use standard file read/write function to support use of configDb
|
||||
- bugfix: FB_CALLMONITOR: fix phonebook file read when using configDb (Forum #30244)
|
||||
- feature: 70_XBMC: added commands: openmovieid, openepisodeid, addon, jsonraw (thanks to siggi85)
|
||||
- change: FB_CALLMONITOR: use standard file read/write function to support
|
||||
use of configDb
|
||||
- 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
|
||||
- feature: 70_XBMC: added mechanism to detect disconnects (TCP)
|
||||
- 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)
|
||||
- fix: sani_heating_boost (possibility to colorize)
|
||||
- feature: FB_CALLMONITOR: add remote phonebook lookup via telnet connection
|
||||
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: 99_Utils.pm: add getUniqueID, getKeyValue, setKeyValue
|
||||
- feature: SMARTMON: additional parameters for smartctl
|
||||
@ -33,7 +44,8 @@
|
||||
- feature: HUEDevice: allow ct presets in webCmd
|
||||
new subTypes extcolordimer and ctdimer
|
||||
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
|
||||
- added: 42_SMARTMON: Frontend to smartctl (maintainer: hexenmeister)
|
||||
- feature: 70_PushNotifier added line break in Messages (xusader)
|
||||
@ -43,7 +55,8 @@
|
||||
- bugfix: FB_CALLMONITOR: fixing not working company numbers
|
||||
reverse search for search.ch
|
||||
- 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
|
||||
- feature: new module 52_I2C_MCP342x.pm added (klausw)
|
||||
- feature: SYSMON: read cpu temp on FritzBox
|
||||
@ -57,7 +70,8 @@
|
||||
- feature: new module 98_logProxy.pm added (justme1968)
|
||||
- change: 66_ECMD: ReadyFn added (fixes issue under Windows)
|
||||
- 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
|
||||
- feature: 10_IT empfang (by bjoernh)
|
||||
- bugfix: PRESENCE: fix race condition, when delete disabled attribute and
|
||||
|
@ -16,6 +16,7 @@ sub FW_answerCall($);
|
||||
sub FW_dev2image($;$);
|
||||
sub FW_devState($$@);
|
||||
sub FW_digestCgi($);
|
||||
sub FW_directNotify($$);
|
||||
sub FW_doDetail($);
|
||||
sub FW_fatal($);
|
||||
sub FW_fileList($);
|
||||
@ -187,11 +188,7 @@ FHEMWEB_Initialize($)
|
||||
closedir(DH);
|
||||
}
|
||||
|
||||
$data{webCmdFn}{slider} = "FW_sliderFn";
|
||||
$data{webCmdFn}{timepicker} = "FW_timepickerFn";
|
||||
$data{webCmdFn}{noArg} = "FW_noArgFn";
|
||||
$data{webCmdFn}{textField} = "FW_textFieldFn";
|
||||
$data{webCmdFn}{"~dropdown"}= "FW_dropdownFn"; # Should be the last
|
||||
$data{webCmdFn}{"~"} = "FW_widgetFallbackFn"; # Should be the last
|
||||
|
||||
if($init_done) { # reload workaround
|
||||
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 = "$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);
|
||||
}
|
||||
$arg = "/$dir/$ofile";
|
||||
@ -617,7 +616,6 @@ FW_answerCall($)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
##############################
|
||||
# FHEMWEB extensions (FLOORPLOAN, SVG_WriteGplot, etc)
|
||||
my $FW_contentFunc;
|
||||
@ -696,18 +694,26 @@ FW_answerCall($)
|
||||
FW_pO "<meta http-equiv=\"refresh\" content=\"$rf\">" if($rf);
|
||||
}
|
||||
|
||||
########################
|
||||
# CSS
|
||||
my $cssTemplate = "<link href=\"$FW_ME/%s\" rel=\"stylesheet\"/>";
|
||||
FW_pO sprintf($cssTemplate, "pgm2/style.css");
|
||||
my @cssFiles = split(" ", AttrVal($FW_wname, "CssFiles", ""));
|
||||
map { FW_pO sprintf($cssTemplate, $_); } @cssFiles;
|
||||
FW_pO sprintf($cssTemplate, "pgm2/jquery-ui.min.css");
|
||||
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
|
||||
my $jsTemplate = '<script type="text/javascript" src="%s"></script>';
|
||||
if(defined($data{FWEXT})) {
|
||||
foreach my $k (sort keys %{$data{FWEXT}}) {
|
||||
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};
|
||||
$script = ($script =~ m,^/,) ? "$FW_ME$script" : "$FW_ME/pgm2/$script";
|
||||
FW_pO sprintf($jsTemplate, $script);
|
||||
@ -715,21 +721,18 @@ FW_answerCall($)
|
||||
}
|
||||
|
||||
#######################
|
||||
# Other JavaScripts
|
||||
FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/svg.js") if($FW_plotmode eq "SVG");
|
||||
# Other JavaScripts + their Attributes
|
||||
map { FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/$_") } @FW_fhemwebjs;
|
||||
|
||||
$jsTemplate = '<script attr=\'%s\' type="text/javascript" src="%s"></script>';
|
||||
map {
|
||||
my $n = $_; $n =~ s+.*/++; $n =~ s/.js$//; $n =~ s/fhem_//; $n .= "Param";
|
||||
FW_pO sprintf($jsTemplate, AttrVal($FW_wname, $n, ""), "$FW_ME/$_");
|
||||
} split(" ", AttrVal($FW_wname, "JavaScripts", ""));
|
||||
|
||||
my $onload = AttrVal($FW_wname, "longpoll", 1) ?
|
||||
"onload=\"FW_delayedStart()\"" : "";
|
||||
my $csrf= ($FW_CSRF ? "fwcsrf='$defs{$FW_wname}{CSRFTOKEN}'" : "");
|
||||
FW_pO "</head>\n<body generated=\"".(time()-1)
|
||||
."\" name=\"$t\" $csrf $onload>";
|
||||
my $gen = 'generated="'.(time()-1).'"';
|
||||
my $lp = 'longpoll="'.AttrVal($FW_wname,"longpoll",1).'"';
|
||||
FW_pO "</head>\n<body name=\"$t\" $gen $lp $csrf>";
|
||||
|
||||
if($FW_activateInform) {
|
||||
$cmd = "style eventMonitor $FW_activateInform";
|
||||
@ -921,7 +924,7 @@ FW_makeTable($$$@)
|
||||
} else {
|
||||
if( $title eq "Attributes" ) {
|
||||
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>";
|
||||
} else {
|
||||
FW_pO "<td><div class=\"dname\">$n</div></td>";
|
||||
@ -978,7 +981,7 @@ FW_makeTable($$$@)
|
||||
##############################
|
||||
# Used only for set or attr lists.
|
||||
sub
|
||||
FW_makeSelect($$$$)
|
||||
FW_detailSelect($$$$)
|
||||
{
|
||||
my ($d, $cmd, $list,$class) = @_;
|
||||
return if(!$list || $FW_hiddenroom{input});
|
||||
@ -987,8 +990,9 @@ FW_makeSelect($$$$)
|
||||
my $selEl = (defined($al[0]) ? $al[0] : " ");
|
||||
$selEl = $1 if($list =~ m/([^ ]*):slider,/); # promote a slider if available
|
||||
$selEl = "room" if($list =~ m/room:/);
|
||||
$list =~ s/"/"/g;
|
||||
|
||||
FW_pO "<div class='makeSelect'>";
|
||||
FW_pO "<div class='makeSelect' dev=\"$d\" cmd=\"$cmd\" list=\"$list\">";
|
||||
FW_pO "<form method=\"$FW_formmethod\" ".
|
||||
"action=\"$FW_ME$FW_subdir\" autocomplete=\"off\">";
|
||||
FW_pO FW_hidden("detail", $d);
|
||||
@ -996,12 +1000,8 @@ FW_makeSelect($$$$)
|
||||
FW_pO FW_hidden("dev.$cmd$d", $d);
|
||||
FW_pO FW_submit("cmd.$cmd$d", $cmd, $class);
|
||||
FW_pO "<div class=\"$class downText\"> $d </div>";
|
||||
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_select("sel_$cmd$d","arg.$cmd$d",\@al, $selEl, $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>";
|
||||
}
|
||||
|
||||
@ -1037,12 +1037,8 @@ FW_doDetail($)
|
||||
use strict "refs";
|
||||
}
|
||||
|
||||
FW_pO "<form method=\"$FW_formmethod\" action=\"$FW_ME\">";
|
||||
FW_pO FW_hidden("detail", $d);
|
||||
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_detailSelect($d, "set", FW_widgetOverride($d, getAllSets($d)), "set");
|
||||
FW_detailSelect($d, "get", FW_widgetOverride($d, getAllGets($d)), "get");
|
||||
|
||||
FW_makeTable("Internals", $d, $h);
|
||||
FW_makeTable("Readings", $d, $h->{READINGS});
|
||||
@ -1057,7 +1053,7 @@ FW_doDetail($)
|
||||
$attrList = FW_widgetOverride($d, $attrList);
|
||||
$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");
|
||||
## dependent objects
|
||||
@ -1070,7 +1066,6 @@ FW_doDetail($)
|
||||
push(@dob, $dn);
|
||||
}
|
||||
}
|
||||
FW_pO "</form>";
|
||||
FW_makeTableFromArray("Probably associated with", "assoc", @dob,);
|
||||
|
||||
FW_pO "</td></tr></table>";
|
||||
@ -1078,6 +1073,7 @@ FW_doDetail($)
|
||||
FW_pH "cmd=style iconFor $d", "Select icon";
|
||||
FW_pH "cmd=style showDSI $d", "Extend devStateIcon";
|
||||
FW_pH "$FW_ME/docs/commandref.html#${t}", "Device specific help";
|
||||
FW_pH "cmd=delete $d", "Delete this device ($d)" if($d ne "global");
|
||||
FW_pO "<br><br>";
|
||||
FW_pO "</div>";
|
||||
|
||||
@ -1300,7 +1296,7 @@ FW_showRoom()
|
||||
$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\">";
|
||||
FW_pO "<div id=\"content\" room=\"$FW_room\">";
|
||||
FW_pO "<table class=\"roomoverview\">"; # Need for equal width of subtables
|
||||
@ -1358,7 +1354,7 @@ FW_showRoom()
|
||||
$icon = FW_makeImage($icon,$icon,"icon") . " " if($icon);
|
||||
|
||||
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 {
|
||||
FW_pH "detail=$d", "$icon$devName", 1, "col1" if(!$usuallyAtEnd{$d});
|
||||
}
|
||||
@ -1506,8 +1502,10 @@ FW_returnFileAsStream($$$$$)
|
||||
}
|
||||
|
||||
if(!open(FH, $path)) {
|
||||
Log3 $FW_wname, 2, "FHEMWEB $FW_wname $path: $!";
|
||||
FW_pO "<div id=\"content\">$path: $!</div>";
|
||||
Log3 $FW_wname, 4, "FHEMWEB $FW_wname $path: $!";
|
||||
TcpServer_WriteBlocking($FW_chash,
|
||||
"HTTP/1.1 404 Not Found\r\n".
|
||||
"Content-Length:0\r\n\r\n");
|
||||
FW_closeConn($FW_chash);
|
||||
return 0;
|
||||
}
|
||||
@ -1569,12 +1567,12 @@ FW_hidden($$)
|
||||
sub
|
||||
FW_select($$$$$@)
|
||||
{
|
||||
my ($id, $n, $va, $def, $class, $jSelFn) = @_;
|
||||
my ($id, $name, $valueArray, $selected, $class, $jSelFn) = @_;
|
||||
$jSelFn = ($jSelFn ? "onchange=\"$jSelFn\"" : "");
|
||||
$id = ($id ? "id=\"$id\" informId=\"$id\"" : "");
|
||||
my $s = "<select $jSelFn $id name=\"$n\" class=\"$class\">";
|
||||
foreach my $v (@{$va}) {
|
||||
if(defined($def) && $v eq $def) {
|
||||
my $s = "<select $jSelFn $id name=\"$name\" class=\"$class\">";
|
||||
foreach my $v (@{$valueArray}) {
|
||||
if(defined($selected) && $v eq $selected) {
|
||||
$s .= "<option selected=\"selected\" value='$v'>$v</option>\n";
|
||||
} else {
|
||||
$s .= "<option value='$v'>$v</option>\n";
|
||||
@ -1750,14 +1748,16 @@ FW_style($$)
|
||||
my $filePath = FW_fileNameToPath($fileName);
|
||||
|
||||
$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) {
|
||||
FW_pO "<div id=\"content\">$filePath: $!</div>";
|
||||
return;
|
||||
}
|
||||
my $ret = FW_fC("rereadcfg") if($filePath eq $attr{global}{configfile});
|
||||
$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);
|
||||
$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
|
||||
FW_roomStatesForInform($$)
|
||||
{
|
||||
@ -2219,7 +2229,7 @@ FW_roomStatesForInform($$)
|
||||
|
||||
my ($allSet, $cmdlist, $txt) = FW_devState($dn, "", \%extPage);
|
||||
if($defs{$dn} && $defs{$dn}{STATE} && $defs{$dn}{TYPE} ne "weblink") {
|
||||
push @data, "$dn<<$defs{$dn}{STATE}<<$txt";
|
||||
push @data, FW_longpollInfo($dn, $defs{$dn}{STATE}, $txt);
|
||||
}
|
||||
}
|
||||
my $data = join("\n", map { s/\n/ /gm; $_ } @data)."\n";
|
||||
@ -2265,7 +2275,7 @@ FW_Notify($$)
|
||||
if( !$modules{$defs{$dn}{TYPE}}{FW_atPageEnd} ) {
|
||||
my ($allSet, $cmdlist, $txt) = FW_devState($dn, "", \%extPage);
|
||||
($FW_wname, $FW_ME, $FW_ss, $FW_tp, $FW_subdir) = @old;
|
||||
push @data, "$dn<<$dev->{STATE}<<$txt";
|
||||
push @data, FW_longpollInfo($dn, $dev->{STATE}, $txt);
|
||||
}
|
||||
|
||||
#Add READINGS
|
||||
@ -2277,8 +2287,8 @@ FW_Notify($$)
|
||||
next; #ignore 'set' commands
|
||||
}
|
||||
my ($readingName,$readingVal) = split(": ",$events->[$i],2);
|
||||
push @data, "$dn-$readingName<<$readingVal<<$readingVal";
|
||||
push @data, "$dn-$readingName-ts<<$tn<<$tn";
|
||||
push @data, FW_longpollInfo("$dn-$readingName",$readingVal,$readingVal);
|
||||
push @data, FW_longpollInfo("$dn-$readingName-ts", $tn, $tn);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2310,6 +2320,24 @@ FW_Notify($$)
|
||||
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
|
||||
sub
|
||||
@ -2371,16 +2399,7 @@ FW_devState($$@)
|
||||
}
|
||||
$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", "");
|
||||
@ -2488,124 +2507,31 @@ FW_htmlEscape($)
|
||||
###########################
|
||||
# Widgets START
|
||||
sub
|
||||
FW_sliderFn($$$$$)
|
||||
FW_widgetFallbackFn()
|
||||
{
|
||||
my ($FW_wname, $d, $FW_room, $cmd, $values) = @_;
|
||||
|
||||
return undef if($values !~ m/^slider,([-\d.]*),([-\d.]*),([-\d.]*)(,1)?$/);
|
||||
return "" if($cmd =~ m/ /); # webCmd pct 30 should generate a link
|
||||
my ($min,$stp, $max, $flt) = ($1, $2, $3, $4);
|
||||
$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>";
|
||||
}
|
||||
# webCmd "temp 30" should remain text
|
||||
# noArg is needed for fhem.cfg.demo / Cinema
|
||||
return "" if(!$values || $values eq "noArg");
|
||||
|
||||
sub
|
||||
FW_noArgFn($$$$$)
|
||||
{
|
||||
my ($FW_wname, $d, $FW_room, $cmd, $values) = @_;
|
||||
|
||||
return undef if($values !~ m/^noArg$/);
|
||||
return "";
|
||||
}
|
||||
|
||||
sub
|
||||
FW_timepickerFn()
|
||||
{
|
||||
my ($FW_wname, $d, $FW_room, $cmd, $values) = @_;
|
||||
|
||||
return undef if($values ne "time");
|
||||
return "" if($cmd =~ m/ /); # webCmd on-for-timer 30 should generate a link
|
||||
my $srf = $FW_room ? "&room=$FW_room" : "";
|
||||
my $cv = ReadingsVal($d, $cmd, Value($d));
|
||||
$cmd = "" if($cmd eq "state");
|
||||
my $c = "\"$FW_ME?cmd=set $d $cmd %$srf\"";
|
||||
return "<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") {
|
||||
$txt = ReadingsVal($d, $cmd, 20);
|
||||
$txt =~ s/ .*//; # Cut off Celsius
|
||||
$txt = sprintf("%2.1f", int(2*$txt)/2) if($txt =~ m/[0-9.-]/);
|
||||
} else {
|
||||
$txt = ReadingsVal($d, $cmd, Value($d));
|
||||
$txt =~ s/$cmd //;
|
||||
my($reading) = split( ' ', $cmd, 2 );
|
||||
my $current;
|
||||
if($cmd eq "desired-temp" || $cmd eq "desiredTemperature") {
|
||||
$current = ReadingsVal($d, $cmd, 20);
|
||||
$current =~ s/ .*//; # Cut off Celsius
|
||||
$current = sprintf("%2.1f", int(2*$current)/2) if($current =~ m/[0-9.-]/);
|
||||
} else {
|
||||
$current = ReadingsVal($d, $reading, undef);
|
||||
if( !defined($current) ) {
|
||||
$reading = 'state';
|
||||
$current = Value($d);
|
||||
}
|
||||
|
||||
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;
|
||||
$fwsel = ($cmd eq "state" ? "" : "$cmd ") .
|
||||
FW_select("$d-$cmd","val.$d", \@tv, $txt,"dropdown","$selFunct");
|
||||
return "<td colspan='2'>$fwsel</td>";
|
||||
$current =~ s/$cmd //;
|
||||
}
|
||||
return undef;
|
||||
return "<td><div class='fhemWidget' cmd='$cmd' reading='$reading' ".
|
||||
"dev='$d' arg='$values' current='$current'></div></td>";
|
||||
}
|
||||
|
||||
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
|
||||
###########################
|
||||
|
||||
@ -3148,18 +3074,23 @@ FW_widgetOverride($$)
|
||||
<li>if the modifier is ":time", then a javascript driven timepicker 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
|
||||
":slider,<min>,<step>,<max>[,1]", then a
|
||||
javascript driven slider is displayed. The optional ,1 at the end
|
||||
avoids the rounding of floating-point numbers.</li>
|
||||
|
||||
<li>if the modifier is of the form ":multiple,val1,val2,...", then
|
||||
multiple values can be selected and own values can be written, the
|
||||
result is comma separated.</li>
|
||||
<li>if the modifier is of the form ":multiple-strict,val1,val2,...", then
|
||||
multiple values can be selected and no new values can be added, the
|
||||
result is comma separated.</li>
|
||||
|
||||
<li>if the modifier is of the form ":multiple-strict,val1,val2,...",
|
||||
then multiple values can be selected and no new values can be
|
||||
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>
|
||||
</ul>
|
||||
If this attribute is specified for a FHEMWEB instance, then it is
|
||||
@ -3167,6 +3098,7 @@ FW_widgetOverride($$)
|
||||
<ul>
|
||||
attr FS20dev widgetOverride on-till:time<br>
|
||||
attr WEB widgetOverride room:textField<br>
|
||||
attr dimmer widgetOverride dim:knob,min:1,max:100,step:1,linecap:round<br>
|
||||
</ul>
|
||||
</li>
|
||||
<br>
|
||||
@ -3714,13 +3646,17 @@ FW_widgetOverride($$)
|
||||
vorgesehene Widgets aendern kann.
|
||||
<ul>
|
||||
<li>Ist der Modifier ":noArg", wird kein weiteres Eingabefeld
|
||||
angezeigt.</li>
|
||||
angezeigt.</li>
|
||||
|
||||
<li>Ist der Modifier ":time", wird ein in Javaskript geschreibenes
|
||||
Zeitauswahlmenü angezeigt.</li>
|
||||
Zeitauswahlmenü angezeigt.</li>
|
||||
|
||||
<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öffnet.</li>
|
||||
|
||||
<li>Ist der Modifier in der Form
|
||||
":slider,<min>,<step>,<max>[,1]", so wird ein in
|
||||
@ -3735,8 +3671,15 @@ FW_widgetOverride($$)
|
||||
Mehrfachauswahl möglich, es können jedoch keine neuen
|
||||
Werte definiert werden. Das Ergebnis ist Komma-separiert.</li>
|
||||
|
||||
<li>In allen anderen Fällen erscheint ein Dropdown mit allen
|
||||
Modifier Werten.</li>
|
||||
<li>Ist der Modifier ":knob,min:1,max:100,...", dass ein
|
||||
jQuery knob Widget wird angezeigt. Die Parameter werden als eine
|
||||
Komma separierte Liste von Key:Value Paaren spezifiziert, wobei das
|
||||
data- Präfix entfällt. </li>
|
||||
|
||||
<li>In allen anderen Fällen (oder falls der Modified explizit
|
||||
mit :select anfaegt) erscheint ein HTML select mit allen Modifier
|
||||
Werten.</li>
|
||||
|
||||
</ul>
|
||||
Falls das Attribut für eine WEB Instanz gesetzt wurde, dann wird
|
||||
es bei allen von diesem Web-Instan angezeigten Geräten angewendet.
|
||||
@ -3744,6 +3687,7 @@ FW_widgetOverride($$)
|
||||
<ul>
|
||||
attr FS20dev widgetOverride on-till:time<br>
|
||||
attr WEB widgetOverride room:textField<br>
|
||||
attr dimmer widgetOverride dim:knob,min:1,max:100,step:1,linecap:round<br>
|
||||
</ul>
|
||||
</li><br>
|
||||
|
||||
|
@ -273,23 +273,18 @@ return "<br>Timespec wizard:".
|
||||
</tr><tr class="even"><td>Timespec</td>
|
||||
<td><input type="text" id="aw_pts"></td>
|
||||
</tr><tr class="even"><td>Timespec</td>
|
||||
<td><input type="text" readonly id="aw_ts" size="5">
|
||||
<input type='button' value='+' id="aw_tsb"></td>
|
||||
<td><input type="text" name="aw_ts" id="aw_ts" size="5"></td>
|
||||
</tr>
|
||||
</tr><tr class="even">
|
||||
<td colspan="2"><input type="button" id="aw_md" value="Modify"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<script type="text/javascript">
|
||||
loadScript("pgm2/jquery.min.js", atDetails);
|
||||
function
|
||||
atDetails()
|
||||
{
|
||||
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() {
|
||||
var c = $("#aw_ip").prop("checked");
|
||||
$("#aw_ts").closest("tr").css("display", !c ? "table-row" : "none");
|
||||
@ -300,7 +295,6 @@ return "<br>Timespec wizard:".
|
||||
$("#aw_ip").prop("checked", ip);
|
||||
$("#aw_ts").val(ip ? "12:00" : ts);
|
||||
$("#aw_pts").val(ip ? ts : 'sunset()');
|
||||
$("#aw_tsb").click(tsClick);
|
||||
$("#aw_ip").change(ipClick);
|
||||
ipClick();
|
||||
$("#aw_md").click(function(){
|
||||
|
@ -951,8 +951,8 @@ FileLog_sampleDataFn($$$$$)
|
||||
for(my $r=0; $r < $max; $r++) {
|
||||
my @f = split(":", ($flog->[$r] ? $flog->[$r] : ":::"), 4);
|
||||
my $ret = "";
|
||||
$ret .= SVG_sel("par_${r}_0", $colnums, $f[0]);
|
||||
$ret .= SVG_sel("par_${r}_1", $colregs, $f[1]);
|
||||
$ret .= SVG_sel("par_${r}_0", $colnums, $f[0], undef, "svgColumn");
|
||||
$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}_3", "", $f[3], 6);
|
||||
push @htmlArr, $ret;
|
||||
|
@ -32,7 +32,7 @@ sub SVG_calcOffsets($$);
|
||||
sub SVG_doround($$$);
|
||||
sub SVG_fmtTime($$);
|
||||
sub SVG_pO($);
|
||||
sub SVG_readgplotfile($$);
|
||||
sub SVG_readgplotfile($$$);
|
||||
sub SVG_render($$$$$$$$$;$$);
|
||||
sub SVG_showLog($);
|
||||
sub SVG_substcfg($$$$$$);
|
||||
@ -40,8 +40,12 @@ sub SVG_time_align($$);
|
||||
sub SVG_time_to_sec($);
|
||||
sub SVG_openFile($$$);
|
||||
sub SVG_doShowLog($$$$;$$);
|
||||
sub SVG_getData($$$$$);
|
||||
sub SVG_sel($$$;$$);
|
||||
|
||||
my %SVG_devs; # hash of from/to entries per device
|
||||
my $SVG_id=0;
|
||||
|
||||
|
||||
#####################################
|
||||
sub
|
||||
@ -50,7 +54,8 @@ SVG_Initialize($)
|
||||
my ($hash) = @_;
|
||||
|
||||
$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->{FW_summaryFn} = "SVG_FwFn";
|
||||
$hash->{FW_detailFn} = "SVG_FwFn";
|
||||
@ -133,6 +138,21 @@ jsSVG_getAttrs($)
|
||||
} 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
|
||||
SVG_FwFn($$$$)
|
||||
@ -141,6 +161,11 @@ SVG_FwFn($$$$)
|
||||
my $hash = $defs{$d};
|
||||
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") {
|
||||
|
||||
my @d=split(":",$defs{$d}{DEF});
|
||||
@ -182,11 +207,10 @@ SVG_FwFn($$$$)
|
||||
"&pos=" . join(";", map {"$_=$FW_pos{$_}"} keys %FW_pos);
|
||||
|
||||
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\">";
|
||||
|
||||
if(AttrVal($FW_wname, "plotEmbed",
|
||||
$FW_userAgent !~ m/(iPhone|iPad|iPod).*OS (8|9)/)) {
|
||||
if(SVG_isEmbed($FW_wname)) {
|
||||
$ret .= "<embed src=\"$arg\" type=\"image/svg+xml\" " .
|
||||
"width=\"$w\" height=\"$h\" name=\"$d\"/>\n";
|
||||
|
||||
@ -236,12 +260,12 @@ SVG_txt($$$$)
|
||||
}
|
||||
|
||||
sub
|
||||
SVG_sel($$$@)
|
||||
SVG_sel($$$;$$)
|
||||
{
|
||||
my ($v,$l,$c,$fnData) = @_;
|
||||
my ($v,$l,$c,$fnData,$class) = @_;
|
||||
my @al = split(",",$l);
|
||||
$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' );
|
||||
|
||||
my $ld = $defs{$d}{LOGDEVICE};
|
||||
my $ldt = $defs{$ld}{TYPE};
|
||||
|
||||
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 $ret = "<br>";
|
||||
@ -280,8 +302,6 @@ SVG_PEdit($$$$)
|
||||
"action=\"$FW_ME/SVG_WriteGplot\">";
|
||||
$ret .= "Plot Editor";
|
||||
$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
|
||||
$ret .= FW_hidden("pos", "zoom=$FW_pos{zoom};off=$FW_pos{off}");
|
||||
}
|
||||
@ -314,22 +334,39 @@ SVG_PEdit($$$$)
|
||||
$ret .= "</tr>";
|
||||
|
||||
my $max = @{$conf{lType}}+1;
|
||||
my ($desc, $htmlArr, $example) = ("Spec", undef, "");
|
||||
if($modules{$ldt}{SVG_sampleDataFn}) {
|
||||
no strict "refs";
|
||||
($desc, $htmlArr, $example) =
|
||||
&{$modules{$ldt}{SVG_sampleDataFn}}($ld, $flog, $max,\%conf, $FW_wname);
|
||||
use strict "refs";
|
||||
} else {
|
||||
my @htmlArr;
|
||||
@htmlArr = map { SVG_txt("par_${_}_0","",$flog->[$_] ? $flog->[$_]:"",20) }
|
||||
(0..$max-1);
|
||||
$htmlArr = \@htmlArr;
|
||||
}
|
||||
my ($desc, $cnt) = ("Spec", 0);
|
||||
my (@srcHtml, @paramHtml, @exampleHtml, @revIdx);
|
||||
my @srcNames = grep { $modules{$defs{$_}{TYPE}}{SVG_sampleDataFn} }
|
||||
sort keys %defs;
|
||||
|
||||
$ret .= "<tr class=\"odd\"><td>Diagramm label</td>";
|
||||
$ret .= "<td>$desc</td>";
|
||||
$ret .=" <td>Y-Axis,Plot-Type,Style,Width</td></tr>";
|
||||
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";
|
||||
my ($ldesc, $paramHtml, $example) =
|
||||
&{$fn}($src, \@argArr, $lmax,\%conf, $FW_wname);
|
||||
use strict "refs";
|
||||
$desc = $ldesc;
|
||||
push @paramHtml, @{$paramHtml};
|
||||
map { push @exampleHtml, $example } (0..$lmax-1);
|
||||
|
||||
} else {
|
||||
push @paramHtml, map { SVG_txt("par_${_}_0","",$_,20) } @argArr;
|
||||
map { push @exampleHtml, "" } (0..$lmax-1);
|
||||
}
|
||||
|
||||
push @srcHtml,
|
||||
map { FW_select(undef,"src_$_",\@srcNames,$src,"svgSrc");} (0..$lmax-1);
|
||||
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;
|
||||
if(SVG_openFile($FW_cssdir,
|
||||
@ -338,33 +375,46 @@ SVG_PEdit($$$$)
|
||||
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++) {
|
||||
$ret .= "<tr class=\"".(($r&1)?"odd":"even")."\"><td>";
|
||||
$ret .= SVG_txt("title_${r}", "", !$conf{lTitle}[$r]&&$r<($max-1) ?
|
||||
"notitle" : $conf{lTitle}[$r], 12);
|
||||
$ret .= "</td><td>";
|
||||
$ret .= $htmlArr->[$r] if($htmlArr && @{$htmlArr} > $r);
|
||||
$ret .= "</td><td>";
|
||||
my $v = $conf{lAxis}[$r];
|
||||
$ret .= SVG_sel("axes_${r}", "left,right",
|
||||
my $idx = $revIdx[$r];
|
||||
$example .= "<div class='ex ex_$idx' style='display:".($idx?"none":"block").
|
||||
"'>$exampleHtml[$r]</div>";
|
||||
my $o = "<tr row='$idx' class=\"".(($r&1)?"odd":"even")."\"><td>";
|
||||
$o .= SVG_txt("title_$idx", "", !$conf{lTitle}[$idx]&&$idx<($max-1) ?
|
||||
"notitle" : $conf{lTitle}[$idx], 12);
|
||||
my $sh = $srcHtml[$r]; $sh =~ s/src_\d+/src_$idx/g;
|
||||
$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");
|
||||
$ret .= SVG_sel("type_${r}", "lines,points,steps,fsteps,histeps,bars",
|
||||
$conf{lType}[$r]);
|
||||
my $ls = $conf{lStyle}[$r];
|
||||
$o .= SVG_sel("type_${idx}", "lines,points,steps,fsteps,histeps,bars",
|
||||
$conf{lType}[$idx]);
|
||||
my $ls = $conf{lStyle}[$idx];
|
||||
if($ls) {
|
||||
$ls =~ s/class=//g;
|
||||
$ls =~ s/"//g;
|
||||
}
|
||||
$ret .= SVG_sel("style_${r}", join(",", @lineStyles), $ls);
|
||||
my $lw = $conf{lWidth}[$r];
|
||||
$o .= SVG_sel("style_$idx", join(",", @lineStyles), $ls);
|
||||
my $lw = $conf{lWidth}[$idx];
|
||||
if($lw) {
|
||||
$lw =~ s/.*stroke-width://g;
|
||||
$lw =~ s/"//g;
|
||||
}
|
||||
$ret .= SVG_sel("width_${r}", "0.2,0.5,1,1.5,2,3,4", ($lw ? $lw : 1));
|
||||
$ret .= "</td></tr>";
|
||||
$o .= SVG_sel("width_$idx", "0.2,0.5,1,1.5,2,3,4", ($lw ? $lw : 1));
|
||||
$o .= "</td></tr>";
|
||||
$output[$idx] = $o;
|
||||
}
|
||||
$ret .= join("", @output);
|
||||
$ret .= "<tr class=\"".(($r++&1)?"odd":"even")."\"><td colspan=\"3\">";
|
||||
$ret .= "Example lines for input:<br>$example</td></tr>";
|
||||
|
||||
@ -374,6 +424,32 @@ SVG_PEdit($$$$)
|
||||
"</td></tr>";
|
||||
|
||||
$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
|
||||
SVG_showData()
|
||||
{
|
||||
@ -446,17 +523,15 @@ SVG_showData()
|
||||
my $hash = $defs{$wl};
|
||||
my ($d, $gplotfile, $file) = split(":", $hash->{DEF});
|
||||
$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) {
|
||||
$FW_RET=$err;
|
||||
return 1;
|
||||
}
|
||||
SVG_calcOffsets($d, $wl);
|
||||
my ($f,$t)=($SVG_devs{$d}{from}, $SVG_devs{$d}{to});
|
||||
my $cmd = "get $d $file - $f $t " . join(" ", @{$flog});
|
||||
my $ret = FW_fC($cmd, 1);
|
||||
$ret =~ s/\n/<br>/gs;
|
||||
$FW_RET = "$cmd<br><br>$ret";
|
||||
$FW_RET = SVG_getData($d, $SVG_devs{$d}{from}, $SVG_devs{$d}{to}, $srcDesc,1);
|
||||
$FW_RET =~ s/\n/<br>/gs;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -480,7 +555,8 @@ SVG_WriteGplot($)
|
||||
}
|
||||
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);
|
||||
|
||||
my @rows;
|
||||
@ -501,7 +577,6 @@ SVG_WriteGplot($)
|
||||
push @rows, "set y2range $FW_webArgs{y2range}" if($FW_webArgs{y2range});
|
||||
push @rows, "";
|
||||
|
||||
my $ld = $FW_webArgs{logdevicetype};
|
||||
my @plot;
|
||||
for(my $i=0; $i <= $maxLines; $i++) {
|
||||
next if(!$FW_webArgs{"title_$i"});
|
||||
@ -512,7 +587,8 @@ SVG_WriteGplot($)
|
||||
join(":", map { $v[$_] =~ s/:/\\x3a/g if($_<$#v); $v[$_] } 0..$#v) :
|
||||
$v[0];
|
||||
|
||||
push @rows, "#$ld $r";
|
||||
my $src = $FW_webArgs{"src_$i"};
|
||||
push @rows, "#$src $r";
|
||||
push @plot, "\"<IN>\" using 1:2 axes ".
|
||||
($FW_webArgs{"axes_$i"} eq "right" ? "x1y2" : "x1y1").
|
||||
($FW_webArgs{"title_$i"} eq "notitle" ? " notitle" :
|
||||
@ -536,31 +612,51 @@ SVG_WriteGplot($)
|
||||
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
|
||||
SVG_readgplotfile($$)
|
||||
SVG_readgplotfile($$$)
|
||||
{
|
||||
my ($wl, $gplot_pgm) = @_;
|
||||
my ($wl, $gplot_pgm, $plotmode) = @_;
|
||||
|
||||
############################
|
||||
# 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
|
||||
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}
|
||||
if($defs{$wl} && $defs{$wl}{LOGDEVICE} && $defs{$defs{$wl}{LOGDEVICE}});
|
||||
$ldType = $defs{$wl}{TYPE}
|
||||
if(!$ldType && $defs{$wl});
|
||||
if($ld && $defs{$ld});
|
||||
if(!$ldType && $defs{$wl}) {
|
||||
$ldType = $defs{$wl}{TYPE};
|
||||
$ld = $wl;
|
||||
}
|
||||
|
||||
my ($err, @svgplotfile) = FileRead($gplot_pgm);
|
||||
return ("$err", undef) if($err);
|
||||
my ($plotfnCnt, $srcNum) = (0,0);
|
||||
my @empty;
|
||||
$srcDesc{all} = "";
|
||||
$srcDesc{order} = \@empty;
|
||||
|
||||
foreach my $l (@svgplotfile) {
|
||||
$l = "$l\n" unless $l =~ m/\n$/;
|
||||
my $plotfn = undef;
|
||||
if($l =~ m/^#$ldType (.*)$/) {
|
||||
$plotfn = $1;
|
||||
Log 3, "$wl: space is not allowed in $ldType definition: $plotfn"
|
||||
if($plotfn =~ m/\s/);
|
||||
my ($src, $plotfn) = (undef, undef);
|
||||
if($l =~ m/^#([^ ]*) (.*)$/) {
|
||||
if($1 eq $ldType) {
|
||||
$src = $ld; $plotfn = $2;
|
||||
} elsif($defs{$1}) {
|
||||
$src = $1; $plotfn = $2;
|
||||
}
|
||||
} elsif($l =~ "^plot" || $plot) {
|
||||
$plot .= $l;
|
||||
} else {
|
||||
@ -568,6 +664,8 @@ SVG_readgplotfile($$)
|
||||
}
|
||||
|
||||
if($plotfn) {
|
||||
Log 3, "$wl: space is not allowed in $ldType definition: $plotfn"
|
||||
if($plotfn =~ m/\s/);
|
||||
my $specval = AttrVal($wl, "plotfunction", undef);
|
||||
if ($specval) {
|
||||
my @spec = split(" ",$specval);
|
||||
@ -577,11 +675,22 @@ SVG_readgplotfile($$)
|
||||
$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
|
||||
@ -592,9 +701,6 @@ SVG_substcfg($$$$$$)
|
||||
# interpret title and label as a perl command and make
|
||||
# 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}
|
||||
if($defs{$wl} && $defs{$wl}{LOGDEVICE});
|
||||
$ldt = "" if(!defined($ldt));
|
||||
@ -605,17 +711,17 @@ SVG_substcfg($$$$$$)
|
||||
my $fileesc = $file;
|
||||
$fileesc =~ s/\\/\\\\/g; # For Windows, by MarkusRR
|
||||
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 @g_label;
|
||||
if ($label) {
|
||||
@g_label = split("::",$label);
|
||||
foreach (@g_label) {
|
||||
$_ = AnalyzeCommand(undef, "{ $_ }");
|
||||
$_ = AnalyzeCommand(undef, "{ $_ }", $allowed);
|
||||
}
|
||||
}
|
||||
$attr{global}{verbose} = $oll;
|
||||
|
||||
my $gplot_script = join("", @{$cfg});
|
||||
$gplot_script .= $plot if(!$splitret);
|
||||
@ -623,7 +729,7 @@ SVG_substcfg($$$$$$)
|
||||
$gplot_script =~ s/<OUT>/$tmpfile/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/<TL>/$title/g;
|
||||
@ -816,10 +922,9 @@ SVG_doShowLog($$$$;$$)
|
||||
{
|
||||
my ($wl, $d, $type, $file, $styleW, $styleH) = @_;
|
||||
my $pm = AttrVal($wl,"plotmode",$FW_plotmode);
|
||||
|
||||
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}) {
|
||||
my $msg = ($defs{$d} ? "Cannot read $gplot_pgm" : "No Logdevice $d");
|
||||
Log3 $FW_wname, 1, $msg;
|
||||
@ -851,8 +956,8 @@ SVG_doShowLog($$$$;$$)
|
||||
# Read the data from the filelog
|
||||
my $oll = $attr{global}{verbose};
|
||||
$attr{global}{verbose} = 0; # Else the filenames will be Log'ged
|
||||
my @path = split(" ", FW_fC("get $d $file $tmpfile $f $t " .
|
||||
join(" ", @{$flog})));
|
||||
my @path = split(" ",
|
||||
FW_fC("get $d $file $tmpfile $f $t $srcDesc->{all}"));
|
||||
$attr{global}{verbose} = $oll;
|
||||
|
||||
# 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 $oll = $attr{global}{verbose};
|
||||
$attr{global}{verbose} = 0; # Else the filenames will be Log'ged
|
||||
my @path = split(" ", FW_fC("get $d $file $tmpfile $f $t " .
|
||||
join(" ", @{$flog})));
|
||||
my @path = split(" ",
|
||||
FW_fC("get $d $file $tmpfile $f $t $srcDesc->{all}"));
|
||||
$attr{global}{verbose} = $oll;
|
||||
|
||||
# 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...
|
||||
$t = 9 if(!$t); # till the end
|
||||
|
||||
Log3 $FW_wname, 5,
|
||||
"plotcommand: get $d $file INT $f $t " . join(" ", @{$flog});
|
||||
Log3 $FW_wname, 5, "plotcommand: get $d $file INT $f $t ".$srcDesc->{all};
|
||||
|
||||
$FW_RETTYPE = "image/svg+xml";
|
||||
|
||||
@ -929,10 +1033,10 @@ SVG_doShowLog($$$$;$$)
|
||||
close(CFH);
|
||||
|
||||
} 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>");
|
||||
my $ret = SVG_render($wl, $f, $t, $cfg,
|
||||
$internal_data, $plot, $FW_wname, $FW_cssdir, $flog,
|
||||
my $ret = SVG_render($wl, $f, $t, $cfg, $da,
|
||||
$plot, $FW_wname, $FW_cssdir, $srcDesc,
|
||||
$styleW, $styleH);
|
||||
$internal_data = "";
|
||||
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
|
||||
@ -1051,17 +1207,16 @@ SVG_render($$$$$$$$$;$$)
|
||||
my $from = shift; # e.g. 2008-01-01
|
||||
my $to = shift; # e.g. 2009-01-01
|
||||
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 $parent_name = shift; # e.g. FHEMWEB instance name
|
||||
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 $styleH = shift;
|
||||
|
||||
$SVG_RET="";
|
||||
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_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 $h = $oh-2*$y; # Rect size
|
||||
|
||||
# Keep only the Filter part of the #FileLog
|
||||
$flog = join(" ", map { my @a=split(":",$_);
|
||||
$a[1]=~s/\.[^\.]*$//; $a[1]; } @{$flog});
|
||||
$flog = AttrVal($parent_name, "longpollSVG", 0) ? "flog=\" $flog \"" : "";
|
||||
my $filter = $srcDesc->{all};
|
||||
$filter =~ s/[^: ]*:([^: ]):[^ ]*/$1/g;
|
||||
$filter = AttrVal($parent_name, "longpollSVG", 0) ? "flog=\" $filter \"" : "";
|
||||
|
||||
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) {
|
||||
SVG_pO '<?xml version="1.0" encoding="UTF-8"?>';
|
||||
SVG_pO '<!DOCTYPE svg>';
|
||||
SVG_pO '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" '.
|
||||
'xmlns:xlink="http://www.w3.org/1999/xlink" '.$flog.'>';
|
||||
SVG_pO "<svg $svghdr>";
|
||||
} else {
|
||||
SVG_pO '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" '.
|
||||
'xmlns:xlink="http://www.w3.org/1999/xlink" '.
|
||||
"style='width:${styleW}px; height:${styleH}px;' ".
|
||||
'>';
|
||||
SVG_pO "<svg $svghdr style='width:${styleW}px; height:${styleH}px;'>";
|
||||
}
|
||||
|
||||
my $prf = AttrVal($parent_name, "stylesheetPrefix", "");
|
||||
@ -1134,17 +1290,6 @@ SVG_render($$$$$$$$$;$$)
|
||||
SVG_pO "<text id=\"svg_title\" x=\"$off1\" y=\"$off2\" " .
|
||||
"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
|
||||
if(!$SVG_ss) {
|
||||
@ -1198,63 +1343,69 @@ SVG_render($$$$$$$$$;$$)
|
||||
my ($dxp, $dyp) = (\(), \());
|
||||
|
||||
my ($d, $v, $ld, $lv) = ("","","","");
|
||||
|
||||
my ($dpl,$dpoff,$l) = (length($$dp), 0, "");
|
||||
while($dpoff < $dpl) { # using split instead is memory hog
|
||||
my $ndpoff = index($$dp, "\n", $dpoff);
|
||||
if($ndpoff == -1) {
|
||||
$l = substr($$dp, $dpoff);
|
||||
} else {
|
||||
$l = substr($$dp, $dpoff, $ndpoff-$dpoff);
|
||||
}
|
||||
$dpoff = $ndpoff+1;
|
||||
if($l =~ m/^#/) {
|
||||
my $a = $conf{lAxis}[$idx];
|
||||
if(defined($a)) {
|
||||
$hmin{$a} = $min if(!defined($hmin{$a}) || $hmin{$a} > $min);
|
||||
$hmax{$a} = $max if(!defined($hmax{$a}) || $hmax{$a} < $max);
|
||||
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, "");
|
||||
while($dpoff < $dpl) { # using split instead is memory hog
|
||||
my $ndpoff = index($$dp, "\n", $dpoff);
|
||||
if($ndpoff == -1) {
|
||||
$l = substr($$dp, $dpoff);
|
||||
} else {
|
||||
$l = substr($$dp, $dpoff, $ndpoff-$dpoff);
|
||||
}
|
||||
($min, $max) = (99999999, -99999999);
|
||||
$hdx[$idx] = $dxp; $hdy[$idx] = $dyp;
|
||||
($dxp, $dyp) = (\(), \());
|
||||
$idx++;
|
||||
|
||||
} elsif( $l =~ /^;/ ) { #allow ;special lines
|
||||
if( $l =~ m/^;p (\S+)\s(\S+)/ ) {# point
|
||||
my $xmul = $w/($xmax-$xmin);
|
||||
my $x1;
|
||||
if( $conf{xrange} ) {
|
||||
$x1 = int(($1-$xmin)*$xmul);
|
||||
} else {
|
||||
$x1 = $x1;
|
||||
$dpoff = $ndpoff+1;
|
||||
if($l =~ m/^#/) {
|
||||
my $a = $conf{lAxis}[$idx];
|
||||
if(defined($a)) {
|
||||
$hmin{$a} = $min if(!defined($hmin{$a}) || $hmin{$a} > $min);
|
||||
$hmax{$a} = $max if(!defined($hmax{$a}) || $hmax{$a} < $max);
|
||||
}
|
||||
my $y1 = $2;
|
||||
($min, $max) = (99999999, -99999999);
|
||||
$hdx[$idx] = $dxp; $hdy[$idx] = $dyp;
|
||||
($dxp, $dyp) = (\(), \());
|
||||
$lIdx++;
|
||||
$idx = $srcDesc->{rev}{$dIdx}{$lIdx};
|
||||
last if(!$idx);
|
||||
|
||||
push @{$dxp}, $x1;
|
||||
push @{$dyp}, $y1;
|
||||
} elsif( $l =~ /^;/ ) { #allow ;special lines
|
||||
if( $l =~ m/^;p (\S+)\s(\S+)/ ) {# point
|
||||
my $xmul = $w/($xmax-$xmin);
|
||||
my $x1;
|
||||
if( $conf{xrange} ) {
|
||||
$x1 = int(($1-$xmin)*$xmul);
|
||||
} else {
|
||||
$x1 = $x1;
|
||||
}
|
||||
my $y1 = $2;
|
||||
|
||||
} elsif( $conf{lType}[$idx] eq "lines" ) {
|
||||
push @{$dxp}, undef;
|
||||
push @{$dyp}, $l;
|
||||
push @{$dxp}, $x1;
|
||||
push @{$dyp}, $y1;
|
||||
|
||||
} elsif( $conf{lType}[$idx] eq "lines" ) {
|
||||
push @{$dxp}, undef;
|
||||
push @{$dyp}, $l;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
($d, $v) = split(" ", $l);
|
||||
$d = ($tmul ? int((SVG_time_to_sec($d)-$fromsec)*$tmul) : $d);
|
||||
if($ld ne $d || $lv ne $v) { # Saves a lot on year zoomlevel
|
||||
$ld = $d; $lv = $v;
|
||||
push @{$dxp}, $d;
|
||||
push @{$dyp}, $v;
|
||||
$min = $v if($min > $v);
|
||||
$max = $v if($max < $v);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
($d, $v) = split(" ", $l);
|
||||
$d = ($tmul ? int((SVG_time_to_sec($d)-$fromsec)*$tmul) : $d);
|
||||
if($ld ne $d || $lv ne $v) { # Saves a lot on year zoomlevel
|
||||
$ld = $d; $lv = $v;
|
||||
push @{$dxp}, $d;
|
||||
push @{$dyp}, $v;
|
||||
$min = $v if($min > $v);
|
||||
$max = $v if($max < $v);
|
||||
}
|
||||
last if($ndpoff == -1);
|
||||
}
|
||||
last if($ndpoff == -1);
|
||||
}
|
||||
|
||||
$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...
|
||||
(!$tmul && !$dxp)) {
|
||||
SVG_pO "</svg>";
|
||||
return $SVG_RET;
|
||||
@ -1392,6 +1543,7 @@ SVG_render($$$$$$$$$;$$)
|
||||
|
||||
my (%hstep,%htics,%axdrawn);
|
||||
|
||||
my $allowed = AttrVal($FW_wname,"allowedCommands",undef);
|
||||
#-- yrange handling for axes x1y1..x1y8
|
||||
for my $idx (0..7) {
|
||||
my $a = "x1y".($idx+1);
|
||||
@ -1399,10 +1551,15 @@ SVG_render($$$$$$$$$;$$)
|
||||
my $yra="y".($idx+1)."range";
|
||||
$yra="yrange" if ($yra eq "y1range");
|
||||
#-- yrange is specified in plotfile
|
||||
if($conf{$yra} && $conf{$yra} =~ /\[(.*):(.*)\]/) {
|
||||
$hmin{$a} = $1 if($1 ne "");
|
||||
$hmax{$a} = $2 if($2 ne "");
|
||||
if($conf{$yra}) {
|
||||
$conf{$yra} = AnalyzeCommand(undef, $1, $allowed)
|
||||
if($conf{$yra} =~ /^({.*})$/);
|
||||
if($conf{$yra} =~ /\[(.*):(.*)\]/) {
|
||||
$hmin{$a} = $1 if($1 ne "");
|
||||
$hmax{$a} = $2 if($2 ne "");
|
||||
}
|
||||
}
|
||||
|
||||
#-- tics handling
|
||||
my $yt="y".($idx+1)."tics";
|
||||
$yt="ytics" if ($yt eq"y1tics");
|
||||
@ -1732,13 +1889,15 @@ SVG_render($$$$$$$$$;$$)
|
||||
}
|
||||
my $style = $conf{lStyle}[$i];
|
||||
$style =~ s/class="/class="legend /;
|
||||
SVG_pO "<text title=\"$desc\" ".
|
||||
"onclick=\"parent.svg_labelselect(evt)\" line_id=\"line_$i\" " .
|
||||
SVG_pO "<text title=\"$desc\" line_id=\"line_$i\" " .
|
||||
"x=\"$txtoff1\" y=\"$txtoff2\" text-anchor=\"end\" $style>$t</text>";
|
||||
$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>";
|
||||
return $SVG_RET;
|
||||
}
|
||||
@ -1974,6 +2133,9 @@ plotAsPng(@)
|
||||
set title <L1><br></li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
The value minAll and maxAll (representing the minimum/maximum over all
|
||||
values) is also available from the data hash.
|
||||
|
||||
</li>
|
||||
|
||||
<a name="title"></a>
|
||||
@ -2025,6 +2187,9 @@ plotAsPng(@)
|
||||
regexp switch.on, and "0" for the regexp switch.off.<br>
|
||||
Write .gplot file again<br>
|
||||
</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>
|
||||
The visibility of the ploteditor can be configured with the FHEMWEB attribute
|
||||
<a href="#ploteditor">ploteditor</a>.
|
||||
@ -2142,7 +2307,7 @@ plotAsPng(@)
|
||||
können ebenfalls die Werte der individuellen Kurve für min,
|
||||
max, mindate, maxdate, avg, cnt, sum, currval (letzter Wert) und currdate
|
||||
(letztes Datum) durch Zugriff der entsprechenden Werte über das
|
||||
DataHash verwendet werden. Siehe untenstehendes Beispiel:<br>
|
||||
data Hash verwendet werden. Siehe untenstehendes Beispiel:<br>
|
||||
<ul>
|
||||
<li>Beschriftunng der rechten und linken y-Achse:<br>
|
||||
<ul>
|
||||
@ -2164,6 +2329,8 @@ plotAsPng(@)
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
Die Werte minAll und maxAll (die das Minimum/Maximum aller Werte
|
||||
repräsentieren) sind ebenfals im data hash vorhanden.
|
||||
</li>
|
||||
|
||||
<a name="title"></a>
|
||||
@ -2229,6 +2396,9 @@ plotAsPng(@)
|
||||
.gplot-Datei erneut speichern<br>
|
||||
</ul>
|
||||
</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>
|
||||
Die sichtbarkeit des Plot-Editors kann mit dem FHEMWEB Attribut <a
|
||||
href="#ploteditor">ploteditor</a> konfiguriert werden.
|
||||
|
@ -17,81 +17,9 @@ Color_Initialize()
|
||||
sub
|
||||
FHEM_colorpickerInit()
|
||||
{
|
||||
$data{webCmdFn}{colorpicker} = "FHEM_colorpickerFn";
|
||||
$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 = (
|
||||
0 => "dim06%",
|
||||
1 => "dim12%",
|
||||
|
@ -1,30 +1,30 @@
|
||||
#Mon Aug 26 16:36:31 2013
|
||||
#Sun Jan 4 16:24:11 2015
|
||||
{
|
||||
'lcCinema' => {
|
||||
'Break' => {
|
||||
'CeilingLight' => 'dim37%',
|
||||
'ReadingLight' => 'dim37%'
|
||||
},
|
||||
'Cinema' => {
|
||||
'Screen' => 'down',
|
||||
'Projector' => 'on',
|
||||
'CeilingLight' => 'off',
|
||||
'ReadingLight' => 'off',
|
||||
'TV' => 'off'
|
||||
},
|
||||
'WatchTV' => {
|
||||
'Screen' => 'up',
|
||||
'Projector' => 'off',
|
||||
'CeilingLight' => 'off',
|
||||
'ReadingLight' => 'dim12%',
|
||||
'TV' => 'on'
|
||||
},
|
||||
'AllOff' => {
|
||||
'Screen' => 'up',
|
||||
'Projector' => 'off',
|
||||
'CeilingLight' => 'off',
|
||||
'ReadingLight' => 'off',
|
||||
'TV' => 'off'
|
||||
}
|
||||
}
|
||||
}
|
||||
'lcCinema' => {
|
||||
'Break' => {
|
||||
'CeilingLight' => 'dim37%',
|
||||
'ReadingLight' => 'dim37%'
|
||||
},
|
||||
'Cinema' => {
|
||||
'CeilingLight' => 'off',
|
||||
'Projector' => 'on',
|
||||
'Screen' => 'down',
|
||||
'ReadingLight' => 'off',
|
||||
'TV' => 'off'
|
||||
},
|
||||
'WatchTV' => {
|
||||
'CeilingLight' => 'off',
|
||||
'Projector' => 'off',
|
||||
'Screen' => 'up',
|
||||
'ReadingLight' => 'dim12%',
|
||||
'TV' => 'on'
|
||||
},
|
||||
'AllOff' => {
|
||||
'CeilingLight' => 'off',
|
||||
'Projector' => 'off',
|
||||
'Screen' => 'up',
|
||||
'ReadingLight' => 'off',
|
||||
'TV' => 'off'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,17 @@
|
||||
#Mon Feb 17 20:54:16 2014
|
||||
#Sun Jan 4 16:24:11 2015
|
||||
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 2013-08-25 14:23:20 LastDevice Office
|
||||
setstate AllLights 2013-08-25 14:23:20 LastDevice_Abs Office
|
||||
setstate AllLights 2013-08-25 14:23:20 state on
|
||||
setstate AllLights 2015-01-04 16:22:04 LastDevice Alarm
|
||||
setstate AllLights 2015-01-04 16:22:04 LastDevice_Abs Alarm
|
||||
setstate AllLights 2015-01-04 16:22:04 state undefined
|
||||
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 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 2013-08-13 08:00:48 DEVFAMILY WS300
|
||||
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_raw 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 tsecs 1376805797
|
||||
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 wind 0.5
|
||||
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.Dewpoint active
|
||||
setstate Log.Garden active
|
||||
setstate Logfile active
|
||||
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 2013-08-25 14:23:20 state on
|
||||
setstate Outdoor 2015-01-04 16:22:21 state on
|
||||
setstate Projector off
|
||||
setstate Projector 2013-08-26 18:01:06 state off
|
||||
setstate ReadingLight dim12%
|
||||
setstate ReadingLight 2013-08-26 18:01:06 state dim12%
|
||||
setstate Projector 2015-01-04 16:22:40 state off
|
||||
setstate RGB off
|
||||
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 SVG_01_Garden initialized
|
||||
setstate SVG_02_Cellar initialized
|
||||
setstate SVG_03_Dewpoint initialized
|
||||
setstate Screen up
|
||||
setstate Screen 2013-08-26 18:01:06 state up
|
||||
setstate TV on
|
||||
setstate TV 2013-08-26 18:01:06 state on
|
||||
setstate Screen 2015-01-04 16:22:40 state up
|
||||
setstate TV off
|
||||
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 autocreate active
|
||||
setstate colorInit 2015-01-04 16:19:04
|
||||
setstate dew_all active
|
||||
setstate eventTypes active
|
||||
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 2014-02-16 13:59:50 durTimerAbsence 0
|
||||
setstate rg_Guest1 2014-02-16 13:34:06 durTimerPresence 0
|
||||
setstate rg_Guest1 2014-02-15 16:15:34 durTimerSleep 0
|
||||
setstate rg_Guest1 2015-01-04 16:19:19 durTimerAbsence 00:00:00
|
||||
setstate rg_Guest1 2015-01-04 16:19:19 durTimerAbsence_cr 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:29 lastAwake 0
|
||||
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-15 16:16:27 wayhome 0
|
||||
setstate rg_Guest2 none
|
||||
setstate rg_Guest2 2014-02-15 16:15:39 durTimerAbsence 0
|
||||
setstate rg_Guest2 2014-02-16 13:34:05 durTimerPresence 0
|
||||
setstate rg_Guest2 2014-02-15 16:15:39 durTimerSleep 0
|
||||
setstate rg_Guest2 2015-01-04 16:19:19 durTimerAbsence 00:00:00
|
||||
setstate rg_Guest2 2015-01-04 16:19:19 durTimerAbsence_cr 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:09:29 lastAwake 0
|
||||
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-15 16:16:29 wayhome 0
|
||||
setstate rgr_Children home
|
||||
setstate rgr_Children 2014-02-17 20:45:12 lastActivity home
|
||||
setstate rgr_Children 2014-02-17 20:45:12 lastActivityBy Baby
|
||||
setstate rgr_Children 2015-01-04 16:19:19 lastActivity gone
|
||||
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-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
|
||||
@ -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-17 20:45:12 lastState asleep
|
||||
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-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-15 16:16:25 residentsGuests 0
|
||||
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-16 14:09:20 state none
|
||||
setstate rgr_Parents home
|
||||
setstate rgr_Parents 2014-02-17 20:45:19 lastActivity absent
|
||||
setstate rgr_Parents 2014-02-17 20:45:19 lastActivityBy Father
|
||||
setstate rgr_Parents 2015-01-04 16:19:19 lastActivity gone
|
||||
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-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
|
||||
@ -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-16 14:16:17 lastState absent
|
||||
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 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:13:39 residentsGuests 0
|
||||
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-16 14:16:17 state home
|
||||
setstate rgr_Residents home
|
||||
setstate rgr_Residents 2014-02-17 20:45:19 lastActivity absent
|
||||
setstate rgr_Residents 2014-02-17 20:45:19 lastActivityBy Father
|
||||
setstate rgr_Residents 2015-01-04 16:19:19 lastActivity gone
|
||||
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: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
|
||||
@ -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:16:17 lastState absent
|
||||
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-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:09:20 residentsGuests 0
|
||||
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-16 14:16:17 state home
|
||||
setstate rr_Baby home
|
||||
setstate rr_Baby 2014-02-16 14:30:21 durTimerAbsence 0
|
||||
setstate rr_Baby 2014-02-17 20:44:42 durTimerPresence 1814
|
||||
setstate rr_Baby 2014-02-17 20:45:12 durTimerSleep 0
|
||||
setstate rr_Baby 2015-01-04 16:19:19 durTimerAbsence 00:00:00
|
||||
setstate rr_Baby 2015-01-04 16:19:19 durTimerAbsence_cr 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-17 20:45:12 lastAwake 2014-02-17 20:45:12
|
||||
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-17 20:45:12 state home
|
||||
setstate rr_Baby 2014-02-16 14:30:21 wayhome 0
|
||||
setstate rr_Daughter absent
|
||||
setstate rr_Daughter 2014-02-17 20:45:42 durTimerAbsence 1787
|
||||
setstate rr_Daughter 2014-02-16 14:26:54 durTimerPresence 0
|
||||
setstate rr_Daughter 2014-02-16 14:02:48 durTimerSleep 0
|
||||
setstate rr_Daughter gone
|
||||
setstate rr_Daughter 2015-01-04 16:23:19 durTimerAbsence 7729:25:20
|
||||
setstate rr_Daughter 2015-01-04 16:23:19 durTimerAbsence_cr 463765
|
||||
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: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
|
||||
@ -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 lastMood calm
|
||||
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 mood -
|
||||
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_Father absent
|
||||
setstate rr_Father 2014-02-17 20:45:19 durTimerAbsence 1818
|
||||
setstate rr_Father 2014-02-16 14:26:52 durTimerPresence 0
|
||||
setstate rr_Father 2014-02-16 13:46:02 durTimerSleep 0
|
||||
setstate rr_Father gone
|
||||
setstate rr_Father 2015-01-04 16:23:19 durTimerAbsence 7729:56:27
|
||||
setstate rr_Father 2015-01-04 16:23:19 durTimerAbsence_cr 463796
|
||||
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: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: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 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 mood -
|
||||
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_Mother home
|
||||
setstate rr_Mother 2014-02-16 14:04:26 durTimerAbsence 0
|
||||
setstate rr_Mother 2014-02-17 20:45:42 durTimerPresence 1829
|
||||
setstate rr_Mother 2014-02-16 13:46:09 durTimerSleep 0
|
||||
setstate rr_Mother 2015-01-04 16:19:19 durTimerAbsence 00:00:00
|
||||
setstate rr_Mother 2015-01-04 16:19:19 durTimerAbsence_cr 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:16 lastDeparture 2014-02-16 14:16:16
|
||||
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 state home
|
||||
setstate rr_Mother 2014-02-16 13:46:09 wayhome 0
|
||||
setstate rr_Son absent
|
||||
setstate rr_Son 2014-02-17 20:45:42 durTimerAbsence 1787
|
||||
setstate rr_Son 2014-02-16 14:26:55 durTimerPresence 0
|
||||
setstate rr_Son 2014-02-16 14:00:53 durTimerSleep 0
|
||||
setstate rr_Son gone
|
||||
setstate rr_Son 2015-01-04 16:23:19 durTimerAbsence 7729:25:18
|
||||
setstate rr_Son 2015-01-04 16:23:19 durTimerAbsence_cr 463765
|
||||
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: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
|
||||
@ -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 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: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 mood -
|
||||
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 sunRise Next: 06:58:34
|
||||
setstate sunSet Next: 18:20:46
|
||||
setstate sunRise Next: 07:45:49
|
||||
setstate sunSet Next: 17:14:06
|
||||
setstate wlCinema initialized
|
||||
|
@ -73,7 +73,7 @@ attr Livingroom icon light_pendant_light
|
||||
attr Livingroom model fs20di
|
||||
attr Livingroom room Light
|
||||
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 group Structure
|
||||
attr AllLights icon light_light
|
||||
@ -164,7 +164,7 @@ attr ReadingLight eventMap off:dim0% on:dim100%
|
||||
attr ReadingLight group Light
|
||||
attr ReadingLight icon light_floor_lamp
|
||||
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")}
|
||||
attr wlCinema room Cinema
|
||||
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_tabcount 1
|
||||
attr anyViews dashboard_width 80%
|
||||
attr anyViews room hidden
|
||||
|
||||
define anyViews_weblink weblink htmlCode {DashboardAsHtml("anyViews")}
|
||||
attr anyViews_weblink room DashboardRoom
|
||||
@ -288,3 +289,29 @@ attr rr_Baby icon status_available
|
||||
attr rr_Baby room Residents
|
||||
attr rr_Baby sortby 0
|
||||
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
|
||||
|
@ -37,13 +37,18 @@ div.block { border:1px solid gray; background: #F8F8E0; padding:0.7em; }
|
||||
.makeSelect { display:inline; float:left; clear:left; }
|
||||
select { margin-left:5px; margin-right:5px; }
|
||||
.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; }
|
||||
select.svgSrc { width:100px; }
|
||||
select.svgColumn { width:50px; }
|
||||
select.svgRegexp { width:120px; }
|
||||
|
||||
.handle { position:relative; cursor:pointer; width:50px;
|
||||
height:20px; line-height:20px;
|
||||
-webkit-user-select:none; -moz-user-select:none; -user-select:none;
|
||||
border:3px solid; color:#278727; text-align:center; }
|
||||
.downText { margin-top:2px; }
|
||||
.makeSelect .slider {background:#F0F0D8; border-radius:8px;} /* detail only */
|
||||
.set .set { margin-bottom:2px; margin-top:3px; } /* timepicker */
|
||||
|
||||
pre { white-space: pre-wrap; }
|
||||
@ -60,8 +65,23 @@ svg.on,svg.FS20_on { fill:orange; }
|
||||
border-color:transparent; }
|
||||
.rc_button img:active { border-color: gray; }
|
||||
|
||||
table#atWizard td:first-child { width: 240px; }
|
||||
|
||||
/* jQuery-UI mods */
|
||||
div.ui-dialog { border:3px solid #278727; padding: 0.2em; }
|
||||
div.ui-dialog div.ui-dialog-titlebar { display:none; }
|
||||
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;
|
||||
}
|
||||
|
@ -1,51 +1,143 @@
|
||||
|
||||
function
|
||||
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);
|
||||
}
|
||||
|
||||
//TODO: realtime picker
|
||||
//
|
||||
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);
|
||||
}
|
||||
|
38
fhem/www/pgm2/fhemweb_knob.js
Normal 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;
|
||||
}
|
@ -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
|
||||
};
|
@ -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
|
||||
};
|
@ -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
|
||||
};
|
@ -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,
|
||||
};
|
@ -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
|
||||
};
|
@ -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
|
||||
};
|
BIN
fhem/www/pgm2/images/ui-bg_flat_0_aaaaaa_40x100.png
Normal file
After Width: | Height: | Size: 180 B |
BIN
fhem/www/pgm2/images/ui-bg_flat_75_ffffff_40x100.png
Normal file
After Width: | Height: | Size: 178 B |
BIN
fhem/www/pgm2/images/ui-bg_glass_65_ffffff_1x400.png
Normal file
After Width: | Height: | Size: 105 B |
BIN
fhem/www/pgm2/images/ui-bg_glass_75_dadada_1x400.png
Normal file
After Width: | Height: | Size: 111 B |
BIN
fhem/www/pgm2/images/ui-bg_glass_75_e6e6e6_1x400.png
Normal file
After Width: | Height: | Size: 110 B |
BIN
fhem/www/pgm2/images/ui-bg_highlight-soft_75_cccccc_1x100.png
Normal file
After Width: | Height: | Size: 101 B |
BIN
fhem/www/pgm2/images/ui-icons_222222_256x240.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
23
fhem/www/pgm2/jquery.knob.min.js
vendored
Executable file
@ -1,13 +1,12 @@
|
||||
var xmlns="http://www.w3.org/2000/svg";
|
||||
var old_title;
|
||||
var old_sel;
|
||||
var svgdoc;
|
||||
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
var to;
|
||||
"use strict";
|
||||
var svgNS = "http://www.w3.org/2000/svg";
|
||||
var svg_b64 ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
var svg_initialized={};
|
||||
|
||||
|
||||
// Base64 encode the xy points (12 bit x, 12 bit y).
|
||||
function
|
||||
compressPoints(pointList)
|
||||
svg_compressPoints(pointList)
|
||||
{
|
||||
var i, x, y, lx = -1, ly, ret = "";
|
||||
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.
|
||||
continue;
|
||||
ret = ret+
|
||||
b64.charAt((x&0xfc0)>>6)+
|
||||
b64.charAt((x&0x3f))+
|
||||
b64.charAt((y&0xfc0)>>6)+
|
||||
b64.charAt((y&0x3f));
|
||||
svg_b64.charAt((x&0xfc0)>>6)+
|
||||
svg_b64.charAt((x&0x3f))+
|
||||
svg_b64.charAt((y&0xfc0)>>6)+
|
||||
svg_b64.charAt((y&0x3f));
|
||||
lx = x; ly = y;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function
|
||||
uncompressPoints(cmpData)
|
||||
svg_uncompressPoints(cmpData)
|
||||
{
|
||||
var i = 0, ret = "";
|
||||
while(i < cmpData.length) {
|
||||
var x = (b64.indexOf(cmpData.charAt(i++))<<6)+
|
||||
b64.indexOf(cmpData.charAt(i++));
|
||||
var y = (b64.indexOf(cmpData.charAt(i++))<<6)+
|
||||
b64.indexOf(cmpData.charAt(i++));
|
||||
var x = (svg_b64.indexOf(cmpData.charAt(i++))<<6)+
|
||||
svg_b64.indexOf(cmpData.charAt(i++));
|
||||
var y = (svg_b64.indexOf(cmpData.charAt(i++))<<6)+
|
||||
svg_b64.indexOf(cmpData.charAt(i++));
|
||||
ret += " "+x+","+y;
|
||||
}
|
||||
return ret;
|
||||
@ -42,130 +41,245 @@ uncompressPoints(cmpData)
|
||||
|
||||
|
||||
function
|
||||
get_cookie()
|
||||
svg_getcookie()
|
||||
{
|
||||
var c = parent.document.cookie;
|
||||
var c = document.cookie;
|
||||
if(c == null)
|
||||
return "";
|
||||
return [];
|
||||
var results = c.match('fhemweb=(.*?)(;|$)' );
|
||||
return (results ? unescape(results[1]) : "");
|
||||
return (results ? unescape(results[1]).split(":") : []);
|
||||
}
|
||||
|
||||
function
|
||||
set_cookie(value)
|
||||
svg_prepareHash(el)
|
||||
{
|
||||
parent.document.cookie="fhemweb="+escape(value);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
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_click(evt)
|
||||
{
|
||||
var t=evt.target;
|
||||
var y_mul = parseFloat(t.getAttribute("y_mul"));
|
||||
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 t = evt.target;
|
||||
var o = svg_prepareHash(t);
|
||||
|
||||
var x_mul = parseFloat(t.getAttribute("x_mul"));
|
||||
var x_off = parseFloat(t.getAttribute("x_off"));
|
||||
var x_min = parseFloat(t.getAttribute("x_min"));
|
||||
var d = new Date((((evt.clientX-x_min)/x_mul)+x_off) * 1000);
|
||||
var y_org = (((o.y_h-evt.clientY)/o.y_mul)+o.y_min).toFixed(o.decimals);
|
||||
var d = new Date((((evt.clientX-o.x_min)/o.x_mul)+o.x_off) * 1000);
|
||||
var ts = (d.getHours() < 10 ? '0' : '') + d.getHours() + ":"+
|
||||
(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+")";
|
||||
}
|
||||
|
||||
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 };
|
||||
|
@ -35,3 +35,5 @@ polyline { stroke:black; fill:none; }
|
||||
.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;}
|
||||
|
||||
circle#svgmarker { fill:#278727; opacity:0.5; }
|
||||
|