CUL_HM changes: devicepair, desired-temp, div. pairings

fhem: inform regexp.


git-svn-id: https://fhem.svn.sourceforge.net/svnroot/fhem/trunk/fhem@1093 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig
2011-11-06 18:49:25 +00:00
parent 1441f8b11d
commit 7ec00264aa
4 changed files with 193 additions and 129 deletions

View File

@@ -65,7 +65,7 @@ my %matchListSlowRF = (
"E:CUL_TX" => "^TX[A-F0-9]{10}", "E:CUL_TX" => "^TX[A-F0-9]{10}",
); );
my %matchListHomeMatic = ( my %matchListHomeMatic = (
"1:CUL_HM" => "^A......................", "1:CUL_HM" => "^A....................",
"8:HMS" => "^810e04....(1|5|9).a001", # CUNO OneWire HMS Emulation "8:HMS" => "^810e04....(1|5|9).a001", # CUNO OneWire HMS Emulation
"D:CUL_IR" => "^I............", "D:CUL_IR" => "^I............",
); );
@@ -813,9 +813,9 @@ CUL_Parse($$$$$)
$rssi = hex(substr($dmsg, $l-2, 2)); $rssi = hex(substr($dmsg, $l-2, 2));
$dmsg = substr($dmsg, 0, $l-2); $dmsg = substr($dmsg, 0, $l-2);
$rssi = ($rssi>=128 ? (($rssi-256)/2-74) : ($rssi/2-74)); $rssi = ($rssi>=128 ? (($rssi-256)/2-74) : ($rssi/2-74));
Log GetLogLevel($name,4), "$name: $dmsg $rssi"; Log GetLogLevel($name,5), "$name: $dmsg $rssi";
} else { } else {
Log GetLogLevel($name,4), "$name: $dmsg"; Log GetLogLevel($name,5), "$name: $dmsg";
} }
########################################### ###########################################

View File

