EnOcean added

git-svn-id: https://svn.fhem.de/fhem/trunk/fhem@957 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
rudolfkoenig 2011-07-24 11:55:36 +00:00
parent 31cdda04e1
commit a97dd7932e
6 changed files with 320 additions and 27 deletions

View File

@ -29,6 +29,11 @@ TCM120_Initialize($)
$hash->{ReadFn} = "TCM120_Read";
$hash->{WriteFn} = "TCM120_Write";
$hash->{ReadyFn} = "TCM120_Ready";
$hash->{Clients} = ":EnOcean:";
my %matchList= (
"1:EnOcean" => "^EnOcean:0B",
);
$hash->{MatchList} = \%matchList;
# Normal devices
$hash->{DefFn} = "TCM120_Define";
@ -134,8 +139,8 @@ TCM120_Read($)
Log $ll5, "$name: wrong checksum: got $crc, computed $mycrc" ;
return;
}
if($net =~ m/^0b/) { # Receive Radio Telegram (RRT)
Dispatch($hash, $net, undef);
if($net =~ m/^0B/) { # Receive Radio Telegram (RRT)
Dispatch($hash, "EnOcean:$net", undef);
} else { # Receive Message Telegram (RMT)
TCM120_Parse($hash, $net, 0);
}
@ -187,7 +192,7 @@ TCM120_Parse($$$)
my $cmd = $parsetbl{substr($rawmsg, 0, 4)};
if(!$cmd) {
$msg ="$name, Unknown command: $rawmsg";
$msg ="Unknown command: $rawmsg";
} else {
if($cmd->{expr}) {
@ -198,6 +203,7 @@ TCM120_Parse($$$)
$msg .= eval $cmd->{expr};
} else {
return "" if($cmd ->{msg} eq "OK" && !$ret); # SKIP Ok
$msg = $cmd->{msg};
}

201
FHEM/10_EnOcean.pm Executable file
View File

@ -0,0 +1,201 @@
##############################################
# CUL HomeMatic handler
package main;
use strict;
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($);
sub
EnOcean_Initialize($)
{
my ($hash) = @_;
$hash->{Match} = "^EnOcean:0B";
$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 ";
}
#############################
sub
EnOcean_Define($$)
{
my ($hash, $def) = @_;
my @a = split("[ \t][ \t]*", $def);
my $name = $hash->{NAME};
return "wrong syntax: define <name> EnOcean 8-digit-hex-code"
if(int(@a)!=3 || $a[2] !~ m/^[A-F0-9]{8}$/i);
$modules{EnOcean}{defptr}{uc($a[2])} = $hash;
AssignIoPort($hash);
# Help FHEMWEB split up davices
$attr{$name}{subType} = $1 if($name =~ m/EnO_(.*)_$a[2]/);
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);
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 $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 $tn = TimeNow();
$hash->{CHANGED}[0] = $cmd;
$hash->{STATE} = $cmd;
$hash->{READINGS}{state}{TIME} = $tn;
$hash->{READINGS}{state}{VAL} = $cmd;
return undef;
}
#############################
sub
EnOcean_Parse($$)
{
my ($iohash, $msg) = @_;
my %ot = ("05"=>"remote", "06"=>"sensor", "07"=>"sensor",
"08"=>"remote", "0A"=>"modem", "0B"=>"modem", );
$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";
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";
}
my $name = $hash->{NAME};
my $ll4 = GetLogLevel($name, 4);
Log $ll4, "EnOcean: ORG:$org, DATA:$data, ID:$id, STATUS:$status";
my @event;
push @event, "0:rp_counter:".(hex($status)&0xf);
my $d1 = hex substr($data,0,2);
#################################
if($org eq "05") { # PTM remote. Queer reporting methods.
my $nu = ((hex($status)&0x10)>>4);
push @event, "0:T21:".((hex($status)&0x20)>>5);
push @event, "0:NU:$nu";
if($nu) {
$msg = sprintf "Btn%d", ($d1&0xe0)>>5;
$msg .= sprintf ",Btn%d", ($d1&0x0e)>>1 if($d1 & 1);
} else {
#confusing for normal use
#my $nbu = (($d1&0xe0)>>5);
#$msg = sprintf "Buttons %d", $nbu ? ($nbu+1) : 0;
$msg = "buttons";
}
$msg .= ($d1&0x10) ? " pressed" : " released";
push @event, "1:state:$msg";
#################################
} elsif($org eq "06") {
push @event, "1:state:$d1";
push @event, "1:sensor1:$d1";
#################################
} 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);
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";
}
my $tn = TimeNow();
my @changed;
for(my $i = 0; $i < int(@event); $i++) {
my ($dochanged, $vn, $vv) = split(":", $event[$i], 3);
if($dochanged) {
if($vn eq "state") {
$hash->{STATE} = $vv;
push @changed, $vv;
} else {
push @changed, "$vn: $vv";
}
}
$hash->{READINGS}{$vn}{TIME} = TimeNow();
$hash->{READINGS}{$vn}{VAL} = $vv;
}
$hash->{CHANGED} = \@changed;
return $name;
}
1;

View File

