mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-25 03:39:21 +00:00
00_TCM: changes see fhem forum
git-svn-id: https://svn.fhem.de/fhem/trunk@23338 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
11f62f2ca6
commit
f8b69f92c3
@ -1,4 +1,3 @@
|
|||||||
##############################################
|
|
||||||
# $Id$
|
# $Id$
|
||||||
|
|
||||||
# This modules handles the communication with a TCM 120 or TCM 310 / TCM 400J /
|
# This modules handles the communication with a TCM 120 or TCM 310 / TCM 400J /
|
||||||
@ -13,6 +12,10 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use DevIo;
|
use DevIo;
|
||||||
use Time::HiRes qw(gettimeofday usleep);
|
use Time::HiRes qw(gettimeofday usleep);
|
||||||
|
my $dupTimeout = 0.6;
|
||||||
|
my $modulesHash = \%modules;
|
||||||
|
my $modulesType = 'TCM';
|
||||||
|
|
||||||
sub TCM_Read($);
|
sub TCM_Read($);
|
||||||
sub TCM_ReadAnswer($$);
|
sub TCM_ReadAnswer($$);
|
||||||
sub TCM_Ready($);
|
sub TCM_Ready($);
|
||||||
@ -24,8 +27,7 @@ sub TCM_CSUM($);
|
|||||||
|
|
||||||
sub TCM_Initialize($) {
|
sub TCM_Initialize($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
# Provider
|
||||||
# Provider
|
|
||||||
$hash->{ReadFn} = "TCM_Read";
|
$hash->{ReadFn} = "TCM_Read";
|
||||||
$hash->{WriteFn} = "TCM_Write";
|
$hash->{WriteFn} = "TCM_Write";
|
||||||
$hash->{ReadyFn} = "TCM_Ready";
|
$hash->{ReadyFn} = "TCM_Ready";
|
||||||
@ -34,8 +36,7 @@ sub TCM_Initialize($) {
|
|||||||
"1:EnOcean" => "^EnOcean:",
|
"1:EnOcean" => "^EnOcean:",
|
||||||
);
|
);
|
||||||
$hash->{MatchList} = \%matchList;
|
$hash->{MatchList} = \%matchList;
|
||||||
|
# Normal devices
|
||||||
# Normal devices
|
|
||||||
$hash->{DefFn} = "TCM_Define";
|
$hash->{DefFn} = "TCM_Define";
|
||||||
$hash->{FingerprintFn} = "TCM_Fingerprint";
|
$hash->{FingerprintFn} = "TCM_Fingerprint";
|
||||||
$hash->{UndefFn} = "TCM_Undef";
|
$hash->{UndefFn} = "TCM_Undef";
|
||||||
@ -43,25 +44,22 @@ sub TCM_Initialize($) {
|
|||||||
$hash->{SetFn} = "TCM_Set";
|
$hash->{SetFn} = "TCM_Set";
|
||||||
$hash->{NotifyFn} = "TCM_Notify";
|
$hash->{NotifyFn} = "TCM_Notify";
|
||||||
$hash->{AttrFn} = "TCM_Attr";
|
$hash->{AttrFn} = "TCM_Attr";
|
||||||
$hash->{AttrList} = "baseID blockSenderID:own,no comModeUTE:auto,biDir,uniDir comType:TCM,RS485 do_not_notify:1,0 " .
|
$hash->{AttrList} = "assignIODev:select,no,yes baseID blockSenderID:own,no comModeUTE:auto,biDir,uniDir comType:TCM,RS485 do_not_notify:1,0 " .
|
||||||
"dummy:1,0 fingerprint:off,on learningDev:all,teachMsg learningMode:always,demand,nearfield " .
|
"dummy:1,0 fingerprint:off,on learningDev:all,teachMsg learningMode:always,demand,nearfield " .
|
||||||
"sendInterval:0,25,40,50,100,150,200,250 smartAckMailboxMax:slider,0,1,20 " .
|
"sendInterval:0,25,40,50,100,150,200,250 smartAckMailboxMax:slider,0,1,20 " .
|
||||||
"smartAckLearnMode:simple,advance,advanceSelectRep";
|
"smartAckLearnMode:simple,advance,advanceSelectRep";
|
||||||
|
$hash->{ShutdownFn} = "TCM_Shutdown";
|
||||||
$hash->{NotifyOrderPrefix} = "45-";
|
$hash->{NotifyOrderPrefix} = "45-";
|
||||||
}
|
}
|
||||||
|
|
||||||
# Define
|
# Define
|
||||||
sub TCM_Define($$){
|
sub TCM_Define($$) {
|
||||||
my ($hash, $def) = @_;
|
my ($hash, $def) = @_;
|
||||||
my @a = split("[ \t][ \t]*", $def);
|
my @a = split("[ \t][ \t]*", $def);
|
||||||
my $name = $a[0];
|
my $name = $a[0];
|
||||||
my $model = $a[2];
|
my $model = $a[2];
|
||||||
|
return "TCM: wrong syntax, correct is: define <name> TCM [ESP2|ESP3] {devicename[\@baudrate]|ip:port|none}"
|
||||||
return "TCM: wrong syntax, correct is: define <name> TCM [ESP2|ESP3] ".
|
if (@a != 4 || $model !~ m/^(ESP2|ESP3|120|310)$/);
|
||||||
"{devicename[\@baudrate]|ip:port|none}"
|
|
||||||
if(@a != 4 || $model !~ m/^(ESP2|ESP3|120|310)$/);
|
|
||||||
|
|
||||||
$hash->{NOTIFYDEV} = "global";
|
|
||||||
DevIo_CloseDev($hash);
|
DevIo_CloseDev($hash);
|
||||||
my $dev = $a[3];
|
my $dev = $a[3];
|
||||||
$hash->{DeviceName} = $dev;
|
$hash->{DeviceName} = $dev;
|
||||||
@ -71,8 +69,10 @@ sub TCM_Define($$){
|
|||||||
$hash->{MODEL} = $model;
|
$hash->{MODEL} = $model;
|
||||||
$hash->{BaseID} = "00000000";
|
$hash->{BaseID} = "00000000";
|
||||||
$hash->{LastID} = "00000000";
|
$hash->{LastID} = "00000000";
|
||||||
|
$hash->{NOTIFYDEV} = "global";
|
||||||
|
$modules{$modulesType}{devHash}{$name} = $hash;
|
||||||
if($dev eq "none") {
|
if($dev eq "none") {
|
||||||
Log3 undef, 1, "TCM $name device is none, commands will be echoed only";
|
Log3 $name, 1, "TCM $name device is none, commands will be echoed only";
|
||||||
$attr{$name}{dummy} = 1;
|
$attr{$name}{dummy} = 1;
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
@ -134,18 +134,27 @@ sub TCM_InitSerialCom($) {
|
|||||||
} elsif ($comType ne "RS485" && $hash->{DeviceName} ne "none") {
|
} elsif ($comType ne "RS485" && $hash->{DeviceName} ne "none") {
|
||||||
my @getBaseID = ("get", "baseID");
|
my @getBaseID = ("get", "baseID");
|
||||||
if (TCM_Get($hash, @getBaseID) =~ /[Ff]{2}[\dA-Fa-f]{6}/) {
|
if (TCM_Get($hash, @getBaseID) =~ /[Ff]{2}[\dA-Fa-f]{6}/) {
|
||||||
$hash->{BaseID} = sprintf "%08X", hex $&;
|
$baseID = sprintf "%08X", hex $&;
|
||||||
|
$hash->{BaseID} = $baseID;
|
||||||
$hash->{LastID} = sprintf "%08X", (hex $&) + 127;
|
$hash->{LastID} = sprintf "%08X", (hex $&) + 127;
|
||||||
} else {
|
} else {
|
||||||
$hash->{BaseID} = "00000000";
|
$baseID = '0' x 8;
|
||||||
$hash->{LastID} = "00000000";
|
$hash->{BaseID} = $baseID;
|
||||||
|
$hash->{LastID} = '0' x 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#push(@{$modules{"$hash->{TYPE}"}{BaseID}}, 'F' x 8);
|
||||||
|
push(@{$modules{"$hash->{TYPE}"}{BaseID}}, $baseID) if (!grep(/^$baseID$/, @{$modules{"$hash->{TYPE}"}{BaseID}}));
|
||||||
|
#push(@{$modules{"$hash->{TYPE}"}{BaseID}}, '0' x 8);
|
||||||
|
@{$hash->{helper}{BaseID}} = @{$modules{"$hash->{TYPE}"}{BaseID}};
|
||||||
if ($hash->{MODEL} eq "ESP3" && $comType ne "RS485" && $hash->{DeviceName} ne "none") {
|
if ($hash->{MODEL} eq "ESP3" && $comType ne "RS485" && $hash->{DeviceName} ne "none") {
|
||||||
# get chipID
|
# get chipID
|
||||||
my @getChipID = ('get', 'version');
|
my @getChipID = ('get', 'version');
|
||||||
if (TCM_Get($hash, @getChipID) =~ m/ChipID:.([\dA-Fa-f]{8})/) {
|
if (TCM_Get($hash, @getChipID) =~ m/ChipID:.([\dA-Fa-f]{8})/) {
|
||||||
$hash->{ChipID} = sprintf "%08X", hex $1;
|
my $chipID = sprintf "%08X", hex $1;
|
||||||
|
$hash->{ChipID} = $chipID;
|
||||||
|
push(@{$modules{"$hash->{TYPE}"}{ChipID}}, $hash->{ChipID}) if (!grep(/^$chipID$/, @{$modules{"$hash->{TYPE}"}{ChipID}}));
|
||||||
|
@{$hash->{helper}{ChipID}} = @{$modules{"$hash->{TYPE}"}{ChipID}};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# default transceiver parameter
|
# default transceiver parameter
|
||||||
@ -192,37 +201,53 @@ sub TCM_Fingerprint($$) {
|
|||||||
my ($IODev, $msg) = @_;
|
my ($IODev, $msg) = @_;
|
||||||
return ($IODev, $msg) if (AttrVal($IODev, "fingerprint", 'off') eq 'off');
|
return ($IODev, $msg) if (AttrVal($IODev, "fingerprint", 'off') eq 'off');
|
||||||
my @msg = split(":", $msg);
|
my @msg = split(":", $msg);
|
||||||
|
|
||||||
if ($msg[1] == 1) {
|
if ($msg[1] == 1) {
|
||||||
|
# RADIO_ERP1
|
||||||
#EnOcean:PacketType:RORG:MessageData:SourceID:Status:OptionalData
|
#EnOcean:PacketType:RORG:MessageData:SourceID:Status:OptionalData
|
||||||
substr($msg[5], 1, 1, "0");
|
substr($msg[5], 1, 1, "0");
|
||||||
substr($msg[6], 0, 2, "01");
|
substr($msg[6], 0, 2, "01");
|
||||||
substr($msg[6], 10, 4, "0000");
|
substr($msg[6], 10, 4, "0000");
|
||||||
|
|
||||||
} elsif ($msg[1] == 2) {
|
} elsif ($msg[1] == 2) {
|
||||||
|
# RESPONSE
|
||||||
#EnOcean:PacketType:ResposeCode:MessageData:OptionalData
|
#EnOcean:PacketType:ResposeCode:MessageData:OptionalData
|
||||||
|
# no dispatch
|
||||||
|
|
||||||
} elsif ($msg[1] == 3) {
|
} elsif ($msg[1] == 3) {
|
||||||
|
# RADIO_SUB_TEL
|
||||||
|
# no dispatch
|
||||||
|
|
||||||
} elsif ($msg[1] == 4) {
|
} elsif ($msg[1] == 4) {
|
||||||
|
# EVENT
|
||||||
#EnOcean:PacketType:eventCode:MessageData
|
#EnOcean:PacketType:eventCode:MessageData
|
||||||
|
# no manipulation of the data necessary
|
||||||
|
|
||||||
} elsif ($msg[1] == 5) {
|
} elsif ($msg[1] == 5) {
|
||||||
|
# COMMON_COMMAND
|
||||||
|
# no dispatch
|
||||||
|
|
||||||
} elsif ($msg[1] == 6) {
|
} elsif ($msg[1] == 6) {
|
||||||
|
# SMART_ACK_COMMAND
|
||||||
#EnOcean:PacketType:smartAckCode:MessageData
|
#EnOcean:PacketType:smartAckCode:MessageData
|
||||||
|
# no manipulation of the data necessary
|
||||||
|
|
||||||
} elsif ($msg[1] == 7) {
|
} elsif ($msg[1] == 7) {
|
||||||
|
# REMOTE_MAN_COMMAND
|
||||||
#EnOcean:PacketType:RORG:MessageData:SourceID:DestinationID:FunctionNumber:ManufacturerID:RSSI:Delay
|
#EnOcean:PacketType:RORG:MessageData:SourceID:DestinationID:FunctionNumber:ManufacturerID:RSSI:Delay
|
||||||
substr($msg[8], 0, 2, "00");
|
substr($msg[8], 0, 2, "00");
|
||||||
substr($msg[9], 0, 2, "00");
|
substr($msg[9], 0, 2, "00");
|
||||||
|
|
||||||
} elsif ($msg[1] == 9) {
|
} elsif ($msg[1] == 9) {
|
||||||
|
# RADIO_MESSAGE
|
||||||
|
# no dispatch
|
||||||
|
|
||||||
} elsif ($msg[1] == 10) {
|
} elsif ($msg[1] == 10) {
|
||||||
|
# RADIO_ERP2
|
||||||
|
# no dispatch
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$msg = join(":", @msg);
|
$msg = join(":", @msg);
|
||||||
#Log3 $IODev, 2, "TCM $IODev <TCM_Fingerprint> PacketType: $msg[1] Data: $msg";
|
#Log3 $IODev, 2, "TCM $IODev <TCM_Fingerprint> PacketType: $msg[1] Data: $msg";
|
||||||
return ($IODev, $msg);
|
return ($IODev, $msg);
|
||||||
@ -296,12 +321,9 @@ sub TCM_Write($$$$) {
|
|||||||
|
|
||||||
# ESP2 CRC
|
# ESP2 CRC
|
||||||
# Used in the TCM120
|
# Used in the TCM120
|
||||||
sub
|
sub TCM_CSUM($) {
|
||||||
TCM_CSUM($)
|
|
||||||
{
|
|
||||||
my $msg = shift;
|
my $msg = shift;
|
||||||
my $ml = length($msg);
|
my $ml = length($msg);
|
||||||
|
|
||||||
my @data;
|
my @data;
|
||||||
for(my $i = 0; $i < $ml; $i += 2) {
|
for(my $i = 0; $i < $ml; $i += 2) {
|
||||||
push(@data, ord(pack('H*', substr($msg, $i, 2))));
|
push(@data, ord(pack('H*', substr($msg, $i, 2))));
|
||||||
@ -336,12 +358,9 @@ my @u8CRC8Table = (
|
|||||||
|
|
||||||
# ESP3 CRC
|
# ESP3 CRC
|
||||||
# Used in the TCM310
|
# Used in the TCM310
|
||||||
sub
|
sub TCM_CRC8($) {
|
||||||
TCM_CRC8($)
|
|
||||||
{
|
|
||||||
my $msg = shift;
|
my $msg = shift;
|
||||||
my $ml = length($msg);
|
my $ml = length($msg);
|
||||||
|
|
||||||
my @data;
|
my @data;
|
||||||
for(my $i = 0; $i < $ml; $i += 2) {
|
for(my $i = 0; $i < $ml; $i += 2) {
|
||||||
push(@data, ord(pack('H*', substr($msg, $i, 2))));
|
push(@data, ord(pack('H*', substr($msg, $i, 2))));
|
||||||
@ -353,17 +372,12 @@ TCM_CRC8($)
|
|||||||
|
|
||||||
# Read
|
# Read
|
||||||
# called from the global loop, when the select for hash->{FD} reports data
|
# called from the global loop, when the select for hash->{FD} reports data
|
||||||
sub
|
sub TCM_Read($) {
|
||||||
TCM_Read($)
|
|
||||||
{
|
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
my $buf = DevIo_SimpleRead($hash);
|
my $buf = DevIo_SimpleRead($hash);
|
||||||
return "" if(!defined($buf));
|
return "" if(!defined($buf));
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $blockSenderID = AttrVal($name, "blockSenderID", "own");
|
my $blockSenderID = AttrVal($name, "blockSenderID", "own");
|
||||||
my $chipID = exists($hash->{ChipID}) ? hex $hash->{ChipID} : 0;
|
|
||||||
my $baseID = exists($hash->{BaseID}) ? hex $hash->{BaseID} : 0;
|
|
||||||
my $lastID = exists($hash->{LastID}) ? hex $hash->{LastID} : 0;
|
|
||||||
my $data = $hash->{PARTIAL} . uc(unpack('H*', $buf));
|
my $data = $hash->{PARTIAL} . uc(unpack('H*', $buf));
|
||||||
Log3 $name, 5, "TCM $name received ESP: $data";
|
Log3 $name, 5, "TCM $name received ESP: $data";
|
||||||
|
|
||||||
@ -396,9 +410,7 @@ TCM_Read($)
|
|||||||
# extract db_0
|
# extract db_0
|
||||||
$d1 = substr($d1, 0, 2);
|
$d1 = substr($d1, 0, 2);
|
||||||
}
|
}
|
||||||
if ($blockSenderID eq "own" && ((hex($id) >= $baseID && hex($id) <= $lastID) || $chipID == hex($id))) {
|
if (!defined TCM_BlockSenderID($hash, $blockSenderID, $id)) {
|
||||||
Log3 $name, 4, "TCM $name own telegram from $id blocked.";
|
|
||||||
} else {
|
|
||||||
Dispatch($hash, "EnOcean:$packetType:$org:$d1:$id:$status:01FFFFFFFF0000", undef) if (exists $hash->{helper}{init_done});
|
Dispatch($hash, "EnOcean:$packetType:$org:$d1:$id:$status:01FFFFFFFF0000", undef) if (exists $hash->{helper}{init_done});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,9 +431,7 @@ TCM_Read($)
|
|||||||
# extract db_0
|
# extract db_0
|
||||||
$d1 = substr($d1, 0, 2);
|
$d1 = substr($d1, 0, 2);
|
||||||
}
|
}
|
||||||
if ($blockSenderID eq "own" && ((hex($id) >= $baseID && hex($id) <= $lastID) || $chipID == hex($id))) {
|
if (!defined TCM_BlockSenderID($hash, $blockSenderID, $id)) {
|
||||||
Log3 $name, 4, "TCM $name own telegram from $id blocked.";
|
|
||||||
} else {
|
|
||||||
Dispatch($hash, "EnOcean:$packetType:$org:$d1:$id:$status:01FFFFFFFF0000", undef) if (exists $hash->{helper}{init_done});
|
Dispatch($hash, "EnOcean:$packetType:$org:$d1:$id:$status:01FFFFFFFF0000", undef) if (exists $hash->{helper}{init_done});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -483,9 +493,7 @@ TCM_Read($)
|
|||||||
);
|
);
|
||||||
$hash->{RSSI} = -$RSSI;
|
$hash->{RSSI} = -$RSSI;
|
||||||
|
|
||||||
if ($blockSenderID eq "own" && ((hex($id) >= $baseID && hex($id) <= $lastID) || $chipID == hex($id))) {
|
if (!defined TCM_BlockSenderID($hash, $blockSenderID, $id)) {
|
||||||
Log3 $name, 4, "TCM $name own telegram from $id blocked.";
|
|
||||||
} else {
|
|
||||||
#EnOcean:PacketType:RORG:MessageData:SourceID:Status:OptionalData
|
#EnOcean:PacketType:RORG:MessageData:SourceID:Status:OptionalData
|
||||||
Dispatch($hash, "EnOcean:$packetType:$org:$d1:$id:$status:$odata", \%addvals) if (exists $hash->{helper}{init_done});
|
Dispatch($hash, "EnOcean:$packetType:$org:$d1:$id:$status:$odata", \%addvals) if (exists $hash->{helper}{init_done});
|
||||||
}
|
}
|
||||||
@ -587,9 +595,7 @@ TCM_Read($)
|
|||||||
$hash->{RSSI} = -hex($RSSI);
|
$hash->{RSSI} = -hex($RSSI);
|
||||||
$packetType = sprintf "%01X", $packetType;
|
$packetType = sprintf "%01X", $packetType;
|
||||||
|
|
||||||
if ($blockSenderID eq "own" && ((hex($2) >= $baseID && hex($2) <= $lastID) || $chipID == hex($2))) {
|
if (!defined TCM_BlockSenderID($hash, $blockSenderID, $2)) {
|
||||||
Log3 $name, 4, "TCM $name own telegram from $2 blocked.";
|
|
||||||
} else {
|
|
||||||
#EnOcean:PacketType:RORG:MessageData:SourceID:DestinationID:FunctionNumber:ManufacturerID:RSSI:Delay
|
#EnOcean:PacketType:RORG:MessageData:SourceID:DestinationID:FunctionNumber:ManufacturerID:RSSI:Delay
|
||||||
Dispatch($hash, "EnOcean:$packetType:C5:$messageData:$2:$1:$function:$manufID:$RSSI:$4", \%addvals) if (exists $hash->{helper}{init_done});
|
Dispatch($hash, "EnOcean:$packetType:C5:$messageData:$2:$1:$function:$manufID:$RSSI:$4", \%addvals) if (exists $hash->{helper}{init_done});
|
||||||
}
|
}
|
||||||
@ -599,7 +605,7 @@ TCM_Read($)
|
|||||||
Log3 $name, 2, "TCM: $name packet type RADIO_MESSAGE not supported: $data";
|
Log3 $name, 2, "TCM: $name packet type RADIO_MESSAGE not supported: $data";
|
||||||
|
|
||||||
} elsif ($packetType == 10) {
|
} elsif ($packetType == 10) {
|
||||||
# packet type RADIO_ADVANCED
|
# packet type RADIO_ERP2
|
||||||
Log3 $name, 2, "TCM $name packet type RADIO_ADVANCED not supported: $data";
|
Log3 $name, 2, "TCM $name packet type RADIO_ADVANCED not supported: $data";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -690,7 +696,7 @@ TCM_Parse310($$$)
|
|||||||
{
|
{
|
||||||
my ($hash,$rawmsg,$ptr) = @_;
|
my ($hash,$rawmsg,$ptr) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
Log3 $name, 5, "TCM_Parse $rawmsg";
|
Log3 $name, 5, "TCM $name TCM_Parse $rawmsg";
|
||||||
my $rc = substr($rawmsg, 0, 2);
|
my $rc = substr($rawmsg, 0, 2);
|
||||||
my $msg = "";
|
my $msg = "";
|
||||||
if($rc ne "00") {
|
if($rc ne "00") {
|
||||||
@ -755,10 +761,14 @@ TCM_Parse310($$$)
|
|||||||
# Ready
|
# Ready
|
||||||
sub TCM_Ready($) {
|
sub TCM_Ready($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
my $ret;
|
||||||
return DevIo_OpenDev($hash, 1, undef)
|
if ($hash->{STATE} eq "disconnected") {
|
||||||
# if($hash->{STATE} ne "opened");
|
#if($hash->{STATE} ne "opened") {
|
||||||
if($hash->{STATE} eq "disconnected");
|
$ret = DevIo_OpenDev($hash, 1, undef);
|
||||||
|
return $ret if (defined $ret);
|
||||||
|
TCM_InitSerialCom($hash) if (DevIo_IsOpen($hash));
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
# This is relevant for windows/USB only
|
# This is relevant for windows/USB only
|
||||||
my $po = $hash->{USBDev};
|
my $po = $hash->{USBDev};
|
||||||
@ -793,9 +803,7 @@ my %gets310 = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
# Get
|
# Get
|
||||||
sub
|
sub TCM_Get($@) {
|
||||||
TCM_Get($@)
|
|
||||||
{
|
|
||||||
my ($hash, @a) = @_;
|
my ($hash, @a) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
return if (AttrVal($name, "comType", "TCM") eq "RS485" || $hash->{DeviceName} eq "none");
|
return if (AttrVal($name, "comType", "TCM") eq "RS485" || $hash->{DeviceName} eq "none");
|
||||||
@ -816,8 +824,15 @@ TCM_Get($@)
|
|||||||
} else {
|
} else {
|
||||||
# TCM 310
|
# TCM 310
|
||||||
my $cmdhash = $gets310{$cmd};
|
my $cmdhash = $gets310{$cmd};
|
||||||
return "Unknown argument $cmd, choose one of " . join(':noArg ', sort keys %gets310) . ':noArg' if(!defined($cmdhash));
|
if (!defined($cmdhash) && $cmd !~ m/^getFreeID|getUsedID$/) {
|
||||||
|
return "Unknown argument $cmd, choose one of getFreeID:noArg getUsedID:noArg " . join(':noArg ', sort keys %gets310) . ':noArg';
|
||||||
|
}
|
||||||
Log3 $name, 3, "TCM $name get $cmd";
|
Log3 $name, 3, "TCM $name get $cmd";
|
||||||
|
if ($cmd eq 'getFreeID') {
|
||||||
|
$msg = substr(EnOcean_CheckSenderID('getFreeID', $name, 8 x '0'), 1);
|
||||||
|
} elsif ($cmd eq 'getUsedID') {
|
||||||
|
$msg = EnOcean_CheckSenderID('getUsedID', $name, 8 x '0');
|
||||||
|
} else {
|
||||||
my $cmdHex = $cmdhash->{cmd};
|
my $cmdHex = $cmdhash->{cmd};
|
||||||
my $oCmdHex = '';
|
my $oCmdHex = '';
|
||||||
$oCmdHex = $cmdhash->{oCmd} if (exists $cmdhash->{oCmd});
|
$oCmdHex = $cmdhash->{oCmd} if (exists $cmdhash->{oCmd});
|
||||||
@ -826,10 +841,10 @@ TCM_Get($@)
|
|||||||
TCM_Write($hash, $hash, sprintf("%04X%02X%02X", length($cmdHex)/2, length($oCmdHex)/2, $cmdhash->{packetType}), $cmdHex . $oCmdHex);
|
TCM_Write($hash, $hash, sprintf("%04X%02X%02X", length($cmdHex)/2, length($oCmdHex)/2, $cmdhash->{packetType}), $cmdHex . $oCmdHex);
|
||||||
($err, $msg) = TCM_ReadAnswer($hash, "get $cmd");
|
($err, $msg) = TCM_ReadAnswer($hash, "get $cmd");
|
||||||
$msg = TCM_Parse310($hash, $msg, $cmdhash) if(!$err);
|
$msg = TCM_Parse310($hash, $msg, $cmdhash) if(!$err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if($err) {
|
if($err) {
|
||||||
Log3 undef, 2, "TCM $name $err";
|
Log3 $name, 2, "TCM $name $err";
|
||||||
return $err;
|
return $err;
|
||||||
}
|
}
|
||||||
readingsSingleUpdate($hash, $cmd, $msg, 1);
|
readingsSingleUpdate($hash, $cmd, $msg, 1);
|
||||||
@ -837,17 +852,20 @@ TCM_Get($@)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# clear teach in flag
|
# clear teach in flag
|
||||||
sub TCM_ClearTeach($)
|
sub TCM_ClearTeach($) {
|
||||||
{
|
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
delete($hash->{Teach});
|
foreach my $iName (keys %defs) {
|
||||||
|
delete $defs{$iName}{Teach} if ($defs{$iName}{TYPE} eq 'TCM');
|
||||||
|
}
|
||||||
|
#delete($hash->{Teach});
|
||||||
|
delete($modules{"$hash->{TYPE}"}{Teach});
|
||||||
}
|
}
|
||||||
|
|
||||||
# clear Smart ACK teach in flag
|
# clear Smart ACK teach in flag
|
||||||
sub TCM_ClearSmartAckLearn($)
|
sub TCM_ClearSmartAckLearn($) {
|
||||||
{
|
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
delete($hash->{SmartAckLearn});
|
delete($hash->{SmartAckLearn});
|
||||||
|
delete($modules{"$hash->{TYPE}"}{SmartAckLearn});
|
||||||
readingsSingleUpdate($hash, "smartAckLearnMode", "Enable: 00 Extended: 00", 1);
|
readingsSingleUpdate($hash, "smartAckLearnMode", "Enable: 00 Extended: 00", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -890,8 +908,7 @@ my %sets310 = (
|
|||||||
);
|
);
|
||||||
|
|
||||||
# Set
|
# Set
|
||||||
sub TCM_Set($@)
|
sub TCM_Set($@) {
|
||||||
{
|
|
||||||
my ($hash, @a) = @_;
|
my ($hash, @a) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
return if (AttrVal($name, "comType", "TCM") eq "RS485" || $hash->{DeviceName} eq "none");
|
return if (AttrVal($name, "comType", "TCM") eq "RS485" || $hash->{DeviceName} eq "none");
|
||||||
@ -940,12 +957,22 @@ sub TCM_Set($@)
|
|||||||
if($cmd eq "teach") {
|
if($cmd eq "teach") {
|
||||||
if ($arg == 0) {
|
if ($arg == 0) {
|
||||||
RemoveInternalTimer($hash, "TCM_ClearTeach");
|
RemoveInternalTimer($hash, "TCM_ClearTeach");
|
||||||
delete $hash->{Teach};
|
while (my ($iDev, $iHash) = each (%{$modules{"$hash->{TYPE}"}{devHash}})) {
|
||||||
|
Log3 $name, 3, "TCM $name clear Teach flag ioDev: $iDev ioHash: $iHash ioDevName: " . $defs{"$iHash->{NAME}"}->{NAME};
|
||||||
|
delete $defs{"$iHash->{NAME}"}->{Teach};
|
||||||
|
}
|
||||||
|
delete $modules{"$hash->{TYPE}"}{Teach};
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
while (my ($iDev, $iHash) = each (%{$modules{"$hash->{TYPE}"}{devHash}})) {
|
||||||
|
#Log3 $name, 2, "TCM $name clear Teach flag ioDev: $iDev ioHash: $iHash ioDevName: " . $defs{"$iHash->{NAME}"}->{NAME};
|
||||||
|
delete $defs{"$iHash->{NAME}"}->{Teach};
|
||||||
|
}
|
||||||
|
$hash->{Teach} = 1;
|
||||||
|
$modules{"$hash->{TYPE}"}{Teach} = $hash;
|
||||||
|
#Log3 $name, 2, "TCM $name set Teach flag ioHash: " . $modules{"$hash->{TYPE}"}{Teach};
|
||||||
RemoveInternalTimer($hash, "TCM_ClearTeach");
|
RemoveInternalTimer($hash, "TCM_ClearTeach");
|
||||||
InternalTimer(gettimeofday() + $arg, "TCM_ClearTeach", $hash, 1);
|
InternalTimer(gettimeofday() + $arg, "TCM_ClearTeach", $hash, 1);
|
||||||
$hash->{Teach} = 1;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -984,16 +1011,19 @@ sub TCM_Set($@)
|
|||||||
# end Smart ACK learnmode
|
# end Smart ACK learnmode
|
||||||
RemoveInternalTimer($hash, "TCM_ClearSmartAckLearn");
|
RemoveInternalTimer($hash, "TCM_ClearSmartAckLearn");
|
||||||
delete $hash->{SmartAckLearn};
|
delete $hash->{SmartAckLearn};
|
||||||
|
delete $modules{"$hash->{TYPE}"}{SmartAckLearn};
|
||||||
} else {
|
} else {
|
||||||
RemoveInternalTimer($hash, "TCM_ClearSmartAckLearn");
|
RemoveInternalTimer($hash, "TCM_ClearSmartAckLearn");
|
||||||
InternalTimer(gettimeofday() + hex(substr($arg, 4, 8)) * 0.001, "TCM_ClearSmartAckLearn", $hash, 1);
|
InternalTimer(gettimeofday() + hex(substr($arg, 4, 8)) * 0.001, "TCM_ClearSmartAckLearn", $hash, 1);
|
||||||
$hash->{SmartAckLearn} = 1;
|
$hash->{SmartAckLearn} = 1;
|
||||||
|
$modules{"$hash->{TYPE}"}{SmartAckLearn} = $hash;
|
||||||
|
Log3 $name, 3, "TCM $name set SmartAckLearn flag ioHash: " . $modules{"$hash->{TYPE}"}{SmartAckLearn};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if($err) {
|
if($err) {
|
||||||
Log3 undef, 2, "TCM $name $err";
|
Log3 $name, 2, "TCM $name $err";
|
||||||
return $err;
|
return $err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1010,15 +1040,11 @@ sub TCM_Set($@)
|
|||||||
}
|
}
|
||||||
|
|
||||||
# read command response data
|
# read command response data
|
||||||
sub TCM_ReadAnswer($$)
|
sub TCM_ReadAnswer($$) {
|
||||||
{
|
|
||||||
my ($hash, $arg) = @_;
|
my ($hash, $arg) = @_;
|
||||||
return ("No FD", undef) if(!$hash || ($^O !~ /Win/ && !defined($hash->{FD})));
|
return ("No FD", undef) if(!$hash || ($^O !~ /Win/ && !defined($hash->{FD})));
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $blockSenderID = AttrVal($name, "blockSenderID", "own");
|
my $blockSenderID = AttrVal($name, "blockSenderID", "own");
|
||||||
my $chipID = exists($hash->{ChipID}) ? hex $hash->{ChipID} : 0;
|
|
||||||
my $baseID = exists($hash->{BaseID}) ? hex $hash->{BaseID} : 0;
|
|
||||||
my $lastID = exists($hash->{LastID}) ? hex $hash->{LastID} : 0;
|
|
||||||
my ($data, $rin, $buf) = ($hash->{PARTIAL}, "", "");
|
my ($data, $rin, $buf) = ($hash->{PARTIAL}, "", "");
|
||||||
# 2 seconds timeout
|
# 2 seconds timeout
|
||||||
my $to = 2;
|
my $to = 2;
|
||||||
@ -1141,9 +1167,7 @@ sub TCM_ReadAnswer($$)
|
|||||||
);
|
);
|
||||||
$hash->{RSSI} = -$RSSI;
|
$hash->{RSSI} = -$RSSI;
|
||||||
|
|
||||||
if ($blockSenderID eq "own" && ((hex($id) >= $baseID && hex($id) <= $lastID) || $chipID == hex($id))) {
|
if (!defined TCM_BlockSenderID($hash, $blockSenderID, $id)) {
|
||||||
Log3 $name, 4, "TCM $name own telegram from $id blocked.";
|
|
||||||
} else {
|
|
||||||
#EnOcean:PacketType:RORG:MessageData:SourceID:Status:OptionalData
|
#EnOcean:PacketType:RORG:MessageData:SourceID:Status:OptionalData
|
||||||
Dispatch($hash, "EnOcean:$packetType:$org:$d1:$id:$status:$odata", \%addvals) if (exists $hash->{helper}{init_done});
|
Dispatch($hash, "EnOcean:$packetType:$org:$d1:$id:$status:$odata", \%addvals) if (exists $hash->{helper}{init_done});
|
||||||
}
|
}
|
||||||
@ -1220,6 +1244,25 @@ sub TCM_ReadAnswer($$)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub TCM_BlockSenderID($$$) {
|
||||||
|
my ($hash, $blockSenderID, $senderID) = @_;
|
||||||
|
return undef if ($blockSenderID eq 'no');
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
foreach (@{$modules{"$hash->{TYPE}"}{BaseID}}) {
|
||||||
|
if (hex($_) == (hex($senderID) & 0xFFFFFF80)) {
|
||||||
|
Log3 $name, 4, "TCM $name received own telegram from SenderID $senderID blocked.";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (@{$modules{"$hash->{TYPE}"}{ChipID}}) {
|
||||||
|
if (hex($_) == hex($senderID)) {
|
||||||
|
Log3 $name, 4, "TCM $name received own telegram from $senderID blocked.";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
sub TCM_Attr(@) {
|
sub TCM_Attr(@) {
|
||||||
my ($cmd, $name, $attrName, $attrVal) = @_;
|
my ($cmd, $name, $attrName, $attrVal) = @_;
|
||||||
@ -1227,25 +1270,44 @@ sub TCM_Attr(@) {
|
|||||||
# return if attribute list is incomplete
|
# return if attribute list is incomplete
|
||||||
return undef if (!$init_done);
|
return undef if (!$init_done);
|
||||||
|
|
||||||
if ($attrName eq "blockSenderID") {
|
if ($attrName eq "assignIODev") {
|
||||||
if (!defined $attrVal) {
|
if (!defined $attrVal) {
|
||||||
|
if (exists $modules{TCM}{assignIODev}) {
|
||||||
} elsif ($attrVal !~ m/^own|no$/) {
|
delete($modules{TCM}{assignIODev}) if ($modules{TCM}{assignIODev} eq $hash);
|
||||||
Log3 $name, 2, "EnOcean $name attribute-value [$attrName] = $attrVal wrong";
|
}
|
||||||
|
} elsif ($attrVal eq 'no') {
|
||||||
|
if (exists $modules{TCM}{assignIODev}) {
|
||||||
|
delete($modules{TCM}{assignIODev}) if ($modules{TCM}{assignIODev} eq $hash);
|
||||||
|
}
|
||||||
|
} elsif ($attrVal eq 'yes') {
|
||||||
|
$modules{TCM}{assignIODev} = $hash;
|
||||||
|
} else {
|
||||||
|
Log3 $name, 2, "TCM $name attribute-value [$attrName] = $attrVal wrong";
|
||||||
CommandDeleteAttr(undef, "$name $attrName");
|
CommandDeleteAttr(undef, "$name $attrName");
|
||||||
|
if (exists $modules{TCM}{assignIODev}) {
|
||||||
|
delete($modules{TCM}{assignIODev}) if ($modules{TCM}{assignIODev} eq $hash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} elsif ($attrName eq "baseID") {
|
} elsif ($attrName eq "baseID") {
|
||||||
if (!defined $attrVal){
|
if (!defined $attrVal){
|
||||||
|
|
||||||
} elsif ($attrVal !~ m/^[Ff]{2}[\dA-Fa-f]{6}$/) {
|
} elsif ($attrVal !~ m/^[Ff]{2}[\dA-Fa-f]{6}$/) {
|
||||||
Log3 $name, 2, "EnOcean $name attribute-value [$attrName] = $attrVal wrong";
|
Log3 $name, 2, "TCM $name attribute-value [$attrName] = $attrVal wrong";
|
||||||
CommandDeleteAttr(undef, "$name $attrName");
|
CommandDeleteAttr(undef, "$name $attrName");
|
||||||
} else {
|
} else {
|
||||||
$hash->{BaseID} = $attrVal;
|
$hash->{BaseID} = $attrVal;
|
||||||
$hash->{LastID} = sprintf "%08X", (hex $attrVal) + 127;
|
$hash->{LastID} = sprintf "%08X", (hex $attrVal) + 127;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} elsif ($attrName eq "blockSenderID") {
|
||||||
|
if (!defined $attrVal) {
|
||||||
|
|
||||||
|
} elsif ($attrVal !~ m/^own|no$/) {
|
||||||
|
Log3 $name, 2, "TCM $name attribute-value [$attrName] = $attrVal wrong";
|
||||||
|
CommandDeleteAttr(undef, "$name $attrName");
|
||||||
|
}
|
||||||
|
|
||||||
} elsif ($attrName eq "comModeUTE") {
|
} elsif ($attrName eq "comModeUTE") {
|
||||||
if (!defined $attrVal){
|
if (!defined $attrVal){
|
||||||
|
|
||||||
@ -1258,7 +1320,7 @@ sub TCM_Attr(@) {
|
|||||||
if (!defined $attrVal){
|
if (!defined $attrVal){
|
||||||
|
|
||||||
} elsif ($attrVal !~ m/^TCM|RS485$/) {
|
} elsif ($attrVal !~ m/^TCM|RS485$/) {
|
||||||
Log3 $name, 2, "EnOcean $name attribute-value [$attrName] = $attrVal wrong";
|
Log3 $name, 2, "TCM $name attribute-value [$attrName] = $attrVal wrong";
|
||||||
CommandDeleteAttr(undef, "$name $attrName");
|
CommandDeleteAttr(undef, "$name $attrName");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1266,7 +1328,7 @@ sub TCM_Attr(@) {
|
|||||||
if (!defined $attrVal){
|
if (!defined $attrVal){
|
||||||
|
|
||||||
} elsif ($attrVal !~ m/^off|on$/) {
|
} elsif ($attrVal !~ m/^off|on$/) {
|
||||||
Log3 $name, 2, "EnOcean $name attribute-value [$attrName] = $attrVal wrong";
|
Log3 $name, 2, "TCM $name attribute-value [$attrName] = $attrVal wrong";
|
||||||
CommandDeleteAttr(undef, "$name $attrName");
|
CommandDeleteAttr(undef, "$name $attrName");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1274,7 +1336,7 @@ sub TCM_Attr(@) {
|
|||||||
if (!defined $attrVal){
|
if (!defined $attrVal){
|
||||||
|
|
||||||
} elsif ($attrVal !~ m/^all|teachMsg$/) {
|
} elsif ($attrVal !~ m/^all|teachMsg$/) {
|
||||||
Log3 $name, 2, "EnOcean $name attribute-value [$attrName] = $attrVal wrong";
|
Log3 $name, 2, "TCM $name attribute-value [$attrName] = $attrVal wrong";
|
||||||
CommandDeleteAttr(undef, "$name $attrName");
|
CommandDeleteAttr(undef, "$name $attrName");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1282,7 +1344,7 @@ sub TCM_Attr(@) {
|
|||||||
if (!defined $attrVal){
|
if (!defined $attrVal){
|
||||||
|
|
||||||
} elsif ($attrVal !~ m/^always|demand|nearfield$/) {
|
} elsif ($attrVal !~ m/^always|demand|nearfield$/) {
|
||||||
Log3 $name, 2, "EnOcean $name attribute-value [$attrName] = $attrVal wrong";
|
Log3 $name, 2, "TCM $name attribute-value [$attrName] = $attrVal wrong";
|
||||||
CommandDeleteAttr(undef, "$name $attrName");
|
CommandDeleteAttr(undef, "$name $attrName");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1290,7 +1352,7 @@ sub TCM_Attr(@) {
|
|||||||
if (!defined $attrVal){
|
if (!defined $attrVal){
|
||||||
|
|
||||||
} elsif (($attrVal + 0) < 0 || ($attrVal + 0) > 250) {
|
} elsif (($attrVal + 0) < 0 || ($attrVal + 0) > 250) {
|
||||||
Log3 $name, 2, "EnOcean $name attribute-value [$attrName] = $attrVal wrong or out of range";
|
Log3 $name, 2, "TCM $name attribute-value [$attrName] = $attrVal wrong or out of range";
|
||||||
CommandDeleteAttr(undef, "$name $attrName");
|
CommandDeleteAttr(undef, "$name $attrName");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1298,7 +1360,7 @@ sub TCM_Attr(@) {
|
|||||||
if (!defined $attrVal){
|
if (!defined $attrVal){
|
||||||
|
|
||||||
} elsif ($attrVal !~ m/^simple|advance|advanceSelectRep$/) {
|
} elsif ($attrVal !~ m/^simple|advance|advanceSelectRep$/) {
|
||||||
Log3 $name, 2, "EnOcean $name attribute-value [$attrName] = $attrVal wrong";
|
Log3 $name, 2, "TCM $name attribute-value [$attrName] = $attrVal wrong";
|
||||||
CommandDeleteAttr(undef, "$name $attrName");
|
CommandDeleteAttr(undef, "$name $attrName");
|
||||||
}
|
}
|
||||||
} elsif ($attrName eq "smartAckMailboxMax") {
|
} elsif ($attrName eq "smartAckMailboxMax") {
|
||||||
@ -1307,7 +1369,7 @@ sub TCM_Attr(@) {
|
|||||||
} elsif (($attrVal + 0) >= 0 && ($attrVal + 0) <= 20) {
|
} elsif (($attrVal + 0) >= 0 && ($attrVal + 0) <= 20) {
|
||||||
TCM_Set($hash, ("set", "smartAckMailboxMax", $attrVal));
|
TCM_Set($hash, ("set", "smartAckMailboxMax", $attrVal));
|
||||||
} else {
|
} else {
|
||||||
Log3 $name, 2, "EnOcean $name attribute-value [$attrName] = $attrVal wrong or out of range";
|
Log3 $name, 2, "TCM $name attribute-value [$attrName] = $attrVal wrong or out of range";
|
||||||
CommandDeleteAttr(undef, "$name $attrName");
|
CommandDeleteAttr(undef, "$name $attrName");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1318,8 +1380,39 @@ sub TCM_Attr(@) {
|
|||||||
#
|
#
|
||||||
sub TCM_Notify(@) {
|
sub TCM_Notify(@) {
|
||||||
my ($hash, $dev) = @_;
|
my ($hash, $dev) = @_;
|
||||||
if ($dev->{NAME} eq "global" && grep (m/^INITIALIZED|REREADCFG$/, @{$dev->{CHANGED}})){
|
if ($dev->{TYPE} eq 'Global' && grep (m/^INITIALIZED|REREADCFG$/, @{$dev->{CHANGED}})){
|
||||||
|
#if ($dev->{NAME} eq "global" && grep (m/^INITIALIZED|REREADCFG$/, @{$dev->{CHANGED}})){
|
||||||
TCM_InitSerialCom($hash);
|
TCM_InitSerialCom($hash);
|
||||||
|
my $assignIODevFlag = AttrVal($hash->{NAME}, 'assignIODev', undef);
|
||||||
|
if (defined $assignIODevFlag) {
|
||||||
|
if ($assignIODevFlag eq 'yes') {
|
||||||
|
$modules{TCM}{assignIODev} = $hash;
|
||||||
|
} else {
|
||||||
|
if (exists $modules{TCM}{assignIODev}) {
|
||||||
|
delete($modules{TCM}{assignIODev}) if ($modules{TCM}{assignIODev} eq $hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exists $modules{$modulesType}{ChipID}) {
|
||||||
|
if (@{$modules{$modulesType}{ChipID}} <= 1) {
|
||||||
|
# one transmitter currently registered
|
||||||
|
#$attr{$hash->{NAME}}{fingerprint} = 'off';
|
||||||
|
#Log3 $hash->{NAME}, 2, "TCM $hash->{NAME} Atribute fingerprint: off";
|
||||||
|
} else {
|
||||||
|
# more then one transmitter currently registered
|
||||||
|
if (!exists $attr{$dev->{NAME}}{dupTimeout}) {
|
||||||
|
$attr{$dev->{NAME}}{dupTimeout} = $dupTimeout;
|
||||||
|
Log3 $dev->{NAME}, 2, "$dev->{TYPE} $dev->{NAME} Attribute dupTimeout: $attr{$dev->{NAME}}{dupTimeout}";
|
||||||
|
}
|
||||||
|
while (my ($iDev, $iHash) = each (%{$modules{$modulesType}{devHash}})) {
|
||||||
|
if (!exists $attr{$iDev}{fingerprint}) {
|
||||||
|
$attr{$iDev}{fingerprint} = 'on';
|
||||||
|
Log3 $iDev, 2, "TCM $iDev Attribute fingerprint: $attr{$iDev}{fingerprint}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log3 $hash->{NAME}, 2, "TCM registered transceiver BaseID: " . join(':', @{$modules{"$hash->{TYPE}"}{BaseID}}) . " ChipID: " . join(':', @{$modules{"$hash->{TYPE}"}{ChipID}});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
@ -1328,22 +1421,39 @@ sub TCM_Notify(@) {
|
|||||||
sub TCM_Undef($$) {
|
sub TCM_Undef($$) {
|
||||||
my ($hash, $arg) = @_;
|
my ($hash, $arg) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
foreach my $d (sort keys %defs) {
|
foreach my $d (sort keys %defs) {
|
||||||
if(defined($defs{$d}) &&
|
if(defined($defs{$d}) && defined($defs{$d}{IODev}) && $defs{$d}{IODev} == $hash) {
|
||||||
defined($defs{$d}{IODev}) &&
|
|
||||||
$defs{$d}{IODev} == $hash)
|
|
||||||
{
|
|
||||||
my $lev = ($reread_active ? 4 : 2);
|
my $lev = ($reread_active ? 4 : 2);
|
||||||
Log3 $name, $lev, "TCM deleting port for $d";
|
Log3 $name, $lev, "TCM $name deleting port for $d";
|
||||||
delete $defs{$d}{IODev};
|
delete $defs{$d}{IODev};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DevIo_CloseDev($hash);
|
DevIo_CloseDev($hash);
|
||||||
|
for (my $i = 0; $i <= @{$modules{"$hash->{TYPE}"}{BaseID}}; $i++) {
|
||||||
|
if (${$modules{"$hash->{TYPE}"}{BaseID}}[$i] eq $hash->{BaseID}) {
|
||||||
|
Log3 $name, 4, "TCM $name remove module BaseID: " . ${$modules{"$hash->{TYPE}"}{BaseID}}[$i];
|
||||||
|
splice(@{$modules{"$hash->{TYPE}"}{BaseID}}, $i, 1);
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (my $i = 0; $i <= @{$modules{"$hash->{TYPE}"}{ChipID}}; $i++) {
|
||||||
|
if (${$modules{"$hash->{TYPE}"}{ChipID}}[$i] eq $hash->{ChipID}) {
|
||||||
|
Log3 $name, 4, "TCM $name remove module ChipID: " . ${$modules{"$hash->{TYPE}"}{ChipID}}[$i];
|
||||||
|
splice(@{$modules{"$hash->{TYPE}"}{ChipID}}, $i, 1);
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
delete $hash->{helper}{init_done};
|
delete $hash->{helper}{init_done};
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Shutdown
|
||||||
|
sub TCM_Shutdown($) {
|
||||||
|
my ($hash) = @_;
|
||||||
|
DevIo_CloseDev($hash);
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
@ -1374,6 +1484,9 @@ sub TCM_Undef($$) {
|
|||||||
of commands depends on the hardware and the firmware version. A firmware update
|
of commands depends on the hardware and the firmware version. A firmware update
|
||||||
is usually not provided.
|
is usually not provided.
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
|
<b>Eltako RS485 bus</b>
|
||||||
|
<ul>
|
||||||
The TCM module enables also a wired connection to Eltako actuators over the
|
The TCM module enables also a wired connection to Eltako actuators over the
|
||||||
Eltako RS485 bus in the switchboard or distribution box via Eltako FGW14 RS232-RS485
|
Eltako RS485 bus in the switchboard or distribution box via Eltako FGW14 RS232-RS485
|
||||||
gateway modules. These actuators are linked to an associated wireless antenna module
|
gateway modules. These actuators are linked to an associated wireless antenna module
|
||||||
@ -1386,7 +1499,58 @@ sub TCM_Undef($$) {
|
|||||||
event-min-interval.
|
event-min-interval.
|
||||||
The Eltako bus uses the EnOcean Serial Protocol version 2 (ESP2). For this reason,
|
The Eltako bus uses the EnOcean Serial Protocol version 2 (ESP2). For this reason,
|
||||||
a FGW14 can be configured as a ESP2. The attribute <a href="#TCM_comType">comType</a>
|
a FGW14 can be configured as a ESP2. The attribute <a href="#TCM_comType">comType</a>
|
||||||
must be set to RS485.<br><br>
|
must be set to RS485.
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<b>Multi-transceiver operation</b>
|
||||||
|
<ul>
|
||||||
|
It is possible to operate multiple transceivers in one Fhem instance in parallel.
|
||||||
|
EnOcean repeaters meet the usual requirements for increasing range in homes much more
|
||||||
|
easily than a multi-transceiver instance. It is interesting to operate several transceivers
|
||||||
|
but with extensive building complexes. In addition, the radio channel utilization can be
|
||||||
|
reduced compared to the use of several repeaters when self-contained spatial zones are formed.
|
||||||
|
After all, multiple transceivers can increase the number of available SenderIDs in Fhem.<br><br>
|
||||||
|
Within an Fhem installation with multiple transceivers, one of these transceivers sends the
|
||||||
|
outgoing telegrams. The transceiver is assigned to IODev when an EnOcean device is set up. One of
|
||||||
|
the enabled transceivers can be specifically selected as the transmitting device (IODev) for manual
|
||||||
|
setup of EnOcean devices. For this purpose, the attribute<br>
|
||||||
|
<ul><code>attr <name> assignIODev yes</code></ul>
|
||||||
|
must be set.
|
||||||
|
<br><br>
|
||||||
|
For teach-in sensors or actuators, the desired transceiver must be set by<br>
|
||||||
|
<ul><code>set <name> teach <t/s></code></ul>
|
||||||
|
into learning mode.
|
||||||
|
<br><br>
|
||||||
|
Incoming telegrams are received by all transceivers. Duplicates are determined and
|
||||||
|
suppressed by the fingerprint function. This function must be used for each transceiver using the<br>
|
||||||
|
<ul><code>attr <name> fingerprint on</code></ul>
|
||||||
|
activated. Furthermore, the global attribute must be<br>
|
||||||
|
<ul><code>attr global dupTimeout 0.6</code></ul>
|
||||||
|
or larger. The attributes are set automatically if they have not already been manually defined.
|
||||||
|
<br><br>
|
||||||
|
Transceivers on remote servers have been tested with the Linux service ser2net. For example,
|
||||||
|
ser2net can be set up on a Raspberry PI Remote server for a transceiver on the
|
||||||
|
/dev/ttyUSB0@57600 USB port (8, 'none', 1) in the following steps:<br><br>
|
||||||
|
Package provisioning<br>
|
||||||
|
<ul><code>sudo apt install ser2net</code></ul>
|
||||||
|
Configuration in the file: /etc/ser2net.conf<br>
|
||||||
|
<ul><code>7000:raw:0:/dev/ttyUSB0:57600 8DATABITS NONE 1STOPBIT HANGUP_WHEN_DONE</code></ul>
|
||||||
|
Program start for a test<br>
|
||||||
|
<ul><code>sudo ser2net -n</code></ul>
|
||||||
|
Automatically boot (insert script /etc/init.d/ser2net into startup procedure)<br>
|
||||||
|
<ul><code>sudo update-rc.d ser2net defaults</code></ul>
|
||||||
|
Take program from the autostart<br>
|
||||||
|
<ul><code>sudo update-rc.d -f ser2net remove</code></ul><br>
|
||||||
|
On the remote server, ser2net and Fhem should not be active in parallel.
|
||||||
|
During Fhem start, the autocreate function may inadvertently integrate the transceiver
|
||||||
|
into Fhem and then errors occur.<br><br>
|
||||||
|
On the target system, the transceiver is then connected to the IP address of the remote server via<br>
|
||||||
|
<ul><code>define TCM_Remote TCM ESP3 <ip1>.<ip2>.<ip3><ip3>.<ip4>:7000</code></ul>
|
||||||
|
set up.<br><br>
|
||||||
|
Only ESP3 transceivers have been tested.
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
<a name="TCMdefine"></a>
|
<a name="TCMdefine"></a>
|
||||||
<b>Define</b>
|
<b>Define</b>
|
||||||
@ -1550,6 +1714,10 @@ sub TCM_Undef($$) {
|
|||||||
<li>freqencyInfo<br>
|
<li>freqencyInfo<br>
|
||||||
Reads Frequency and protocol of the Device, see
|
Reads Frequency and protocol of the Device, see
|
||||||
<a href="https://www.enocean.com/esp">EnOcean Serial Protocol 3 (ESP3)</a></li>
|
<a href="https://www.enocean.com/esp">EnOcean Serial Protocol 3 (ESP3)</a></li>
|
||||||
|
<li>getFreeID<br>
|
||||||
|
Get free Transceiver SenderIDs.</li>
|
||||||
|
<li>getUsedID<br>
|
||||||
|
Get used Transceiver SenderIDs.</li>
|
||||||
<li>numSecureDev<br>
|
<li>numSecureDev<br>
|
||||||
Read number of teached in secure devices.</li>
|
Read number of teached in secure devices.</li>
|
||||||
<li>remanRepeating<br>
|
<li>remanRepeating<br>
|
||||||
@ -1576,6 +1744,10 @@ sub TCM_Undef($$) {
|
|||||||
<a name="TCMattr"></a>
|
<a name="TCMattr"></a>
|
||||||
<b>Attributes</b>
|
<b>Attributes</b>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li><a name="TCM_assignIODev">assignIODev</a> <no|yes>,
|
||||||
|
[assignIODev] = no is default.<br>
|
||||||
|
Transceiver used as IO device (IODev) for manually set up EnOcean devices.
|
||||||
|
</li>
|
||||||
<li><a name="TCM_blockSenderID">blockSenderID</a> <own|no>,
|
<li><a name="TCM_blockSenderID">blockSenderID</a> <own|no>,
|
||||||
[blockSenderID] = own is default.<br>
|
[blockSenderID] = own is default.<br>
|
||||||
Block receiving telegrams with a TCM SenderID sent by repeaters.
|
Block receiving telegrams with a TCM SenderID sent by repeaters.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user