From e4aa75335ea9f3f0bb1f77c5484263f140e7ae0e Mon Sep 17 00:00:00 2001 From: rudolfkoenig <> Date: Tue, 9 Aug 2011 17:44:33 +0000 Subject: [PATCH] EnOcean updates git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@975 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- FHEM/00_TCM.pm | 33 ++++--- FHEM/10_EnOcean.pm | 201 +++++++++++++++++++++++-------------------- docs/commandref.html | 76 ++++++++-------- 3 files changed, 170 insertions(+), 140 deletions(-) diff --git a/FHEM/00_TCM.pm b/FHEM/00_TCM.pm index c23de29a5..da6487c3c 100755 --- a/FHEM/00_TCM.pm +++ b/FHEM/00_TCM.pm @@ -46,7 +46,7 @@ TCM_Initialize($) $hash->{ReadyFn} = "TCM_Ready"; $hash->{Clients} = ":EnOcean:"; my %matchList= ( - "1:EnOcean" => "^EnOcean:0B", + "1:EnOcean" => "^EnOcean:", ); $hash->{MatchList} = \%matchList; @@ -210,10 +210,23 @@ TCM_Read($) Log $ll2, "$name: wrong checksum: got $crc, computed $mycrc" ; return; } - if($net =~ m/^0B/) { # Receive Radio Telegram (RRT) - Dispatch($hash, "EnOcean:$net", undef); + + # Receive Radio Telegram (RRT) + if($net =~ m/^0B(..)(........)(........)(..)/) { + my ($org, $d1,$id,$status) = ($1, $2); + + # Re-translate the ORG to RadioORG / TCM310 equivalent + my %orgmap = ("05"=>"F6", "06"=>"D5", "07"=>"A5", ); + if($orgmap{$org}) { + $org = $orgmap{$org}; + } else { + Log 1, "TCM120: unknown ORG mapping for $org"; + } + Dispatch($hash, "EnOcean:$org:$d1:$id:$status", undef); + } else { # Receive Message Telegram (RMT) TCM_Parse120($hash, $net, 0); + } @@ -254,18 +267,14 @@ TCM_Read($) } if($t eq "01") { # Radio - my %orgmap = ("F6"=>"05", "D5"=>"06", "A5"=>"07", ); $mdata =~ m/^(..)(.*)(........)(..)$/; - my $org = $orgmap{$1}; - Log 1, "TCM310: unknown ORG mapping for $1" if(!$org); - my $net = sprintf("0B%s%s%s%s%s", - $org ? $org:"00", $2, "0"x(8-length($2)), $3, $4); - $odata =~ m/^(..)(........)(..)(..)$/; - my %addvals = (SubTelNum => $1, DestinationID => $2, - RSSI => $3, SecurityLevel => $4,); + my ($org, $d1, $id, $status) = ($1,$2,$3,$4); + + my %addvals = (SubTelNum => hex($1), DestinationID => $2, + RSSI => hex($3), SecurityLevel => hex($4),); $hash->{RSSI} = $3; - Dispatch($hash, "EnOcean:$net", \%addvals); + Dispatch($hash, "EnOcean:$org:$d1:$id:$status:$odata", \%addvals); } else { Log $ll2, "$name: unknown packet type $t: $data" ; diff --git a/FHEM/10_EnOcean.pm b/FHEM/10_EnOcean.pm index c4bcbdc50..e9ac213a0 100755 --- a/FHEM/10_EnOcean.pm +++ b/FHEM/10_EnOcean.pm @@ -7,27 +7,34 @@ use warnings; sub EnOcean_Define($$); sub EnOcean_Initialize($); -sub EnOcean_Pair(@); sub EnOcean_Parse($$); -sub EnOcean_PushCmdStack($$); -sub EnOcean_SendCmd($$$$); sub EnOcean_Set($@); -sub EnOcean_convTemp($); + +# TODO +# Send120 +# Send310 +# Test windowHandle sub EnOcean_Initialize($) { my ($hash) = @_; - $hash->{Match} = "^EnOcean:0B"; + $hash->{Match} = "^EnOcean:"; $hash->{DefFn} = "EnOcean_Define"; $hash->{ParseFn} = "EnOcean_Parse"; $hash->{SetFn} = "EnOcean_Set"; $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 " . "showtime:1,0 loglevel:0,1,2,3,4,5,6 model " . - "subType:remote,sensor,modem,windowHandle,contact,SR04PT "; + "subType:switch,contact,sensor,windowHandle,SR04"; } +my %rorgname = ("F6"=>"switch", # RPS + "D5"=>"contact", # 1BS + "A5"=>"sensor", # 4BS + ); +my @ptm200btn = ("AI", "A0", "BI", "B0", "CI", "C0", "DI", "D0"); +my %ptm200btn; ############################# sub @@ -44,35 +51,37 @@ EnOcean_Define($$) AssignIoPort($hash); # Help FHEMWEB split up devices $attr{$name}{subType} = $1 if($name =~ m/EnO_(.*)_$a[2]/); + + for(my $i=0; $i<@ptm200btn;$i++) { + $ptm200btn{$ptm200btn[$i]} = "$i:30"; + } + $ptm200btn{released} = "0:20"; return undef; } -my %sets = ( Btn0=>"10:30", Btn1=>"30:30", Btn2=>"20:30", Btn2=>"70:30", - "Btn0,Btn2"=>"15:30", "Btn1,Btn2"=>"35:30", - "Btn0,Btn3"=>"17:30", "Btn1,Btn3"=>"37:30", - "released"=>"00:20" ); - ############################# # Simulate a PTM sub EnOcean_Set($@) { my ($hash, @a) = @_; - return "no set value specified" if(@a != 2); + return "no set value specified" if(@a < 2); + return "there a no set commands with argument" if(@a > 2); my $cmd = $a[1]; my $arg = $a[2]; - my $cmdhash = $sets{$cmd}; - return "Unknown argument $cmd, choose one of " . join(" ", sort keys %sets) - if(!defined($cmdhash)); + my $cmdhash = $ptm200btn{$cmd}; + return "Unknown argument $cmd, choose one of " . + join(" ", sort keys %ptm200btn) if(!defined($cmdhash)); my $name = $hash->{NAME}; my $ll2 = GetLogLevel($name, 2); Log $ll2, "EnOcean: set $name $cmd"; - my ($d1, $status) = split(":", $cmdhash, 2); - IOWrite($hash, "", sprintf("6B05%s000000%s%s", $d1, $hash->{DEF}, $status)); + my ($db_3, $status) = split(":", $cmdhash, 2); + IOWrite($hash, "", + sprintf("6B05%s000000%s%s", ($db_3<<5), $hash->{DEF}, $status)); my $tn = TimeNow(); $hash->{CHANGED}[0] = $cmd; @@ -87,117 +96,119 @@ sub EnOcean_Parse($$) { my ($iohash, $msg) = @_; - my %ot = ("05"=>"remote", "06"=>"sensor", "07"=>"sensor", - "08"=>"remote", "0A"=>"modem", "0B"=>"modem", ); + my (undef,$rorg,$data,$id,$status,$odata) = split(":", $msg); - $msg =~ m/^EnOcean:0B(..)(........)(........)(..)/; - my ($org,$data,$id,$status) = ($1,$2,$3,$4,$5); - - my $ot = $ot{$org}; - if(!$ot) { - Log 2, "Unknown EnOcean ORG: $org received from $id"; + my $rorgname = $rorgname{$rorg}; + if(!$rorgname) { + Log 2, "Unknown EnOcean RORG ($rorg) received from $id"; return ""; } - $id = ($id & 0xffff) if($org eq "0A"); - $id = (($id & 0xffff0000)>>16) if($org eq "0B"); - my $hash = $modules{EnOcean}{defptr}{$id}; if(!$hash) { Log 3, "EnOcean Unknown device with ID $id, please define it"; - return "UNDEFINED EnO_${ot}_$id EnOcean $id"; + return "UNDEFINED EnO_${rorgname}_$id EnOcean $id"; } my $name = $hash->{NAME}; - my $st = AttrVal($name, "subType", ""); my $ll4 = GetLogLevel($name, 4); - Log $ll4, "EnOcean: ORG:$org, DATA:$data, ID:$id, STATUS:$status"; + Log $ll4, "$name: ORG:$rorg DATA:$data ID:$id STATUS:$status"; + my @event; + #push @event, "1:rp_counter:".(hex($status)&0xf); - push @event, "0:rp_counter:".(hex($status)&0xf); + my $dl = length($data); + my $db_3 = hex substr($data,0,2); + my $db_2 = hex substr($data,2,2) if($dl > 2); + my $db_1 = hex substr($data,4,2) if($dl > 4); + my $db_0 = hex substr($data,6,2) if($dl > 6); + my $st = AttrVal($name, "subType", ""); - my $d1 = hex substr($data,0,2); ################################# - if($org eq "05") { # PTM remote. Queer reporting methods. + # RPS: PTM200 based switch/remote or a windowHandle + if($rorg eq "F6") { my $nu = ((hex($status)&0x10)>>4); - push @event, "0:T21:".((hex($status)&0x20)>>5); - push @event, "0:NU:$nu"; + #push @event, "1:T21:".((hex($status)&0x20)>>5); + #push @event, "1:NU:$nu"; if($nu) { - $msg = sprintf "Btn%d", ($d1&0xe0)>>5; - $msg .= sprintf ",Btn%d", ($d1&0x0e)>>1 if($d1 & 1); - $msg .= ($d1&0x10) ? " pressed" : " released"; + + $msg = $ptm200btn[($db_3&0xe0)>>5]; + $msg .= ",".$ptm200btn[($db_3&0x0e)>>1] if($db_3 & 1); } else { - #confusing for normal use - #my $nbu = (($d1&0xe0)>>5); - #$msg = sprintf "Buttons %d", $nbu ? ($nbu+1) : 0; - $msg = "buttons " . ($d1&0x10 ? "pressed" : "released"); - if($st eq "windowHandle") { - $msg = "closed" if($d1 == 0xF0); - $msg = "open" if($d1 == 0xE0); - $msg = "tilted" if($d1 == 0xD0); - $msg = "open from tilted" if($d1 == 0xC0); + # Couldnt test + if($db_3 == 112) { # KeyCard + $msg = "keycard inserted"; + + # Only the windowHandle is setting these bits when nu=0 + } elsif($db_3 & 0xC0) { + $msg = "closed" if($db_3 == 0xF0); + $msg = "open" if($db_3 == 0xE0); + $msg = "tilted" if($db_3 == 0xD0); + $msg = "open from tilted" if($db_3 == 0xC0); + + } else { + if($st eq "keycard") { + $msg = "keycard removed"; + + } else { + $msg = "buttons ". (($db_3&0x10) ? "pressed" : "released"); + + } + } } - push @event, "1:state:$msg"; + push @event, "3:state:$msg"; ################################# - } elsif($org eq "06") { - if($st eq "contact") { - push @event, "1:state:" . ($d1 == 9 ? "closed" : "open"); + # 1BS. Only contact is defined in the EEP2.1 for 1BS + } elsif($rorg eq "D5") { + push @event, "3:state:" . ($db_3&1 ? "closed" : "open"); + push @event, "3:learnBtn:on" if(!($db_3&0x8)); + + ################################# + } elsif($rorg eq "A5") { + if($st eq "SR04") { + my ($fspeed, $temp, $present); + $fspeed = 3; + $fspeed = 2 if($db_3 >= 145); + $fspeed = 1 if($db_3 >= 165); + $fspeed = 0 if($db_3 >= 190); + $fspeed = "Auto" if($db_3 >= 210); + $temp = sprintf("%0.1f", $db_1/6.375); # 40..0 + $present= $db_0&0x1 ? "no" : "yes"; + + push @event, "3:state:temperature $temp"; + push @event, "3:set_point:$db_3"; + push @event, "3:fan:$fspeed"; + push @event, "3:present:$present" if($present eq "yes"); + push @event, "3:learnBtn:on" if(!($db_0&0x8)); + push @event, "3:T:$temp SP: $db_3 F: $fspeed P: $present"; } else { - push @event, "1:state:sensor:$d1"; - push @event, "1:sensor:$d1"; + push @event, "3:state:$db_3"; + push @event, "3:sensor1:$db_3"; + push @event, "3:sensor2:$db_2"; + push @event, "3:sensor3:$db_1"; + push @event, "3:D3:".(($db_0&0x8)?1:0); + push @event, "3:D2:".(($db_0&0x4)?1:0); + push @event, "3:D1:".(($db_0&0x2)?1:0); + push @event, "3:D0:".(($db_0&0x1)?1:0); + } - ################################# - } elsif($org eq "07") { - my $d2 = hex substr($data,2,2); - my $d3 = hex substr($data,4,2); - my $d4 = hex substr($data,6,2); - if($st eq "SR04PT") { - push @event, "1:state:alive"; - push @event, "1:present:".(($d4&0x1)?"No":"Yes"); - push @event, "1:desired:$d1"; - } else { - push @event, "1:state:$d1"; - push @event, "1:sensor1:$d1"; - push @event, "1:sensor2:$d2"; - push @event, "1:sensor3:$d3"; - push @event, "1:D3:".(($d4&0x8)?1:0); - push @event, "1:D2:".(($d4&0x4)?1:0); - push @event, "1:D1:".(($d4&0x2)?1:0); - push @event, "1:D0:".(($d4&0x1)?1:0); - } - - ################################# - } elsif($org eq "08") { # CTM remote. - # Dont understand the SR bit - $msg = sprintf "Btn%d", ($d1&0xe0)>>5; - $msg .= ($d1&0x10) ? " pressed" : " released"; - push @event, "1:state:$msg"; - - ################################# - } elsif($org eq "0A") { - push @event, "1:state:Modem:".substr($msg, 12, 6); - - ################################# - } elsif($org eq "0B") { - push @event, "1:state:Modem:ACK"; - - } elsif($org eq "00") { } my $tn = TimeNow(); my @changed; for(my $i = 0; $i < int(@event); $i++) { - my ($dochanged, $vn, $vv) = split(":", $event[$i], 3); - if($dochanged) { + my ($flag, $vn, $vv) = split(":", $event[$i], 3); + + if($flag & 2) { if($vn eq "state") { $hash->{STATE} = $vv; push @changed, $vv; @@ -208,8 +219,10 @@ EnOcean_Parse($$) } } - $hash->{READINGS}{$vn}{TIME} = TimeNow(); - $hash->{READINGS}{$vn}{VAL} = $vv; + if($flag & 1) { + $hash->{READINGS}{$vn}{TIME} = TimeNow(); + $hash->{READINGS}{$vn}{VAL} = $vv; + } } $hash->{CHANGED} = \@changed; diff --git a/docs/commandref.html b/docs/commandref.html index c6e77546a..23ca9c5f9 100644 --- a/docs/commandref.html +++ b/docs/commandref.html @@ -2742,17 +2742,6 @@ A line ending with \ will be concatenated with the next one, so long lines Define an EnOcean device, connected via a TCM. The <ID> parameter is an 8 digit hex number. For remotes and sensors the autocreate module may help you.
- In order to control devices, you cannot reuse the ID's of other devices - (like remotes), instead you have to create your own, which must be in the - allowed ID-Range of the underlying IO device. For this first query the - TCM with the "get <tcm> idbase" command. You can use - up to 128 ID's starting with the base shown there. If you are using an - ID outside of the allowed range, you'll see an ERR_ID_RANGE message in the - fhem log.
- - For each ID there is the possibility to use 8 different commands, so - in fact you can control 8*128/2=512 switches.

- Example: