From 9dc00abe3544b394c1aa7c4a9c058c5637e95b26 Mon Sep 17 00:00:00 2001
From: rudolfkoenig <>
Date: Sun, 24 Oct 2010 16:08:48 +0000
Subject: [PATCH] FHEM2FHEM and associated changes
git-svn-id: https://svn.fhem.de/fhem/trunk@732 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/CHANGED | 2 +
fhem/FHEM/16_CUL_RFR.pm | 1 +
fhem/FHEM/98_structure.pm | 18 ---------
fhem/docs/commandref.html | 63 +++++++++++++++++++++++++++++-
fhem/fhem.pl | 81 ++++++++++++++++++++++++++++++++++-----
5 files changed, 137 insertions(+), 28 deletions(-)
diff --git a/fhem/CHANGED b/fhem/CHANGED
index 0acd7b73f..78afe7240 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -2,6 +2,8 @@
- feature: smallscreen optimizations for iPhone
- feature: FHT8V rewrite (and moved from contrib into the FHEM directory).
- feature: PID rewrite (and moved from contrib into the FHEM directory).
+ - feature: FHEM2FHEM module
+ - bugfix: CUL get should not digest foreign events (fhtsoftbuffer)
- 2010-08-15 (5.0)
- **NOTE*: The default installation path is changed to satisfy lintian
diff --git a/fhem/FHEM/16_CUL_RFR.pm b/fhem/FHEM/16_CUL_RFR.pm
index 4c2ec804b..ea8d3ed22 100755
--- a/fhem/FHEM/16_CUL_RFR.pm
+++ b/fhem/FHEM/16_CUL_RFR.pm
@@ -25,6 +25,7 @@ CUL_RFR_Initialize($)
$hash->{WriteFn} = "CUL_RFR_Write";
$hash->{GetFn} = "CUL_Get";
$hash->{SetFn} = "CUL_Set";
+ $hash->{noRawInform} = 1; # Our message was already sent as raw.
}
diff --git a/fhem/FHEM/98_structure.pm b/fhem/FHEM/98_structure.pm
index d650c6716..c55ff0247 100755
--- a/fhem/FHEM/98_structure.pm
+++ b/fhem/FHEM/98_structure.pm
@@ -4,8 +4,6 @@ package main;
use strict;
use warnings;
-sub addToAttrList($);
-
#####################################
sub
structure_Initialize($)
@@ -199,20 +197,4 @@ structure_Attr($@)
return undef;
}
-sub
-addToAttrList($)
-{
- my $arg = shift;
-
- my $ua = "";
- $ua = $attr{global}{userattr} if($attr{global}{userattr});
- my @al = split(" ", $ua);
- my %hash;
- foreach my $a (@al) {
- $hash{$a} = 1;
- }
- $hash{$arg} = 1;
- $attr{global}{userattr} = join(" ", sort keys %hash);
-}
-
1;
diff --git a/fhem/docs/commandref.html b/fhem/docs/commandref.html
index c3a72d954..e67d00665 100644
--- a/fhem/docs/commandref.html
+++ b/fhem/docs/commandref.html
@@ -121,6 +121,7 @@
Helper modules
DbLog
+ FHEM2FHEM
FHEMRENDERER
FHEMWEB
FileLog
@@ -506,7 +507,7 @@ A line ending with \ will be concatenated with the next one, so long lines
inform
- inform [on|off|timer]
+ inform [on|off|timer|raw]
If set to on, and a device state changes, send a notification to the current
client. This command can be used by other programs/modules to receive a
@@ -4694,6 +4695,66 @@ Terminating
+
+FHEM2FHEM
+
+ FHEM2FHEM is a helper module to connect separate fhem installations.
+
+
+ Define
+
+ define <name> FHEM2FHEM <host:portnr> [LOG:regexp|RAW:devicename]
+
+
+
+ Conect to the remote fhem on host. portnr is the global port
+ attribute of the remote fhem. The next parameter specifies the connection
+ type:
+
+ - LOG
+ Using this type you will receive all events generated by the remote fhem,
+ just like when using the inform on command, and you
+ can use these events just like any local event for FileLog or notify.
+ The regexp will prefilter the events distributed locally, for the syntax
+ see the notify definition.
+ Drawbacks: the remote devices wont be created locally, so list wont
+ show them and it is not possible to manipulate them from the local
+ fhem. It is possible to create a device with the same name on both fhem
+ instances, but if both of them receive the same event (e.g. because both
+ of them have a CUL attached), then all associated FileLogs/notifys will be
+ triggered twice.
+
+ - RAW
+ By using this type the local fhem will receive raw events from the remote
+ fhem device devicename, just like if it would be attached to the
+ local fhem.
+ Drawback: only devices using the Dispatch function (CUL, FHZ, CM11,
+ SISPM, RFXCOM) generate raw messages.
+
+ Examples:
+
+ define ds1 FHEM2FHEM 192.168.0.1:7072 LOG:.*
+ define ds2 FHEM2FHEM 192.168.0.1:7072 RAW:CUL
+
+
+
+
+ Set
+
+
+ Get
+
+
+ Attributes
+
+
+
+
+
FHEMWEB
diff --git a/fhem/fhem.pl b/fhem/fhem.pl
index 55b1c9464..0150b1f79 100755
--- a/fhem/fhem.pl
+++ b/fhem/fhem.pl
@@ -44,6 +44,7 @@ sub AnalyzeCommand($$);
sub AnalyzeCommandChain($$);
sub AnalyzeInput($);
sub AssignIoPort($);
+sub addToAttrList($);
sub CallFn(@);
sub CommandChain($$);
sub CheckDuplicate($$);
@@ -87,6 +88,7 @@ sub CommandGet($$);
sub CommandHelp($$);
sub CommandInclude($$);
sub CommandInform($$);
+sub CommandIOWrite($$);
sub CommandList($$);
sub CommandModify($$);
sub CommandReload($$);
@@ -142,6 +144,7 @@ use vars qw($internal_data); #
use vars qw(%cmds); # Global command name hash. To be expanded
use vars qw(%data); # Hash for user data
use vars qw($devcount); # To sort the devices
+use vars qw(%defaultattr); # Default attributes, used by FHEM2FHEM
use vars qw($reread_active);
@@ -154,13 +157,12 @@ my %client; # Client array
my $rcvdquit; # Used for quit handling in init files
my $sig_term = 0; # if set to 1, terminate (saving the state)
my $modpath_set; # Check if modpath was used, and report if not.
-my %defaultattr; # Default attributes
my %intAt; # Internal at timer hash.
my $nextat; # Time when next timer will be triggered.
my $intAtCnt=0;
my %duplicate; # Pool of received msg for multi-fhz/cul setups
my $duplidx=0; # helper for the above pool
-my $cvsid = '$Id: fhem.pl,v 1.113 2010-10-10 08:23:29 rudolfkoenig Exp $';
+my $cvsid = '$Id: fhem.pl,v 1.114 2010-10-24 16:08:48 rudolfkoenig Exp $';
my $namedef =
"where is either:\n" .
"- a single device name\n" .
@@ -201,7 +203,9 @@ $modules{_internal_}{AttrFn} = "GlobalAttr";
"include" => { Fn=>"CommandInclude",
Hlp=>",read the commands from " },
"inform" => { Fn=>"CommandInform",
- Hlp=>"{on|timer|off},echo all commands and events to this client" },
+ Hlp=>"{on|timer|raw|off},echo all events to this client" },
+ "iowrite" => { Fn=>"CommandIOWrite",
+ Hlp=>" ,write raw data with iodev" },
"list" => { Fn=>"CommandList",
Hlp=>"[devspec],list definitions and status info" },
"modify" => { Fn=>"CommandModify",
@@ -533,6 +537,33 @@ IOWrite($@)
return $ret;
}
+#####################################
+sub
+CommandIOWrite($$)
+{
+ my ($cl, $param) = @_;
+ my @a = split(" ", $param);
+
+ return "Usage: iowrite ..." if(int(@a) <= 2);
+
+ my $name = shift(@a);
+ my $hash = $defs{$name};
+ return "$name not found" if(!$hash);
+ return undef if(IsDummy($name) || IsIgnored($name));
+ if(!$hash->{TYPE} ||
+ !$modules{$hash->{TYPE}} ||
+ !$modules{$hash->{TYPE}}{WriteFn}) {
+ Log 1, "No IO device or WriteFn found for $name";
+ return;
+ }
+ unshift(@a, "") if(int(@a) == 1);
+ no strict "refs";
+ my $ret = &{$modules{$hash->{TYPE}}{WriteFn}}($hash, @a);
+ use strict "refs";
+ return $ret;
+}
+
+
#####################################
sub
AnalyzeInput($)
@@ -1135,10 +1166,12 @@ AssignIoPort($)
{
my ($hash) = @_;
- # Set the I/O device
+ # Set the I/O device, search for the last compatible one.
for my $p (sort { $defs{$b}{NR} <=> $defs{$a}{NR} } keys %defs) {
my $cl = $modules{$defs{$p}{TYPE}}{Clients};
- if(defined($cl) && $cl =~ m/:$hash->{TYPE}:/ &&
+ my $re = $modules{$defs{$p}{TYPE}}{regexpClients};
+ if(((defined($cl) && $cl =~ m/:$hash->{TYPE}:/) ||
+ (defined($re) && $hash->{TYPE} =~ m/$re/)) &&
$defs{$p}{NAME} ne $hash->{NAME}) { # e.g. RFR
$hash->{IODev} = $defs{$p};
last;
@@ -1675,7 +1708,8 @@ CommandInform($$)
$param = lc($param);
- return "Usage: inform {on|off|timer}" if($param !~ m/^(on|off|timer)$/);
+ return "Usage: inform {on|timer|raw|off}"
+ if($param !~ m/^(on|off|raw|timer)$/);
if($param =~ m/off/) {
delete($client{$cl}{inform});
} else {
@@ -1922,7 +1956,7 @@ DoTrigger($$)
################
# Inform
foreach my $c (keys %client) { # Do client loop first, is cheaper
- next if(!$client{$c}{inform});
+ next if(!$client{$c}{inform} || $client{$c}{inform} eq "raw");
my $tn = TimeNow();
if($attr{global}{mseclog}) {
my ($seconds, $microseconds) = gettimeofday();
@@ -1930,7 +1964,6 @@ DoTrigger($$)
}
for(my $i = 0; $i < $max; $i++) {
my $state = $defs{$dev}{CHANGED}[$i];
- my $fe = "$dev:$state";
syswrite($client{$c}{fd},
($client{$c}{inform} eq "timer" ? "$tn " : "") .
"$defs{$dev}{TYPE} $dev $state\n");
@@ -2125,7 +2158,11 @@ Dispatch($$$)
my @found;
foreach my $m (sort { $modules{$a}{ORDER} cmp $modules{$b}{ORDER} }
grep {defined($modules{$_}{ORDER})} keys %modules) {
- next if($iohash->{Clients} !~ m/:$m:/);
+
+ my $cl = $iohash->{Clients};
+ my $re = $iohash->{regexpClients};
+ next if(!(defined($cl) && $cl =~ m/:$m:/) ||
+ (defined($re) && $m =~ m/$re/));
# Module is not loaded or the message is not for this module
next if(!$modules{$m}{Match} || $dmsg !~ m/$modules{$m}{Match}/i);
@@ -2170,6 +2207,15 @@ Dispatch($$$)
}
}
+ ################
+ # Inform raw
+ if(!$iohash->{noRawInform}) {
+ foreach my $c (keys %client) {
+ next if(!$client{$c}{inform} || $client{$c}{inform} ne "raw");
+ syswrite($client{$c}{fd}, "$hash->{TYPE} $name $dmsg\n");
+ }
+ }
+
return undef if($found[0] eq ""); # Special return: Do not notify
foreach my $found (@found) {
@@ -2270,3 +2316,20 @@ ReadingsVal($$$)
}
return $default;
}
+
+sub
+addToAttrList($)
+{
+ my $arg = shift;
+
+ my $ua = "";
+ $ua = $attr{global}{userattr} if($attr{global}{userattr});
+ my @al = split(" ", $ua);
+ my %hash;
+ foreach my $a (@al) {
+ $hash{$a} = 1;
+ }
+ $hash{$arg} = 1;
+ $attr{global}{userattr} = join(" ", sort keys %hash);
+}
+