2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-12 16:46:35 +00:00
git-svn-id: https://svn.fhem.de/fhem/trunk@1039 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig 2011-10-02 12:26:43 +00:00
parent 5bbe227096
commit 9c57d9ae86
5 changed files with 210 additions and 79 deletions

View File

@ -6375,7 +6375,12 @@ href="http://www.elv.de/output/controller.aspx?cid=74&detail=10&detail2=29870">U
<br><br>
</li>
<a name="longpoll"></a>
<li>longpoll<br>
Affects devices states in the room overview only.<br>
In this mode status update is refreshed more or less instantaneously,
and state change (on/off only) is done without requesting a complete
refresh from the server.
</ul>
</ul>

View File

@ -120,8 +120,6 @@
iPhone frontends:
<a href="itms://itunes.apple.com/us/app/fhemobile/id389951065?mt=8">Fhemobile</a> (native app),
<a href="http://www.gschaden.com/wp/2009/01/18/fhem-iphone-gateway/">
fhemgw</a>,
<a href="http://www.dhs-computertechnik.de/support-iphone.html">
dhs-computertechnik</a> or
<a href="http://code.google.com/p/phyfhem/">phyfhem</a>

View File

@ -62,10 +62,14 @@ my $FW_RETTYPE; # image/png or the like
my $FW_room; # currently selected room
my %FW_rooms; # hash of all rooms
my %FW_types; # device types, for sorting
my $FW_wname; # Web instance name
my $FW_wname; # Web instance
my $FW_cname; # Current connection
my @FW_zoom; # "qday", "day","week","month","year"
my %FW_zoom; # the same as @FW_zoom
my %FW_hiddenroom; # hash of hidden rooms
my $FW_longpoll;
my $FW_inform;
my $FW_XHR;
#####################################
@ -78,10 +82,11 @@ FHEMWEB_Initialize($)
$hash->{AttrFn} = "FW_Attr";
$hash->{DefFn} = "FW_Define";
$hash->{UndefFn} = "FW_Undef";
$hash->{NotifyFn}= "FW_Notify";
$hash->{AttrList}= "loglevel:0,1,2,3,4,5,6 webname fwmodpath fwcompress " .
"plotmode:gnuplot,gnuplot-scroll,SVG plotsize refresh " .
"touchpad smallscreen plotfork basicAuth basicAuthMsg ".
"stylesheet hiddenroom HTTPS";
"stylesheet hiddenroom HTTPS longpoll";
###############
# Initialize internal structures
@ -207,9 +212,9 @@ FW_Read($)
}
$FW_wname = $hash->{SNAME};
$FW_cname = $name;
my $ll = GetLogLevel($FW_wname,4);
my $c = $hash->{CD};
if(!$zlib_loaded && $try_zlib && AttrVal($FW_wname, "fwcompress", 1)) {
$zlib_loaded = 1;
eval { require Compress::Zlib; };
@ -229,10 +234,10 @@ FW_Read($)
# Data from HTTP Client
my $buf;
my $ret = sysread($hash->{CD}, $buf, 1024);
my $ret = sysread($c, $buf, 1024);
if(!defined($ret) || $ret <= 0) {
my $r = CommandDelete(undef, $name);
CommandDelete(undef, $name);
Log($ll, "Connection closed for $name");
return;
}
@ -271,8 +276,9 @@ FW_Read($)
$hash->{INUSE} = 1;
my $cacheable = FW_AnswerCall($arg);
delete($hash->{INUSE});
return if($cacheable == -1); # Longpoll / inform request;
if(!$selectlist{$name}) { # removed by rereadcfg, reinsert
$selectlist{$name} = $hash;
$defs{$name} = $hash;
@ -390,12 +396,31 @@ FW_AnswerCall($)
$FW_reldoc = "$FW_ME/commandref.html";
$FW_cmdret = $docmd ? fC($cmd) : "";
if($FW_inform) { # Longpoll header
$defs{$FW_cname}{inform} = $FW_room;
my $c = $defs{$FW_cname}{CD};
print $c "HTTP/1.1 200 OK\r\n",
"Content-Type: text/plain; charset=ISO-8859-1\r\n\r\n";
return -1;
}
if($FW_XHR) {
$FW_RETTYPE = "text/plain; charset=ISO-8859-1";
pO $FW_cmdret;
return 0;
}
FW_updateHashes();
if($cmd =~ m/^showlog /) {
FW_showLog($cmd);
return 0;
}
$FW_longpoll = (AttrVal($FW_wname, "longpoll", undef) &&
$FW_room &&
!$FW_detail);
if($cmd =~ m/^toweblink (.*)$/) {
my @aa = split(":", $1);
my $max = 0;
@ -433,10 +458,12 @@ FW_AnswerCall($)
pO "<meta http-equiv=\"refresh\" content=\"$rf\">" if($rf);
my $stylecss = ($FW_ss ? "style_smallscreen.css" :
$FW_tp ? "style_touchpad.css" : "style.css");
$stylecss = AttrVal($FW_wname, "stylecss", $stylecss);
$stylecss = AttrVal($FW_wname, "stylesheet", $stylecss);
pO "<link href=\"$FW_ME/$stylecss\" rel=\"stylesheet\"/>";
pO "<script type=\"text/javascript\" src=\"$FW_ME/svg.js\"></script>"
if($FW_plotmode eq "SVG");
pO "<script type=\"text/javascript\" src=\"$FW_ME/longpoll.js\"></script>"
if($FW_longpoll);
pO "</head>\n<body name=\"$t\">";
if($FW_cmdret) {
@ -473,9 +500,11 @@ FW_digestCgi($)
my (%arg, %val, %dev);
my ($cmd, $c) = ("","","");
$FW_detail = "";
%FW_pos = ();
$FW_room = "";
$FW_detail = "";
$FW_XHR = undef;
$FW_inform = undef;
$arg =~ s,^[?/],,;
foreach my $pv (split("&", $arg)) {
@ -495,6 +524,8 @@ FW_digestCgi($)
if($p =~ m/^cmd\.(.*)$/) { $cmd = $v; $c= $1; }
if($p eq "pos") { %FW_pos = split(/[=;]/, $v); }
if($p eq "data") { $FW_data = $v; }
if($p eq "XHR") { $FW_XHR = 1; }
if($p eq "inform") { $FW_inform = $v; }
}
$cmd.=" $dev{$c}" if(defined($dev{$c}));
@ -537,13 +568,13 @@ FW_makeTable($$@)
my($name, $hash, $cmd) = (@_);
return if(!$hash || !int(keys %{$hash}));
pO " <table class=\"block wide\">";
pO "<table class=\"block wide\">";
my $row = 1;
foreach my $n (sort keys %{$hash}) {
my $r = ref($hash->{$n});
next if($r && ($r ne "HASH" || !defined($hash->{$n}{VAL})));
pF " <tr class=\"%s\">", ($row&1)?"odd":"even";
pF "<tr class=\"%s\">", ($row&1)?"odd":"even";
$row++;
my $val = $hash->{$n};
@ -578,7 +609,7 @@ FW_makeTable($$@)
pO "</tr>";
}
pO " </table>";
pO "</table>";
pO "<br>";
}
@ -622,9 +653,9 @@ FW_doDetail($)
FW_makeTable($d, $attr{$d}, "deleteattr");
if($t eq "FileLog" ) {
pO " <table class=\"block wide\">";
pO "<table class=\"block wide\">";
FW_dumpFileLog($d, 0, 1);
pO " </table>";
pO "</table>";
}
pO "</td></tr></table>";
@ -728,25 +759,25 @@ FW_roomOverview($)
pO "<div id=\"menu\">";
pO "<table>";
if($FW_ss) { # Make a selection sensitive dropdown list
pO " <tr><td><select OnChange=\"location.href=" .
pO "<tr><td><select OnChange=\"location.href=" .
"this.options[this.selectedIndex].value\">";
foreach(my $idx = 0; $idx < @list1; $idx++) {
next if(!$list1[$idx]);
my $sel = ($list1[$idx] eq $FW_room ? " selected=\"selected\"" : "");
pO " <option value=$list2[$idx]$sel>$list1[$idx]</option>";
pO "<option value=$list2[$idx]$sel>$list1[$idx]</option>";
}
pO " </select></td></tr>";
pO "</select></td></tr>";
} else {
foreach(my $idx = 0; $idx < @list1; $idx++) {
my ($l1, $l2) = ($list1[$idx], $list2[$idx]);
if(!$l1) {
pO " </table></td></tr>" if($idx);
pO " <tr><td><table id=\"room\">"
pO "</table></td></tr>" if($idx);
pO "<tr><td><table id=\"room\">"
if($idx<int(@list1)-1);
} else {
pF " <tr%s>", $l1 eq $FW_room ? " class=\"sel\"" : "";
pF "<tr%s>", $l1 eq $FW_room ? " class=\"sel\"" : "";
if($l2 =~ m/.html$/ || $l2 =~ m/^http/) {
pO "<td><a href=\"$l2\">$l1</a></td>";
} else {
@ -774,7 +805,7 @@ FW_showRoom()
pO "<form method=\"get\" action=\"$FW_ME\">";
pO "<div id=\"content\">";
pO " <table>"; # Need for equal width of subtables
pO "<table>"; # Need for equal width of subtables
my $rf = ($FW_room ? "&amp;room=$FW_room" : ""); # stay in the room
@ -790,22 +821,14 @@ FW_showRoom()
!IsIgnored($_) } keys %{$FW_types{$type}};
next if(!@devs);
pO " <tr><td><div class=\"devType\">$type</div></td></tr>";
pO " <tr><td>";
pO " <table class=\"block wide\" id=\"$type\">";
pO "\n<tr><td><div class=\"devType\">$type</div></td></tr>";
pO "<tr><td>";
pO "<table class=\"block wide\" id=\"$type\">";
foreach my $d (sort @devs) {
my $type = $defs{$d}{TYPE};
my $allSets = " " . getAllSets($d) . " ";
my $hasOnOff = ($allSets =~ m/ on / && $allSets =~ m/ off /);
if(!$hasOnOff) { # Check the eventMap
my $em = AttrVal($d, "eventMap", "") . " ";
$hasOnOff = ($em =~ m/:on / && $em =~ m/:off /);
}
pF " <tr class=\"%s\">", ($row&1)?"odd":"even";
pF "\n<tr class=\"%s\">", ($row&1)?"odd":"even";
if($FW_hiddenroom{detail}) {
pO "<td><div class=\"col1\">$d</div></td>";
@ -816,39 +839,14 @@ FW_showRoom()
$row++;
my $state = $defs{$d}{STATE};
$state = "" if(!defined($state));
my $txt = $state;
if(defined(AttrVal($d, "showtime", undef))) {
$txt = $defs{$d}{READINGS}{state}{TIME};
} elsif($allSets =~ m/ desired-temp /) {
$txt = ReadingsVal($d, "measured-temp", "");
$txt =~ s/ .*//;
$txt .= "&deg;"
} else {
my $icon;
$icon = FW_dev2image($d);
$txt = "<img src=\"$FW_ME/icons/$icon\" alt=\"$txt\"/>" if($icon);
}
pO "<td>";
# align needed for FireFox
$txt = "<div align=\"center\" class=\"col2\">$txt</div>" if($FW_ss);
if($hasOnOff) {
pHPlain "cmd.$d=set $d ".($state eq "on" ? "off":"on").$rf, $txt, 0;
} else {
pO $txt;
}
my ($allSets, $hasOnOff, $txt) = FW_devState($d, $rf);
pO "<td id=\"$d\">$txt";
if(!$FW_ss) {
pO "</td>";
if($hasOnOff) {
pH "cmd.$d=set $d on$rf", ReplaceEventMap($d, "on", 1), 1, "col2";
pH "cmd.$d=set $d off$rf", ReplaceEventMap($d, "off", 1), 1, "col2";
pH "cmd.$d=set $d on$rf", ReplaceEventMap($d, "on", 1), 1, "col3";
pH "cmd.$d=set $d off$rf", ReplaceEventMap($d, "off", 1), 1, "col3";
} elsif($allSets =~ m/ desired-temp /) {
$txt = ReadingsVal($d, "measured-temp", "");
@ -872,10 +870,10 @@ FW_showRoom()
}
pO "</td>";
}
pO " </table>";
pO " </td></tr>";
pO "</table>";
pO "</td></tr>";
}
pO " </table><br>";
pO "</table><br>";
# Now the weblinks
my $buttons = 1;
@ -1384,9 +1382,9 @@ FW_style($$)
push(@fl, FW_fileList("$FW_dir/.*html"));
pO "<div id=\"content\">";
pO " <table><tr><td>";
pO " $msg<br><br>" if($msg);
pO " <table class=\"block\" id=\"at\">";
pO "<table><tr><td>";
pO "$msg<br><br>" if($msg);
pO "<table class=\"block\" id=\"at\">";
my $row = 0;
foreach my $file (@fl) {
pO "<tr class=\"" . ($row?"odd":"even") . "\">";
@ -1398,17 +1396,17 @@ FW_style($$)
pO "</tr>";
$row = ($row+1)%2;
}
pO " </table>";
pO " </td></tr></table>";
pO "</table>";
pO "</td></tr></table>";
pO "</div>";
} elsif($a[1] eq "examples") {
my @fl = FW_fileList("$FW_dir/example.*");
pO "<div id=\"content\">";
pO " <table><tr><td>";
pO " $msg<br><br>" if($msg);
pO " <table class=\"block\" id=\"at\">";
pO "<table><tr><td>";
pO "$msg<br><br>" if($msg);
pO "<table class=\"block\" id=\"at\">";
my $row = 0;
foreach my $file (@fl) {
pO "<tr class=\"" . ($row?"odd":"even") . "\">";
@ -1416,8 +1414,8 @@ FW_style($$)
pO "</tr>";
$row = ($row+1)%2;
}
pO " </table>";
pO " </td></tr></table>";
pO "</table>";
pO "</td></tr></table>";
pO "</div>";
} elsif($a[1] eq "edit") {
@ -1434,7 +1432,7 @@ FW_style($$)
my $ncols = $FW_ss ? 40 : 80;
pO "<div id=\"content\">";
pO " <form>";
pO "<form>";
$f =~ s,^.*/,,;
pO FW_submit("save", "Save $f") . "<br><br>";
pO FW_hidden("cmd", "style save $a[2]");
@ -1510,6 +1508,7 @@ pHPlain(@)
}
##################
# print formatted
sub
@ -1722,4 +1721,94 @@ FW_dumpFileLog($$$)
}
return $row;
}
sub
FW_Notify($$)
{
my ($ntfy, $dev) = @_;
my $filter = $ntfy->{inform};
return undef if(!$filter);
my $ln = $ntfy->{NAME};
my $dn = $dev->{NAME};
return undef if(AttrVal($dn, "room", "") ne $filter);
FW_ReadIcons();
$FW_wname = $ntfy->{SNAME};
$FW_ME = "/" . AttrVal($FW_wname, "webname", "fhem");
$FW_longpoll = 1;
$FW_ss = AttrVal($FW_wname, "smallscreen", 0);
$FW_tp = AttrVal($FW_wname, "touchpad", $FW_ss);
my ($allSet, $hasOnOff, $txt) = FW_devState($dn, "");
$ntfy->{INFORMBUF} = "" if(!defined($ntfy->{INFORMBUF}));
$ntfy->{INFORMBUF} .= "$dn;$dev->{STATE};$txt\n";
Log 0, "Sending $txt";
RemoveInternalTimer($ln);
InternalTimer(gettimeofday()+0.1, "FW_FlushInform", $ln, 0);
return undef;
}
sub
FW_FlushInform($)
{
my ($name) = @_;
my $hash = $defs{$name};
my $c = $hash->{CD};
print $c $hash->{INFORMBUF};
CommandDelete(undef, $name);
}
sub
FW_devState($$)
{
my ($d, $rf) = @_;
my $allSets = " " . getAllSets($d) . " ";
my $hasOnOff = ($allSets =~ m/ on / && $allSets =~ m/ off /);
if(!$hasOnOff) { # Check the eventMap
my $em = AttrVal($d, "eventMap", "") . " ";
$hasOnOff = ($em =~ m/:on / && $em =~ m/:off /);
}
my $state = $defs{$d}{STATE};
$state = "" if(!defined($state));
my $txt = $state;
if(defined(AttrVal($d, "showtime", undef))) {
$txt = $defs{$d}{READINGS}{state}{TIME};
} elsif($allSets =~ m/ desired-temp /) {
$txt = ReadingsVal($d, "measured-temp", "");
$txt =~ s/ .*//;
$txt .= "&deg;"
} else {
my $icon;
$icon = FW_dev2image($d);
$txt = "<img src=\"$FW_ME/icons/$icon\" alt=\"$txt\"/>"
if($icon);
}
$txt = "<div id=\"$d\" align=\"center\" class=\"col2\">$txt</div>";
if($hasOnOff) {
my $link = "cmd.$d=set $d ".($state eq "on" ? "off":"on");
if($FW_longpoll) {
$txt = "<a onClick=\"cmd('$FW_ME?XHR=1&$link')\">$txt</a>";
} elsif($FW_ss || $FW_tp) {
$txt = "<a onClick=\"location.href='$FW_ME?$link$rf'\">$txt</a>";
} else {
$txt = "<a href=\"$FW_ME?$link\">$txt</a>";
}
}
return ($allSets, $hasOnOff, $txt);
}
1;

View File

@ -0,0 +1,39 @@
var pollConn;
function
cmd(arg)
{
var req = new XMLHttpRequest();
req.open("GET", arg, true);
req.send(null);
}
function
doUpdate()
{
if(pollConn.readyState != 4)
return;
var lines = pollConn.responseText.split("\n");
for(var i=0; i < lines.length; i++) {
var d = lines[i].split(";", 3); // Complete arg
if(d.length != 3)
continue;
var el = document.getElementById(d[0]);
if(el)
el.innerHTML=d[2];
}
pollConn.abort();
longpoll();
}
function
longpoll()
{
pollConn = new XMLHttpRequest();
pollConn.open("GET", document.location.pathname+document.location.search+
"&XHR=1&inform=1", true);
pollConn.onreadystatechange = doUpdate;
pollConn.send(null);
}
window.onload = longpoll;

View File

@ -17,7 +17,7 @@ table.block tr.odd { background: #F0F0D8; }
table.block tr.sel { background: #F0F0D8; }
table { -moz-border-radius:8px; border-radius:8px; }
.col1, .col2 { padding: 8px; }
.col1, .col2, .col3 { padding: 8px; }
.dname, .dval { padding: 0px; font-size: 14px; }
table#room { border:1px solid gray; width: 100%; background: #D7FFFF; }