@@ -124,7 +124,7 @@ CUL_HM_Initialize($)
{ {
my ($hash) = @_; my ($hash) = @_;
$hash->{Match} = "^A......................"; $hash->{Match} = "^A....................";
$hash->{DefFn} = "CUL_HM_Define"; $hash->{DefFn} = "CUL_HM_Define";
$hash->{ParseFn} = "CUL_HM_Parse"; $hash->{ParseFn} = "CUL_HM_Parse";
$hash->{SetFn} = "CUL_HM_Set"; $hash->{SetFn} = "CUL_HM_Set";
@@ -187,7 +187,9 @@ CUL_HM_Parse($$)
$msg =~ m/A(..)(..)(....)(......)(......)(.*)/; $msg =~ m/A(..)(..)(....)(......)(......)(.*)/;
my @msgarr = ($1,$2,$3,$4,$5,$6,$7); my @msgarr = ($1,$2,$3,$4,$5,$6,$7);
my ($len,$msgcnt,$cmd,$src,$dst,$p) = @msgarr; my ($len,$msgcnt,$cmd,$src,$dst,$p) = @msgarr;
$p = "" if(!defined($p));
# cmdX / msgX used for duplicate detection
my $cmdX = $cmd; my $cmdX = $cmd;
$cmdX =~ s/^A4/A0/; $cmdX =~ s/^A4/A0/;
$cmdX =~ s/^0B/0A/; $cmdX =~ s/^0B/0A/;
@@ -197,13 +199,13 @@ CUL_HM_Parse($$)
# $shash will be replaced for multichannel commands # $shash will be replaced for multichannel commands
my $shash = $modules{CUL_HM}{defptr}{$src}; my $shash = $modules{CUL_HM}{defptr}{$src};
my $lcm = "$len$cmd"; my $lcm = "$len$cmd";
my $dhash = $modules{CUL_HM}{defptr}{$dst}; my $dhash = $modules{CUL_HM}{defptr}{$dst};
my $dname = $dhash ? $dhash->{NAME} : my $dname = $dhash ? $dhash->{NAME} :
($dst eq "000000" ? "broadcast" : ($dst eq "000000" ? "broadcast" :
($dst eq $id ? $iohash->{NAME} : $dst)); ($dst eq $id ? $iohash->{NAME} : $dst));
my $target = ($dst eq $id) ? "" : " (to $dname)"; my $target = ($dst eq $id) ? "" : " (to $dname)";
if($p =~ m/NACK$/) { # HMLAN special if($p =~ m/NACK$/) { # HMLAN special
if($dhash) { if($dhash) {
delete($dhash->{ackCmdSent}); delete($dhash->{ackCmdSent});
@@ -217,13 +219,14 @@ CUL_HM_Parse($$)
CUL_HM_DumpProtocol("RCV", $iohash, @msgarr); CUL_HM_DumpProtocol("RCV", $iohash, @msgarr);
# Generate an UNKNOWN event with a better name if(!$shash) { # Unknown source
if(!$shash) {
my $sname = "CUL_HM_$src";
if($lcm =~ m/1A8.00/) { # Pairing request
# Prefer subType over model to make autocreate easier. # Generate an UNKNOWN event for pairing requests, ignore everything else
# besides the model names are quite cryptic if($lcm =~ m/1A8.00/) {
my $sname = "CUL_HM_$src";
# prefer subType over model to make autocreate easier
# model names are quite cryptic anyway
my $model = substr($p, 2, 4); my $model = substr($p, 2, 4);
my $stc = substr($p, 26, 2); # subTypeCode my $stc = substr($p, 26, 2); # subTypeCode
if($culHmDevProps{$stc}) { if($culHmDevProps{$stc}) {
@@ -237,6 +240,7 @@ CUL_HM_Parse($$)
Log 3, "CUL_HM Unknown device $sname, please define it"; Log 3, "CUL_HM Unknown device $sname, please define it";
return "UNDEFINED $sname CUL_HM $src $msg"; return "UNDEFINED $sname CUL_HM $src $msg";
} }
return ""; return "";
} }
@@ -246,16 +250,47 @@ CUL_HM_Parse($$)
my $model = AttrVal($name, "model", ""); my $model = AttrVal($name, "model", "");
my $tn = TimeNow(); my $tn = TimeNow();
if($cmd eq "8002") { # Ack if($cmd eq "8002") { # Ack / Nack
# Multi-channel device: Switch to the shadow source hash
my $chn = $2 if($p =~ m/^(..)(..)/);
if($chn && $chn ne "01" && $chn ne "00") {
my $sshash = $modules{CUL_HM}{defptr}{"$src$chn"};
$shash = $sshash if($sshash);
}
if($p =~ m/^8/) {
delete($shash->{cmdStack});
push @event, "state:NACK";
} else {
CUL_HM_ProcessCmdStack($shash); CUL_HM_ProcessCmdStack($shash);
push @event, ""; push @event, "";
} }
$shash->{READINGS}{CommandAccepted}{TIME} = $tn;
$shash->{READINGS}{CommandAccepted}{VAL} = ($p =~ m/^8/ ? "no" : "yes");
}
if($cmd ne "8002" && $shash->{cmdStack}) {
# i have to tell something, dont care what it said
CUL_HM_SendCmd($shash, "++8002$id${src}00",1,0) # Send Ack
if($id eq $dst && $cmd ne "8002");
CUL_HM_ProcessCmdStack($shash);
push @event, "";
} elsif($lcm eq "09A112") { ### Another fhem wants to talk (HAVE_DATA)
;
} elsif($lcm eq "1A8400" || $lcm eq "1A8000") { #### Pairing-Request
if($lcm eq "1A8400" || $lcm eq "1A8000") { #### Pairing-Request
if($shash->{cmdStack}) { if($shash->{cmdStack}) {
CUL_HM_SendCmd($shash, "++A112$id$src", 1, 1); #CUL_HM_SendCmd($shash, "++A112$id$src", 1, 1); # HAVE_DATA
CUL_HM_ProcessCmdStack($shash);
} else { } else {
push @event, CUL_HM_Pair($name, $shash, @msgarr); push @event, CUL_HM_Pair($name, $shash, @msgarr);
} }
} elsif($cmd =~ m/^A0[01]{2}$/ && $dst eq $id) {#### Pairing-Request-Convers. } elsif($cmd =~ m/^A0[01]{2}$/ && $dst eq $id) {#### Pairing-Request-Convers.
@@ -308,16 +343,8 @@ CUL_HM_Parse($$)
push @event, "humidity:$h"; push @event, "humidity:$h";
# If we have something to tell: # If we have something to tell:
my $sdt = $shash->{SET_DESIRED_TEMP}; # DOES NOT WORK
if($sdt) {
CUL_HM_SendCmd($shash,
sprintf("++A011%s%s0201${sdt}0000", $id,$dst), 1, 1);
delete($shash->{SET_DESIRED_TEMP});
} else {
CUL_HM_SendCmd($shash, "++A112$id$src", 1, 1) if($shash->{cmdStack}); CUL_HM_SendCmd($shash, "++A112$id$src", 1, 1) if($shash->{cmdStack});
} }
}
if($cmd eq "A258" && $p =~ m/^(..)(..)/) { if($cmd eq "A258" && $p =~ m/^(..)(..)/) {
my ( $d1, $vp) = my ( $d1, $vp) =
@@ -411,7 +438,7 @@ CUL_HM_Parse($$)
} }
if($cmd eq "A410" && $p =~ m/^0602(..)........$/) { if($cmd eq "A410" && $p =~ m/^0602(..)........$/) {
push @event, "desired-temp: " .hex($1)/2; push @event, "desired-temp:" .hex($1)/2;
} }
CUL_HM_SendCmd($shash, "++8002$id${src}00",1,0) # Send Ack CUL_HM_SendCmd($shash, "++8002$id${src}00",1,0) # Send Ack
@@ -426,9 +453,11 @@ CUL_HM_Parse($$)
(hex($3), $4); (hex($3), $4);
$vp = int($vp)/2; # valve position in % $vp = int($vp)/2; # valve position in %
push @event, "actuator:$vp %"; push @event, "actuator:$vp %";
if($d1 eq "10") { push @event, "actuator:movement_open";
} elsif($d1 eq "20") { push @event, "actuator:movement_close"; # I think this is too much info:
} # if($d1 eq "10") { push @event, "actuator:movement_open";
# } elsif($d1 eq "20") { push @event, "actuator:movement_close";
# }
} }
# CMD:A010 SRC:13F251 DST:5D24C9 0401000000000509000A070000 # CMD:A010 SRC:13F251 DST:5D24C9 0401000000000509000A070000
@@ -486,7 +515,9 @@ CUL_HM_Parse($$)
&& $cmd ne "A002") { && $cmd ne "A002") {
my $msgType = $1; my $msgType = $1;
my $chn = $2; my $chn = $2;
if($chn ne "01" && $chn ne "00") { # Switch to the shadow device
# Multi-channel device: Switch to the shadow source hash
if($chn ne "01" && $chn ne "00") {
my $cSrc = "$src$chn"; my $cSrc = "$src$chn";
if($modules{CUL_HM}{defptr}{$cSrc}) { if($modules{CUL_HM}{defptr}{$cSrc}) {
$shash = $modules{CUL_HM}{defptr}{$cSrc}; $shash = $modules{CUL_HM}{defptr}{$cSrc};
@@ -737,16 +768,19 @@ my %culHmSubTypeSets = (
{ "on-for-timer"=>"sec", on =>"", off=>"", toggle=>"", pct=>"" }, { "on-for-timer"=>"sec", on =>"", off=>"", toggle=>"", pct=>"" },
remote => remote =>
{ text => "<btn> [on|off] <txt1> <txt2>", { text => "<btn> [on|off] <txt1> <txt2>",
devicepair => "<btn> device", }, devicepair => "<btnNumber> device", },
winMatic => winMatic =>
{ matic => "<btn>", read => "<btn>", keydef => "<btn> <txt1> <txt2>", create => "<txt>" }, { matic => "<btn>",
read => "<btn>",
keydef => "<btn> <txt1> <txt2>",
create => "<txt>" },
); );
my %culHmModelSets = ( my %culHmModelSets = (
"HM-CC-TC"=> "HM-CC-TC"=>
{ "day-temp" => "temp", { "day-temp" => "temp",
"night-temp" => "temp", "night-temp" => "temp",
"party-temp" => "temp", "party-temp" => "temp",
#"desired-temp" => "temp", # does not work "desired-temp" => "temp", # does not work
"tempListSat"=> "HH:MM temp ...", "tempListSat"=> "HH:MM temp ...",
"tempListSun"=> "HH:MM temp ...", "tempListSun"=> "HH:MM temp ...",
"tempListMon"=> "HH:MM temp ...", "tempListMon"=> "HH:MM temp ...",
@@ -762,8 +796,7 @@ sub
CUL_HM_Set($@) CUL_HM_Set($@)
{ {
my ($hash, @a) = @_; my ($hash, @a) = @_;
my $ret = ""; my ($ret, $tval);
my $tval;
return "no set value specified" if(@a < 2); return "no set value specified" if(@a < 2);
@@ -785,6 +818,10 @@ CUL_HM_Set($@)
my @h; my @h;
@h = split(" ", $h) if($h); @h = split(" ", $h) if($h);
my $isSender = (AttrVal($name, "hmClass", "") eq "sender" ||
AttrVal($name, "model", "") eq "HM-CC-TC");
if(!defined($h) && defined($culHmSubTypeSets{$st}{pct}) && $cmd =~ m/^\d+/) { if(!defined($h) && defined($culHmSubTypeSets{$st}{pct}) && $cmd =~ m/^\d+/) {
$cmd = "pct"; $cmd = "pct";
@@ -808,61 +845,70 @@ CUL_HM_Set($@)
} }
my $id = CUL_HM_Id($hash->{IODev}); my $id = CUL_HM_Id($hash->{IODev});
my $sndcmd;
my $state = join(" ", @a[1..(int(@a)-1)]); my $state = join(" ", @a[1..(int(@a)-1)]);
if($cmd eq "raw") { ################################################## if($cmd eq "raw") { ##################################################
return "Usage: set $a[0] $cmd data [data ...]" if(@a < 3); return "Usage: set $a[0] $cmd data [data ...]" if(@a < 3);
$sndcmd = $a[2]; for (my $i = 2; $i < @a; $i++) {
for (my $i = 3; $i < @a; $i++) {
CUL_HM_PushCmdStack($hash, $a[$i]); CUL_HM_PushCmdStack($hash, $a[$i]);
} }
$state = ""; $state = "";
} elsif($cmd eq "reset") { ############################################ } elsif($cmd eq "reset") { ############################################
$sndcmd = sprintf("++A011%s%s0400", $id,$dst); CUL_HM_PushCmdStack($hash,
sprintf("++A011%s%s0400", $id,$dst));
} elsif($cmd eq "pair") { ############################################# } elsif($cmd eq "pair") { #############################################
return "pair is not enabled for this device, use set <IODev> hmPairForSec"
if($isSender);
my $serialNr = AttrVal($name, "serialNr", undef); my $serialNr = AttrVal($name, "serialNr", undef);
return "serialNr is not set" if(!$serialNr); return "serialNr is not set" if(!$serialNr);
$sndcmd = sprintf("++A401%s000000010A%s", $id, unpack("H*",$serialNr)); CUL_HM_PushCmdStack($hash,
sprintf("++A401%s000000010A%s", $id, unpack("H*",$serialNr)));
$hash->{hmPairSerial} = $serialNr; $hash->{hmPairSerial} = $serialNr;
} elsif($cmd eq "unpair") { ########################################### } elsif($cmd eq "unpair") { ###########################################
CUL_HM_pushConfig($hash, $id, $dst, 0, 0, "02010A000B000C00"); CUL_HM_pushConfig($hash, $id, $dst, 0, 0, "02010A000B000C00");
$sndcmd = shift @{$hash->{cmdStack}};
} elsif($cmd eq "sign") { ############################################ } elsif($cmd eq "sign") { ############################################
CUL_HM_pushConfig($hash, $id, $dst, $chn, $chn, CUL_HM_pushConfig($hash, $id, $dst, $chn, $chn,
"08" . ($a[2] eq "on" ? "01":"02")); "08" . ($a[2] eq "on" ? "01":"02"));
$sndcmd = shift @{$hash->{cmdStack}};
} elsif($cmd eq "statusRequest") { #################################### } elsif($cmd eq "statusRequest") { ####################################
$sndcmd = sprintf("++A001%s%s%s0E", $id,$dst, $chn); CUL_HM_PushCmdStack($hash,
sprintf("++A001%s%s%s0E", $id,$dst, $chn));
} elsif($cmd eq "on") { ############################################### } elsif($cmd eq "on") { ###############################################
$sndcmd = sprintf("++A011%s%s02%sC80000", $id,$dst, $chn); CUL_HM_PushCmdStack($hash,
sprintf("++A011%s%s02%sC80000", $id,$dst, $chn));
} elsif($cmd eq "off") { ############################################## } elsif($cmd eq "off") { ##############################################
$sndcmd = sprintf("++A011%s%s02%s000000", $id,$dst,$chn); CUL_HM_PushCmdStack($hash,
sprintf("++A011%s%s02%s000000", $id,$dst,$chn));
} elsif($cmd eq "on-for-timer") { ##################################### } elsif($cmd eq "on-for-timer") { #####################################
($tval,$ret) = CUL_HM_encodeTime16($a[2]); ($tval,$ret) = CUL_HM_encodeTime16($a[2]);
$sndcmd = sprintf("++A011%s%s02%sC80000%s", $id,$dst, $chn, $tval); Log 1, $ret if($ret);
CUL_HM_PushCmdStack($hash,
sprintf("++A011%s%s02%sC80000%s", $id,$dst, $chn, $tval));
} elsif($cmd eq "toggle") { ########################################### } elsif($cmd eq "toggle") { ###########################################
$hash->{toggleIndex} = 1 if(!$hash->{toggleIndex}); $hash->{toggleIndex} = 1 if(!$hash->{toggleIndex});
$hash->{toggleIndex} = (($hash->{toggleIndex}+1) % 128); $hash->{toggleIndex} = (($hash->{toggleIndex}+1) % 128);
$sndcmd = sprintf("++A03E%s%s%s40%s%02X", $id, $dst, CUL_HM_PushCmdStack($hash, sprintf("++A03E%s%s%s40%s%02X", $id, $dst,
$dst, $chn, $hash->{toggleIndex}); $dst, $chn, $hash->{toggleIndex}));
} elsif($cmd eq "pct") { ############################################## } elsif($cmd eq "pct") { ##############################################
$a[1] = 100 if ($a[1] > 100); $a[1] = 100 if ($a[1] > 100);
$sndcmd = sprintf("++A011%s%s02%s%02X0000", $id, $dst, $chn, $a[1]*2); my $cmd = sprintf("++A011%s%s02%s%02X0000", $id, $dst, $chn, $a[1]*2);
if(@a > 2) { if(@a > 2) {
($tval,$ret) = CUL_HM_encodeTime16($a[2]); ($tval,$ret) = CUL_HM_encodeTime16($a[2]);
$sndcmd .= $tval; Log 1, $ret if($ret);
$cmd .= $tval;
} }
CUL_HM_PushCmdStack($hash, $cmd);
} elsif($cmd eq "text") { ############################################# } elsif($cmd eq "text") { #############################################
$state = ""; $state = "";
@@ -884,13 +930,12 @@ CUL_HM_Set($@)
$l1 .= $l2; $l1 .= $l2;
CUL_HM_pushConfig($hash, $id, $dst, $bn, 1, $l1); CUL_HM_pushConfig($hash, $id, $dst, $bn, 1, $l1);
return "Set your remote in learning mode to transmit the data";
} elsif($cmd =~ m/^desired-temp$/) { ################## } elsif($cmd =~ m/^desired-temp$/) { ##################
my $temp = CUL_HM_convTemp($a[2]); my $temp = CUL_HM_convTemp($a[2]);
return $temp if(length($temp) > 2); return $temp if(length($temp) > 2);
$hash->{SET_DESIRED_TEMP} = $temp; CUL_HM_PushCmdStack($hash,
return; sprintf("++A011%s%s0201%s0000", $id,$dst,$temp));
} elsif($cmd =~ m/^(day|night|party)-temp$/) { ################## } elsif($cmd =~ m/^(day|night|party)-temp$/) { ##################
my %tt = (day=>"03", night=>"04", party=>"06"); my %tt = (day=>"03", night=>"04", party=>"06");
@@ -898,7 +943,6 @@ CUL_HM_Set($@)
my $temp = CUL_HM_convTemp($a[2]); my $temp = CUL_HM_convTemp($a[2]);
return $temp if(length($temp) > 2); return $temp if(length($temp) > 2);
CUL_HM_pushConfig($hash, $id, $dst, 2, 5, "$tt$temp"); # List 5 CUL_HM_pushConfig($hash, $id, $dst, 2, 5, "$tt$temp"); # List 5
return;
} elsif($cmd =~ m/^tempList(...)/) { ################################## } elsif($cmd =~ m/^tempList(...)/) { ##################################
my %day2off = ( "Sat"=>"5 0B", "Sun"=>"5 3B", "Mon"=>"5 6B", my %day2off = ( "Sat"=>"5 0B", "Sun"=>"5 3B", "Mon"=>"5 6B",
@@ -908,12 +952,10 @@ CUL_HM_Set($@)
my ($list,$addr) = split(" ", $day2off{$wd}); my ($list,$addr) = split(" ", $day2off{$wd});
$addr = hex($addr); $addr = hex($addr);
return "To few arguments" if(@a < 4); return "To few arguments" if(@a < 4);
return "To many arguments, max is 24 pairs" if(@a > 50); return "To many arguments, max is 24 pairs" if(@a > 50);
return "Bad format, use HH:MM TEMP ..." if(@a % 2); return "Bad format, use HH:MM TEMP ..." if(@a % 2);
return "Last time spec must be 24:00" if($a[@a-2] ne "24:00"); return "Last time spec must be 24:00" if($a[@a-2] ne "24:00");
my $data = ""; my $data = "";
my $msg = ""; my $msg = "";
for(my $idx = 2; $idx < @a; $idx += 2) { for(my $idx = 2; $idx < @a; $idx += 2) {
@@ -935,51 +977,55 @@ CUL_HM_Set($@)
$hash->{READINGS}{$vn}{TIME} = TimeNow(); $hash->{READINGS}{$vn}{TIME} = TimeNow();
$hash->{READINGS}{$vn}{VAL} = $msg; $hash->{READINGS}{$vn}{VAL} = $msg;
return;
} elsif($cmd eq "matic") { ##################################### } elsif($cmd eq "matic") { #####################################
# Trigger pre-programmed action in the winmatic. These actions must be # Trigger pre-programmed action in the winmatic. These actions must be
# programmed via the original software. # programmed via the original software.
$sndcmd = sprintf("++B03E%s%s%s40%02X%s", $id, $dst, $id, $a[2], $chn); CUL_HM_PushCmdStack($hash,
sprintf("++B03E%s%s%s40%02X%s", $id, $dst, $id, $a[2], $chn));
} elsif($cmd eq "create") { ################################### } elsif($cmd eq "create") { ###################################
$sndcmd = sprintf("++B001%s%s0101%s%02X%s", $id, $dst, $id, $a[2], $chn); CUL_HM_PushCmdStack($hash,
CUL_HM_SendCmd($hash, $sndcmd, 1, 1); sprintf("++B001%s%s0101%s%02X%s", $id, $dst, $id, $a[2], $chn));
sleep(2); CUL_HM_PushCmdStack($hash,
$sndcmd = sprintf("++A001%s%s0104%s%02X%s", $id, $dst, $id, $a[2], $chn); sprintf("++A001%s%s0104%s%02X%s", $id, $dst, $id, $a[2], $chn));
} elsif($cmd eq "read") { ################################### } elsif($cmd eq "read") { ###################################
$sndcmd = sprintf("++B001%s%s0104%s%02X03", $id, $dst, $id, $a[2]); CUL_HM_PushCmdStack($hash,
sprintf("++B001%s%s0104%s%02X03", $id, $dst, $id, $a[2]));
} elsif($cmd eq "keydef") { ##################################### } elsif($cmd eq "keydef") { #####################################
my $cmd;
if ($a[3] eq "tilt") { if ($a[3] eq "tilt") {
$sndcmd = CUL_HM_maticFn($hash, $id, $dst, $a[2],"0B220D838B228D83"); $cmd = CUL_HM_maticFn($hash, $id, $dst, $a[2],"0B220D838B228D83");
} elsif ($a[3] eq "close") { } elsif ($a[3] eq "close") {
$sndcmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], "0B550D838B558D83"); $cmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], "0B550D838B558D83");
} elsif ($a[3] eq "closed") { } elsif ($a[3] eq "closed") {
$sndcmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], "0F008F00"); $cmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], "0F008F00");
} elsif ($a[3] eq "bolt") { } elsif ($a[3] eq "bolt") {
$sndcmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], "0FFF8FFF"); $cmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], "0FFF8FFF");
} elsif ($a[3] eq "delete") { } elsif ($a[3] eq "delete") {
$sndcmd = sprintf("++B001%s%s0102%s%02X%s", $id, $dst, $id, $a[2], $chn); $cmd = sprintf("++B001%s%s0102%s%02X%s", $id, $dst, $id, $a[2], $chn);
} elsif ($a[3] eq "speedclose") { } elsif ($a[3] eq "speedclose") {
$sndcmd = $a[4]*2; $cmd = $a[4]*2;
$sndcmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], $cmd = CUL_HM_maticFn($hash, $id, $dst, $a[2],
sprintf("23%02XA3%02X", $sndcmd, $sndcmd)); sprintf("23%02XA3%02X", $cmd, $cmd));
} elsif ($a[3] eq "speedtilt") { } elsif ($a[3] eq "speedtilt") {
$sndcmd = $a[4]*2; $cmd = $a[4]*2;
$sndcmd = CUL_HM_maticFn($hash, $id, $dst, $a[2], $cmd = CUL_HM_maticFn($hash, $id, $dst, $a[2],
sprintf("22%02XA2%02X", $sndcmd, $sndcmd)); sprintf("22%02XA2%02X", $cmd, $cmd));
} } else {
return "unknown argument $a[3]";
}
CUL_HM_PushCmdStack($hash, $cmd) if($cmd);
} elsif($cmd eq "devicepair") { ##################################### } elsif($cmd eq "devicepair") { #####################################
return "$a[2] is not a button number" if($a[2] !~ m/^\d$/ || $a[2] < 1); return "$a[2] is not a button number" if($a[2] !~ m/^\d$/ || $a[2] < 1);
@@ -992,36 +1038,36 @@ CUL_HM_Set($@)
my $dst2 = $dhash->{DEF}; my $dst2 = $dhash->{DEF};
my $chn2 = "01"; my $chn2 = "01";
if(length($dst) == 8) { # shadow switch device for multi-channel switch if(length($dst2) == 8) { # shadow switch device for multi-channel switch
$chn2 = substr($dst2, 6, 2); $chn2 = substr($dst2, 6, 2);
$dst2 = substr($dst2, 0, 6); $dst2 = substr($dst2, 0, 6);
$dhash = $modules{CUL_HM}{defptr}{$dst2};
} }
# First the remote # First the remote (one loop for on, one for off)
for(my $i = 1; $i <= 2; $i++) { for(my $i = 1; $i <= 2; $i++) {
my $b = ($i==1 ? $b1 : $b2); my $b = ($i==1 ? $b1 : $b2);
CUL_HM_PushCmdStack($hash, "++A001${id}${dst}${b}03");
# PEER_ADD, START, WRITE_INDEX, END
CUL_HM_PushCmdStack($hash, "++A001${id}${dst}${b}01${dst2}${chn2}00"); CUL_HM_PushCmdStack($hash, "++A001${id}${dst}${b}01${dst2}${chn2}00");
CUL_HM_PushCmdStack($hash, "++A001${id}${dst}${b}05${dst2}${chn2}04"); CUL_HM_PushCmdStack($hash, "++A001${id}${dst}${b}05${dst2}${chn2}04");
CUL_HM_PushCmdStack($hash, "++A001${id}${dst}${b}080100"); CUL_HM_PushCmdStack($hash, "++A001${id}${dst}${b}080100");
CUL_HM_PushCmdStack($hash, "++A001${id}${dst}${b}06"); CUL_HM_PushCmdStack($hash, "++A001${id}${dst}${b}06");
CUL_HM_PushCmdStack($hash, "++A001${id}${dst}${b}04${dst2}${chn2}04");
} }
# Now the switch. # Now the switch: PEER_ADD, PARAM_REQ:on, PARAM_REQ:off
$sndcmd = "++A001${id}${dst2}${chn2}01${dst}${b2}${b1}"; CUL_HM_PushCmdStack($dhash, "++A001${id}${dst2}${chn2}01${dst}${b2}${b1}");
CUL_HM_PushCmdStack($dhash, "++A001${id}${dst2}${chn2}04${dst}${b1}03"); CUL_HM_PushCmdStack($dhash, "++A001${id}${dst2}${chn2}04${dst}${b1}03");
CUL_HM_PushCmdStack($dhash, "++A001${id}${dst2}${chn2}04${dst}${b2}03"); CUL_HM_PushCmdStack($dhash, "++A001${id}${dst2}${chn2}04${dst}${b2}03");
$hash = $dhash; # Exchange the hash, as the switch is always alive. $hash = $dhash; # Exchange the hash, as the switch is always alive.
$isSender=0; # the other device is a switch. ahem.
} }
if($state) { $hash->{STATE} = $state if($state);
$hash->{STATE} = $state;
$hash->{cmdSent} = $state; CUL_HM_ProcessCmdStack($hash) if(!$isSender);
} return "";
CUL_HM_SendCmd($hash, $sndcmd, 0, 1) if($sndcmd);
return $ret;
} }
@@ -1057,22 +1103,26 @@ CUL_HM_Pair(@)
my $model = substr($p, 2, 4); my $model = substr($p, 2, 4);
my $dp = $culHmDevProps{$stc}; my $dp = $culHmDevProps{$stc};
$attr{$name}{model} = $culHmModel{$model}? $culHmModel{$model} :"unknown"; $model = $culHmModel{$model} ? $culHmModel{$model} :"unknown";
my $serNo = pack('H*', substr($p, 6, 20));
my $devInfo = substr($p,28);
$attr{$name}{model} = $model;
$attr{$name}{subType} = $dp ? $dp->{st} : "unknown"; $attr{$name}{subType} = $dp ? $dp->{st} : "unknown";
$attr{$name}{hmClass} = $dp ? $dp->{cl} : "unknown"; $attr{$name}{hmClass} = $dp ? $dp->{cl} : "unknown";
$attr{$name}{serialNr} = pack('H*', substr($p, 6, 20)); $attr{$name}{serialNr} = $serNo;
$attr{$name}{firmware} = sprintf("%d.%d", hex(substr($p,0,1)),hex(substr($p,1,1))); $attr{$name}{firmware} =
$attr{$name}{devInfo} = substr($p,28); sprintf("%d.%d", hex(substr($p,0,1)),hex(substr($p,1,1)));
$attr{$name}{devInfo} = $devInfo;
my $stn = $attr{$name}{subType}; # subTypeName my $stn = $attr{$name}{subType}; # subTypeName
my $stt = $stn eq "unknown" ? "subType unknown" : "is a $stn"; my $stt = $stn eq "unknown" ? "subType unknown" : "is a $stn";
Log GetLogLevel($name,2), Log GetLogLevel($name,2),
"CUL_HM pair: $name $stt, model $attr{$name}{model} ". "CUL_HM pair: $name $stt, model $model serialNr $serNo";
"serialNr $attr{$name}{serialNr}";
# Create shadow device for multi-channel # Create shadow device for multi-channel
if($stn eq "switch" && if($stn eq "switch" &&
$attr{$name}{devInfo} =~ m,(..)(..)(..), ) { $devInfo =~ m,(..)(..)(..), ) {
my ($b1, $b2, $b3) = (hex($1), hex($2), $3); my ($b1, $b2, $b3) = (hex($1), hex($2), $3);
for(my $i = $b2+1; $i<=$b1; $i++) { for(my $i = $b2+1; $i<=$b1; $i++) {
my $nSrc = sprintf("%s%02X", $src, $i); my $nSrc = sprintf("%s%02X", $src, $i);
@@ -1085,7 +1135,8 @@ CUL_HM_Pair(@)
# Abort if we are not authorized # Abort if we are not authorized
if($dst eq "000000") { if($dst eq "000000") {
if(!$iohash->{hmPair}) { if(!$iohash->{hmPair} &&
(!$iohash->{hmPairSerial} || $iohash->{hmPairSerial} ne $serNo)) {
Log GetLogLevel($name,2), Log GetLogLevel($name,2),
$iohash->{NAME}. " pairing (hmPairForSec) not enabled"; $iohash->{NAME}. " pairing (hmPairForSec) not enabled";
return ""; return "";
@@ -1099,25 +1150,11 @@ CUL_HM_Pair(@)
} }
# delete($hash->{cmdStack}); # Why? Disables 4Dis text commands my $chn = 0;
if($stn ne "remote") { #$chn = hex($2) if($devInfo =~ m,(..)(..), && $stn eq "remote");
CUL_HM_pushConfig($hash, $id, $src, 0, 0, "0201$idstr"); CUL_HM_pushConfig($hash, $id, $src, $chn, 0, "0201$idstr");
CUL_HM_SendCmd($hash, shift @{$hash->{cmdStack}}, 1, 1); CUL_HM_SendCmd($hash, shift @{$hash->{cmdStack}}, 1, 1);
} else {
# remotes are AES per default, so the method above does not work. the
# following works at least for the 4Dis, not for the HM-RC-4
my ($fwvers, $mystc, $mymodel, $mybtn, $myserNr) =
("10", "10", "0011", "010100", unpack('H*',"FHEM$id"));
CUL_HM_SendCmd($hash,
$msgcnt."A000".$id.$src.$fwvers.$mymodel.$myserNr.$mystc.$mybtn, 1, 1);
CUL_HM_SendCmd($hash, "++A001$id${src}0105${src}0104", 1, 1);
CUL_HM_PushCmdStack($hash, "++A001$id${src}01080201$idstr");
CUL_HM_PushCmdStack($hash, "++A001$id${src}0106");
}
return ""; return "";
} }
@@ -1302,6 +1339,7 @@ my %culHmBits = (
LONG => '00,02,$val=(hex($val)&0x40)?1:0', LONG => '00,02,$val=(hex($val)&0x40)?1:0',
LOWBAT => '00,02,$val=(hex($val)&0x80)?1:0', LOWBAT => '00,02,$val=(hex($val)&0x80)?1:0',
COUNTER => "02,02", } }, COUNTER => "02,02", } },
"A112" => { txt => "HAVE_DATA"},
); );
sub sub