@ -86,6 +86,7 @@
<a href="#ECMD">ECMD</a> &nbsp;
<a href="#ECMDDevice">ECMDDevice</a> &nbsp;
<a href="#DS18S20">DS18S20</a> &nbsp;
<a href="#EnOcean">EnOcean</a> &nbsp;
<a href="#EM">EM</a> &nbsp;
<a href="#EMEM">EMEM</a> &nbsp;
<a href="#EMGZ">EMGZ</a> &nbsp;
@ -2720,6 +2721,84 @@ A line ending with \ will be concatenated with the next one, so long lines
<br>
<a name="EnOcean"></a>
<h3>EnOcean</h3>
<ul>
Devices sold by numerous hardware verndors (e.g. Eltako, Peha, etc), using
the RF Protocol provided by the EnOcean Alliance.
This module is currently only tested to work with remotes, but other types of
devices should also work. Feedback is welcome.
<br><br>
<a name="EnOceandefine"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; EnOcean &lt;ID&gt;</code>
<br><br>
Define an EnOcean device, connected via a <a href="#TCM120">TCM120</a>. The
&lt;ID&gt; parameter is an 8 digit hex number. For remotes and sensors the
<a href="#autocreate">autocreate</a> module may help you.<br>
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
TCM120 with the "<code>get &lt;tcm&gt; idbase</code>" 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.<br>
For each ID there is the possibility to use 8 different commands, so
in fact you can control 8*128/2=512 switches.<br><br>
Example:
<ul>
<code>define switch1 EnOcean ffc54500</code><br>
</ul>
</ul>
<br>
<a name="EnOceanset"></a>
<b>Set</b>
<ul>
<code>set switch1 &lt;value&gt;</code>
<br><br>
where <code>value</code> is one of Btn0, Btn1, Btn2, Btn3, then certain
combinations of these buttons: Btn0,Btn2 Btn0,Btn3 Btn1,Btn2 Btn1,Btn3 and
released.<br>
In fact we are trying to emulate a PTM100 type remote, which is capable to
report either single buttons, some combinations of 2 buttons and the
released state.<br>
If you define an <a href="#eventMap">eventMap</a> attribute with on/off,
then you'll be able to easily set the device from the <a
href="#FHEMWEB">WEB</a> frontend.<br><br>
Example:
<ul><code>
set switch1 Btn1<br>
set switch1 Btn0,Btn2<br>
attr eventMap Btn1:on Btn0,Btn2:off<br>
set switch1 on<br>
</code></ul>
</ul>
<br>
<a name="EnOceanget"></a>
<b>Get</b> <ul>N/A</ul><br>
<a name="EnOceanattr"></a>
<b>Attributes</b>
<ul>
<li><a href="#eventMap">eventMap</a></li>
<li><a href="#IODev">IODev</a></li>
<li><a href="#loglevel">loglevel</a></li>
<li><a href="#do_not_notify">do_not_notify</a></li>
<li><a href="#ignore">ignore</a></li>
<li><a href="#showtime">showtime</a></li>
<li><a href="#model">model</a></li>
<li><a href="#subType">subType</a></li>
</ul>
<br>
</ul>
<a name="EM"></a>
<h3>EM</h3>
<ul>
@ -5656,6 +5735,8 @@ Readings and STATE of temperature/humidity sensors are compatible with the CUL_W
<b>Set </b>
<ul>
<li>idbase<br>
Set the ID base. Note: The firmware executes this command only up to then
times to prevent misuse.
<li>modem_off<br>
<li>modem_on<br>
<li>reset<br>
@ -5671,6 +5752,9 @@ Readings and STATE of temperature/humidity sensors are compatible with the CUL_W
<b>Get</b>
<ul>
<li>idbase<br>
Get the ID base. You need this command in order to control EnOcean
devices, see the <a href="#EnOceandefine">EnOcean</a>
paragraph.<br><br>
<li>modem_status<br>
<li>sensitivity<br>
<li>sw_ver<br>

View File

@ -119,7 +119,7 @@
<h3>Features</h3>
<ul>
<li>support for a lot of protocols used in house automation like FS20,
FHT, HMS, OneWire, X10, S300, EM, HomeMatic, KNX. See the <a
FHT, HMS, OneWire, X10, S300, EM, HomeMatic, KNX, EnOcean. See the <a
href="#Hardware">Hardware</a> section for more.
</li>
<li>autocreating devices/logs when receiving data from a new device:
@ -207,6 +207,9 @@
href="http://www.busware.de">www.busware.de</a>) access to the EIB/KNX
protocol.
<div id="dist"></div>
<li>Via a TCM120 (e.g. the BSC BOR) access to the EnOcean protocol.
<div id="dist"></div>
<div id="dist"></div>
<div id="dist"></div>

12
fhem.pl
View File

