mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-08 07:24:21 +00:00
Rewrite for the new select handling
git-svn-id: https://svn.fhem.de/fhem/trunk@237 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
4a2aa40f12
commit
076f2c8345
@ -424,3 +424,8 @@
|
|||||||
|
|
||||||
- ==DATE== (4.5)
|
- ==DATE== (4.5)
|
||||||
- feature: further 01_FHEMWEB cleanup
|
- feature: further 01_FHEMWEB cleanup
|
||||||
|
- feature: CUL support for FS20(r/w), FHT(readonly), KS300, EM
|
||||||
|
- feature: list outputs the device attributes too
|
||||||
|
- bugfix: rename bugs fixed
|
||||||
|
- bugfix: better integration of ReadyFn (Windows), slight overall speedup
|
||||||
|
- bugfix: Ignore/correct "type" casing when autoloading modules
|
||||||
|
@ -104,7 +104,12 @@ CUL_Define($$)
|
|||||||
Log 3, "CUL opened CUL device $dev";
|
Log 3, "CUL opened CUL device $dev";
|
||||||
|
|
||||||
$hash->{PortObj} = $po;
|
$hash->{PortObj} = $po;
|
||||||
$hash->{FD} = $po->FILENO if !( $^O =~ /Win/ );
|
if( $^O !~ /Win/ ) {
|
||||||
|
$hash->{FD} = $po->FILENO;
|
||||||
|
$selectlist{"$name.$dev"} = $hash;
|
||||||
|
} else {
|
||||||
|
$readyfnlist{"$name.$dev"} = $hash;
|
||||||
|
}
|
||||||
|
|
||||||
$hash->{DeviceName} = $dev;
|
$hash->{DeviceName} = $dev;
|
||||||
$hash->{PARTIAL} = "";
|
$hash->{PARTIAL} = "";
|
||||||
@ -138,7 +143,7 @@ CUL_Set($@)
|
|||||||
my ($hash, @a) = @_;
|
my ($hash, @a) = @_;
|
||||||
|
|
||||||
return "\"set CUL\" needs at least one parameter" if(@a < 2);
|
return "\"set CUL\" needs at least one parameter" if(@a < 2);
|
||||||
return "Unknown argument $a[1], choose one of " . join(",", sort keys %sets)
|
return "Unknown argument $a[1], choose one of " . join(" ", sort keys %sets)
|
||||||
if(!defined($sets{$a[1]}));
|
if(!defined($sets{$a[1]}));
|
||||||
|
|
||||||
my $arg = ($a[2] ? $a[2] : "");
|
my $arg = ($a[2] ? $a[2] : "");
|
||||||
@ -153,7 +158,7 @@ CUL_Get($@)
|
|||||||
my ($hash, @a) = @_;
|
my ($hash, @a) = @_;
|
||||||
|
|
||||||
return "\"get CUL\" needs at least one parameter" if(@a < 2);
|
return "\"get CUL\" needs at least one parameter" if(@a < 2);
|
||||||
return "Unknown argument $a[1], choose one of " . join(",", sort keys %gets)
|
return "Unknown argument $a[1], choose one of " . join(" ", sort keys %gets)
|
||||||
if(!defined($gets{$a[1]}));
|
if(!defined($gets{$a[1]}));
|
||||||
|
|
||||||
my $arg = ($a[2] ? $a[2] : "");
|
my $arg = ($a[2] ? $a[2] : "");
|
||||||
@ -481,12 +486,13 @@ Log 1, "CUL: $dmsg";
|
|||||||
|
|
||||||
goto NEXTMSG if($found[0] eq ""); # Special return: Do not notify
|
goto NEXTMSG if($found[0] eq ""); # Special return: Do not notify
|
||||||
|
|
||||||
|
# The trigger needs a device: we create a minimal temporary one
|
||||||
if($found[0] =~ m/^(UNDEFINED) ([^ ]*) (.*)$/) {
|
if($found[0] =~ m/^(UNDEFINED) ([^ ]*) (.*)$/) {
|
||||||
my $d = $1;
|
my $d = $1;
|
||||||
$defs{$d}{NAME} = $1;
|
$defs{$d}{NAME} = $1;
|
||||||
$defs{$d}{TYPE} = $last_module;
|
$defs{$d}{TYPE} = $last_module;
|
||||||
DoTrigger($d, "$2 $3");
|
DoTrigger($d, "$2 $3");
|
||||||
delete $defs{$d};
|
CommandDelete(undef, $d); # Remove the device
|
||||||
goto NEXTMSG;
|
goto NEXTMSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ FHZ_Initialize($)
|
|||||||
$hash->{ReadFn} = "FHZ_Read";
|
$hash->{ReadFn} = "FHZ_Read";
|
||||||
$hash->{WriteFn} = "FHZ_Write";
|
$hash->{WriteFn} = "FHZ_Write";
|
||||||
$hash->{Clients} = ":FHZ:FS20:FHT:HMS:KS300:";
|
$hash->{Clients} = ":FHZ:FS20:FHT:HMS:KS300:";
|
||||||
$hash->{ReadyFn} = "FHZ_Ready" if ($^O eq 'MSWin32');
|
$hash->{ReadyFn} = "FHZ_Ready";
|
||||||
|
|
||||||
# Consumer
|
# Consumer
|
||||||
$hash->{Match} = "^81..C9..0102";
|
$hash->{Match} = "^81..C9..0102";
|
||||||
@ -273,7 +273,12 @@ FHZ_Define($$)
|
|||||||
|
|
||||||
|
|
||||||
$hash->{PortObj} = $po;
|
$hash->{PortObj} = $po;
|
||||||
$hash->{FD} = $po->FILENO if !( $^O =~ /Win/ );
|
if( $^O !~ /Win/ ) {
|
||||||
|
$hash->{FD} = $po->FILENO;
|
||||||
|
$selectlist{"$name.$dev"} = $hash;
|
||||||
|
} else {
|
||||||
|
$readyfnlist{"$name.$dev"} = $hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$hash->{DeviceName} = $dev;
|
$hash->{DeviceName} = $dev;
|
||||||
@ -643,12 +648,13 @@ FHZ_Read($)
|
|||||||
|
|
||||||
goto NEXTMSG if($found[0] eq ""); # Special return: Do not notify
|
goto NEXTMSG if($found[0] eq ""); # Special return: Do not notify
|
||||||
|
|
||||||
|
# The trigger needs a device: we create a minimal temporary one
|
||||||
if($found[0] =~ m/^(UNDEFINED) ([^ ]*) (.*)$/) {
|
if($found[0] =~ m/^(UNDEFINED) ([^ ]*) (.*)$/) {
|
||||||
my $d = $1;
|
my $d = $1;
|
||||||
$defs{$d}{NAME} = $1;
|
$defs{$d}{NAME} = $1;
|
||||||
$defs{$d}{TYPE} = $last_module;
|
$defs{$d}{TYPE} = $last_module;
|
||||||
DoTrigger($d, "$2 $3");
|
DoTrigger($d, "$2 $3");
|
||||||
delete $defs{$d};
|
CommandDelete(undef, $d); # Remove the device
|
||||||
goto NEXTMSG;
|
goto NEXTMSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ LIRC_Define($$)
|
|||||||
|
|
||||||
$hash->{LircObj} = $lirc;
|
$hash->{LircObj} = $lirc;
|
||||||
$hash->{FD} = $lirc->sock;
|
$hash->{FD} = $lirc->sock;
|
||||||
|
$selectlist{"$name.$config"} = $hash;
|
||||||
$hash->{SelectObj} = $select;
|
$hash->{SelectObj} = $select;
|
||||||
$hash->{DeviceName} = $name;
|
$hash->{DeviceName} = $name;
|
||||||
$hash->{STATE} = "Opened";
|
$hash->{STATE} = "Opened";
|
||||||
|
@ -205,7 +205,7 @@ FS20_Set($@)
|
|||||||
###########################################
|
###########################################
|
||||||
# Set the state of a device to off if on-for-timer is called
|
# Set the state of a device to off if on-for-timer is called
|
||||||
if($follow{$a[0]}) {
|
if($follow{$a[0]}) {
|
||||||
CommandDelete(undef, "at .*setstate.*$a[0]");
|
CommandDelete(undef, $a[0] . "_timer");
|
||||||
delete $follow{$a[0]};
|
delete $follow{$a[0]};
|
||||||
}
|
}
|
||||||
if($a[1] eq "on-for-timer" && $na == 3 &&
|
if($a[1] eq "on-for-timer" && $na == 3 &&
|
||||||
@ -303,8 +303,12 @@ FS20_Undef($$)
|
|||||||
my ($hash, $name) = @_;
|
my ($hash, $name) = @_;
|
||||||
foreach my $c (keys %{ $hash->{CODE} } ) {
|
foreach my $c (keys %{ $hash->{CODE} } ) {
|
||||||
$c = $hash->{CODE}{$c};
|
$c = $hash->{CODE}{$c};
|
||||||
delete($defptr{$c}{$name}) if($defptr{$c});
|
|
||||||
delete($defptr{$c}{$name}) if(!%{$defptr{$c}});
|
# As after a rename the $name my be different from the $defptr{$c}{$n}
|
||||||
|
# we look for the hash.
|
||||||
|
foreach my $dname (keys %{ $defptr{$c} }) {
|
||||||
|
delete($defptr{$c}{$dname}) if($defptr{$c}{$dname} == $hash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ CUL_EM_Parse($$)
|
|||||||
$cum *= $corr;
|
$cum *= $corr;
|
||||||
$lst *= $corr;
|
$lst *= $corr;
|
||||||
$top *= $corr;
|
$top *= $corr;
|
||||||
$val = sprintf("CND %d CUM: %0.3f 5MIN: %0.3f TOP: %0.3f",
|
$val = sprintf("CNT %d CUM: %0.3f 5MIN: %0.3f TOP: %0.3f",
|
||||||
$cnt, $cum, $lst, $top);
|
$cnt, $cum, $lst, $top);
|
||||||
my $n = $hash->{NAME};
|
my $n = $hash->{NAME};
|
||||||
Log GetLogLevel($n,1), "CUL_EM $n: $val";
|
Log GetLogLevel($n,1), "CUL_EM $n: $val";
|
||||||
|
@ -45,9 +45,6 @@ EM_Define($$)
|
|||||||
my $po;
|
my $po;
|
||||||
$hash->{STATE} = "Initialized";
|
$hash->{STATE} = "Initialized";
|
||||||
|
|
||||||
delete $hash->{PortObj};
|
|
||||||
delete $hash->{FD};
|
|
||||||
|
|
||||||
my $name = $a[0];
|
my $name = $a[0];
|
||||||
my $dev = $a[2];
|
my $dev = $a[2];
|
||||||
|
|
||||||
|
@ -43,9 +43,6 @@ M232_Define($$)
|
|||||||
|
|
||||||
$hash->{STATE} = "Initialized";
|
$hash->{STATE} = "Initialized";
|
||||||
|
|
||||||
delete $hash->{PortObj};
|
|
||||||
delete $hash->{FD};
|
|
||||||
|
|
||||||
my $dev = $a[2];
|
my $dev = $a[2];
|
||||||
$attr{$a[0]}{savefirst} = 1;
|
$attr{$a[0]}{savefirst} = 1;
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ package main;
|
|||||||
# Modul for FHEM
|
# Modul for FHEM
|
||||||
#
|
#
|
||||||
# contributed by thomas dressler 2008
|
# contributed by thomas dressler 2008
|
||||||
# $Id: 87_WS2000.pm,v 1.3 2008-05-11 21:17:30 tdressler Exp $
|
# $Id: 87_WS2000.pm,v 1.4 2008-09-06 08:33:25 rudolfkoenig Exp $
|
||||||
###########################
|
###########################
|
||||||
use strict;
|
use strict;
|
||||||
use Switch;
|
use Switch;
|
||||||
@ -81,6 +81,7 @@ WS2000_Define($$)
|
|||||||
return "Can't open Device $PortName: $^E\n";
|
return "Can't open Device $PortName: $^E\n";
|
||||||
}
|
}
|
||||||
#$hash->{FD}=$PortObj->{_HANDLE};
|
#$hash->{FD}=$PortObj->{_HANDLE};
|
||||||
|
$readyfnlist{"$a[0].$a[2]"} = $hash;
|
||||||
} else {
|
} else {
|
||||||
eval ("use Device::SerialPort;");
|
eval ("use Device::SerialPort;");
|
||||||
if ($@) {
|
if ($@) {
|
||||||
@ -94,7 +95,8 @@ WS2000_Define($$)
|
|||||||
Log 1,"Error opening Serial Device $PortName";
|
Log 1,"Error opening Serial Device $PortName";
|
||||||
return "Can't open Device $PortName: $^E\n";
|
return "Can't open Device $PortName: $^E\n";
|
||||||
}
|
}
|
||||||
#$hash->{FD}=$PortObj->FILENO;
|
$hash->{FD}=$PortObj->FILENO;
|
||||||
|
$selectlist{"$a[0].$a[2]"} = $hash;
|
||||||
}
|
}
|
||||||
#Parameter 19200,8,2,Odd,None
|
#Parameter 19200,8,2,Odd,None
|
||||||
$PortObj->baudrate(19200);
|
$PortObj->baudrate(19200);
|
||||||
@ -125,13 +127,14 @@ WS2000_Define($$)
|
|||||||
}
|
}
|
||||||
$xport->autoflush(1);
|
$xport->autoflush(1);
|
||||||
$hash->{FD}=$xport->fileno;
|
$hash->{FD}=$xport->fileno;
|
||||||
|
$selectlist{"$a[0].$a[2]"} = $hash;
|
||||||
$hash->{socket}=$xport;
|
$hash->{socket}=$xport;
|
||||||
|
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
$hash->{STATE} = "$PortName is no device and not implemented";
|
$hash->{STATE} = "$PortName is no device and not implemented";
|
||||||
Log 1,"$PortName is no device and not implemented";
|
Log 1,"$PortName is no device and not implemented";
|
||||||
return "$PortName is no device and not implemented\n";
|
return "$PortName is no device and not implemented\n";
|
||||||
}
|
}
|
||||||
Log 4, "$name connected to device $PortName";
|
Log 4, "$name connected to device $PortName";
|
||||||
$hash->{STATE} = "open";
|
$hash->{STATE} = "open";
|
||||||
|
@ -92,7 +92,7 @@ at_Exec($)
|
|||||||
|
|
||||||
my $count = $defs{$name}{REP};
|
my $count = $defs{$name}{REP};
|
||||||
my $def = $defs{$name}{DEF};
|
my $def = $defs{$name}{DEF};
|
||||||
delete $defs{$name};
|
CommandDelete(undef, $name); # Recreate ourselves
|
||||||
|
|
||||||
if($count) {
|
if($count) {
|
||||||
$def =~ s/{\d+}/{$count}/ if($def =~ m/^\+?\*{/); # Replace the count }
|
$def =~ s/{\d+}/{$count}/ if($def =~ m/^\+?\*{/); # Replace the count }
|
||||||
|
@ -163,6 +163,18 @@ make editing of multiline commands transparent.<br><br>
|
|||||||
see the <a href="#FileLog">FileLog</a> section.
|
see the <a href="#FileLog">FileLog</a> section.
|
||||||
</li><br>
|
</li><br>
|
||||||
|
|
||||||
|
<a name="nofork"></a>
|
||||||
|
<li>nofork<br>
|
||||||
|
If set and the logfile is not "-", do not try to background. Needed
|
||||||
|
on some Fritzbox installations.
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
<a name="mseclog"></a>
|
||||||
|
<li>nofork<br>
|
||||||
|
If set, the timestamp in the logfile will contain a millisecond part.
|
||||||
|
</li><br>
|
||||||
|
|
||||||
|
|
||||||
<a name="modpath"></a>
|
<a name="modpath"></a>
|
||||||
<li>modpath<br>
|
<li>modpath<br>
|
||||||
Specify the path to the modules directory <code>FHEM</code>. The path
|
Specify the path to the modules directory <code>FHEM</code>. The path
|
||||||
|
@ -81,6 +81,7 @@ and <a href="faq.html">faq.html</a> for more documentation.
|
|||||||
http://developer.berlios.de/projects/fhem</a><br>
|
http://developer.berlios.de/projects/fhem</a><br>
|
||||||
LinViex (home automation frontend):
|
LinViex (home automation frontend):
|
||||||
<a href="http://sourceforge.net/projects/linviex">
|
<a href="http://sourceforge.net/projects/linviex">
|
||||||
|
<a href=http://shop.busware.de/product_info.php?products_id=29">CUL</CUL>
|
||||||
|
|
||||||
http://sourceforge.net/projects/linviex</a><br><br>
|
http://sourceforge.net/projects/linviex</a><br><br>
|
||||||
Device/OS Specific installation guides:<br>
|
Device/OS Specific installation guides:<br>
|
||||||
|
159
fhem/fhem.pl
159
fhem/fhem.pl
@ -114,7 +114,7 @@ sub CommandTrigger($$);
|
|||||||
# NR - its "serial" number
|
# NR - its "serial" number
|
||||||
# DEF - its definition
|
# DEF - its definition
|
||||||
# READINGS- The readings. Each value has a "VAL" and a "TIME" component.
|
# READINGS- The readings. Each value has a "VAL" and a "TIME" component.
|
||||||
# FD - FileDescriptor. If set, it will be integrated into the global select
|
# FD - FileDescriptor. Used by selectlist / readyfnlist
|
||||||
# IODev - attached to io device
|
# IODev - attached to io device
|
||||||
# CHANGED - Currently changed attributes of this device. Used by NotifyFn
|
# CHANGED - Currently changed attributes of this device. Used by NotifyFn
|
||||||
# VOLATILE- Set if the definition should be saved to the "statefile"
|
# VOLATILE- Set if the definition should be saved to the "statefile"
|
||||||
@ -122,6 +122,8 @@ sub CommandTrigger($$);
|
|||||||
use vars qw(%modules); # List of loaded modules (device/log/etc)
|
use vars qw(%modules); # List of loaded modules (device/log/etc)
|
||||||
use vars qw(%defs); # FHEM device/button definitions
|
use vars qw(%defs); # FHEM device/button definitions
|
||||||
use vars qw(%attr); # Attributes
|
use vars qw(%attr); # Attributes
|
||||||
|
use vars qw(%selectlist); # devices which want a "select"
|
||||||
|
use vars qw(%readyfnlist); # devices which want a "readyfn"
|
||||||
|
|
||||||
use vars qw(%value); # Current values, see commandref.html
|
use vars qw(%value); # Current values, see commandref.html
|
||||||
use vars qw(%oldvalue); # Old values, see commandref.html
|
use vars qw(%oldvalue); # Old values, see commandref.html
|
||||||
@ -143,7 +145,14 @@ my $nextat; # Time when next timer will be triggered.
|
|||||||
my $intAtCnt=0;
|
my $intAtCnt=0;
|
||||||
my $reread_active = 0;
|
my $reread_active = 0;
|
||||||
my $AttrList = "room comment";
|
my $AttrList = "room comment";
|
||||||
my $cvsid = '$Id: fhem.pl,v 1.53 2008-08-25 09:52:29 rudolfkoenig Exp $';
|
my $cvsid = '$Id: fhem.pl,v 1.54 2008-09-06 08:33:55 rudolfkoenig Exp $';
|
||||||
|
my $namedef =
|
||||||
|
"where <name> is either:\n" .
|
||||||
|
"- a single device name\n" .
|
||||||
|
"- a list seperated by komma (,)\n" .
|
||||||
|
"- a regexp, if contains one of the following characters: *[]^\$\n" .
|
||||||
|
"- a range seperated by dash (-)\n";
|
||||||
|
|
||||||
|
|
||||||
$init_done = 0;
|
$init_done = 0;
|
||||||
|
|
||||||
@ -152,7 +161,7 @@ $modules{_internal_}{LOADED} = 1;
|
|||||||
$modules{_internal_}{AttrList} =
|
$modules{_internal_}{AttrList} =
|
||||||
"archivecmd allowfrom archivedir configfile lastinclude logfile " .
|
"archivecmd allowfrom archivedir configfile lastinclude logfile " .
|
||||||
"modpath nrarchive pidfilename port statefile title userattr " .
|
"modpath nrarchive pidfilename port statefile title userattr " .
|
||||||
"verbose:1,2,3,4,5 mseclog version";
|
"verbose:1,2,3,4,5 mseclog version nofork";
|
||||||
|
|
||||||
|
|
||||||
my %cmds = (
|
my %cmds = (
|
||||||
@ -242,7 +251,7 @@ my $ret = CommandInclude(undef, $attr{global}{configfile});
|
|||||||
die($ret) if($ret);
|
die($ret) if($ret);
|
||||||
|
|
||||||
# Go to background if the logfile is a real file (not stdout)
|
# Go to background if the logfile is a real file (not stdout)
|
||||||
if($attr{global}{logfile} ne "-") {
|
if($attr{global}{logfile} ne "-" && !$attr{global}{nofork}) {
|
||||||
defined(my $pid = fork) || die "Can't fork: $!";
|
defined(my $pid = fork) || die "Can't fork: $!";
|
||||||
exit(0) if $pid;
|
exit(0) if $pid;
|
||||||
}
|
}
|
||||||
@ -273,13 +282,15 @@ while (1) {
|
|||||||
my ($rout, $rin) = ('', '');
|
my ($rout, $rin) = ('', '');
|
||||||
|
|
||||||
vec($rin, $server->fileno(), 1) = 1;
|
vec($rin, $server->fileno(), 1) = 1;
|
||||||
foreach my $p (keys %defs) {
|
foreach my $p (keys %selectlist) {
|
||||||
vec($rin, $defs{$p}{FD}, 1) = 1 if($defs{$p}{FD});
|
vec($rin, $selectlist{$p}{FD}, 1) = 1
|
||||||
}
|
}
|
||||||
foreach my $c (keys %client) {
|
foreach my $c (keys %client) {
|
||||||
vec($rin, fileno($client{$c}{fd}), 1) = 1;
|
vec($rin, fileno($client{$c}{fd}), 1) = 1;
|
||||||
}
|
}
|
||||||
my $timeout=HandleTimeout()||0.2;#0.2s if nothing else defined
|
|
||||||
|
my $timeout = HandleTimeout();
|
||||||
|
$timeout = 0.1 if(!defined($timeout) && keys %readyfnlist);
|
||||||
my $nfound = select($rout=$rin, undef, undef, $timeout);
|
my $nfound = select($rout=$rin, undef, undef, $timeout);
|
||||||
|
|
||||||
CommandShutdown(undef, undef) if($sig_term);
|
CommandShutdown(undef, undef) if($sig_term);
|
||||||
@ -290,12 +301,16 @@ while (1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
# Message from the hardware (FHZ1000/WS3000/etc) via FD or from Ready Function
|
# Message from the hardware (FHZ1000/WS3000/etc) via select or the Ready
|
||||||
foreach my $p (keys %defs) {
|
# Function. The latter ist needed for Windows, where USB devices are not
|
||||||
my $ready = CallFn($p,"ReadyFn",$defs{$p});
|
# reported by select.
|
||||||
if(($defs{$p}{FD} && vec($rout, $defs{$p}{FD}, 1)) || $ready) {
|
foreach my $p (keys %selectlist) {
|
||||||
CallFn($p, "ReadFn", $defs{$p});
|
CallFn($selectlist{$p}{NAME}, "ReadFn", $selectlist{$p})
|
||||||
}
|
if(vec($rout, $selectlist{$p}{FD}, 1));
|
||||||
|
}
|
||||||
|
foreach my $p (keys %readyfnlist) {
|
||||||
|
CallFn($readyfnlist{$p}{NAME}, "ReadFn", $readyfnlist{$p})
|
||||||
|
if(CallFn($readyfnlist{$p}{NAME}, "ReadyFn", $readyfnlist{$p}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(vec($rout, $server->fileno(), 1)) {
|
if(vec($rout, $server->fileno(), 1)) {
|
||||||
@ -569,18 +584,11 @@ AnalyzeCommand($$)
|
|||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#####################################
|
|
||||||
my $namedef =
|
|
||||||
"where <name> is either:\n" .
|
|
||||||
"- a single device name\n" .
|
|
||||||
"- a list seperated by komma (,)\n" .
|
|
||||||
"- a regexp, if contains one of the following characters: *[]^\$\n" .
|
|
||||||
"- a range seperated by dash (-)\n";
|
|
||||||
|
|
||||||
sub
|
sub
|
||||||
devspec2array($)
|
devspec2array($)
|
||||||
{
|
{
|
||||||
my ($name) = @_;
|
my ($name) = @_;
|
||||||
|
return "" if(!defined($name));
|
||||||
return $name if(defined($defs{$name}));
|
return $name if(defined($defs{$name}));
|
||||||
my @ret;
|
my @ret;
|
||||||
|
|
||||||
@ -874,8 +882,7 @@ CommandSet($$)
|
|||||||
{
|
{
|
||||||
my ($cl, $param) = @_;
|
my ($cl, $param) = @_;
|
||||||
my @a = split("[ \t][ \t]*", $param);
|
my @a = split("[ \t][ \t]*", $param);
|
||||||
return "Usage: set <name> <type-dependent-options>\n" .
|
return "Usage: set <name> <type-dependent-options>\n$namedef" if(int(@a)<1);
|
||||||
"$namedef" if(int(@a)<1);
|
|
||||||
|
|
||||||
my @rets;
|
my @rets;
|
||||||
foreach my $sdev (devspec2array($a[0])) {
|
foreach my $sdev (devspec2array($a[0])) {
|
||||||
@ -901,8 +908,7 @@ CommandGet($$)
|
|||||||
my ($cl, $param) = @_;
|
my ($cl, $param) = @_;
|
||||||
|
|
||||||
my @a = split("[ \t][ \t]*", $param);
|
my @a = split("[ \t][ \t]*", $param);
|
||||||
return "Usage: get <name> <type-dependent-options>\n" .
|
return "Usage: get <name> <type-dependent-options>\n$namedef" if(int(@a) < 1);
|
||||||
"$namedef" if(int(@a) < 1);
|
|
||||||
|
|
||||||
|
|
||||||
my @rets;
|
my @rets;
|
||||||
@ -932,25 +938,41 @@ CommandDefine($$)
|
|||||||
|
|
||||||
return "Usage: define <name> <type> <type dependent arguments>"
|
return "Usage: define <name> <type> <type dependent arguments>"
|
||||||
if(int(@a) < 2);
|
if(int(@a) < 2);
|
||||||
|
|
||||||
my $m = $a[1];
|
|
||||||
if($modules{$m} && !$modules{$m}{LOADED}) { # autoload
|
|
||||||
my $o = $modules{$m}{ORDER};
|
|
||||||
CommandReload($cl, "${o}_$m");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!$modules{$m} || !$modules{$m}{DefFn}) {
|
|
||||||
my @m;
|
|
||||||
foreach my $i (sort keys %modules) { # Return a list of modules
|
|
||||||
push @m, $i if($modules{$i}{DefFn} || !$modules{$i}{LOADED});
|
|
||||||
}
|
|
||||||
return "Unknown argument $m, choose one of @m";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "$a[0] already defined, delete it first" if(defined($defs{$a[0]}));
|
return "$a[0] already defined, delete it first" if(defined($defs{$a[0]}));
|
||||||
return "Invalid characters in name (not A-Za-z0-9.:_): $a[0]"
|
return "Invalid characters in name (not A-Za-z0-9.:_): $a[0]"
|
||||||
if($a[0] !~ m/^[a-z0-9.:_]*$/i);
|
if($a[0] !~ m/^[a-z0-9.:_]*$/i);
|
||||||
|
|
||||||
|
my $m = $a[1];
|
||||||
|
if(!$modules{$m}) { # Perhaps just wrong case?
|
||||||
|
foreach my $i (keys %modules) {
|
||||||
|
if(uc($m) eq uc($i)) {
|
||||||
|
$m = $i;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($modules{$m} && !$modules{$m}{LOADED}) { # autoload
|
||||||
|
my $o = $modules{$m}{ORDER};
|
||||||
|
CommandReload($cl, "${o}_$m");
|
||||||
|
|
||||||
|
if(!$modules{$m}{LOADED}) { # Case corrected by reload?
|
||||||
|
foreach my $i (keys %modules) {
|
||||||
|
if(uc($m) eq uc($i) && $modules{$i}{LOADED}) {
|
||||||
|
delete($modules{$m});
|
||||||
|
$m = $i;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$modules{$m} || !$modules{$m}{DefFn}) {
|
||||||
|
my @m = grep { $modules{$_}{DefFn} || !$modules{$_}{LOADED} }
|
||||||
|
sort keys %modules;
|
||||||
|
return "Unknown argument $m, choose one of @m";
|
||||||
|
}
|
||||||
|
|
||||||
my %hash;
|
my %hash;
|
||||||
|
|
||||||
$hash{NAME} = $a[0];
|
$hash{NAME} = $a[0];
|
||||||
@ -965,7 +987,8 @@ CommandDefine($$)
|
|||||||
|
|
||||||
my $ret = CallFn($a[0], "DefFn", \%hash, $def);
|
my $ret = CallFn($a[0], "DefFn", \%hash, $def);
|
||||||
if($ret) {
|
if($ret) {
|
||||||
delete $defs{$a[0]}
|
delete $defs{$a[0]}; # Veto
|
||||||
|
delete $attr{$a[0]};
|
||||||
} else {
|
} else {
|
||||||
foreach my $da (sort keys (%defaultattr)) { # Default attributes
|
foreach my $da (sort keys (%defaultattr)) { # Default attributes
|
||||||
CommandAttr($cl, "$a[0] $da $defaultattr{$da}");
|
CommandAttr($cl, "$a[0] $da $defaultattr{$da}");
|
||||||
@ -1021,8 +1044,7 @@ CommandDelete($$)
|
|||||||
{
|
{
|
||||||
my ($cl, $def) = @_;
|
my ($cl, $def) = @_;
|
||||||
|
|
||||||
return "Usage: delete <name>\n" .
|
return "Usage: delete <name>$namedef\n" if(!$def);
|
||||||
"$namedef" if(!$def);
|
|
||||||
|
|
||||||
my @rets;
|
my @rets;
|
||||||
foreach my $sdev (devspec2array($def)) {
|
foreach my $sdev (devspec2array($def)) {
|
||||||
@ -1036,8 +1058,18 @@ CommandDelete($$)
|
|||||||
push @rets, $ret;
|
push @rets, $ret;
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Delete releated hashes
|
||||||
|
foreach my $p (keys %selectlist) {
|
||||||
|
delete $selectlist{$p} if($selectlist{$p}{NAME} eq $sdev);
|
||||||
|
}
|
||||||
|
foreach my $p (keys %readyfnlist) {
|
||||||
|
delete $readyfnlist{$p} if($readyfnlist{$p}{NAME} eq $sdev);
|
||||||
|
}
|
||||||
|
|
||||||
delete($attr{$sdev});
|
delete($attr{$sdev});
|
||||||
delete($defs{$sdev});
|
delete($defs{$sdev}); # Remove the main entry
|
||||||
|
|
||||||
}
|
}
|
||||||
return join("\n", @rets);
|
return join("\n", @rets);
|
||||||
}
|
}
|
||||||
@ -1049,8 +1081,7 @@ CommandDeleteAttr($$)
|
|||||||
my ($cl, $def) = @_;
|
my ($cl, $def) = @_;
|
||||||
|
|
||||||
my @a = split(" ", $def, 2);
|
my @a = split(" ", $def, 2);
|
||||||
return "Usage: deleteattr <name> [<attrname>]\n" .
|
return "Usage: deleteattr <name> [<attrname>]\n$namedef" if(@a < 1);
|
||||||
"$namedef" if(@a < 1);
|
|
||||||
|
|
||||||
my @rets;
|
my @rets;
|
||||||
foreach my $sdev (devspec2array($a[0])) {
|
foreach my $sdev (devspec2array($a[0])) {
|
||||||
@ -1141,6 +1172,8 @@ CommandList($$)
|
|||||||
}
|
}
|
||||||
$str .= "Internals:\n";
|
$str .= "Internals:\n";
|
||||||
$str .= PrintHash($defs{$sdev}, 2);
|
$str .= PrintHash($defs{$sdev}, 2);
|
||||||
|
$str .= "Attributes:\n";
|
||||||
|
$str .= PrintHash($attr{$sdev}, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1254,6 +1287,7 @@ CommandReload($$)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$ret = &{ "${fnname}_Initialize" }(\%hash);
|
$ret = &{ "${fnname}_Initialize" }(\%hash);
|
||||||
|
$m = $fnname;
|
||||||
};
|
};
|
||||||
|
|
||||||
if($@) {
|
if($@) {
|
||||||
@ -1281,7 +1315,8 @@ CommandRename($$)
|
|||||||
return "Cannot rename global" if($old eq "global");
|
return "Cannot rename global" if($old eq "global");
|
||||||
|
|
||||||
$defs{$new} = $defs{$old};
|
$defs{$new} = $defs{$old};
|
||||||
delete($defs{$old});
|
$defs{$new}{NAME} = $new;
|
||||||
|
delete($defs{$old}); # The new pointer will preserve the hash
|
||||||
|
|
||||||
$attr{$new} = $attr{$old} if(defined($attr{$old}));
|
$attr{$new} = $attr{$old} if(defined($attr{$old}));
|
||||||
delete($attr{$old});
|
delete($attr{$old});
|
||||||
@ -1378,7 +1413,7 @@ GlobalAttr($$)
|
|||||||
next if($m !~ m/^([0-9][0-9])_(.*)\.pm$/);
|
next if($m !~ m/^([0-9][0-9])_(.*)\.pm$/);
|
||||||
$modules{$2}{ORDER} = $1;
|
$modules{$2}{ORDER} = $1;
|
||||||
CommandReload(undef, $m) # Always load utility modules
|
CommandReload(undef, $m) # Always load utility modules
|
||||||
if($1 eq "99" && $modules{$2} && !$modules{$2}{LOADED});
|
if($1 eq "99" && !$modules{$2}{LOADED});
|
||||||
$counter++;
|
$counter++;
|
||||||
}
|
}
|
||||||
closedir(DH);
|
closedir(DH);
|
||||||
@ -1403,8 +1438,8 @@ CommandAttr($$)
|
|||||||
my @a;
|
my @a;
|
||||||
@a = split(" ", $param, 3) if($param);
|
@a = split(" ", $param, 3) if($param);
|
||||||
|
|
||||||
return "Usage: attr <name> <attrname> [<attrvalue>]\n" .
|
return "Usage: attr <name> <attrname> [<attrvalue>]\n$namedef"
|
||||||
"$namedef" if(@a && @a < 2);
|
if(@a && @a < 2);
|
||||||
|
|
||||||
my @rets;
|
my @rets;
|
||||||
foreach my $sdev (devspec2array($a[0])) {
|
foreach my $sdev (devspec2array($a[0])) {
|
||||||
@ -1475,8 +1510,7 @@ CommandSetstate($$)
|
|||||||
my ($cl, $param) = @_;
|
my ($cl, $param) = @_;
|
||||||
|
|
||||||
my @a = split(" ", $param, 2);
|
my @a = split(" ", $param, 2);
|
||||||
return "Usage: setstate <name> <state>\n" .
|
return "Usage: setstate <name> <state>\n$namedef" if(@a != 2);
|
||||||
"$namedef" if(@a != 2);
|
|
||||||
|
|
||||||
|
|
||||||
my @rets;
|
my @rets;
|
||||||
@ -1528,8 +1562,7 @@ CommandTrigger($$)
|
|||||||
my ($cl, $param) = @_;
|
my ($cl, $param) = @_;
|
||||||
|
|
||||||
my ($dev, $state) = split(" ", $param, 2);
|
my ($dev, $state) = split(" ", $param, 2);
|
||||||
return "Usage: trigger <name> <state>\n" .
|
return "Usage: trigger <name> <state>\n$namedef" if(!$state);
|
||||||
"$namedef" if(!$state);
|
|
||||||
|
|
||||||
my @rets;
|
my @rets;
|
||||||
foreach my $sdev (devspec2array($dev)) {
|
foreach my $sdev (devspec2array($dev)) {
|
||||||
@ -1794,11 +1827,11 @@ DoTrigger($$)
|
|||||||
|
|
||||||
################
|
################
|
||||||
# Inform
|
# Inform
|
||||||
for(my $i = 0; $i < $max; $i++) {
|
foreach my $c (keys %client) { # Do client loop first, is cheaper
|
||||||
my $state = $defs{$dev}{CHANGED}[$i];
|
next if(!$client{$c}{inform});
|
||||||
my $fe = "$dev:$state";
|
for(my $i = 0; $i < $max; $i++) {
|
||||||
foreach my $c (keys %client) {
|
my $state = $defs{$dev}{CHANGED}[$i];
|
||||||
next if(!$client{$c}{inform});
|
my $fe = "$dev:$state";
|
||||||
syswrite($client{$c}{fd}, "$defs{$dev}{TYPE} $dev $state\n");
|
syswrite($client{$c}{fd}, "$defs{$dev}{TYPE} $dev $state\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1839,9 +1872,13 @@ CallFn(@)
|
|||||||
{
|
{
|
||||||
my $d = shift;
|
my $d = shift;
|
||||||
my $n = shift;
|
my $n = shift;
|
||||||
|
|
||||||
|
if(!$defs{$d}) {
|
||||||
|
Log 0, "Strange call for nonexistent $d: $n";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
if(!$defs{$d}{TYPE}) {
|
if(!$defs{$d}{TYPE}) {
|
||||||
Log 0, "Removing $d, has no TYPE";
|
Log 0, "Strange call for typeless $d: $n";
|
||||||
delete($defs{$d});
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
my $fn = $modules{$defs{$d}{TYPE}}{$n};
|
my $fn = $modules{$defs{$d}{TYPE}}{$n};
|
||||||
|
@ -97,6 +97,8 @@ FW_Define($$)
|
|||||||
return "Can't open server port at $port: $!" if(!$hash->{PORT});
|
return "Can't open server port at $port: $!" if(!$hash->{PORT});
|
||||||
|
|
||||||
$hash->{FD} = $hash->{PORT}->fileno();
|
$hash->{FD} = $hash->{PORT}->fileno();
|
||||||
|
|
||||||
|
$selectlist{"$name.$port"} = $hash;
|
||||||
$hash->{SERVERSOCKET} = 1;
|
$hash->{SERVERSOCKET} = 1;
|
||||||
Log(2, "FHEMWEB port $port opened");
|
Log(2, "FHEMWEB port $port opened");
|
||||||
|
|
||||||
@ -108,7 +110,8 @@ sub
|
|||||||
FW_Undef($$)
|
FW_Undef($$)
|
||||||
{
|
{
|
||||||
my ($hash, $arg) = @_;
|
my ($hash, $arg) = @_;
|
||||||
close($hash->{PORT}) if(defined($hash->{PORT})); # Clients do not have PORT
|
close($hash->{CD}) if(defined($hash->{CD})); # Clients
|
||||||
|
close($hash->{PORT}) if(defined($hash->{PORT})); # Server
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +146,8 @@ FW_Read($)
|
|||||||
$nhash{BUF} = "";
|
$nhash{BUF} = "";
|
||||||
|
|
||||||
$defs{$nhash{NAME}} = \%nhash;
|
$defs{$nhash{NAME}} = \%nhash;
|
||||||
|
$selectlist{$nhash{NAME}} = \%nhash;
|
||||||
|
|
||||||
Log($ll, "Connection accepted from $nhash{NAME}");
|
Log($ll, "Connection accepted from $nhash{NAME}");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -157,9 +162,7 @@ FW_Read($)
|
|||||||
my $ret = sysread($hash->{CD}, $buf, 1024);
|
my $ret = sysread($hash->{CD}, $buf, 1024);
|
||||||
|
|
||||||
if(!defined($ret) || $ret <= 0) {
|
if(!defined($ret) || $ret <= 0) {
|
||||||
close($hash->{CD});
|
my $r = CommandDelete(undef, $hash->{NAME});
|
||||||
delete($defs{$hash->{NAME}});
|
|
||||||
# Don't delete the attr entry.
|
|
||||||
Log($ll, "Connection closed for $hash->{NAME}");
|
Log($ll, "Connection closed for $hash->{NAME}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1212,6 +1215,7 @@ FW_style($$)
|
|||||||
pO "$f: $!";
|
pO "$f: $!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
$__data =~ s/\r//g if($^O ne 'MSWin32');
|
||||||
print FH $__data;
|
print FH $__data;
|
||||||
close(FH);
|
close(FH);
|
||||||
FW_style("style list", "Saved file $f");
|
FW_style("style list", "Saved file $f");
|
||||||
@ -1269,7 +1273,7 @@ FW_showWeblink($$$)
|
|||||||
pO "<td><a href=\"$v\">$d</a></td>\n";
|
pO "<td><a href=\"$v\">$d</a></td>\n";
|
||||||
} elsif($t eq "fileplot") {
|
} elsif($t eq "fileplot") {
|
||||||
my @va = split(":", $v, 3);
|
my @va = split(":", $v, 3);
|
||||||
if(@va != 3 || !$defs{$va[0]}{currentlogfile}) {
|
if(@va != 3 || !$defs{$va[0]} || !$defs{$va[0]}{currentlogfile}) {
|
||||||
pO "<td>Broken definition: $v</a></td>";
|
pO "<td>Broken definition: $v</a></td>";
|
||||||
} else {
|
} else {
|
||||||
if($va[2] eq "CURRENT") {
|
if($va[2] eq "CURRENT") {
|
||||||
|
@ -29,9 +29,19 @@ table.KS300 tr.odd { background: #A7FFA7; }
|
|||||||
table.FHZ { border:thin solid; width: 100%; background: #C0C0C0; }
|
table.FHZ { border:thin solid; width: 100%; background: #C0C0C0; }
|
||||||
table.FHZ tr.odd { background: #D7D7D7; }
|
table.FHZ tr.odd { background: #D7D7D7; }
|
||||||
|
|
||||||
|
table.CUL { border:thin solid; width: 100%; background: #C0C0C0; }
|
||||||
|
table.CUL tr.odd { background: #D7D7D7; }
|
||||||
|
|
||||||
table.EM { border:thin solid; width: 100%; background: #E0E0E0; }
|
table.EM { border:thin solid; width: 100%; background: #E0E0E0; }
|
||||||
table.EM tr.odd { background: #F0F0F0; }
|
table.EM tr.odd { background: #F0F0F0; }
|
||||||
|
|
||||||
|
table.CUL_EM { border:thin solid; width: 100%; background: #E0E0E0; }
|
||||||
|
table.CUL_EM tr.odd { background: #F0F0F0; }
|
||||||
|
|
||||||
|
table.CUL_WS { border:thin solid; width: 100%; background: #FFC0C0; }
|
||||||
|
table.CUL_WS tr.odd { background: #FFD7D7; }
|
||||||
|
|
||||||
|
|
||||||
table.FHEMWEB { border:thin solid; width: 100%; background: #E0E0E0; }
|
table.FHEMWEB { border:thin solid; width: 100%; background: #E0E0E0; }
|
||||||
table.FHEMWEB tr.odd { background: #F0F0F0; }
|
table.FHEMWEB tr.odd { background: #F0F0F0; }
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user