View File

@@ -534,7 +534,7 @@ A line ending with \ will be concatenated with the next one, so long lines
<a name="inform"></a> <a name="inform"></a>
<h3>inform</h3> <h3>inform</h3>
<ul> <ul>
<code>inform [on|off|timer|raw]</code> <br> <code>inform {on|off|timer|raw} [regexp]</code> <br>
<br> <br>
If set to on, and a device state changes, send a notification to the current 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 client. This command can be used by other programs/modules to receive a
@@ -2755,6 +2755,7 @@ A line ending with \ will be concatenated with the next one, so long lines
<li>toggle - toggle the switch.</li> <li>toggle - toggle the switch.</li>
</ul></li> </ul></li>
<br> <br>
<li>dimmer, blindActuator <li>dimmer, blindActuator
<ul> <ul>
<li>0 - 100 with a resolution of 0.5:<br> <li>0 - 100 with a resolution of 0.5:<br>
@@ -2763,6 +2764,15 @@ A line ending with \ will be concatenated with the next one, so long lines
this corresponds to 100 or 0 %. this corresponds to 100 or 0 %.
</ul></li> </ul></li>
<br> <br>
<li>remotes
<ul>
devicepair <btnNumber> hmDevice<br>
Pair a remote directly with a switch. The command for the switch is
sent out directly, the remote must be set into learning mode first.
</ul>
<br>
<li>4Dis (HM-PB-4DIS-WM) <li>4Dis (HM-PB-4DIS-WM)
<ul> <ul>
<li>text &lt;btn_no&gt; [on|off] &lt;text1&gt; &lt;text2&gt;<br> <li>text &lt;btn_no&gt; [on|off] &lt;text1&gt; &lt;text2&gt;<br>
@@ -2776,12 +2786,14 @@ A line ending with \ will be concatenated with the next one, so long lines
</ul> </ul>
</ul></li> </ul></li>
<br> <br>
<li>Climate-Control (HM-CC-TC) <li>Climate-Control (HM-CC-TC)
<ul> <ul>
<li>day-temp &lt;tmp&gt;<br> <li>day-temp &lt;tmp&gt;<br>
night-temp &lt;tmp&gt;<br> night-temp &lt;tmp&gt;<br>
party-temp &lt;tmp&gt;<br> party-temp &lt;tmp&gt;<br>
Set the day or night temperature. Temp must be between 6 and 30 desired-temp &lt;tmp&gt;<br>
Set different temperatures. Temp must be between 6 and 30
Celsius, and precision is half a degree. Celsius, and precision is half a degree.
<li>tempListSat HH:MM temp ... 24:00 temp<br> <li>tempListSat HH:MM temp ... 24:00 temp<br>
tempListSun HH:MM temp ... 24:00 temp<br> tempListSun HH:MM temp ... 24:00 temp<br>

