6 Commits

Author SHA1 Message Date
Marc Hoppe
2cfb5f7cee ... 2012-03-11 17:38:39 +01:00
Marc Hoppe
0ad35c9742 commandref: Enocean changes 2012-03-11 17:38:39 +01:00
Marc Hoppe
77106140e7 Enocean: eltakoRoll 2012-03-11 17:38:39 +01:00
Marc Hoppe
4536c9f754 Enocean: eltakoDimmer: new commands 'dimup', 'dimdown' and 'on'/'off' new attr 'dimTime' 2012-03-11 17:38:38 +01:00
Marc Hoppe
d0ccfba735 EnOcean: if there is an 'attr' 'subId' use it for sending data to an Actuator
There is no subType 'dimmer' and 'dimmctrl' anymore these are replaced by 'eltakoDimmer'.
 The commands supported are 'dimto' and 'teach'
 The readings which will be set are 'state' and 'value'
2012-03-11 17:38:38 +01:00
Marc Hoppe
dfb1994ad6 00_TCM: Read Base-Id of Tcm on start 2012-03-11 17:38:38 +01:00
3 changed files with 215 additions and 49 deletions

View File

@@ -12,7 +12,7 @@ package main;
# EnOcean Serial Protocol 3 (ESP3) (for the TCM310) # EnOcean Serial Protocol 3 (ESP3) (for the TCM310)
# TODO: # TODO:
# Check BSC Temp # Check BSC Temp
# Check Stick Temp # Check Stick Temp
# Check Stick WriteRadio # Check Stick WriteRadio
@@ -77,10 +77,21 @@ TCM_Define($$)
$attr{$name}{dummy} = 1; $attr{$name}{dummy} = 1;
return undef; return undef;
} }
$hash->{DeviceName} = $dev; $hash->{DeviceName} = $dev;
$hash->{MODEL} = $model; $hash->{MODEL} = $model;
my $ret = DevIo_OpenDev($hash, 0, undef); my $ret = DevIo_OpenDev($hash, 0, undef);
if($hash->{STATE} eq "opened") {
# Read Base-Id of Enocean-Module
my $cnt=0;
do { # this does not always work, so we try several times
my $answer=TCM_Get($hash, ($name, "idbase") );
my @fields=split(/[=,]/, $answer);
$hash->{BASEID}=$fields[1];
$cnt++;
} while ($cnt<3 and $hash->{BASEID} eq "");
}
return $ret; return $ret;
} }
@@ -586,7 +597,7 @@ TCM_ReadAnswer($$)
if($^O =~ m/Win/ && $hash->{USBDev}) { if($^O =~ m/Win/ && $hash->{USBDev}) {
$hash->{USBDev}->read_const_time($to*1000); # set timeout (ms) $hash->{USBDev}->read_const_time($to*1000); # set timeout (ms)
# Read anstatt input sonst funzt read_const_time nicht. # Read anstatt input sonst funzt read_const_time nicht.
$buf = $hash->{USBDev}->read(999); $buf = $hash->{USBDev}->read(999);
return ("$name Timeout reading answer for $arg", undef) return ("$name Timeout reading answer for $arg", undef)
if(length($buf) == 0); if(length($buf) == 0);

View File

@@ -1,5 +1,5 @@
############################################## ##############################################
# $Id$ # $Id: 10_EnOcean.pm 1130 2011-12-14 07:57:59Z rudolfkoenig $
package main; package main;
use strict; use strict;
@@ -10,6 +10,7 @@ sub EnOcean_Initialize($);
sub EnOcean_Parse($$); sub EnOcean_Parse($$);
sub EnOcean_Set($@); sub EnOcean_Set($@);
sub EnOcean_MD15Cmd($$$); sub EnOcean_MD15Cmd($$$);
sub EnOcean_GetMyDeviceId($);
my %rorgname = ("F6"=>"switch", # RPS my %rorgname = ("F6"=>"switch", # RPS
"D5"=>"contact", # 1BS "D5"=>"contact", # 1BS
@@ -64,10 +65,11 @@ EnOcean_Initialize($)
$hash->{DefFn} = "EnOcean_Define"; $hash->{DefFn} = "EnOcean_Define";
$hash->{ParseFn} = "EnOcean_Parse"; $hash->{ParseFn} = "EnOcean_Parse";
$hash->{SetFn} = "EnOcean_Set"; $hash->{SetFn} = "EnOcean_Set";
$hash->{AttrFn} = "EnOcean_Attr";
$hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 " . $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 " .
"showtime:1,0 loglevel:0,1,2,3,4,5,6 model " . "showtime:1,0 loglevel:0,1,2,3,4,5,6 model " .
"subType:switch,contact,sensor,windowHandle,SR04,MD15,PM101,". "subType:switch,contact,sensor,windowHandle,SR04,MD15," .
"dimmer,dimmCtrl actualTemp"; "eltakoDimmer,eltakoRoll subId actualTemp, dimTime";
for(my $i=0; $i<@ptm200btn;$i++) { for(my $i=0; $i<@ptm200btn;$i++) {
$ptm200btn{$ptm200btn[$i]} = "$i:30"; $ptm200btn{$ptm200btn[$i]} = "$i:30";
@@ -76,6 +78,28 @@ EnOcean_Initialize($)
return undef; return undef;
} }
# ---------------------------------------------
sub EnOcean_Attr($)
{
my @a = @_;
my $name= $a[1];
my $ll2 = GetLogLevel($name, 2);
if($a[2] eq "subType") {
Log $ll2, "EO_Attr subtype";
if( $a[3] eq "eltakoDimmer"
or $a[3] eq "eltakoSwitch") {
Log $ll2, "EO_Attr subtype dimmer/switch";
$attr{$name}{eventMap}="B0:on B1:off"
}
}
return undef;
}
############################# #############################
sub sub
EnOcean_Define($$) EnOcean_Define($$)
@@ -140,32 +164,113 @@ EnOcean_Set($@)
$hash->{READINGS}{$cmd}{TIME} = $tn; $hash->{READINGS}{$cmd}{TIME} = $tn;
$hash->{READINGS}{$cmd}{VAL} = $arg; $hash->{READINGS}{$cmd}{VAL} = $arg;
} elsif($st eq "dimmCtrl") { # Tested for Eltako-Dimmer ###########################
} elsif($st eq "eltakoDimmer") {
my $sendDimCmd=0;
my $time=AttrVal($name, "time", 0);
my $onoff=1;
my $dimVal=100;
$dimVal=$hash->{VALUE} if(defined $hash->{VALUE});
if($cmd eq "teach") { if($cmd eq "teach") {
my $data=sprintf("A502000000%s00", $hash->{DEF}); my $idSrc=EnOcean_GetMyDeviceId($hash);
Log $ll2, "dimmCtrl.Teach: " . $data; my $data=sprintf("A502000000%s00", $idSrc);
Log $ll2, "$st.Teach: " . $data;
IOWrite($hash, "000A0001", $data); # len:000a optlen:00 pakettype:1(radio) IOWrite($hash, "000A0001", $data); # len:000a optlen:00 pakettype:1(radio)
} elsif($cmd eq "dimm") { } elsif($cmd eq "dimto") {
return "Usage: dimm percent [time 01-FF FF:slowest] [on/off]" if(@a<2); return "Usage: $cmd percent" if(@a<2 or $a[1]>100);
my $time=0;
my $onoff=1;
# for eltako relative (0-100) (but not compliant to EEP because DB0.2 is 0) # for eltako relative (0-100) (but not compliant to EEP because DB0.2 is 0)
my $dimVal=$a[1]; $dimVal=$a[1];
shift(@a); shift(@a);
if(defined($a[1])) { $time=$a[1]; shift(@a); } if(defined($a[1])) { $time=$a[1]; shift(@a); }
if(defined($a[1])) { $onoff=($a[1] eq "off") ? 0 : 1; shift(@a); } if(defined($a[1])) { $onoff=($a[1] eq "off") ? 0 : 1; shift(@a); }
# EEP: A5/38/08 Central Command ->Typ 0x02: Dimming $sendDimCmd=1;
my $data=sprintf("A502%02X%02X%02X%s00", $dimVal, $time, $onoff|0x08, $hash->{DEF});
IOWrite($hash, "000A0001", $data); } elsif($cmd eq "dimup") {
Log $ll2, "dimmCtrl.dimm: " . $data; return "Usage: $cmd percent" if(@a<2 or $a[1]>100);
$dimVal+=$a[1];
Log $ll2, "$st.$cmd val:" . $hash->{VALUE} . " par:" . $a[1] . " val:" . $dimVal;
shift(@a);
$sendDimCmd=1;
} elsif($cmd eq "dimdown") {
return "Usage: $cmd percent" if(@a<2 or $a[1]>100);
$dimVal-=$a[1];
shift(@a);
$sendDimCmd=1;
} elsif($cmd eq "on" or $cmd eq "B0") {
$sendDimCmd=1;
} elsif($cmd eq "off" or $cmd eq "B1") {
$onoff=0;
$sendDimCmd=1;
} else { } else {
return "Unknown argument $cmd, choose one of: teach, dimm" return "Unknown argument $cmd, choose one of: teach, dimto, dimup, dimdown, on ,off";
} }
if($sendDimCmd) {
if($dimVal > 100) { $dimVal=100; }
if($dimVal <= 0) { $dimVal=0; $onoff=0; }
# EEP: A5/38/08 Central Command ->Typ 0x02: Dimming
my $idSrc=EnOcean_GetMyDeviceId($hash);
my $data=sprintf("A502%02X%02X%02X%s00", $dimVal, $time, $onoff|0x08, $idSrc);
IOWrite($hash, "000A0001", $data);
Log $ll2, "$st.$cmd: " . $data;
}
########################### ###########################
} elsif($st eq "eltakoRoll") {
if($cmd eq "teach") {
my $data=sprintf("A5FFF80D80%s00", $hash->{DEF});
Log $ll2, "eltakoRollCtrl.Teach: " . $data;
IOWrite($hash, "000A0001", $data); # len:000a optlen:00 pakettype:1(radio)
} else {
my %eltakoRollCtrlCommands = ( down=>0x02, up=>0x01, stop=>0x00 );
my $usage = "Usage: (" . join("|", sort keys %eltakoRollCtrlCommands) . ")";
my $rollcmd= $eltakoRollCtrlCommands{$cmd};
return $usage if(!defined($rollcmd));
my $time=AttrVal($name, "time", 0);
# EEP: A5/3F/7F Universal ???
my $idSrc=EnOcean_GetMyDeviceId($hash);
my $data=sprintf("A5%02X%02X%02X%02X%s00", 0, $time, $rollcmd, 0x08, $idSrc);
IOWrite($hash, "000A0001", $data);
Log $ll2, "eltakoRoll.$cmd" . $data;
}
###########################
} elsif($st eq "eltakoSwitch") {
my $sendCmd=0;
my $onoff=1;
if($cmd eq "teach") {
my $idSrc=EnOcean_GetMyDeviceId($hash);
my $data=sprintf("A501000000%s00", $idSrc);
Log $ll2, "$st.Teach: " . $data;
IOWrite($hash, "000A0001", $data); # len:000a optlen:00 pakettype:1(radio)
} elsif($cmd eq "on" or $cmd eq "B0") {
$sendCmd=1;
} elsif($cmd eq "off" or $cmd eq "B1") {
$onoff=0;
$sendCmd=1;
} else {
return "Unknown argument $cmd, choose one of: teach, on ,off";
}
if($sendDimCmd) {
# EEP: A5/38/08 Central Command ->Typ 0x01: Switch
my $idSrc=EnOcean_GetMyDeviceId($hash);
my $data=sprintf("A5010000%02X%s00", $onoff|0x08, $idSrc);
IOWrite($hash, "000A0001", $data);
Log $ll2, "$st.$cmd: " . $data;
}
###########################
} else { # Simulate a PTM } else { # Simulate a PTM
my ($c1,$c2) = split(",", $cmd, 2); my ($c1,$c2) = split(",", $cmd, 2);
return "Unknown argument $cmd, choose one of " . return "Unknown argument $cmd, choose one of " .
@@ -176,14 +281,14 @@ EnOcean_Set($@)
my ($db_3, $status) = split(":", $ptm200btn{$c1}, 2); my ($db_3, $status) = split(":", $ptm200btn{$c1}, 2);
$db_3 <<= 5; $db_3 <<= 5;
$db_3 |= 0x10 if($c1 ne "released"); # set the pressed flag $db_3 |= 0x10 if($c1 ne "released"); # set the pressed flag
if($c2) { if($c2) {
my ($d2, undef) = split(":", $ptm200btn{$c2}, 2); my ($d2, undef) = split(":", $ptm200btn{$c2}, 2);
$db_3 |= ($d2<<1) | 0x01; $db_3 |= ($d2<<1) | 0x01;
} }
IOWrite($hash, "", IOWrite($hash, "",
sprintf("6B05%02X000000%s%s", $db_3, $hash->{DEF}, $status)); sprintf("6B05%02X000000%s%s", $db_3, $hash->{DEF}, $status));
} }
select(undef, undef, undef, 0.1) if($i < int(@a)-1); select(undef, undef, undef, 0.1) if($i < int(@a)-1);
} }
@@ -196,6 +301,7 @@ EnOcean_Set($@)
return undef; return undef;
} }
############################# #############################
sub sub
EnOcean_Parse($$) EnOcean_Parse($$)
@@ -209,7 +315,7 @@ EnOcean_Parse($$)
return ""; return "";
} }
my $hash = $modules{EnOcean}{defptr}{$id}; my $hash = $modules{EnOcean}{defptr}{$id};
if(!$hash) { if(!$hash) {
Log 3, "EnOcean Unknown device with ID $id, please define it"; Log 3, "EnOcean Unknown device with ID $id, please define it";
return "UNDEFINED EnO_${rorgname}_$id EnOcean $id"; return "UNDEFINED EnO_${rorgname}_$id EnOcean $id";
@@ -262,15 +368,17 @@ EnOcean_Parse($$)
} else { } else {
if($st eq "keycard") { if($st eq "keycard") {
$msg = "keycard removed"; $msg = "keycard removed";
} else { } else {
$msg = (($db_3&0x10) ? "pressed" : "released"); $msg = (($db_3&0x10) ? "pressed" : "released");
} }
} }
} }
# eltakoRoll: BI: unten / B0: oben / released:running/stopped
# released events are disturbing when using a remote, since it overwrites # released events are disturbing when using a remote, since it overwrites
# the "real" state immediately # the "real" state immediately
@@ -303,7 +411,7 @@ EnOcean_Parse($$)
if("$fn.$tp" eq "20.01" && $iohash->{pair}) { # MD15 if("$fn.$tp" eq "20.01" && $iohash->{pair}) { # MD15
select(undef, undef, undef, 0.1); # max 10 Seconds select(undef, undef, undef, 0.1); # max 10 Seconds
EnOcean_A5Cmd($hash, "800800F0", "00000000"); EnOcean_A5Cmd($hash, "800800F0", EnOcean_GetMyDeviceId($hash));
select(undef, undef, undef, 0.5); select(undef, undef, undef, 0.5);
EnOcean_MD15Cmd($hash, $name, 128); # 128 == 20 degree C EnOcean_MD15Cmd($hash, $name, 128); # 128 == 20 degree C
} }
@@ -343,7 +451,7 @@ EnOcean_Parse($$)
push @event, "3:actuatorStatus:".(($db_2 & 0x01) ? "obstructed" : "ok"); push @event, "3:actuatorStatus:".(($db_2 & 0x01) ? "obstructed" : "ok");
push @event, "3:measured-temp:". sprintf "%.1f", ($db_1*40/255); push @event, "3:measured-temp:". sprintf "%.1f", ($db_1*40/255);
EnOcean_MD15Cmd($hash, $name, $db_1); EnOcean_MD15Cmd($hash, $name, $db_1);
} elsif($st eq "PM101") { } elsif($st eq "PM101") {
#################################### ####################################
# Ratio Presence Sensor Eagle PM101, code by aicgazi # Ratio Presence Sensor Eagle PM101, code by aicgazi
@@ -355,9 +463,7 @@ EnOcean_Parse($$)
push @event, "3:channel1:" . ($db_0 & 0x01 ? "off" : "on"); push @event, "3:channel1:" . ($db_0 & 0x01 ? "off" : "on");
push @event, "3:channel2:" . ($db_0 & 0x02 ? "off" : "on"); push @event, "3:channel2:" . ($db_0 & 0x02 ? "off" : "on");
} elsif($st eq "dimmer") { } elsif($st eq "eltakoDimmer") {
# todo: create a more general solution for the central-command responses
# response command from (Eltako-)Actor ( Central-Command:A5/38/08 ) # response command from (Eltako-)Actor ( Central-Command:A5/38/08 )
if($db_3 eq 0x01) { # switch if($db_3 eq 0x01) { # switch
push @event, "3:state:" . (($db_0 & 0x01) ? "on": "off"); push @event, "3:state:" . (($db_0 & 0x01) ? "on": "off");
@@ -366,12 +472,7 @@ EnOcean_Parse($$)
} elsif($db_3 eq 0x02) { # dimm } elsif($db_3 eq 0x02) { # dimm
push @event, "3:state:" . (($db_0 & 0x01) ? "on": "off"); push @event, "3:state:" . (($db_0 & 0x01) ? "on": "off");
push @event, "3:dimmValue:$db_2"; push @event, "3:value:$db_2";
} elsif($db_3 eq 0x03) { # setpoint-switch, todo
} elsif($db_3 eq 0x04) { # basic setpoint, todo
} elsif($db_3 eq 0x05) { # control-variable, todo
} elsif($db_3 eq 0x06) { # fan-stage, todo
} }
} else { } else {
@@ -400,10 +501,11 @@ EnOcean_Parse($$)
if($vn eq "state") { if($vn eq "state") {
$hash->{STATE} = $vv; $hash->{STATE} = $vv;
push @changed, $vv; push @changed, $vv;
} elsif($vn eq "value") {
$hash->{VALUE} = $vv if($vv>0);
push @changed, "$vn: $vv";
} else { } else {
push @changed, "$vn: $vv"; push @changed, "$vn: $vv";
} }
} }
@@ -413,7 +515,7 @@ EnOcean_Parse($$)
} }
} }
$hash->{CHANGED} = \@changed; $hash->{CHANGED} = \@changed;
return $name; return $name;
} }
@@ -430,7 +532,7 @@ EnOcean_MD15Cmd($$$)
$msg = sprintf("%02X000000", $arg1); $msg = sprintf("%02X000000", $arg1);
} elsif($cmd eq "desired-temp") { } elsif($cmd eq "desired-temp") {
$msg = sprintf("%02X%02X0400", $arg1*255/40, $msg = sprintf("%02X%02X0400", $arg1*255/40,
AttrVal($name, "actualTemp", ($db_1*40/255)) * 255/40); AttrVal($name, "actualTemp", ($db_1*40/255)) * 255/40);
} elsif($cmd eq "initialize") { } elsif($cmd eq "initialize") {
@@ -440,7 +542,7 @@ EnOcean_MD15Cmd($$$)
if($msg) { if($msg) {
select(undef, undef, undef, 0.2); select(undef, undef, undef, 0.2);
EnOcean_A5Cmd($hash, $msg, "00000000"); EnOcean_A5Cmd($hash, $msg, EnOcean_GetMyDeviceId($hash));
if($cmd eq "initialize") { if($cmd eq "initialize") {
delete($defs{$name}{READINGS}{CMD}); delete($defs{$name}{READINGS}{CMD});
delete($defs{$name}{READINGS}{$cmd}); delete($defs{$name}{READINGS}{$cmd});
@@ -452,10 +554,30 @@ EnOcean_MD15Cmd($$$)
sub sub
EnOcean_A5Cmd($$$) EnOcean_A5Cmd($$$)
{ {
my ($hash, $msg, $org) = @_; my ($hash, $msg, $org) = @_;
IOWrite($hash, "000A0701", # varLen=0A optLen=07 msgType=01=radio, IOWrite($hash, "000A0701", # varLen=0A optLen=07 msgType=01=radio,
sprintf("A5%s%s0001%sFF00",$msg,$org,$hash->{DEF})); sprintf("A5%s%s0001%sFF00",$msg,$org,$hash->{DEF}));
# type=A5 msg:4 senderId:4 status=00 subTelNum=01 destId:4 dBm=FF Security=00 # type=A5 msg:4 senderId:4 status=00 subTelNum=01 destId:4 dBm=FF Security=00
} }
# ---------------------------------------------
#
# compose the Src-Id for a command to send
#
sub EnOcean_GetMyDeviceId($)
{
my ($hash) = @_;
my $myId=0; # default: use Device-ID of EUL
my $name = $hash->{NAME};
my $baseId=hex($hash->{IODev}{BASEID}) if(defined $hash->{IODev}{BASEID});
my $subId = AttrVal($name, "subId", "");
if(defined $baseId and defined $subId) {
# if there is a base-id an a subid -> use this combination
$myId=sprintf("%08X", $baseId | $subId);
}
return $myId;
}
1; 1;

View File

@@ -3348,8 +3348,16 @@ A line ending with \ will be concatenated with the next one, so long lines
<a name="EnOcean"></a> <a name="EnOcean"></a>
<h3>EnOcean</h3> <h3>EnOcean</h3>
<ul> <ul>
Devices sold by numerous hardware verndors (e.g. Eltako, Peha, etc), using Devices sold by numerous hardware vendors (e.g. Eltako, Peha, etc), using
the RF Protocol provided by the EnOcean Alliance. the RF Protocol provided by the EnOcean Alliance.
<br>
To send commands to an Enocean-actuator the <a href="#TCM">TCM</a> can either use the
unique Chip-ID (then you can control only one actuator, but nobody else
can send commands to your device from a normal enocean-module). Or you can set/use the
Base-ID and define a Sub-ID for every device to control (then up to 128 devices
can be controlled, but anyone take over your devices simply by sniffing and copying the base-id).
<br>
To use Sub-IDs set the attribute <code>subId</code> to different values (0-127) for all your devices.
<br><br> <br><br>
<a name="EnOceandefine"></a> <a name="EnOceandefine"></a>
<b>Define</b> <b>Define</b>
@@ -3384,6 +3392,31 @@ A line ending with \ will be concatenated with the next one, so long lines
Do not regulate the MD15.</li> Do not regulate the MD15.</li>
</ul></li> </ul></li>
<li>Eltako-Dimmer-Switch (FUD12NPN, FUD61NP, FUD61NPN). Set subtype: <code>attr mydimmer subType eltakoDimmer</code>
<br>
Commands:
<ul>
<li>dimto &lt;value&gt;</li>
<li>dimup &lt;value&gt;</li>
<li>dimdown &lt;value&gt;</li>
<li>on</li>
<li>off</li>
<li>teach</li>
</ul>
Attributes:
<ul>
<li>dimTime &lt;value&gt;<br>. Set Dimm-velocity (0-255) 0: fast</li>
</ul></li>
<li>Eltako-Roller-Shutter (FSB12, FSB61). Set subtype: <code>attr myroll subType eltakoRoll</code>
<br>
Commands:
<ul>
<li>up</li>
<li>down</li>
<li>stop</li>
<li>teach</li>
</ul></li>
<li>all other: <li>all other:
<ul> <ul>