2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-13 05:06:35 +00:00

CUL_HM switch and remote support

git-svn-id: https://svn.fhem.de/fhem/trunk@756 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig 2010-11-14 14:49:23 +00:00
parent cf66f01387
commit 6ff0de2a79
4 changed files with 256 additions and 114 deletions

View File

@ -7,7 +7,7 @@
- bugfix: S300TH sanity check won't allow negative temperatures.
- feature: decode CUL uptime
- feature: USB doc changes, FHZ initFS20_02/stopHMS parameters by Andreas.
- feature: CUL_HM (experimental) for HomeMatic devices.
- feature: CUL_HM for some HomeMatic devices.
- bugfix: HTML-Syntax check of the pgm2 output and documents (*.html)
- feature: added date alias for FHT80b (Boris)

View File

@ -10,22 +10,22 @@ sub CUL_HM_Id($);
sub CUL_HM_Initialize($);
sub CUL_HM_Pair(@);
sub CUL_HM_Parse($$);
sub CUL_HM_SendCmd($$$);
sub CUL_HM_SendCmd($$$$);
sub CUL_HM_Set($@);
my %culHmSubType=(
"10" => "switch",
"20" => "dimmer",
"30" => "blindActuator",
"40" => "remote",
"41" => "sensor",
"42" => "swi",
"43" => "pushButton",
"80" => "threeStateSensor",
"81" => "motionDetector",
"C0" => "keyMatic",
"C1" => "winMatic",
"CD" => "smokeDetector",
my %culHmDevProps=(
"10" => { st => "switch", cl => "receiver" },
"20" => { st => "dimmer", cl => "receiver" },
"30" => { st => "blindActuator", cl => "receiver" },
"40" => { st => "remote", cl => "sender" },
"41" => { st => "sensor", cl => "sender" },
"42" => { st => "swi", cl => "sender" },
"43" => { st => "pushButton", cl => "sender" },
"80" => { st => "threeStateSensor",cl => "sender" },
"81" => { st => "motionDetector", cl => "sender" },
"C0" => { st => "keyMatic", cl => "sender" },
"C1" => { st => "winMatic", cl => "receiver" },
"CD" => { st => "smokeDetector", cl => "sender" },
);
my %culHmModel=(
@ -121,7 +121,8 @@ CUL_HM_Initialize($)
"showtime:1,0 loglevel:0,1,2,3,4,5,6 model " .
"subType:switch,dimmer,blindActuator,remote,sensor,".
"swi,pushButton,threeStateSensor,motionDetector,".
"keyMatic,winMatic,smokeDetector";
"keyMatic,winMatic,smokeDetector " .
"hmClass:receiver,sender";
}
@ -136,48 +137,78 @@ CUL_HM_Define($$)
if(!(int(@a)==3 || int(@a)==4) || $a[2] !~ m/^[A-F0-9]{6}$/i);
$modules{CUL_HM}{defptr}{uc($a[2])} = $hash;
$hash->{STATE} = "Defined";
if(int(@a) == 4) {
CUL_HM_Parse($hash, $a[3]);
$hash->{DEF} = $a[2];
}
$hash->{STATE} = "???";
AssignIoPort($hash);
if(int(@a) == 4) {
$hash->{DEF} = $a[2];
CUL_HM_Parse($hash, $a[3]);
}
return undef;
}
#############################
sub
CUL_HM_Parse($$)
{
my ($hash, $msg) = @_;
my $id = CUL_HM_Id($hash);
# Msg format: Allnnccttssssssddddddpp...
$msg =~ m/A(..)(..)(..)(..)(......)(......)(.*)/;
my @msgarr = ($1,$2,$3,$4,$5,$6,$7);
my ($len,$msgcnt,$channel,$msgtype,$src,$dst,$p) = @msgarr;
Log 1, "CUL_HM L:$len N:$msgcnt C:$channel T:$msgtype SRC:$src DST:$dst $p";
my $def = $modules{CUL_HM}{defptr}{$src};
my $shash = $modules{CUL_HM}{defptr}{$src};
if(!$def) {
Log 3, "CUL_HM Unknown device $src, please define it";
return "UNDEFINED CUL_HM_$src CUL_HM $src $msg";
my $dhash = $modules{CUL_HM}{defptr}{$dst};
my $dname = $dhash ? $dhash->{NAME} : "unknown";
$dname = "broadcast" if($dst eq "000000");
$dname = $hash->{NAME} if($dst eq $id);
if(!$shash) {
my $sname = "CUL_HM_$src";
if("$channel$msgtype" eq "8400" && $len eq "1A") {
my $model = substr($p, 2, 4);
if($culHmModel{$model}) {
$sname = $culHmModel{$model} . "_" . $src;
$sname =~ s/-/_/g;
}
}
Log 3, "CUL_HM Unknown device $sname, please define it";
return "UNDEFINED $sname CUL_HM $src $msg";
}
my $name = $def->{NAME};
my $name = $shash->{NAME};
my @event;
my $isack;
if($shash->{ackWaiting}) {
delete($shash->{ackWaiting});
delete($shash->{ackCmdSent});
RemoveInternalTimer($shash);
$isack = 1;
}
my $st = AttrVal($name, "subType", undef);
if("$channel$msgtype" =~ m/(8400|A000|A001|8002)/) { # Pairing-Request
push @event, CUL_HM_Pair($name, $def, @msgarr);
if("$channel$msgtype" =~ m/(8400|A000|A001)/) { # Pairing-Request
push @event, CUL_HM_Pair($name, $shash, @msgarr);
} elsif(!$st) { # Will trigger unknown
;
} elsif($st eq "switch") {
} elsif("$channel$msgtype" eq "8002" &&
$shash->{pairingStep} &&
$len eq "0A") { # Ack Pair
push @event, CUL_HM_Pair($name, $shash, @msgarr);
if($p =~ m/^0601(..)00$/) {
push @event, "state:" .
($1 eq "C8" ? "on" : ($1 eq "00" ? "off" : "unknown $1"));
} elsif($st eq "switch") { ############################################
if($p =~ m/^0.01(..)00/) {
my $val = ($1 eq "C8" ? "on" : ($1 eq "00" ? "off" : "unknown $1"));
push @event, "ackedCmd:$val";
push @event, "state:$val" if(!$isack);
} elsif($p =~ m/^0600(..)00$/) {
my $s = ($1 eq "C8" ? "on" : ($1 eq "00" ? "off" : "unknown $1"));
@ -186,7 +217,20 @@ CUL_HM_Parse($$)
}
} elsif($st eq "smokeDetector") {
} elsif($st eq "remote") { ############################################
if("$channel$msgtype" =~ m/A.4./ && $p =~ m/^(..)(..)$/) {
my $btn = int(($1+1)/2);
my $state = $1&1 ? "off" : "on";
my $add = ($dst eq $id) ? "" : " (to $dname)";
push @event, "state:Btn$btn:$state$add";
if($id eq $dst) {
CUL_HM_SendCmd($shash, "++8002".$id.$src."0101". # Send Ack.
($state eq "on"?"C8":"00")."0028", 1, 0);
}
}
} elsif($st eq "smokeDetector") { #####################################
if($p eq "0106C8") {
push @event, "state:on";
@ -208,18 +252,19 @@ CUL_HM_Parse($$)
Log GetLogLevel($name,2), "CUL_HM $name $vn:$vv" if($vn eq "unknown");
if($vn eq "state") {
$def->{STATE} = $vv;
$def->{CHANGED}[$i] = $vv;
$shash->{STATE} = $vv;
$shash->{CHANGED}[$i] = $vv;
} else {
$def->{CHANGED}[$i] = "$vn: $vv";
$shash->{CHANGED}[$i] = "$vn: $vv";
}
$def->{READINGS}{$vn}{TIME} = $tn;
$def->{READINGS}{$vn}{VAL} = $vv;
$shash->{READINGS}{$vn}{TIME} = $tn;
$shash->{READINGS}{$vn}{VAL} = $vv;
}
return $name;
}
@ -238,91 +283,151 @@ CUL_HM_Set($@)
my $cmd = $a[1];
my $id = CUL_HM_Id($hash->{IODev});
my $sndcmd;
my $state;
if($st eq "switch") {
if($cmd eq "on" || $cmd eq "off") {
CUL_HM_SendCmd($hash,
sprintf("++9441%s%s0101%s", $id, $hash->{DEF}, $cmd eq "on"?"C8":"00"),
0);
} elsif($cmd eq "raw") {
CUL_HM_SendCmd($hash,
sprintf("++9441%s%s%s", $id, $hash->{DEF}, $a[2]), 0);
$state = $cmd;
$sndcmd = sprintf("++A440%s%s%02d%02d", $id, $hash->{DEF},
$cmd eq "on" ? 2: 1, $hash->{"${cmd}MsgNr"}++);
}
} else {
return "$name: Unknown subtype, cannot set";
}
return "$name: Unknown device subtype or command" if(!$sndcmd);
CUL_HM_SendCmd($hash, $sndcmd, 0, 1);
if($state) {
$hash->{STATE} = $state;
$hash->{READINGS}{state}{TIME} = TimeNow();
$hash->{READINGS}{state}{VAL} = $state;
}
return "";
}
###################################
# A pairing between rrrrrr (remote) and ssssss (switch) looks like the
# following (nn and ff is the index of the on and off button):
# 1A 66 84 00 ssssss 000000 19 0011 46 4551303 03831363537 10 01 0100
# 1A CF 84 00 rrrrrr ssssss 12 0035 47 4551303 03333333633 40 04 nnff
# 0A D0 80 02 ssssss rrrrrr 00
# 10 D0 A0 01 ssssss rrrrrr nn05 ssssss 0104
# 0A D0 80 02 rrrrrr ssssss 00
# 0E D0 A0 01 ssssss rrrrrr nn07 020201
# 0A D0 80 02 rrrrrr ssssss 00
# 0B D0 A0 01 ssssss rrrrrr nn06
# 0A D0 80 02 rrrrrr ssssss 00
# 10 D0 A0 01 ssssss rrrrrr ff05 ssssss 0104
# 0A D0 80 02 rrrrrr ssssss 00
# 0E D0 A0 01 ssssss rrrrrr ff07 020201
# 0A D0 80 02 rrrrrr ssssss 02
# 0B D0 A0 01 ssssss rrrrrr ff06
# 0A D0 80 02 rrrrrr ssssss 00
sub
CUL_HM_Pair(@)
{
my ($name, $def, $len,$msgcnt,$channel,$msgtype,$src,$dst,$p) = @_;
my $id = CUL_HM_Id($def->{IODev});
my $l4 = GetLogLevel($name,4);
my $ps = $def->{pairingStep} ? $def->{pairingStep} : "";
# Starting pair message with everything we need
if($len eq "1A") {
my $st = substr($p, 26, 2);
my $stc = substr($p, 26, 2); # subTypeCode
my $model = substr($p, 2, 4);
$attr{$name}{subType} = $culHmSubType{$st} ? $culHmSubType{$st} : "unknown";
$attr{$name}{model} = $culHmModel{$model} ? $culHmModel{$model} : "unknown";
my $dp = $culHmDevProps{$stc};
$st = $attr{$name}{subType};
$st = $st eq "unknown" ? "subType unknown" : "is a $st";
Log GetLogLevel($name,2), "CUL_HM $name $st, model $attr{$name}{model}";
$attr{$name}{model} = $culHmModel{$model}? $culHmModel{$model} :"unknown";
$attr{$name}{subType} = $dp ? $dp->{st} : "unknown";
$attr{$name}{hmClass} = $dp ? $dp->{cl} : "unknown";
# Lets answer if we are authorized
my $ion = $def->{IODev}->{NAME};
if(($dst eq "000000" && $attr{$ion} && $attr{$ion}{hm_autopair}) ||
$dst eq $id) {
CUL_HM_SendCmd($def,
"${msgcnt}A000$id${src}EEEEEE48455130313236373039EE000100", 1);
$def->{pairingStep} = 1;
Log $l4, "Pairing Step 1 (Send reply)";
my $stn = $attr{$name}{subType}; # subTypeName
my $stt = $stn eq "unknown" ? "subType unknown" : "is a $stn";
# First message
if(!$ps) {
Log GetLogLevel($name,2), "CUL_HM $name $stt, model $attr{$name}{model}";
if($stn eq "unknown") {
Log GetLogLevel($name,1), "CUL_HM unknown subType $stc, cannot pair";
return "";
}
# Abort if we are not authorized
my $ion = $def->{IODev}->{NAME};
return ""
if(!($dst eq "000000" && AttrVal($ion, "hm_autopair", 1) ||
$dst eq $id));
# Sender pair mode, before btn is pressed
$def->{pairButtons} = substr($p, 30, 4);
return "" if($def->{pairButtons} eq "0000");
my ($mystc, $mymodel, $mybtn, $myunknown);
if(AttrVal($name,"hmClass","") eq "sender") {
$mymodel = "0011"; # Emulate a HM-LC-SW1-PL
$mystc = "10"; # switch
$mybtn = "010100";# No buttons (?)
$myunknown = "46455130303831363537"
} else {
$mymodel = "0060"; # Emulate a HM-PB-4DIS-WM
$mystc = "40"; # remote
$mybtn = "940201";# Buttons 02 (on) & 01 (off)
$myunknown = "48455130303634393136";
}
if($dst eq "000000") {
Log $l4, "CUL_HM Pairing Step 1";
CUL_HM_SendCmd($def,
$msgcnt."A000".$id.$src."19".$mymodel.$myunknown.$mystc.$mybtn, 1, 0);
}
$ps = $def->{pairingStep} = 1;
return "" if(AttrVal($name,"hmClass","") eq "receiver");
}
} elsif($dst ne $id) {
return "";
} elsif($len eq "0A") {
my $ps = $def->{pairingStep};
if($ps) {
$def->{pairingStep} = ++$ps;
Log 1, "Pairing Step $ps (GOT ACK)";
return "" if($ps == 2);
CUL_HM_SendCmd($def, "++A001$id${src}0105${src}0103", 1)
if($ps == 6);
CUL_HM_SendCmd($def, "++A001$id${src}0108011202120312043205B40A01", 1)
if($ps == 7);
CUL_HM_SendCmd($def, "++A001$id${src}01080B140C240D248A00", 1)
if($ps == 8);
CUL_HM_SendCmd($def, "++A001$id${src}0106", 1)
if($ps == 9);
CUL_HM_SendCmd($def, "++A001$id${src}0105${id}0104", 1)
if($ps == 10);
Log $l4, "Pairing finished" if($ps == 11);
}
} elsif($len eq "10") {
CUL_HM_SendCmd($def, "${msgcnt}8002$id${src}80", 1);
my $ps = $def->{pairingStep};
$ps = 2 if(!$ps);
$def->{pairingStep} = ++$ps;
Log $l4, "Pairing Step $ps (SEND ACK)";
CUL_HM_SendCmd($def, "++A001$id${src}0101${src}0100", 10)
if($ps == 4);
}
if(!$ps || $dst ne $id) {
Log 4, "CUL_HM $name pairing step with other device";
return "";
}
# If the partner is a receiver, then we only have to ack every message
# after the first.
if($ps && AttrVal($name,"hmClass","") eq "receiver") {
CUL_HM_SendCmd($def, $msgcnt."8002".$id.$src."00", 1, 0);
return "";
}
# switch emulation (sender is ack only and handled above);
$def->{pairButtons} =~ m/(..)(..)/;
my ($b1, $b2, $cmd) = ($1, $2, "");
$cmd = "++A001$id$src${b1}05$src${b1}04" if($ps == 1);
$cmd = "++A001$id$src${b1}07020201" if($ps == 2);
$cmd = "++A001$id$src${b1}06" if($ps == 3);
$cmd = "++A001$id$src${b2}05$src${b1}04" if($ps == 4);
$cmd = "++A001$id$src${b2}07020201" if($ps == 5);
$cmd = "++A001$id$src${b2}06" if($ps == 6);
if($ps == 7) {
delete($def->{pairingStep});
return "";
}
CUL_HM_SendCmd($def, $cmd, 1, 1);
$def->{pairingStep} = ++$ps;
Log $l4, "CUL_HM Pairing Step $ps ($cmd)";
return "";
}
###################################
sub
CUL_HM_SendCmd($$$)
CUL_HM_SendCmd($$$$)
{
my ($hash, $cmd, $sleep) = @_;
my ($hash, $cmd, $sleep, $waitforack) = @_;
my $io = $hash->{IODev};
my $l4 = GetLogLevel($hash->{NAME},4);
@ -341,17 +446,41 @@ CUL_HM_SendCmd($$$)
}
$io->{HM_CMDNR} = $mn;
$cmd = sprintf("As%02X%02x%s", length($cmd2)/2+1, $mn, $cmd2);
Log $l4, $cmd;
Log $l4, "CUL_HM $cmd";
IOWrite($hash, "", $cmd);
if($waitforack) {
$hash->{ackWaiting} = $cmd;
$hash->{ackCmdSent} = 1;
InternalTimer(gettimeofday()+0.4, "CUL_HM_Resend", $hash, 0);
}
}
###################################
sub
CUL_HM_Resend($)
{
my $hash = shift;
my $name = $hash->{NAME};
if($hash->{ackCmdSent} == 3) {
delete($hash->{ackCmdSent});
delete($hash->{ackWaiting});
$hash->{STATE} = "MISSING ACK";
DoTrigger($name, "MISSING ACK");
return;
}
IOWrite($hash, "", $hash->{ackWaiting});
$hash->{ackCmdSent}++;
DoTrigger($name, "resend nr ".$hash->{ackCmdSent});
InternalTimer(gettimeofday()+0.4, "CUL_HM_Resend", $hash, 0);
}
###################################
sub
CUL_HM_Id($)
{
my ($io) = @_;
return "000000" if(!$io || !$io->{FHTID});
return "123456" if(!$io || !$io->{FHTID});
return "F1" . $io->{FHTID};
}

View File

@ -2123,12 +2123,22 @@ A line ending with \ will be concatenated with the next one, so long lines
<a name="CUL_HM"></a>
<h3>CUL_HM</h3>
<ul>
Support for eQ-3 HomeMatic devices via the CUL. Note: The <a
href="#rfmode">rfmode </a> attribute of at least one attache CUL/CUN device
must be set to HomeMatic. Note: The protocoll used by HomeMatic devices
(BidCos, known as AskSin in the culfw) must be enabled in the culfw firmware.
This is the default for all CUN and for newer CUL (i.e. V3.0 and greater)
devices. <b>Note: This module is experimental!</b>
Support for eQ-3 HomeMatic devices via the CUL.<br>
Prerequisites:
<ul>
<li>The <a href="#rfmode">rfmode </a> attribute of at least one attached
CUL/CUN device must be set to HomeMatic.
</li>
<li>The protocol used by HomeMatic devices (BidCos, known as AskSin
in the culfw) must be enabled in the culfw firmware. This is the
default for all CUN and for newer CUL (i.e. V3.0 and greater) devices
with culfw firmware version 1.38 and newer.
</li>
<li><b>Note</b>: Currently only remote and switch class devices are
supported.
</li>
</ul>
<br><br>
<a name="CUL_HMdefine"></a>
@ -2136,10 +2146,13 @@ A line ending with \ will be concatenated with the next one, so long lines
<ul>
<code>define &lt;name&gt; CUL_HM &lt;6-digit-hex-code&gt;</code>
<br><br>
Best to avoid this command with the <a href="#autocreate">autocreate</a>
Try to avoid this command with the <a href="#autocreate">autocreate</a>
module enabled, and the <a href="#hm_autopair">hm_autopair</a> attribute
set for the corresponding CUL device. Now set the physical device in
pairing mode (Anlernmodus), the rest should happen automatically.
pairing mode (Anlernmodus), the rest should happen automatically.<br>
<br>
If a device was not paired with the CUL, then it won't know its subType,
and therefore won't be able to interpret device messages correctly.
</ul><br>
<a name="CUL_HMset"></a>
@ -2164,13 +2177,13 @@ A line ending with \ will be concatenated with the next one, so long lines
<li><a href="#ignore">ignore</a></li>
<li><a href="#showtime">showtime</a></li>
<li><a href="#loglevel">loglevel</a></li>
<li><a name="#model">name</a><br>
This attribute is set automatically after a successful pairing.
It is not supposed to be set by hand.</li>
<li><a name="#subType">subType</a><br>
This attribute is set automatically after a successful pairing.
It is not supposed to be set by hand. It is necessary to be set
in order to use the set command.</li>
<li><a name="#model">hmClass</a>,
<a name="#model">model</a>,
<a name="#subType">subType</a><br>
These attributes are set automatically after a successful pairing.
They are not supposed to be set by hand, and are necessary in order to
correctly interpret device messages or to be able to send them.</li>
</ul>
<br>
</ul>

View File

@ -162,7 +162,7 @@ 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.116 2010-11-06 19:31:38 rudolfkoenig Exp $';
my $cvsid = '$Id: fhem.pl,v 1.117 2010-11-14 14:49:23 rudolfkoenig Exp $';
my $namedef =
"where <name> is either:\n" .
"- a single device name\n" .
@ -2323,7 +2323,7 @@ sub
AttrVal($$$)
{
my ($d,$n,$default) = @_;
return $attr{$d}{$n} if(defined($attr{$d}) && defined($attr{$d}{$n}));
return $attr{$d}{$n} if($d && defined($attr{$d}) && defined($attr{$d}{$n}));
return $default;
}