30
fhem.pl
View File

@@ -1327,7 +1327,6 @@ PrintHash($$)
my ($str,$sstr) = ("",""); my ($str,$sstr) = ("","");
foreach my $c (sort keys %{$h}) { foreach my $c (sort keys %{$h}) {
if(ref($h->{$c})) { if(ref($h->{$c})) {
if(ref($h->{$c}) eq "HASH") { if(ref($h->{$c}) eq "HASH") {
if(defined($h->{$c}{TIME}) && defined($h->{$c}{VAL})) { if(defined($h->{$c}{TIME}) && defined($h->{$c}{VAL})) {
@@ -1335,11 +1334,17 @@ PrintHash($$)
$lev," ", $h->{$c}{TIME},$c,$h->{$c}{VAL}); $lev," ", $h->{$c}{TIME},$c,$h->{$c}{VAL});
} elsif($c eq "IODev" || $c eq "HASH") { } elsif($c eq "IODev" || $c eq "HASH") {
$str .= sprintf("%*s %-10s %s\n", $lev," ",$c, $h->{$c}{NAME}); $str .= sprintf("%*s %-10s %s\n", $lev," ",$c, $h->{$c}{NAME});
} else { } else {
$sstr .= sprintf("%*s %s:\n", $sstr .= sprintf("%*s %s:\n",
$lev, " ", uc(substr($c,0,1)).lc(substr($c,1))); $lev, " ", uc(substr($c,0,1)).lc(substr($c,1)));
$sstr .= PrintHash($h->{$c}, $lev+2); $sstr .= PrintHash($h->{$c}, $lev+2);
} }
} elsif(ref($h->{$c}) eq "ARRAY") {
$sstr .= sprintf("%*s %s:\n", $lev, " ", $c);
foreach my $v (@{$h->{$c}}) {
$sstr .= sprintf("%*s %s\n", $lev+2, " ", $v);
}
} }
} else { } else {
$str .= sprintf("%*s %-10s %s\n", $lev," ",$c, $h->{$c}); $str .= sprintf("%*s %-10s %s\n", $lev," ",$c, $h->{$c});
@@ -1651,7 +1656,8 @@ CommandAttr($$)
} }
} }
if(!$found) { if(!$found) {
push @rets, "Unknown attribute $a[1], use attr global userattr $a[1]"; push @rets, "Unknown attribute $a[1], ".
"choose one of $list or use attr global userattr $a[1]";
next; next;
} }
} }
@@ -1787,15 +1793,21 @@ CommandInform($$)
return; return;
} }
$param = lc($param); return "Usage: inform {on|timer|raw|off} [regexp]"
if($param !~ m/^(on|off|raw|timer)/);
return "Usage: inform {on|timer|raw|off}"
if($param !~ m/^(on|off|raw|timer)$/);
if($param =~ m/off/) {
delete($client{$cl}{inform}); delete($client{$cl}{inform});
} else { delete($client{$cl}{informRegexp});
$client{$cl}{inform} = $param; if($param !~ m/^off/) {
my ($type, $regexp) = split(" ", $param);
$client{$cl}{inform} = $type;
if($regexp) {
eval { "Hallo" =~ m/$regexp/ };
return "Bad regexp: $@" if($@);
$client{$cl}{informRegexp} = $regexp;
}
Log 4, "Setting inform to $param"; Log 4, "Setting inform to $param";
} }
return undef; return undef;
@@ -2090,8 +2102,10 @@ DoTrigger($$)
my ($seconds, $microseconds) = gettimeofday(); my ($seconds, $microseconds) = gettimeofday();
$tn .= sprintf(".%03d", $microseconds/1000); $tn .= sprintf(".%03d", $microseconds/1000);
} }
my $re = $client{$c}{informRegexp};
for(my $i = 0; $i < $max; $i++) { for(my $i = 0; $i < $max; $i++) {
my $state = $defs{$dev}{CHANGED}[$i]; my $state = $defs{$dev}{CHANGED}[$i];
next if($re && $state !~ m/$re/);
syswrite($client{$c}{fd}, syswrite($client{$c}{fd},
($client{$c}{inform} eq "timer" ? "$tn " : "") . ($client{$c}{inform} eq "timer" ? "$tn " : "") .
"$defs{$dev}{TYPE} $dev $state\n"); "$defs{$dev}{TYPE} $dev $state\n");