From edc0cf2c08dfba2742fbff83e2bee22c40599daf Mon Sep 17 00:00:00 2001 From: klaus-schauer Date: Mon, 10 Jun 2013 11:13:56 +0000 Subject: [PATCH] # teach-in: delete standard readings after teach-in # sub EnOcean_SndRadio: new unified and expanded ESP3 routine, replaced sub EnOcean_A5Cmd and other # sub EnOcean_Parse: new dynamic extraction of the data bytes $db[x] ... $db[0] # profile MD15 and sub EnOcean_MD15Cmd: adjustments to the changed data structure and routines # analysis of the packet type data prepared # ESP3: unicast telegrams now supported # EEP: VLD basic functions implemented (no teach-in) # commandref: further explanations added git-svn-id: https://svn.fhem.de/fhem/trunk@3270 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/10_EnOcean.pm | 1361 +++++++++++++++++++++------------------ 1 file changed, 725 insertions(+), 636 deletions(-) diff --git a/fhem/FHEM/10_EnOcean.pm b/fhem/FHEM/10_EnOcean.pm index a7cf07cb0..9bf2561a2 100755 --- a/fhem/FHEM/10_EnOcean.pm +++ b/fhem/FHEM/10_EnOcean.pm @@ -12,10 +12,15 @@ sub EnOcean_Initialize($); sub EnOcean_Parse($$); sub EnOcean_Set($@); sub EnOcean_MD15Cmd($$$); +sub EnOcean_SndRadio($$$$$$$); +sub EnOcean_ReadingScaled($$$$); +sub EnOcean_TimerSet($); +sub EnOcean_Undef($$); -my %EnO_rorgname = ("F6" => "switch", # org 05, RPS - "D5" =>" contact", # org 06, 1BS - "A5" => "sensor", # org 07, 4BS +my %EnO_rorgname = ("F6" => "switch", # RPS, org 05 + "D5" =>" contact", # 1BS, org 06 + "A5" => "sensor", # 4BS, org 07 + "D2" => "vld", # VLD ); my @EnO_ptm200btn = ("AI", "A0", "BI", "B0", "CI", "C0", "DI", "D0"); my %EnO_ptm200btn; @@ -168,9 +173,10 @@ my %EnO_subType = ( "F6.10.00" => "windowHandle", 1 => "switch", 2 => "sensor", - 3 => "FRW", - 4 => "PM101", - 5 => "raw", + 3 => "vld", + 4 => "FRW", + 5 => "PM101", + 6 => "raw", ); my @EnO_models = qw ( @@ -197,12 +203,13 @@ EnOcean_Initialize($) $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 dummy:0,1 " . "showtime:1,0 loglevel:0,1,2,3,4,5,6 " . "actualTemp angleMax:slider,-180,20,180 angleMin:slider,-180,20,180 " . - "angleTime:0,1,2,3,4,5,6 dimValueOn " . + "angleTime:0,1,2,3,4,5,6 destinationID dimValueOn " . "model:" . join(",", @EnO_models) . " " . "gwCmd:" . join(",", sort @EnO_gwCmd) . " " . "manufID:" . join(",", keys %EnO_manuf) . " " . "rampTime repeatingAllowed:yes,no " . "scaleDecimals:0,1,2,3,4,5,6,7,8,9 scaleMax scaleMin " . + "securityLevel:unencrypted " . "shutTime shutTimeCloses subDef subDef0 subDefI " . "subType:" . join(",", sort grep { !$subTypeList{$_}++ } values %EnO_subType) . " " . "subTypeSet:" . join(",", sort grep { !$subTypeSetList{$_}++ } values %EnO_subType) . " " . @@ -243,17 +250,25 @@ EnOcean_Set($@) my $name = $hash->{NAME}; my $data; - my $header; + my $destinationID = AttrVal($name, "destinationID", undef); + if (!defined $destinationID || $destinationID eq "multicast") { + $destinationID = "FFFFFFFF"; + } elsif ($destinationID eq "unicast") { + $destinationID = $hash->{DEF}; + } elsif ($destinationID !~ m/^[\dA-F]{8}$/) { + return "DestinationID $destinationID wrong, choose <8-digit-hex-code>."; + } my $ll2 = GetLogLevel($name, 2); my $manufID = AttrVal($name, "manufID", ""); my $model = AttrVal($name, "model", ""); - my $repeatingAllowed = AttrVal($name, "repeatingAllowed", "yes"); + my $rorg; my $sendCmd = "yes"; my $status = "00"; my $st = AttrVal($name, "subType", ""); my $stSet = AttrVal($name, "subTypeSet", undef); if (defined $stSet) {$st = $stSet;} - my $subDef = AttrVal($name, "subDef", "$hash->{DEF}"); + my $subDef = AttrVal($name, "subDef", $hash->{DEF}); + if ($subDef !~ m/^[\dA-F]{8}$/) {return "SenderID $subDef wrong, choose <8-digit-hex-code>.";} my $switchMode = AttrVal($name, "switchMode", "switch"); my $tn = TimeNow(); my $updateState = 1; @@ -267,6 +282,7 @@ EnOcean_Set($@) # [Kieback&Peter MD15-FTL-xx] # See also http://www.oscat.de/community/index.php/topic,985.30.html # Maintenance commands (runInit, liftSet, valveOpen, valveClosed) + $rorg = "A5"; my %sets = ( "desired-temp" => "\\d+(\\.\\d)?", "actuator" => "\\d+", @@ -302,29 +318,29 @@ EnOcean_Set($@) # select Command from attribute gwCmd or command line my $gwCmd = AttrVal($name, "gwCmd", undef); if ($gwCmd && $EnO_gwCmd{$gwCmd}) { - # PHC Command from attribute gwCmd + # command from attribute gwCmd if ($EnO_gwCmd{$cmd}) { # shift $cmd $cmd = $a[1]; shift(@a); } } elsif ($EnO_gwCmd{$cmd}) { - # PHC Command from command line + # command from command line $gwCmd = $cmd; $cmd = $a[1]; shift(@a); } else { - return "Unknown Gateway Command " . $cmd . ", choose one of " . join(" ", sort keys %EnO_gwCmd); + return "Unknown Gateway command " . $cmd . ", choose one of " . join(" ", sort keys %EnO_gwCmd); } my $gwCmdID; + $rorg = "A5"; my $setCmd = 0; - ## $status = "00"; my $time = 0; if ($gwCmd eq "switching") { # Switching $gwCmdID = 1; if($cmd eq "teach") { - $data = sprintf "A5%02X000000", $gwCmdID; + $data = sprintf "%02X000000", $gwCmdID; } elsif ($cmd eq "on" || $cmd eq "B0") { $setCmd = 9; if ($a[1]) { @@ -333,7 +349,7 @@ EnOcean_Set($@) shift(@a); } $updateState = 0; - $data = sprintf "A5%02X%04X%02X", $gwCmdID, $time, $setCmd; + $data = sprintf "%02X%04X%02X", $gwCmdID, $time, $setCmd; } elsif ($cmd eq "off" || $cmd eq "BI") { $setCmd = 8; if ($a[1]) { @@ -342,12 +358,12 @@ EnOcean_Set($@) shift(@a); } $updateState = 0; - $data = sprintf "A5%02X%04X%02X", $gwCmdID, $time, $setCmd; + $data = sprintf "%02X%04X%02X", $gwCmdID, $time, $setCmd; } else { my $cmdList = "B0 BI teach"; return SetExtensions ($hash, $cmdList, $name, @a); $updateState = 0; - $data = sprintf "A5%02X%04X%02X", $gwCmdID, $time, $setCmd; + $data = sprintf "%02X%04X%02X", $gwCmdID, $time, $setCmd; } } elsif ($gwCmd eq "dimming") { @@ -359,7 +375,7 @@ EnOcean_Set($@) $setCmd = 9; if ($cmd eq "teach") { $setCmd = 0; - $data = sprintf "A5%02X000000", $gwCmdID; + $data = sprintf "%02X000000", $gwCmdID; } elsif ($cmd eq "dim") { return "Usage: $cmd dim/% [rampTime/s lock|unlock]" if(@a < 2 || $a[1] < 0 || $a[1] > 100 || $a[1] !~ m/^[+-]?\d+$/); @@ -461,17 +477,17 @@ EnOcean_Set($@) if ($rampTime > 255) { $rampTime = 255; } if ($rampTime < 0) { $rampTime = 0; } $updateState = 0; - $data = sprintf "A5%02X%02X%02X%02X", $gwCmdID, $dimVal, $rampTime, $setCmd; + $data = sprintf "%02X%02X%02X%02X", $gwCmdID, $dimVal, $rampTime, $setCmd; } } elsif ($gwCmd eq "setpointShift") { $gwCmdID = 3; if ($cmd eq "teach") { - $data = sprintf "A5%02X000000", $gwCmdID; + $data = sprintf "%02X000000", $gwCmdID; } elsif ($cmd eq "shift") { if (($a[1] =~ m/^[+-]?\d+(\.\d+)?$/) && ($a[1] >= -12.7) && ($a[1] <= 12.8)) { $updateState = 0; - $data = sprintf "A5%02X00%02X08", $gwCmdID, ($a[1] + 12.7) * 10; + $data = sprintf "%02X00%02X08", $gwCmdID, ($a[1] + 12.7) * 10; shift(@a); } else { return "Usage: $a[1] is not numeric or out of range"; @@ -487,7 +503,7 @@ EnOcean_Set($@) } elsif ($cmd eq "basic") { if (($a[1] =~ m/^[+-]?\d+(\.\d+)?$/) && ($a[1] >= 0) && ($a[1] <= 51.2)) { $updateState = 0; - $data = sprintf "A5%02X00%02X08", $gwCmdID, $a[1] * 5; + $data = sprintf "%02X00%02X08", $gwCmdID, $a[1] * 5; shift(@a); } else { return "Usage: $cmd parameter is not numeric or out of range."; @@ -512,7 +528,7 @@ EnOcean_Set($@) return "Usage: $cmd parameter unknown."; } shift(@a); - $data = sprintf "A5%02X00%02X%02X", $gwCmdID, $controlVar, $setCmd; + $data = sprintf "%02X00%02X%02X", $gwCmdID, $controlVar, $setCmd; } elsif ($cmd eq "energyHoldOff") { if ($a[1] eq "normal") { $setCmd = 8; @@ -522,7 +538,7 @@ EnOcean_Set($@) return "Usage: $cmd parameter unknown."; } shift(@a); - $data = sprintf "A5%02X00%02X%02X", $gwCmdID, $controlVar, $setCmd; + $data = sprintf "%02X00%02X%02X", $gwCmdID, $controlVar, $setCmd; } elsif ($cmd eq "controllerMode") { if ($a[1] eq "auto") { $setCmd = 8; @@ -536,7 +552,7 @@ EnOcean_Set($@) return "Usage: $cmd parameter unknown."; } shift(@a); - $data = sprintf "A5%02X00%02X%02X", $gwCmdID, $controlVar, $setCmd; + $data = sprintf "%02X00%02X%02X", $gwCmdID, $controlVar, $setCmd; } elsif ($cmd eq "controllerState") { if ($a[1] eq "auto") { $setCmd = 8; @@ -553,7 +569,7 @@ EnOcean_Set($@) } shift(@a); $updateState = 0; - $data = sprintf "A5%02X00%02X%02X", $gwCmdID, $controlVar, $setCmd; + $data = sprintf "%02X00%02X%02X", $gwCmdID, $controlVar, $setCmd; } else { return "Unknown argument, choose one of teach presence:absent,present,standby energyHoldOff:holdoff,normal controllerMode:cooling,heating,off controllerState:auto,override"; } @@ -561,14 +577,14 @@ EnOcean_Set($@) } elsif ($gwCmd eq "fanStage") { $gwCmdID = 6; if($cmd eq "teach") { - $data = sprintf "A5%02X000000", $gwCmdID; + $data = sprintf "%02X000000", $gwCmdID; } elsif ($cmd eq "stage") { if ($a[1] eq "auto") { $updateState = 0; - $data = sprintf "A5%02X00%02X08", $gwCmdID, 255; + $data = sprintf "%02X00%02X08", $gwCmdID, 255; } elsif ($a[1] && $a[1] =~ m/^[0-3]$/) { $updateState = 0; - $data = sprintf "A5%02X00%02X08", $gwCmdID, $a[1]; + $data = sprintf "%02X00%02X08", $gwCmdID, $a[1]; } else { return "Usage: $cmd parameter is not numeric or out of range" } @@ -730,15 +746,12 @@ EnOcean_Set($@) $updateState = 0; } else { } - $data = sprintf "A5%02X%02X%02X%02X", $gwCmdID, $blindParam1, $blindParam2, $setCmd; + $data = sprintf "%02X%02X%02X%02X", $gwCmdID, $blindParam1, $blindParam2, $setCmd; } else { - return "Unknown Gateway Command " . $cmd . ", choose one of ". join(" ", sort keys %EnO_gwCmd); + return "Unknown Gateway command " . $cmd . ", choose one of ". join(" ", sort keys %EnO_gwCmd); } - # write gateway command - # header: len: 0x000A optlen: 0x00 pakettype: 0x01(radio) - $header = "000A0001"; - Log $ll2, "EnOcean: set $name $cmd"; + Log $ll2, "EnOcean: set $name $cmd $setCmd"; } elsif ($st eq "manufProfile") { if ($manufID eq "00D") { @@ -748,6 +761,7 @@ EnOcean_Set($@) my $anglePos = ReadingsVal($name, "anglePos", undef); my $angleTime = AttrVal($name, "angleTime", 0); my $position = ReadingsVal($name, "position", undef); + $rorg = "A5"; my $shutTime = AttrVal($name, "shutTime", 255); my $shutTimeCloses = AttrVal($name, "shutTimeCloses", $shutTime); $shutTimeCloses = $shutTime if ($shutTimeCloses < $shutTimeCloses); @@ -767,7 +781,7 @@ EnOcean_Set($@) $shutTime = 255 if ($shutTime > 255); $shutTime = 1 if ($shutTime < 1); if ($cmd eq "teach") { - $data = "A5FFF80D80"; + $data = "FFF80D80"; } elsif ($cmd eq "stop") { # stop # delete readings, as they are undefined @@ -872,7 +886,6 @@ EnOcean_Set($@) if (defined $a[1] && $a[1] =~ m/^[+-]?\d+$/ && $a[1] >= 0 && $a[1] <= 100) { if ($position < $a[1]) { # down - ## $angleTime = $angleTime * ($angleMax - $anglePos)/($angleMax - $angleMin); $shutTime = $shutTime * ($a[1] - $position) / 100 + $angleTime; $position = $a[1] + $angleTime / $shutTimeSet * 100; @@ -887,7 +900,6 @@ EnOcean_Set($@) } } elsif ($position > $a[1]) { # up - ## $angleTime = $angleTime * ($anglePos - $angleMin) /($angleMax - $angleMin); $shutTime = $shutTime * ($position - $a[1]) / 100 + $angleTime; $position = $a[1] - $angleTime / $shutTimeSet * 100; @@ -927,15 +939,15 @@ EnOcean_Set($@) } if($shutCmd || $cmd eq "stop") { $updateState = 0; - $data = sprintf "A5%02X%02X%02X%02X", 0, $shutTime, $shutCmd, 8; + $data = sprintf "%02X%02X%02X%02X", 0, $shutTime, $shutCmd, 8; } - $header = "000A0001"; Log $ll2, "EnOcean: set $name $cmd"; } } elsif ($st eq "contact") { # 1BS Telegram # Single Input Contact (EEP D5-00-01) + $rorg = "D5"; my $setCmd; if ($cmd eq "teach") { $setCmd = 0; @@ -946,8 +958,7 @@ EnOcean_Set($@) } else { return "Unknown argument $cmd, choose one of open closed teach"; } - $data = sprintf "D5%02X", $setCmd; - $header = "00070001"; + $data = sprintf "%02X", $setCmd; Log $ll2, "EnOcean: set $name $cmd"; } elsif ($st eq "raw") { @@ -956,29 +967,52 @@ EnOcean_Set($@) if ($cmd eq "4BS"){ # 4BS Telegram if ($a[1] && $a[1] =~ m/^[\dA-F]{8}$/) { - $data = sprintf "A5%s", $a[1]; - $header = "000A0001"; + $data = $a[1]; + $rorg = "A5"; } else { return "Wrong parameter, choose 4BS [status 1 Byte hex]"; } } elsif ($cmd eq "1BS") { # 1BS Telegram if ($a[1] && $a[1] =~ m/^[\dA-F]{2}$/) { - $data = sprintf "D5%s", $a[1]; - $header = "00070001"; + $data = $a[1]; + $rorg = "D5"; } else { return "Wrong parameter, choose 1BS [status 1 Byte hex]"; } } elsif ($cmd eq "RPS") { # RPS Telegram if ($a[1] && $a[1] =~ m/^[\dA-F]{2}$/) { - $data = sprintf "F6%s", $a[1]; - $header = "00070001"; + $data = $a[1]; + $rorg = "F6"; } else { return "Wrong parameter, choose RPS [status 1 Byte hex]"; } + } elsif ($cmd eq "VLD") { + # VLD Telegram + if ($a[1] && $a[1] =~ m/^[\dA-F]{2,28}$/ && !(length($a[1]) % 2)) { + $data = $a[1]; + $rorg = "D2"; + } else { + return "Wrong parameter, choose VLD [status 1 Byte hex]"; + } + } elsif ($cmd eq "timer") { + ### test + if ($a[1] && $a[1] =~ m/^[\d]{2}$/) { + $data = "09"; + $rorg = "F6"; + + readingsSingleUpdate($hash, "test", 127, 1); + readingsSingleUpdate($hash, "testScaled", EnOcean_ReadingScaled($hash, 127, 0, 255), 1) ; + + my @timerCmd = ($name, "RPS", "08"); + my %par = (hash => $hash, timerCmd => \@timerCmd); + InternalTimer(gettimeofday() + $a[1], "EnOcean_TimerSet", \%par, 0); + } else { + return "Wrong parameter, choose timer