git-svn-id: svn://svn.code.sf.net/p/fhem/code/trunk@1039 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig
2011-10-02 12:26:43 +00:00
parent 6336df52fd
commit 0ba5110cce
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}));
@@ -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 "\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", "");
@@ -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; }