@ -167,7 +167,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.147 2011-07-15 08:59:31 rudolfkoenig Exp $';
my $cvsid = '$Id: fhem.pl,v 1.148 2011-07-24 11:53:11 rudolfkoenig Exp $';
my $namedef =
"where <name> is either:\n" .
"- a single device name\n" .
@ -179,14 +179,14 @@ my $stt_day; # Used by SecondsTillTomorrow()
$init_done = 0;
$modules{_internal_}{ORDER} = -1;
$modules{_internal_}{LOADED} = 1;
$modules{_internal_}{AttrList} =
$modules{Global}{ORDER} = -1;
$modules{Global}{LOADED} = 1;
$modules{Global}{AttrList} =
"archivecmd allowfrom archivedir configfile lastinclude logfile " .
"modpath nrarchive pidfilename port statefile title userattr " .
"verbose:1,2,3,4,5 mseclog version nofork logdir holiday2we " .
"autoload_undefined_devices dupTimeout";
$modules{_internal_}{AttrFn} = "GlobalAttr";
$modules{Global}{AttrFn} = "GlobalAttr";
my $commonAttr = "eventMap";
@ -2174,7 +2174,7 @@ doGlobalDef($)
$devcount = 1;
$defs{global}{NR} = $devcount++;
$defs{global}{TYPE} = "_internal_";
$defs{global}{TYPE} = "Global";
$defs{global}{STATE} = "<no definition>";
$defs{global}{DEF} = "<no definition>";
$defs{global}{NAME} = "global";

View File

@ -79,7 +79,7 @@ FHEMWEB_Initialize($)
$hash->{AttrList}= "loglevel:0,1,2,3,4,5,6 webname fwmodpath fwcompress " .
"plotmode:gnuplot,gnuplot-scroll,SVG plotsize refresh " .
"touchpad smallscreen plotfork basicAuth basicAuthMsg ".
"HTTPS";
"stylesheet HTTPS";
###############
# Initialize internal structures
@ -329,7 +329,7 @@ FW_AnswerCall($)
return 1;
} elsif($arg =~ m,^$FW_ME/icons/(.*)$, ||
$arg =~ m,^$FW_ME/(.*.png)$,) {
$arg =~ m,^$FW_ME/(.*.png)$,i) {
my $img = $1;
my $cachable = 1;
if(!open(FH, "$FW_dir/$img")) {
@ -427,6 +427,7 @@ FW_AnswerCall($)
pO "<meta http-equiv=\"refresh\" content=\"$rf\">" if($rf);
my $stylecss = ($FW_ss ? "style_smallscreen.css" :
$FW_tp ? "style_touchpad.css" : "style.css");
$stylecss = AttrVal($FW_wname, "stylecss", $stylecss);
pO "<link href=\"$FW_ME/$stylecss\" rel=\"stylesheet\"/>";
pO "<script type=\"text/javascript\" src=\"$FW_ME/svg.js\"></script>"
if($FW_plotmode eq "SVG");
@ -800,20 +801,24 @@ FW_showRoom()
############################
# Print the table headers
my @sortedDevs = sort keys %{$FW_types{$type}};
my $allSets = " " . getAllSets($sortedDevs[0]) . " ";
my @roomDevs = grep { $FW_room && ($FW_room eq "all" ||
$FW_rooms{$FW_room}{$_}) }
sort keys %{$FW_types{$type}};
my $allSets = " " . getAllSets($roomDevs[0]) . " ";
my $hasOnOff = ($allSets =~ m/ on / && $allSets =~ m/ off /);
if(!$hasOnOff) { # Check the eventMap
my $em = AttrVal($roomDevs[0], "eventMap", "") . " ";
$hasOnOff = ($em =~ m/:on / && $em =~ m/:off /);
}
my $th;
my $id = "class=\"block\"";
if($hasOnOff) {
$th = "$type</th><th>State</th><th colspan=\"2\">Set to";
} elsif($type eq "FHT") {
$th = "FHT dev.</th><th>Measured</th><th>Set to";
} elsif($allSets =~ m/ desired-temp /) {
$th = "Device</th><th>Measured</th><th>Set to";
} elsif($type eq "at") { $th = "Scheduled commands (at)";
} elsif($type eq "FileLog") { $th = "Logs";
} elsif($type eq "_internal_") { $th = "Global variables";
} elsif($type eq "weblink") { $th = ""; $id = "";
} else {
$th = $type;
@ -822,7 +827,7 @@ FW_showRoom()
pO " <tr><th>$th</th></tr>" if($th);
my $row=1;
foreach my $d (@sortedDevs) {
foreach my $d (@roomDevs) {
next if($FW_room && $FW_room ne "all" &&
!$FW_rooms{$FW_room}{$d});
@ -831,18 +836,13 @@ FW_showRoom()
my $v = $defs{$d}{STATE};
if($hasOnOff) {
my $iv = $v; # icon value
my $iname = "";
if(defined(AttrVal($d, "showtime", undef))) {
$v = $defs{$d}{READINGS}{state}{TIME};
} elsif($iv) {
$iname = FW_dev2image($d);
}
$v = "" if(!defined($v));
@ -858,8 +858,7 @@ FW_showRoom()
pH "cmd.$d=set $d off$rf", "off", 1;
}
} elsif($type eq "FHT") {
} elsif($allSets =~ m/ desired-temp /) {
$v = ReadingsVal($d, "measured-temp", "");
$v =~ s/ .*//;