mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-12 16:46:35 +00:00
new TRX modules added
git-svn-id: https://svn.fhem.de/fhem/trunk@1283 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
11e9841667
commit
b10dc6ae9a
@ -14,6 +14,7 @@
|
||||
- feature: FHEMWEB redirectCmds attribute added
|
||||
- feature: CUL_TX minsecs attribute (by Arno)
|
||||
- feature: webCmd in smallScreen added
|
||||
- feature: TRX modules by Willi
|
||||
|
||||
- 2011-12-31 (5.2)
|
||||
- bugfix: applying smallscreen attributes to firefox/opera
|
||||
|
363
fhem/FHEM/45_TRX.pm
Executable file
363
fhem/FHEM/45_TRX.pm
Executable file
@ -0,0 +1,363 @@
|
||||
#################################################################################
|
||||
# 45_TRX.pm
|
||||
# Module for FHEM
|
||||
#
|
||||
# Tested with RFXtrx-Receiver (433.92MHz, USB)
|
||||
# (see http://www.RFXCOM.com/).
|
||||
# To use this module, you need to define an RFXTRX transceiver:
|
||||
# define RFXTRX TRX /dev/ttyUSB0
|
||||
#
|
||||
# The module also has code to access a RFXtrx transceiver attached via LAN.
|
||||
#
|
||||
# To use it define the IP-Adresss and the Port:
|
||||
# define RFXTRX TRX 192.168.169.111:10001
|
||||
# optionally you may issue not to initialize the device (useful if you share an RFXtrx device with other programs)
|
||||
# define RFXTRX TRX 192.168.169.111:10001 noinit
|
||||
#
|
||||
# The RFXtrx transceivers supports lots of protocols that may be implemented for FHEM
|
||||
# writing the appropriate FHEM modules. See the
|
||||
#
|
||||
# Willi Herzig, 2012
|
||||
#
|
||||
# This script is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
#################################################################################
|
||||
# derived from 00_CUL.pm
|
||||
#
|
||||
###########################
|
||||
# $Id:
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
||||
my $last_rmsg = "abcd";
|
||||
my $last_time = 1;
|
||||
|
||||
sub TRX_Clear($);
|
||||
sub TRX_Read($);
|
||||
sub TRX_Ready($);
|
||||
sub TRX_Parse($$$$);
|
||||
|
||||
sub
|
||||
TRX_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
|
||||
require "$attr{global}{modpath}/FHEM/DevIo.pm";
|
||||
|
||||
# Provider
|
||||
$hash->{ReadFn} = "TRX_Read";
|
||||
$hash->{WriteFn} = "TRX_Write";
|
||||
$hash->{Clients} =
|
||||
":TRX_WEATHER:TRX_SECURITY:TRX_LIGHT:";
|
||||
my %mc = (
|
||||
"1:TRX_WEATHER" => "^..(50|52|54|55|56).*",
|
||||
"2:TRX_SECURITY" => "^..(20).*",
|
||||
"3:TRX_LIGHT" => "^..(10).*",
|
||||
"4:TRX_ELSE" => "^..(0|3|4|6|7|8|9).*",
|
||||
);
|
||||
$hash->{MatchList} = \%mc;
|
||||
|
||||
$hash->{ReadyFn} = "TRX_Ready";
|
||||
|
||||
# Normal devices
|
||||
$hash->{DefFn} = "TRX_Define";
|
||||
$hash->{UndefFn} = "TRX_Undef";
|
||||
$hash->{GetFn} = "TRX_Get";
|
||||
$hash->{SetFn} = "TRX_Set";
|
||||
$hash->{StateFn} = "TRX_SetState";
|
||||
$hash->{AttrList}= "do_not_notify:1,0 dummy:1,0 do_not_init:1:0 addvaltrigger:1:0 longids loglevel:0,1,2,3,4,5,6";
|
||||
$hash->{ShutdownFn} = "TRX_Shutdown";
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_Define($$)
|
||||
{
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split("[ \t][ \t]*", $def);
|
||||
|
||||
return "wrong syntax: define <name> TRX devicename [noinit]"
|
||||
if(@a != 3 && @a != 4);
|
||||
|
||||
DevIo_CloseDev($hash);
|
||||
|
||||
my $name = $a[0];
|
||||
my $dev = $a[2];
|
||||
my $opt = $a[3] if(@a == 4);;
|
||||
|
||||
if($dev eq "none") {
|
||||
Log 1, "TRX: $name device is none, commands will be echoed only";
|
||||
$attr{$name}{dummy} = 1;
|
||||
return undef;
|
||||
}
|
||||
|
||||
if(defined($opt)) {
|
||||
if($opt eq "noinit") {
|
||||
Log 1, "TRX: $name no init is done";
|
||||
$attr{$name}{do_not_init} = 1;
|
||||
} else {
|
||||
return "wrong syntax: define <name> TRX devicename [noinit]"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$hash->{DeviceName} = $dev;
|
||||
my $ret = DevIo_OpenDev($hash, 0, "TRX_DoInit");
|
||||
return $ret;
|
||||
}
|
||||
|
||||
#####################################
|
||||
# Input is hexstring
|
||||
sub
|
||||
TRX_Write($$$)
|
||||
{
|
||||
my ($hash,$fn,$msg) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $ll5 = GetLogLevel($name,5);
|
||||
|
||||
return if(!defined($fn));
|
||||
|
||||
my $bstring;
|
||||
$bstring = "$fn$msg";
|
||||
Log $ll5, "$hash->{NAME} sending $bstring";
|
||||
|
||||
DevIo_SimpleWrite($hash, $bstring, 1);
|
||||
}
|
||||
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_Undef($$)
|
||||
{
|
||||
my ($hash, $arg) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
foreach my $d (sort keys %defs) {
|
||||
if(defined($defs{$d}) &&
|
||||
defined($defs{$d}{IODev}) &&
|
||||
$defs{$d}{IODev} == $hash)
|
||||
{
|
||||
my $lev = ($reread_active ? 4 : 2);
|
||||
Log GetLogLevel($name,$lev), "deleting port for $d";
|
||||
delete $defs{$d}{IODev};
|
||||
}
|
||||
}
|
||||
|
||||
DevIo_CloseDev($hash);
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_Shutdown($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_Set($@)
|
||||
{
|
||||
my ($hash, @a) = @_;
|
||||
|
||||
my $msg;
|
||||
my $name=$a[0];
|
||||
my $reading= $a[1];
|
||||
$msg="$name => No Set function ($reading) implemented";
|
||||
return $msg;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_Get($@)
|
||||
{
|
||||
my ($hash, @a) = @_;
|
||||
|
||||
my $msg;
|
||||
my $name=$a[0];
|
||||
my $reading= $a[1];
|
||||
$msg="$name => No Get function ($reading) implemented";
|
||||
Log 1,$msg;
|
||||
return $msg;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_SetState($$$$)
|
||||
{
|
||||
my ($hash, $tim, $vt, $val) = @_;
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub
|
||||
TRX_Clear($)
|
||||
{
|
||||
my $hash = shift;
|
||||
my $buf;
|
||||
|
||||
# clear buffer:
|
||||
if($hash->{USBDev}) {
|
||||
while ($hash->{USBDev}->lookfor()) {
|
||||
$buf = DevIo_SimpleRead($hash);
|
||||
}
|
||||
}
|
||||
if($hash->{TCPDev}) {
|
||||
# TODO
|
||||
return $buf;
|
||||
}
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_DoInit($)
|
||||
{
|
||||
my $hash = shift;
|
||||
my $name = $hash->{NAME};
|
||||
my $err;
|
||||
my $msg = undef;
|
||||
my $buf;
|
||||
my $char = undef ;
|
||||
|
||||
|
||||
# Reset
|
||||
my $init = pack('H*', "0D00000000000000000000000000");
|
||||
DevIo_SimpleWrite($hash, $init, 0);
|
||||
DevIo_TimeoutRead($hash, 0.5);
|
||||
|
||||
TRX_Clear($hash);
|
||||
|
||||
if(defined($attr{$name}) && defined($attr{$name}{"do_not_init"})) {
|
||||
Log 1, "TRX: defined with noinit. Do not send init string to device.";
|
||||
$hash->{STATE} = "Initialized" if(!$hash->{STATE});
|
||||
|
||||
# Reset the counter
|
||||
delete($hash->{XMIT_TIME});
|
||||
delete($hash->{NR_CMD_LAST_H});
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#
|
||||
# Get Status
|
||||
$init = pack('H*', "0D00000102000000000000000000");
|
||||
DevIo_SimpleWrite($hash, $init, 0);
|
||||
$buf = DevIo_TimeoutRead($hash, 0.1);
|
||||
|
||||
if (! $buf) {
|
||||
Log 1, "TRX: Initialization Error: No character read";
|
||||
return "TRX: Initialization Error $name: no char read";
|
||||
} elsif ($buf !~ m/^\x0d\x01\x00.........../) {
|
||||
my $hexline = unpack('H*', $buf);
|
||||
Log 1, "TRX: Initialization Error hexline='$hexline'";
|
||||
return "TRX: Initialization Error %name expected char=0x2c, but char=$char received.";
|
||||
} else {
|
||||
Log 1, "TRX: Init OK";
|
||||
$hash->{STATE} = "Initialized" if(!$hash->{STATE});
|
||||
}
|
||||
#
|
||||
|
||||
# Reset the counter
|
||||
delete($hash->{XMIT_TIME});
|
||||
delete($hash->{NR_CMD_LAST_H});
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
#####################################
|
||||
# called from the global loop, when the select for hash->{FD} reports data
|
||||
sub
|
||||
TRX_Read($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
my $name = $hash->{NAME};
|
||||
|
||||
my $char;
|
||||
|
||||
my $mybuf = DevIo_SimpleRead($hash);
|
||||
|
||||
if(!defined($mybuf) || length($mybuf) == 0) {
|
||||
DevIo_Disconnected($hash);
|
||||
return "";
|
||||
}
|
||||
|
||||
my $TRX_data = $hash->{PARTIAL};
|
||||
#Log 5, "TRX/RAW: $TRX_data/$mybuf";
|
||||
$TRX_data .= $mybuf;
|
||||
|
||||
#my $hexline = unpack('H*', $TRX_data);
|
||||
#Log 1, "TRX: TRX_Read '$hexline'";
|
||||
|
||||
# first char as byte represents number of bytes of the message
|
||||
my $num_bytes = ord($TRX_data);
|
||||
|
||||
while(length($TRX_data) > $num_bytes) {
|
||||
# the buffer contains at least the number of bytes we need
|
||||
my $rmsg;
|
||||
$rmsg = substr($TRX_data, 0, $num_bytes+1);
|
||||
#my $hexline = unpack('H*', $rmsg);
|
||||
#Log 1, "TRX_Read rmsg '$hexline'";
|
||||
$TRX_data = substr($TRX_data, $num_bytes+1);;
|
||||
#$hexline = unpack('H*', $TRX_data);
|
||||
#Log 1, "TRX_Read TRX_data '$hexline'";
|
||||
#
|
||||
TRX_Parse($hash, $hash, $name, unpack('H*', $rmsg));
|
||||
}
|
||||
#Log 1, "TRX_Read END";
|
||||
|
||||
$hash->{PARTIAL} = $TRX_data;
|
||||
}
|
||||
|
||||
sub
|
||||
TRX_Parse($$$$)
|
||||
{
|
||||
my ($hash, $iohash, $name, $rmsg) = @_;
|
||||
|
||||
#Log 1, "TRX_Parse1 '$rmsg'";
|
||||
Log 5, "TRX_Parse1 '$rmsg'";
|
||||
|
||||
my %addvals;
|
||||
# Parse only if message is different within 2 seconds
|
||||
# (some Oregon sensors always sends the message twice, X10 security sensors even sends the message five times)
|
||||
if (("$last_rmsg" ne "$rmsg") || (time() - $last_time) > 1) {
|
||||
#Log 1, "TRX_Dispatch '$rmsg'";
|
||||
%addvals = (RAWMSG => $rmsg);
|
||||
Dispatch($hash, $rmsg, \%addvals);
|
||||
$hash->{"${name}_MSGCNT"}++;
|
||||
$hash->{"${name}_TIME"} = TimeNow();
|
||||
$hash->{RAWMSG} = $rmsg;
|
||||
} else {
|
||||
#Log 1, "TRX_Dispatch '$rmsg' dup";
|
||||
#Log 1, "<-duplicate->";
|
||||
}
|
||||
|
||||
$last_rmsg = $rmsg;
|
||||
$last_time = time();
|
||||
|
||||
}
|
||||
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_Ready($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
return DevIo_OpenDev($hash, 1, "TRX_Ready")
|
||||
if($hash->{STATE} eq "disconnected");
|
||||
|
||||
# This is relevant for windows/USB only
|
||||
my $po = $hash->{USBDev};
|
||||
my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status;
|
||||
return ($InBytes>0);
|
||||
}
|
||||
|
||||
1;
|
102
fhem/FHEM/46_TRX_ELSE.pm
Executable file
102
fhem/FHEM/46_TRX_ELSE.pm
Executable file
@ -0,0 +1,102 @@
|
||||
#################################################################################
|
||||
# 46_TRX_ELSE.pm
|
||||
# Modul for FHEM for unkown RFXTRX messages
|
||||
#
|
||||
# This script is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
##################################
|
||||
#
|
||||
# values for "set global verbose"
|
||||
# 4: log unknown protocols
|
||||
# 5: log decoding hexlines for debugging
|
||||
#
|
||||
# $Id:
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Switch;
|
||||
|
||||
my $time_old = 0;
|
||||
|
||||
sub
|
||||
TRX_ELSE_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{Match} = "^.*";
|
||||
$hash->{DefFn} = "TRX_ELSE_Define";
|
||||
$hash->{UndefFn} = "TRX_ELSE_Undef";
|
||||
$hash->{ParseFn} = "TRX_ELSE_Parse";
|
||||
$hash->{AttrList} = "IODev do_not_notify:1,0 loglevel:0,1,2,3,4,5,6";
|
||||
Log 1, "TRX_ELSE: Initialize";
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_ELSE_Define($$)
|
||||
{
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split("[ \t][ \t]*", $def);
|
||||
|
||||
my $a = int(@a);
|
||||
#print "a0 = $a[0]";
|
||||
return "wrong syntax: define <name> TRX_ELSE code" if(int(@a) != 3);
|
||||
|
||||
my $name = $a[0];
|
||||
my $code = $a[2];
|
||||
|
||||
$hash->{CODE} = $code;
|
||||
#$modules{TRX_ELSE}{defptr}{$name} = $hash;
|
||||
$modules{TRX_ELSE}{defptr}{$code} = $hash;
|
||||
AssignIoPort($hash);
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_ELSE_Undef($$)
|
||||
{
|
||||
my ($hash, $name) = @_;
|
||||
delete($modules{TRX_ELSE}{defptr}{$name});
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
my $DOT = q{_};
|
||||
|
||||
sub
|
||||
TRX_ELSE_Parse($$)
|
||||
{
|
||||
my ($hash, $msg) = @_;
|
||||
|
||||
my $time = time();
|
||||
if ($time_old ==0) {
|
||||
Log 5, "TRX_ELSE: decoding delay=0 hex=$msg";
|
||||
} else {
|
||||
my $time_diff = $time - $time_old ;
|
||||
Log 5, "TRX_ELSE: decoding delay=$time_diff hex=$msg";
|
||||
}
|
||||
$time_old = $time;
|
||||
|
||||
# convert to binary
|
||||
my $bin_msg = pack('H*', $msg);
|
||||
#my $hexline = unpack('H*', $bin_msg);
|
||||
#Log 1, "TRX_ELSE: 2 hex=$hexline";
|
||||
|
||||
# convert string to array of bytes. Skip length byte
|
||||
my @rfxcom_data_array = ();
|
||||
foreach (split(//, substr($bin_msg,1))) {
|
||||
push (@rfxcom_data_array, ord($_) );
|
||||
}
|
||||
|
||||
Log 0, "TRX_ELSE: hex=$msg";
|
||||
|
||||
return "Test";
|
||||
}
|
||||
|
||||
1;
|
425
fhem/FHEM/46_TRX_LIGHT.pm
Executable file
425
fhem/FHEM/46_TRX_LIGHT.pm
Executable file
@ -0,0 +1,425 @@
|
||||
#################################################################################
|
||||
# 46_TRX_LIGHT.pm
|
||||
#
|
||||
# Modul for FHEM for
|
||||
# "X10" -> X10 lighting
|
||||
# "ARC" -> ARC
|
||||
# "AB400D" -> ELRO AB400D
|
||||
# "WAVEMAN" -> Waveman
|
||||
# "EMW200" -> Chacon EMW200
|
||||
# "IMPULS" -> IMPULS
|
||||
#
|
||||
# - ms14a: motion sensor
|
||||
# - x10: generic X10 sensor
|
||||
#
|
||||
# This script is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
##################################
|
||||
#
|
||||
# values for "set global verbose"
|
||||
# 4: log unknown protocols
|
||||
# 5: log decoding hexlines for debugging
|
||||
#
|
||||
# $Id: 43_TRX_LIGHT.pm 1098 2011-11-12 07:51:08Z rudolfkoenig $
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Switch;
|
||||
|
||||
# Debug this module? YES = 1, NO = 0
|
||||
my $TRX_LIGHT_debug = 0;
|
||||
|
||||
my $time_old = 0;
|
||||
|
||||
my $TRX_LIGHT_type_default = "ds10a";
|
||||
my $TRX_LIGHT_X10_type_default = "x10";
|
||||
|
||||
my $DOT = q{_};
|
||||
|
||||
my %light_device_codes = ( # HEXSTRING => "NAME", "name of reading",
|
||||
0x00 => [ "X10", "light" ],
|
||||
0x01 => [ "ARC", "light" ],
|
||||
0x02 => [ "AB400D", "light" ],
|
||||
0x03 => [ "WAVEMAN", "light" ],
|
||||
0x04 => [ "EMW200", "light"],
|
||||
0x05 => [ "IMPULS", "light"],
|
||||
);
|
||||
|
||||
my %light_device_commands = ( # HEXSTRING => commands
|
||||
0x00 => [ "off", "on", "dim", "bright", "all_off", "all_on", ""],
|
||||
0x01 => [ "off", "on", "", "", "all_off", "all_on", "chime"],
|
||||
0x02 => [ "off", "on", "", "", "", "", ""],
|
||||
0x03 => [ "off", "on", "", "", "", "", ""],
|
||||
0x04 => [ "off", "on", "", "", "all_off", "all_on", ""],
|
||||
0x05 => [ "off", "on", "", "", "", "", ""],
|
||||
);
|
||||
|
||||
my %light_device_c2b; # DEVICE_TYPE->hash (reverse of light_device_codes)
|
||||
|
||||
# Get the binary value for a command
|
||||
# return -1 if command not valid dor dev_type
|
||||
sub TRX_LIGHT_cmd_to_binary {
|
||||
my ($dev_type, $command) = @_;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
sub
|
||||
TRX_LIGHT_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
foreach my $k (keys %light_device_codes) {
|
||||
$light_device_c2b{$light_device_codes{$k}->[0]} = $k;
|
||||
}
|
||||
|
||||
#$hash->{Match} = "^\\).*"; # 0x29
|
||||
$hash->{Match} = "^(\\ |\\)).*"; # 0x20 or 0x29
|
||||
$hash->{SetFn} = "TRX_LIGHT_Set";
|
||||
$hash->{DefFn} = "TRX_LIGHT_Define";
|
||||
$hash->{UndefFn} = "TRX_LIGHT_Undef";
|
||||
$hash->{ParseFn} = "TRX_LIGHT_Parse";
|
||||
$hash->{AttrList} = "IODev do_not_notify:1,0 loglevel:0,1,2,3,4,5,6";
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_LIGHT_SetState($$$$)
|
||||
{
|
||||
my ($hash, $tim, $vt, $val) = @_;
|
||||
|
||||
$val = $1 if($val =~ m/^(.*) \d+$/);
|
||||
# to be done. Just accept everything right now.
|
||||
#return "Undefined value $val" if(!defined($fs20_c2b{$val}));
|
||||
return undef;
|
||||
}
|
||||
|
||||
###################################
|
||||
sub
|
||||
TRX_LIGHT_Set($@)
|
||||
{
|
||||
my ($hash, @a) = @_;
|
||||
my $ret = undef;
|
||||
my $na = int(@a);
|
||||
|
||||
return "no set value specified" if($na < 2 || $na > 3);
|
||||
|
||||
# look for device_type
|
||||
|
||||
my $name = $a[0];
|
||||
my $command = $a[1];
|
||||
|
||||
my $device_type = $hash->{TRX_LIGHT_type};
|
||||
my $deviceid = $hash->{TRX_LIGHT_deviceid};
|
||||
|
||||
my $house;
|
||||
my $unit;
|
||||
if ($deviceid =~ /(.)(.*)/ ) {
|
||||
$house = ord("$1");
|
||||
$unit = $2;
|
||||
} else {
|
||||
Log 4,"TRX_LIGHT_Set wrong deviceid: name=$name device_type=$device_type, deviceid=$deviceid";
|
||||
return "error set name=$name deviveid=$deviceid";
|
||||
}
|
||||
|
||||
my $device_type_num = $light_device_c2b{$device_type};
|
||||
if(!defined($device_type_num)) {
|
||||
return "Unknown device_type, choose one of " .
|
||||
join(" ", sort keys %light_device_c2b);
|
||||
}
|
||||
|
||||
# Now check if the command is valid and retrieve the command id:
|
||||
my $rec = $light_device_commands{$device_type_num};
|
||||
my $i;
|
||||
for ($i=0; $i <= $#$rec && ($rec->[$i] ne $command); $i++) { ;}
|
||||
|
||||
if($i > $#$rec) {
|
||||
my $error = "Unknown command $command, choose one of " . join(" ", sort @$rec);
|
||||
Log 4, $error;
|
||||
return $error;
|
||||
}
|
||||
|
||||
|
||||
my $seqnr = 0;
|
||||
my $cmnd = $i;
|
||||
|
||||
my $hex_command = sprintf "0710%02x%02x%02x%02x%02x00", $device_type_num, $seqnr, $house, $unit, $cmnd;
|
||||
Log 1,"TRX_LIGHT_Set name=$name device_type=$device_type, deviceid=$deviceid house=$house, unit=$unit command=$command" if ($TRX_LIGHT_debug == 1);
|
||||
Log 1,"TRX_LIGHT_Set hexline=$hex_command" if ($TRX_LIGHT_debug == 1);
|
||||
|
||||
#IOWrite($hash, pack('H*', $hex_command));
|
||||
IOWrite($hash, "", $hex_command);
|
||||
|
||||
my $tn = TimeNow();
|
||||
$hash->{CHANGED}[0] = $command;
|
||||
$hash->{STATE} = $command;
|
||||
$hash->{READINGS}{state}{TIME} = $tn;
|
||||
$hash->{READINGS}{state}{VAL} = $command;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_LIGHT_Define($$)
|
||||
{
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split("[ \t][ \t]*", $def);
|
||||
|
||||
my $a = int(@a);
|
||||
|
||||
if(int(@a) != 5 && int(@a) != 7) {
|
||||
Log 1,"TRX_LIGHT wrong syntax '@a'. \nCorrect syntax is 'define <name> TRX_LIGHT <type> <deviceid> <devicelog> [<deviceid2> <devicelog2>]'";
|
||||
return "wrong syntax: define <name> TRX_LIGHT <type> <deviceid> <devicelog> [<deviceid2> <devicelog2>]";
|
||||
}
|
||||
|
||||
|
||||
my $name = $a[0];
|
||||
|
||||
my $type = lc($a[2]);
|
||||
my $deviceid = $a[3];
|
||||
my $devicelog = $a[4];
|
||||
|
||||
|
||||
$type = uc($type);
|
||||
|
||||
my $device_name = "TRX".$DOT.$type.$DOT.$deviceid;
|
||||
|
||||
if ($type ne "X10" && $type ne "ARC" && $type ne "MS14A" && $type ne "AB400D" && $type ne "WAVEMAN" && $type ne "EMW200" && $type ne "IMPULS") {
|
||||
Log 1,"RFX10SEC define: wrong type: $type";
|
||||
return "RFX10SEC: wrong type: $type";
|
||||
}
|
||||
|
||||
$hash->{TRX_LIGHT_deviceid} = $deviceid;
|
||||
$hash->{TRX_LIGHT_devicelog} = $devicelog;
|
||||
$hash->{TRX_LIGHT_type} = $type;
|
||||
#$hash->{TRX_LIGHT_CODE} = $deviceid;
|
||||
$modules{TRX_LIGHT}{defptr}{$device_name} = $hash;
|
||||
|
||||
|
||||
if (int(@a) == 7) {
|
||||
# there is a second deviceid:
|
||||
#
|
||||
my $deviceid2 = $a[5];
|
||||
my $devicelog2 = $a[6];
|
||||
|
||||
my $device_name2 = "TRX".$DOT.$type.$DOT.$deviceid2;
|
||||
|
||||
$hash->{TRX_LIGHT_deviceid2} = $deviceid2;
|
||||
$hash->{TRX_LIGHT_devicelog2} = $devicelog2;
|
||||
#$hash->{TRX_LIGHT_CODE2} = $deviceid2;
|
||||
$modules{TRX_LIGHT}{defptr2}{$device_name2} = $hash;
|
||||
}
|
||||
|
||||
AssignIoPort($hash);
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_LIGHT_Undef($$)
|
||||
{
|
||||
my ($hash, $name) = @_;
|
||||
delete($modules{TRX_LIGHT}{defptr}{$name});
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
#####################################
|
||||
sub TRX_LIGHT_parse_X10 {
|
||||
my $bytes = shift;
|
||||
|
||||
my $error;
|
||||
|
||||
|
||||
#my $device;
|
||||
|
||||
my $subtype = $bytes->[1];
|
||||
my $dev_type;
|
||||
my $dev_reading;
|
||||
my $rest;
|
||||
if (exists $light_device_codes{$subtype}) {
|
||||
my $rec = $light_device_codes{$subtype};
|
||||
($dev_type, $dev_reading) = @$rec;
|
||||
} else {
|
||||
$error = sprintf "TRX_LIGHT: error undefined subtype=%02x", $subtype;
|
||||
Log 1, $error;
|
||||
return $error;
|
||||
}
|
||||
|
||||
my $dev_first = "?";
|
||||
|
||||
my %x10_housecode =
|
||||
(
|
||||
0x41 => "A",
|
||||
0x42 => "B",
|
||||
0x43 => "C",
|
||||
0x44 => "D",
|
||||
0x45 => "E",
|
||||
0x46 => "F",
|
||||
0x47 => "G",
|
||||
0x48 => "H",
|
||||
0x49 => "I",
|
||||
0x4A => "J",
|
||||
0x4B => "K",
|
||||
0x4C => "L",
|
||||
0x4D => "M",
|
||||
0x4E => "N",
|
||||
0x4F => "O",
|
||||
0x50 => "P",
|
||||
);
|
||||
my $devnr = $bytes->[3]; # housecode
|
||||
if (exists $x10_housecode{$devnr}) {
|
||||
$dev_first = $x10_housecode{$devnr};
|
||||
} else {
|
||||
$error = sprintf "TRX_SECURITY: x10_housecode wrong housecode=%02x", $devnr;
|
||||
Log 1, $error;
|
||||
return $error;
|
||||
}
|
||||
|
||||
my $unit = $bytes->[4]; # unitcode
|
||||
|
||||
my $device = sprintf '%s%0d', $dev_first, $unit;
|
||||
|
||||
my $data = $bytes->[5];
|
||||
my $hexdata = sprintf '%02x', $data;
|
||||
|
||||
|
||||
my $command = "";
|
||||
if ($data == 0xff) {
|
||||
$command = "illegal_cmd";
|
||||
} else {
|
||||
if (exists $light_device_commands{$subtype}) {
|
||||
my $code = $light_device_commands{$subtype};
|
||||
if (exists $code->[$data]) {
|
||||
$command = $code->[$data];
|
||||
} else {
|
||||
$error = sprintf "TRX_LIGHT: out of range for subtype=%02x data=%02x", $subtype, $data;
|
||||
Log 1, $error;
|
||||
return $error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#my @res;
|
||||
my $current = "";
|
||||
|
||||
#--------------
|
||||
my $device_name = "TRX".$DOT.$dev_type.$DOT.$device;
|
||||
Log 1, "TRX_LIGHT: device_name=$device_name data=$hexdata" if ($TRX_LIGHT_debug == 1);
|
||||
|
||||
my $firstdevice = 1;
|
||||
my $def = $modules{TRX_LIGHT}{defptr}{$device_name};
|
||||
if(!$def) {
|
||||
$firstdevice = 0;
|
||||
$def = $modules{TRX_LIGHT}{defptr2}{$device_name};
|
||||
if (!$def) {
|
||||
Log 1, "UNDEFINED $device_name TRX_SECURITY $dev_type $device $dev_reading" if ($TRX_LIGHT_debug == 1);
|
||||
Log 3, "TRX_LIGHT: TRX_LIGHT Unknown device $device_name, please define it";
|
||||
return "UNDEFINED $device_name TRX_LIGHT $dev_type $device $dev_reading";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
# Use $def->{NAME}, because the device may be renamed:
|
||||
my $name = $def->{NAME};
|
||||
|
||||
Log 1, "TRX_LIGHT: $name devn=$device_name first=$firstdevice command=$command, cmd=$hexdata" if ($TRX_LIGHT_debug == 1);
|
||||
|
||||
my $n = 0;
|
||||
my $tm = TimeNow();
|
||||
my $val = "";
|
||||
|
||||
my $device_type = $def->{TRX_LIGHT_type};
|
||||
|
||||
my $sensor = "";
|
||||
|
||||
if ($device_type eq "MS14A") {
|
||||
# for ms14a behave like x10, but flip second deviceid
|
||||
$device_type = "X10";
|
||||
if ($firstdevice == 1) {
|
||||
$command = ($command eq "on") ? "alert" : "normal" ;
|
||||
} else {
|
||||
$command = ($command eq "on") ? "off" : "on" ;
|
||||
}
|
||||
}
|
||||
|
||||
#if ($device_type eq "X10") {
|
||||
if (1) {
|
||||
# try to use it for all types:
|
||||
$current = $command;
|
||||
|
||||
$sensor = $firstdevice == 1 ? $def->{TRX_LIGHT_devicelog} : $def->{TRX_LIGHT_devicelog2};
|
||||
$val .= $current;
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $current;
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $current;
|
||||
} else {
|
||||
Log 1, "TRX_LIGHT: X10 error unknown sensor type=$device_type $name devn=$device_name first=$firstdevice type=$command, user=$device (hex $hexdata)";
|
||||
return "TRX_LIGHT X10 error unknown sensor type=$device_type for $device_name device=$device";
|
||||
}
|
||||
|
||||
if (($firstdevice == 1) && $val) {
|
||||
$def->{STATE} = $val;
|
||||
$def->{TIME} = $tm;
|
||||
$def->{CHANGED}[$n++] = $val;
|
||||
}
|
||||
|
||||
DoTrigger($name, undef);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_LIGHT_Parse($$)
|
||||
{
|
||||
my ($iohash, $hexline) = @_;
|
||||
|
||||
my $time = time();
|
||||
# convert to binary
|
||||
my $msg = pack('H*', $hexline);
|
||||
if ($time_old ==0) {
|
||||
Log 5, "TRX_LIGHT: decoding delay=0 hex=$hexline";
|
||||
} else {
|
||||
my $time_diff = $time - $time_old ;
|
||||
Log 5, "TRX_LIGHT: decoding delay=$time_diff hex=$hexline";
|
||||
}
|
||||
$time_old = $time;
|
||||
|
||||
# convert string to array of bytes. Skip length byte
|
||||
my @rfxcom_data_array = ();
|
||||
foreach (split(//, substr($msg,1))) {
|
||||
push (@rfxcom_data_array, ord($_) );
|
||||
}
|
||||
|
||||
my $num_bytes = ord($msg);
|
||||
|
||||
if ($num_bytes < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
my $type = $rfxcom_data_array[0];
|
||||
|
||||
#Log 1, "TRX_LIGHT: num_bytes=$num_bytes hex=$hexline type=$type" if ($TRX_LIGHT_debug == 1);
|
||||
my $res = "";
|
||||
if ($type == 0x10) {
|
||||
Log 1, "TRX_LIGHT: X10 num_bytes=$num_bytes hex=$hexline" if ($TRX_LIGHT_debug == 1);
|
||||
$res = TRX_LIGHT_parse_X10(\@rfxcom_data_array);
|
||||
Log 1, "TRX_LIGHT: unsupported hex=$hexline" if ($res ne "" && $res !~ /^UNDEFINED.*/);
|
||||
return $res;
|
||||
} else {
|
||||
Log 0, "TRX_LIGHT: not implemented num_bytes=$num_bytes hex=$hexline";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
1;
|
401
fhem/FHEM/46_TRX_SECURITY.pm
Executable file
401
fhem/FHEM/46_TRX_SECURITY.pm
Executable file
@ -0,0 +1,401 @@
|
||||
#################################################################################
|
||||
# 46_TRX_SECURITY.pm
|
||||
#
|
||||
# Modul for FHEM for X10, KD101, Visonic
|
||||
# - X10 security messages tested for
|
||||
# - ds10a: X10 Door / Window Sensor or compatible devices
|
||||
# - ss10a: X10 motion sensor
|
||||
# - sd90: Marmitek smoke detector
|
||||
# - kr18: X10 remote control
|
||||
#
|
||||
##################################
|
||||
#
|
||||
# Willi Herzig, 2012
|
||||
#
|
||||
# This script is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
##################################
|
||||
#
|
||||
# Some code from X10security code is derived from http://www.xpl-perl.org.uk/.
|
||||
# xpl-perl/lib/xPL/RF/X10Security.pm:
|
||||
# Thanks a lot to Mark Hindess who wrote xPL.
|
||||
#
|
||||
#SEE ALSO
|
||||
# Project website: http://www.xpl-perl.org.uk/
|
||||
# AUTHOR: Mark Hindess, soft-xpl-perl@temporalanomaly.com
|
||||
#
|
||||
#Copyright (C) 2007, 2009 by Mark Hindess
|
||||
#
|
||||
#This library is free software; you can redistribute it and/or modify
|
||||
#it under the same terms as Perl itself, either Perl version 5.8.7 or,
|
||||
#at your option, any later version of Perl 5 you may have available.
|
||||
#
|
||||
##################################
|
||||
#
|
||||
# values for "set global verbose"
|
||||
# 4: log unknown protocols
|
||||
# 5: log decoding hexlines for debugging
|
||||
#
|
||||
# $Id: 43_TRX_SECURITY.pm 1098 2011-11-12 07:51:08Z rudolfkoenig $
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Switch;
|
||||
|
||||
# Debug this module? YES = 1, NO = 0
|
||||
my $TRX_SECURITY_debug = 0;
|
||||
|
||||
my $time_old = 0;
|
||||
|
||||
my $TRX_SECURITY_type_default = "ds10a";
|
||||
|
||||
my $DOT = q{_};
|
||||
|
||||
sub
|
||||
TRX_SECURITY_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{Match} = "^(\\ |\\)).*"; # 0x20 or 0x29
|
||||
$hash->{DefFn} = "TRX_SECURITY_Define";
|
||||
$hash->{UndefFn} = "TRX_SECURITY_Undef";
|
||||
$hash->{ParseFn} = "TRX_SECURITY_Parse";
|
||||
$hash->{AttrList} = "IODev do_not_notify:1,0 loglevel:0,1,2,3,4,5,6";
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_SECURITY_Define($$)
|
||||
{
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split("[ \t][ \t]*", $def);
|
||||
|
||||
my $a = int(@a);
|
||||
|
||||
if(int(@a) != 5 && int(@a) != 7) {
|
||||
Log 1,"TRX_SECURITY wrong syntax '@a'. \nCorrect syntax is 'define <name> TRX_SECURITY <type> <deviceid> <devicelog> [<deviceid2> <devicelog2>]'";
|
||||
return "wrong syntax: define <name> TRX_SECURITY <type> <deviceid> <devicelog> [<deviceid2> <devicelog2>]";
|
||||
}
|
||||
|
||||
|
||||
my $name = $a[0];
|
||||
|
||||
my $type = lc($a[2]);
|
||||
my $deviceid = $a[3];
|
||||
my $devicelog = $a[4];
|
||||
|
||||
|
||||
$type = uc($type);
|
||||
|
||||
my $device_name = "TRX".$DOT.$type.$DOT.$deviceid;
|
||||
|
||||
if ($type ne "DS10A" && $type ne "SD90" && $type ne "MS10A" && $type ne "MS14A" && $type ne "KR18" && $type ne "KD101" && $type ne "VISONIC_WINDOW" & $type ne "VISONIC_MOTION" & $type ne "VISONIC_REMOTE") {
|
||||
Log 1,"RFX10SEC define: wrong type: $type";
|
||||
return "RFX10SEC: wrong type: $type";
|
||||
}
|
||||
|
||||
$hash->{TRX_SECURITY_deviceid} = $deviceid;
|
||||
$hash->{TRX_SECURITY_devicelog} = $devicelog;
|
||||
$hash->{TRX_SECURITY_type} = $type;
|
||||
#$hash->{TRX_SECURITY_CODE} = $deviceid;
|
||||
$modules{TRX_SECURITY}{defptr}{$device_name} = $hash;
|
||||
|
||||
|
||||
if (int(@a) == 7) {
|
||||
# there is a second deviceid:
|
||||
#
|
||||
my $deviceid2 = $a[5];
|
||||
my $devicelog2 = $a[6];
|
||||
|
||||
my $device_name2 = "TRX_SECURITY".$DOT.$deviceid2;
|
||||
|
||||
$hash->{TRX_SECURITY_deviceid2} = $deviceid2;
|
||||
$hash->{TRX_SECURITY_devicelog2} = $devicelog2;
|
||||
#$hash->{TRX_SECURITY_CODE2} = $deviceid2;
|
||||
$modules{TRX_SECURITY}{defptr2}{$device_name2} = $hash;
|
||||
}
|
||||
|
||||
AssignIoPort($hash);
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_SECURITY_Undef($$)
|
||||
{
|
||||
my ($hash, $name) = @_;
|
||||
delete($modules{TRX_SECURITY}{defptr}{$name});
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#####################################
|
||||
sub TRX_SECURITY_parse_X10Sec {
|
||||
my $bytes = shift;
|
||||
|
||||
my $error;
|
||||
|
||||
my $subtype = $bytes->[1];
|
||||
|
||||
my $device;
|
||||
if ($subtype >= 3) {
|
||||
$device = sprintf '%02x%02x%02x', $bytes->[3], $bytes->[4], $bytes->[5];
|
||||
} else {
|
||||
# that's how we do it on 43_RFXX10REC.pm
|
||||
$device = sprintf '%02x%02x', $bytes->[5], $bytes->[3];
|
||||
}
|
||||
|
||||
my %security_devtype =
|
||||
( # HEXSTRING =>
|
||||
0x00 => [ "DS10A", "Window" ], # X10 security door/window sensor
|
||||
0x01 => [ "MS10A", "motion" ], # X10 security motion sensor
|
||||
0x02 => [ "KR18", "key" ], # X10 security remote (no alive packets)
|
||||
0x03 => [ "KD101", "smoke" ], # KD101 (no alive packets)
|
||||
0x04 => [ "VISONIC_WINDOW", "window" ], # Visonic PowerCode door/window sensor – primary contact (with alive packets)
|
||||
0x05 => [ "VISONIC_MOTION", "motion" ], # Visonic PowerCode motion sensor (with alive packets)
|
||||
0x06 => [ "VISONIC_REMOTE", "key" ], # Visonic CodeSecure (no alive packets)
|
||||
0x07 => [ "VISONIC_WINDOW", "window" ], # Visonic PowerCode door/window sensor – auxiliary contact (no alive packets)
|
||||
);
|
||||
|
||||
my $dev_type;
|
||||
my $dev_reading;
|
||||
if (exists $security_devtype{$subtype}) {
|
||||
my $rec = $security_devtype{$subtype};
|
||||
if (ref $rec) {
|
||||
($dev_type, $dev_reading ) = @$rec;
|
||||
} else {
|
||||
$error = "TRX_SECURITY: x10_devtype wrong for subtype=$subtype";
|
||||
Log 1, $error;
|
||||
return $error;
|
||||
}
|
||||
} else {
|
||||
$error = "TRX_SECURITY: error undefined subtype=$subtype";
|
||||
Log 1, $error;
|
||||
return $error;
|
||||
}
|
||||
|
||||
#Log 4, "device_type=$device_type";
|
||||
|
||||
#--------------
|
||||
my $device_name = "TRX".$DOT.$dev_type.$DOT.$device;
|
||||
Log 4, "device_name=$device_name";
|
||||
|
||||
my $firstdevice = 1;
|
||||
my $def = $modules{TRX_SECURITY}{defptr}{$device_name};
|
||||
if(!$def) {
|
||||
$firstdevice = 0;
|
||||
$def = $modules{TRX_SECURITY}{defptr2}{$device_name};
|
||||
if (!$def) {
|
||||
Log 1, "UNDEFINED $device_name TRX_SECURITY $dev_type $device $dev_reading";
|
||||
Log 3, "TRX_SECURITY: TRX_SECURITY Unknown device $device_name, please define it";
|
||||
return "UNDEFINED $device_name TRX_SECURITY $dev_type $device $dev_reading";
|
||||
}
|
||||
}
|
||||
|
||||
# Use $def->{NAME}, because the device may be renamed:
|
||||
my $name = $def->{NAME};
|
||||
|
||||
my $data = $bytes->[6];
|
||||
|
||||
my $hexdata = sprintf '%02x', $data;
|
||||
|
||||
my %x10_security =
|
||||
(
|
||||
0x00 => ['X10Sec', 'normal', 'min_delay', ''],
|
||||
0x01 => ['X10Sec', 'normal', 'max_delay', ''],
|
||||
|
||||
0x02 => ['X10Sec', 'alert', 'min_delay', ''],
|
||||
0x03 => ['X10Sec', 'alert', 'max_delay', ''],
|
||||
|
||||
0x04 => ['X10Sec', 'alert', '', ''],
|
||||
0x05 => ['X10Sec', 'normal', '', ''],
|
||||
|
||||
0x06 => ['X10Sec', 'alert', '', ''],
|
||||
0x07 => ['X10Sec', 'normal', '', ''],
|
||||
|
||||
0x08 => ['X10Sec', 'tamper', '', ''],
|
||||
|
||||
0x09 => ['X10Sec', 'Security-Arm_Away', 'min_delay', ''], # kr18
|
||||
0x0a => ['X10Sec', 'Security-Arm_Away', 'max_delay', ''], # kr18
|
||||
0x0b => ['X10Sec', 'Security-Arm_Home', 'min_delay', ''], # kr18
|
||||
0x0c => ['X10Sec', 'Security-Arm_Home', 'max_delay', ''], # kr18
|
||||
0x0d => ['X10Sec', 'Security-Disarm', 'min_delay', ''], # kr18
|
||||
|
||||
0x10 => ['X10Sec', 'ButtonA-on', '', ''], # kr18
|
||||
0x11 => ['X10Sec', 'ButtonA-off', '', ''], # kr18
|
||||
0x12 => ['X10Sec', 'ButtonB-on', '', ''], # kr18
|
||||
0x13 => ['X10Sec', 'ButtonB-off', '', ''], # kr18
|
||||
|
||||
0x14 => ['X10Sec', 'dark', '', ''],
|
||||
0x15 => ['X10Sec', 'light', '', ''],
|
||||
0x16 => ['X10Sec', 'normal', '', 'batt_low'],
|
||||
|
||||
0x17 => ['X10Sec', 'pair KD101', '', ''],
|
||||
|
||||
);
|
||||
|
||||
my $command = "";
|
||||
my $type = "";
|
||||
my $delay = "";
|
||||
my $battery = "";
|
||||
my @res;
|
||||
if (exists $x10_security{$data}) {
|
||||
my $rec = $x10_security{$data};
|
||||
if (ref $rec) {
|
||||
($type, $command, $delay, $battery) = @$rec;
|
||||
} else {
|
||||
$command = $rec;
|
||||
}
|
||||
} else {
|
||||
Log 1, "TRX_SECURITY undefined command cmd=$data device-nr=$device, hex=$hexdata";
|
||||
return "TRX_SECURITY undefined command";
|
||||
}
|
||||
|
||||
my $battery_level = $bytes->[7] & 0x0f;
|
||||
if (($battery eq "") && ($dev_type ne "kd101")) {
|
||||
if ($battery_level == 0x9) { $battery = 'batt_ok'}
|
||||
elsif ($battery_level == 0x0) { $battery = 'batt_low'}
|
||||
else {
|
||||
Log 1,"TRX-X10: X10Sec unkown battery_level=$battery_level";
|
||||
}
|
||||
}
|
||||
|
||||
my $current = "";
|
||||
|
||||
Log 1, "TRX_SECURITY: $name devn=$device_name first=$firstdevice subtype=$subtype command=$command, delay=$delay, batt=$battery cmd=$hexdata" if ($TRX_SECURITY_debug == 1);
|
||||
|
||||
my $n = 0;
|
||||
my $tm = TimeNow();
|
||||
my $val = "";
|
||||
|
||||
my $device_type = $def->{TRX_SECURITY_type};
|
||||
|
||||
my $sensor = "";
|
||||
|
||||
if ($device_type eq "sd90") {
|
||||
$sensor = $firstdevice == 1 ? $def->{TRX_SECURITY_devicelog} : $def->{TRX_SECURITY_devicelog2};
|
||||
} else {
|
||||
$sensor = $def->{TRX_SECURITY_devicelog};
|
||||
}
|
||||
|
||||
$current =$command;
|
||||
if (($device_type eq "DS10A") || ($device_type eq "VISONIC_WINDOW")) {
|
||||
$current = "Error";
|
||||
$current = "Open" if ($command eq "alert");
|
||||
$current = "Closed" if ($command eq "normal");
|
||||
}
|
||||
|
||||
if (($dev_type ne "kr18") || ($dev_type ne "VISONIC_REMOTE")) {
|
||||
if ($firstdevice == 1) {
|
||||
$val .= $current;
|
||||
}
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $current;
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $current;
|
||||
|
||||
if (($def->{STATE} ne $val)) {
|
||||
$sensor = "statechange";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $current;
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $current;
|
||||
}
|
||||
} else {
|
||||
# kr18 remote control or VISONIC_REMOTE
|
||||
$current = $command;
|
||||
|
||||
#$sensor = $def->{TRX_SECURITY_devicelog};
|
||||
$val = $current;
|
||||
#$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
#$def->{READINGS}{$sensor}{VAL} = $current;
|
||||
#$def->{CHANGED}[$n++] = $sensor . ": " . $current;
|
||||
|
||||
my @cmd_split = split(/-/, $command);
|
||||
$sensor = $cmd_split[0];
|
||||
$current = $cmd_split[1];
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $current;
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $current;
|
||||
}
|
||||
|
||||
if ($battery ne "") {
|
||||
$sensor = "battery";
|
||||
$current = "Error";
|
||||
$current = "ok" if ($battery eq "batt_ok");
|
||||
$current = "low" if ($battery eq "batt_low");
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $current;
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $current;
|
||||
}
|
||||
|
||||
if ($delay ne '') {
|
||||
$sensor = "delay";
|
||||
$current = "Error";
|
||||
$current = "min" if ($delay eq "min_delay");
|
||||
$current = "max" if ($delay eq "max_delay");
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $current;
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $current;
|
||||
}
|
||||
|
||||
if (($firstdevice == 1) && $val) {
|
||||
$def->{STATE} = $val;
|
||||
$def->{TIME} = $tm;
|
||||
$def->{CHANGED}[$n++] = $val;
|
||||
}
|
||||
|
||||
DoTrigger($name, undef);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
sub
|
||||
TRX_SECURITY_Parse($$)
|
||||
{
|
||||
my ($iohash, $hexline) = @_;
|
||||
|
||||
my $time = time();
|
||||
# convert to binary
|
||||
my $msg = pack('H*', $hexline);
|
||||
if ($time_old ==0) {
|
||||
Log 5, "TRX_SECURITY: decoding delay=0 hex=$hexline";
|
||||
} else {
|
||||
my $time_diff = $time - $time_old ;
|
||||
Log 5, "TRX_SECURITY: decoding delay=$time_diff hex=$hexline";
|
||||
}
|
||||
$time_old = $time;
|
||||
|
||||
# convert string to array of bytes. Skip length byte
|
||||
my @rfxcom_data_array = ();
|
||||
foreach (split(//, substr($msg,1))) {
|
||||
push (@rfxcom_data_array, ord($_) );
|
||||
}
|
||||
|
||||
my $num_bytes = ord($msg);
|
||||
|
||||
if ($num_bytes < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
my $type = $rfxcom_data_array[0];
|
||||
|
||||
#Log 1, "TRX_SECURITY: X10Sec num_bytes=$num_bytes hex=$hexline type=$type" if ($TRX_SECURITY_debug == 1);
|
||||
my $res = "";
|
||||
if ($type == 0x20) {
|
||||
Log 1, "TRX_SECURITY: X10Sec num_bytes=$num_bytes hex=$hexline" if ($TRX_SECURITY_debug == 1);
|
||||
$res = TRX_SECURITY_parse_X10Sec(\@rfxcom_data_array);
|
||||
Log 1, "TRX_SECURITY: unsupported hex=$hexline" if ($res ne "" && $res !~ /^UNDEFINED.*/);
|
||||
return $res;
|
||||
} else {
|
||||
Log 0, "TRX_SECURITY: not implemented num_bytes=$num_bytes hex=$hexline";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
1;
|
828
fhem/FHEM/46_TRX_WEATHER.pm
Executable file
828
fhem/FHEM/46_TRX_WEATHER.pm
Executable file
@ -0,0 +1,828 @@
|
||||
#################################################################################
|
||||
# 46_TRX_WEATHER.pm
|
||||
# Module for FHEM to decode weather sensor messages for RFXtrx
|
||||
#
|
||||
# The following devices are implemented to be received:
|
||||
#
|
||||
# temperature sensors (TEMP):
|
||||
# * "THR128" is THR128/138, THC138
|
||||
# * "THGR132N" is THC238/268,THN132,THWR288,THRN122,THN122,AW129/131
|
||||
# * "THWR800" is THWR800
|
||||
# * "RTHN318" is RTHN318
|
||||
# * "TX3_T" is LaCrosse TX3, TX4, TX17
|
||||
#
|
||||
# temperature/humidity sensors (TEMPHYDRO):
|
||||
# * "THGR228N" is THGN122/123, THGN132, THGR122/228/238/268
|
||||
# * "THGR810" is THGR810
|
||||
# * "RTGR328" is RTGR328
|
||||
# * "THGR328" is THGR328
|
||||
# * "WTGR800_T" is WTGR800
|
||||
# * "THGR918" is THGR918, THGRN228, THGN500
|
||||
# * "TFATS34C" is TFA TS34C
|
||||
#
|
||||
# temperature/humidity/pressure sensors (TEMPHYDROBARO):
|
||||
# * "BTHR918" is BTHR918
|
||||
# * "BTHR918N" is BTHR918N, BTHR968
|
||||
#
|
||||
# rain gauge sensors (RAIN):
|
||||
# * "RGR918" is RGR126/682/918
|
||||
# * "PCR800" is PCR800
|
||||
# * "TFA_RAIN" is TFA
|
||||
#
|
||||
# wind sensors (WIND):
|
||||
# * "WTGR800_A" is WTGR800
|
||||
# * "WGR800_A" is WGR800
|
||||
# * "WGR918_A" is STR918, WGR918
|
||||
# * "TFA_WIND" is TFA
|
||||
#
|
||||
# derived from 41_OREGON.pm
|
||||
#
|
||||
# Willi Herzig, 2012
|
||||
#
|
||||
# This script is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
##################################
|
||||
#
|
||||
# values for "set global verbose"
|
||||
# 4: log unknown protocols
|
||||
# 5: log decoding hexlines for debugging
|
||||
#
|
||||
# $Id:
|
||||
package main;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# Hex-Debugging into READING hexline? YES = 1, NO = 0
|
||||
my $TRX_HEX_debug = 0;
|
||||
|
||||
my $time_old = 0;
|
||||
|
||||
sub
|
||||
TRX_WEATHER_Initialize($)
|
||||
{
|
||||
my ($hash) = @_;
|
||||
|
||||
$hash->{Match} = "^[\x38-\x78].*";
|
||||
#$hash->{Match} = "^[^\x30]";
|
||||
$hash->{DefFn} = "TRX_WEATHER_Define";
|
||||
$hash->{UndefFn} = "TRX_WEATHER_Undef";
|
||||
$hash->{ParseFn} = "TRX_WEATHER_Parse";
|
||||
$hash->{AttrList} = "IODev do_not_notify:1,0 loglevel:0,1,2,3,4,5,6";
|
||||
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_WEATHER_Define($$)
|
||||
{
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split("[ \t][ \t]*", $def);
|
||||
|
||||
my $a = int(@a);
|
||||
#print "a0 = $a[0]";
|
||||
return "wrong syntax: define <name> TRX_WEATHER code" if(int(@a) != 3);
|
||||
|
||||
my $name = $a[0];
|
||||
my $code = $a[2];
|
||||
|
||||
$hash->{CODE} = $code;
|
||||
#$modules{TRX_WEATHER}{defptr}{$name} = $hash;
|
||||
$modules{TRX_WEATHER}{defptr}{$code} = $hash;
|
||||
AssignIoPort($hash);
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
#####################################
|
||||
sub
|
||||
TRX_WEATHER_Undef($$)
|
||||
{
|
||||
my ($hash, $name) = @_;
|
||||
delete($modules{TRX_WEATHER}{defptr}{$name});
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#########################################
|
||||
# From xpl-perl/lib/xPL/Util.pm:
|
||||
sub hi_nibble {
|
||||
($_[0]&0xf0)>>4;
|
||||
}
|
||||
sub lo_nibble {
|
||||
$_[0]&0xf;
|
||||
}
|
||||
sub nibble_sum {
|
||||
my $c = $_[0];
|
||||
my $s = 0;
|
||||
foreach (0..$_[0]-1) {
|
||||
$s += hi_nibble($_[1]->[$_]);
|
||||
$s += lo_nibble($_[1]->[$_]);
|
||||
}
|
||||
$s += hi_nibble($_[1]->[$_[0]]) if (int($_[0]) != $_[0]);
|
||||
return $s;
|
||||
}
|
||||
|
||||
# --------------------------------------------
|
||||
# From xpl-perl/lib/xPL/RF/Oregon.pm:
|
||||
# This function creates a simple key from a device type and message
|
||||
# length (in bits). It is used to as the index for the parts table.
|
||||
sub type_length_key {
|
||||
($_[0] << 8) + $_[1]
|
||||
}
|
||||
|
||||
# --------------------------------------------
|
||||
# sensor types
|
||||
|
||||
my %types =
|
||||
(
|
||||
# TEMP
|
||||
type_length_key(0x50, 0x08) =>
|
||||
{
|
||||
part => 'TEMP', method => \&common_temp,
|
||||
},
|
||||
# TEMP HYDRO
|
||||
type_length_key(0x52, 0x0a) =>
|
||||
{
|
||||
part => 'TEMPHYDRO', method => \&common_temphydro,
|
||||
},
|
||||
# TEMP HYDRO BARO
|
||||
type_length_key(0x54, 0x0d) =>
|
||||
{
|
||||
part => 'TEMPHYDROBARO', method => \&common_temphydrobaro,
|
||||
},
|
||||
# RAIN
|
||||
type_length_key(0x55, 0x0b) =>
|
||||
{
|
||||
part => 'RAIN', method => \&common_rain,
|
||||
},
|
||||
# WIND
|
||||
type_length_key(0x56, 0x10) =>
|
||||
{
|
||||
part => 'WIND', method => \&common_anemometer,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
# --------------------------------------------
|
||||
|
||||
#my $DOT = q{.};
|
||||
# Important: change it to _, because FHEM uses regexp
|
||||
my $DOT = q{_};
|
||||
|
||||
my @TRX_WEATHER_winddir_name=("N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW");
|
||||
|
||||
# --------------------------------------------
|
||||
# The following functions are changed:
|
||||
# - some parameter like "parent" and others are removed
|
||||
# - @res array return the values directly (no usage of xPL::Message)
|
||||
|
||||
sub temperature {
|
||||
my ($bytes, $dev, $res, $off) = @_;
|
||||
|
||||
my $temp =
|
||||
(
|
||||
(($bytes->[$off] & 0x80) ? -1 : 1) *
|
||||
(($bytes->[$off] & 0x7f)*256 + $bytes->[$off+1])
|
||||
)/10;
|
||||
|
||||
push @$res, {
|
||||
device => $dev,
|
||||
type => 'temp',
|
||||
current => $temp,
|
||||
units => 'Grad Celsius'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub humidity {
|
||||
my ($bytes, $dev, $res, $off) = @_;
|
||||
my $hum = $bytes->[$off];
|
||||
my $hum_str = ['dry', 'comfortable', 'normal', 'wet']->[$bytes->[$off+1]];
|
||||
push @$res, {
|
||||
device => $dev,
|
||||
type => 'humidity',
|
||||
current => $hum,
|
||||
string => $hum_str,
|
||||
units => '%'
|
||||
}
|
||||
}
|
||||
|
||||
sub pressure {
|
||||
my ($bytes, $dev, $res, $off) = @_;
|
||||
|
||||
#my $offset = 795 unless ($offset);
|
||||
my $hpa = ($bytes->[$off])*256 + $bytes->[$off+1];
|
||||
my $forecast = { 0x00 => 'noforecast',
|
||||
0x01 => 'sunny',
|
||||
0x02 => 'partly',
|
||||
0x03 => 'cloudy',
|
||||
0x04 => 'rain',
|
||||
}->{$bytes->[$off+2]} || 'unknown';
|
||||
push @$res, {
|
||||
device => $dev,
|
||||
type => 'pressure',
|
||||
current => $hpa,
|
||||
units => 'hPa',
|
||||
forecast => $forecast,
|
||||
}
|
||||
}
|
||||
|
||||
sub simple_battery {
|
||||
my ($bytes, $dev, $res, $off) = @_;
|
||||
|
||||
my $battery;
|
||||
|
||||
my $battery_level = $bytes->[$off] & 0x0f;
|
||||
if ($battery_level == 0x9) { $battery = 'ok'}
|
||||
elsif ($battery_level == 0x0) { $battery = 'low'}
|
||||
else {
|
||||
$battery = sprintf("unknown-%02x",$battery_level);
|
||||
}
|
||||
|
||||
push @$res, {
|
||||
device => $dev,
|
||||
type => 'battery',
|
||||
current => $battery,
|
||||
}
|
||||
}
|
||||
|
||||
sub battery {
|
||||
my ($bytes, $dev, $res, $off) = @_;
|
||||
|
||||
my $battery;
|
||||
|
||||
my $battery_level = ($bytes->[$off] & 0x0f) + 1;
|
||||
|
||||
if ($battery_level > 5) {
|
||||
$battery = sprintf("ok %d0%%",$battery_level);
|
||||
} else {
|
||||
$battery = sprintf("low %d0%%",$battery_level);
|
||||
}
|
||||
|
||||
push @$res, {
|
||||
device => $dev,
|
||||
type => 'battery',
|
||||
current => $battery,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my @uv_str =
|
||||
(
|
||||
qw/low low low/, # 0 - 2
|
||||
qw/medium medium medium/, # 3 - 5
|
||||
qw/high high/, # 6 - 7
|
||||
'very high', 'very high', 'very high', # 8 - 10
|
||||
);
|
||||
|
||||
sub uv_string {
|
||||
$uv_str[$_[0]] || 'dangerous';
|
||||
}
|
||||
|
||||
# Test if to use longid for device type
|
||||
sub use_longid {
|
||||
my ($longids,$dev_type) = @_;
|
||||
|
||||
return 0 if ($longids eq "");
|
||||
return 0 if ($longids eq "0");
|
||||
|
||||
return 1 if ($longids eq "1");
|
||||
return 1 if ($longids eq "ALL");
|
||||
|
||||
return 1 if(",$longids," =~ m/,$dev_type,/);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------
|
||||
#
|
||||
sub common_anemometer {
|
||||
my $type = shift;
|
||||
my $longids = shift;
|
||||
my $bytes = shift;
|
||||
|
||||
my $subtype = sprintf "%02x", $bytes->[1];
|
||||
#Log 1,"subtype=$subtype";
|
||||
my $dev_type;
|
||||
|
||||
my %devname =
|
||||
( # HEXSTRING => "NAME"
|
||||
0x01 => "WTGR800_A",
|
||||
0x02 => "WGR800_A",
|
||||
0x03 => "WGR918_A",
|
||||
0x04 => "TFA_WIND",
|
||||
);
|
||||
|
||||
if (exists $devname{$bytes->[1]}) {
|
||||
$dev_type = $devname{$bytes->[1]};
|
||||
} else {
|
||||
Log 1,"TRX_WEATHER: error undefined subtype=$subtype";
|
||||
my @res = ();
|
||||
return @res;
|
||||
}
|
||||
|
||||
#my $seqnbr = sprintf "%02x", $bytes->[2];
|
||||
#Log 1,"seqnbr=$seqnbr";
|
||||
|
||||
my $dev_str = $dev_type;
|
||||
if (use_longid($longids,$dev_type)) {
|
||||
$dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
|
||||
}
|
||||
if ($bytes->[4] > 0) {
|
||||
$dev_str .= $DOT.sprintf("%d", $bytes->[4]);
|
||||
}
|
||||
|
||||
my @res = ();
|
||||
|
||||
# hexline debugging
|
||||
if ($TRX_HEX_debug) {
|
||||
my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
|
||||
push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
|
||||
}
|
||||
|
||||
my $dir = $bytes->[5]*256 + $bytes->[6];
|
||||
my $dirname = $TRX_WEATHER_winddir_name[$dir/22.5];
|
||||
|
||||
my $avspeed = $bytes->[7]*256 + $bytes->[8];
|
||||
my $speed = $bytes->[9]*256 + $bytes->[10];
|
||||
|
||||
push @res, {
|
||||
device => $dev_str,
|
||||
type => 'speed',
|
||||
current => $speed,
|
||||
average => $avspeed,
|
||||
units => 'mps',
|
||||
} , {
|
||||
device => $dev_str,
|
||||
type => 'direction',
|
||||
current => $dir,
|
||||
string => $dirname,
|
||||
units => 'degrees',
|
||||
}
|
||||
;
|
||||
simple_battery($bytes, $dev_str, \@res, 15);
|
||||
|
||||
return @res;
|
||||
}
|
||||
|
||||
|
||||
# -----------------------------
|
||||
sub common_temp {
|
||||
my $type = shift;
|
||||
my $longids = shift;
|
||||
my $bytes = shift;
|
||||
|
||||
my $subtype = sprintf "%02x", $bytes->[1];
|
||||
#Log 1,"subtype=$subtype";
|
||||
my $dev_type;
|
||||
|
||||
my %devname =
|
||||
( # HEXSTRING => "NAME"
|
||||
0x01 => "THR128",
|
||||
0x02 => "THGR132N", # was THGR228N,
|
||||
0x03 => "THWR800",
|
||||
0x04 => "RTHN318",
|
||||
0x05 => "TX3_T",
|
||||
);
|
||||
|
||||
if (exists $devname{$bytes->[1]}) {
|
||||
$dev_type = $devname{$bytes->[1]};
|
||||
} else {
|
||||
Log 1,"RFX_WEATHER: error undefined subtype=$subtype";
|
||||
my @res = ();
|
||||
return @res;
|
||||
}
|
||||
|
||||
#my $seqnbr = sprintf "%02x", $bytes->[2];
|
||||
#Log 1,"seqnbr=$seqnbr";
|
||||
|
||||
my $dev_str = $dev_type;
|
||||
if (use_longid($longids,$dev_type)) {
|
||||
$dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
|
||||
}
|
||||
if ($bytes->[4] > 0) {
|
||||
$dev_str .= $DOT.sprintf("%d", $bytes->[4]);
|
||||
}
|
||||
#Log 1,"dev_str=$dev_str";
|
||||
|
||||
my @res = ();
|
||||
|
||||
# hexline debugging
|
||||
if ($TRX_HEX_debug) {
|
||||
my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
|
||||
push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
|
||||
}
|
||||
|
||||
temperature($bytes, $dev_str, \@res, 5);
|
||||
simple_battery($bytes, $dev_str, \@res, 7);
|
||||
return @res;
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
sub common_temphydro {
|
||||
my $type = shift;
|
||||
my $longids = shift;
|
||||
my $bytes = shift;
|
||||
|
||||
my $subtype = sprintf "%02x", $bytes->[1];
|
||||
#Log 1,"subtype=$subtype";
|
||||
my $dev_type;
|
||||
|
||||
my %devname =
|
||||
( # HEXSTRING => "NAME"
|
||||
0x01 => "THGR228N", # THGN122/123, THGN132, THGR122/228/238/268
|
||||
0x02 => "THGR810",
|
||||
0x03 => "RTGR328",
|
||||
0x04 => "THGR328",
|
||||
0x05 => "WTGR800_T",
|
||||
0x06 => "THGR918",
|
||||
0x07 => "TFATS34C",
|
||||
);
|
||||
|
||||
if (exists $devname{$bytes->[1]}) {
|
||||
$dev_type = $devname{$bytes->[1]};
|
||||
} else {
|
||||
Log 1,"RFX_WEATHER: error undefined subtype=$subtype";
|
||||
my @res = ();
|
||||
return @res;
|
||||
}
|
||||
|
||||
my $dev_str = $dev_type;
|
||||
if (use_longid($longids,$dev_type)) {
|
||||
$dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
|
||||
}
|
||||
if ($bytes->[4] > 0) {
|
||||
$dev_str .= $DOT.sprintf("%d", $bytes->[4]);
|
||||
}
|
||||
#Log 1,"dev_str=$dev_str";
|
||||
|
||||
my @res = ();
|
||||
|
||||
# hexline debugging
|
||||
if ($TRX_HEX_debug) {
|
||||
my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
|
||||
push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
|
||||
}
|
||||
|
||||
temperature($bytes, $dev_str, \@res, 5);
|
||||
humidity($bytes, $dev_str, \@res, 7);
|
||||
simple_battery($bytes, $dev_str, \@res, 9);
|
||||
return @res;
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
sub common_temphydrobaro {
|
||||
my $type = shift;
|
||||
my $longids = shift;
|
||||
my $bytes = shift;
|
||||
|
||||
my $subtype = sprintf "%02x", $bytes->[1];
|
||||
#Log 1,"subtype=$subtype";
|
||||
my $dev_type;
|
||||
|
||||
my %devname =
|
||||
( # HEXSTRING => "NAME"
|
||||
0x01 => "BTHR918",
|
||||
0x02 => "BTHR918N",
|
||||
);
|
||||
|
||||
if (exists $devname{$bytes->[1]}) {
|
||||
$dev_type = $devname{$bytes->[1]};
|
||||
} else {
|
||||
Log 1,"RFX_WEATHER: error undefined subtype=$subtype";
|
||||
my @res = ();
|
||||
return @res;
|
||||
}
|
||||
|
||||
my $dev_str = $dev_type;
|
||||
if (use_longid($longids,$dev_type)) {
|
||||
$dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
|
||||
}
|
||||
if ($bytes->[4] > 0) {
|
||||
$dev_str .= $DOT.sprintf("%d", $bytes->[4]);
|
||||
}
|
||||
#Log 1,"dev_str=$dev_str";
|
||||
|
||||
my @res = ();
|
||||
|
||||
# hexline debugging
|
||||
if ($TRX_HEX_debug) {
|
||||
my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
|
||||
push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
|
||||
}
|
||||
|
||||
temperature($bytes, $dev_str, \@res, 5);
|
||||
humidity($bytes, $dev_str, \@res, 7);
|
||||
pressure($bytes, $dev_str, \@res, 9);
|
||||
simple_battery($bytes, $dev_str, \@res, 12);
|
||||
return @res;
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
sub common_rain {
|
||||
my $type = shift;
|
||||
my $longids = shift;
|
||||
my $bytes = shift;
|
||||
|
||||
|
||||
my $subtype = sprintf "%02x", $bytes->[1];
|
||||
#Log 1,"subtype=$subtype";
|
||||
my $dev_type;
|
||||
|
||||
my %devname =
|
||||
( # HEXSTRING => "NAME"
|
||||
0x01 => "RGR918",
|
||||
0x02 => "PCR800",
|
||||
0x03 => "TFA_RAIN",
|
||||
);
|
||||
|
||||
if (exists $devname{$bytes->[1]}) {
|
||||
$dev_type = $devname{$bytes->[1]};
|
||||
} else {
|
||||
Log 1,"RFX_WEATHER: error undefined subtype=$subtype";
|
||||
my @res = ();
|
||||
return @res;
|
||||
}
|
||||
|
||||
my $dev_str = $dev_type;
|
||||
if (use_longid($longids,$dev_type)) {
|
||||
$dev_str .= $DOT.sprintf("%02x", $bytes->[3]);
|
||||
}
|
||||
if ($bytes->[4] > 0) {
|
||||
$dev_str .= $DOT.sprintf("%d", $bytes->[4]);
|
||||
}
|
||||
#Log 1,"dev_str=$dev_str";
|
||||
|
||||
my @res = ();
|
||||
|
||||
# hexline debugging
|
||||
if ($TRX_HEX_debug) {
|
||||
my $hexline = ""; for (my $i=0;$i<@$bytes;$i++) { $hexline .= sprintf("%02x",$bytes->[$i]);}
|
||||
push @res, { device => $dev_str, type => 'hexline', current => $hexline, units => 'hex', };
|
||||
}
|
||||
|
||||
my $rain = $bytes->[5]*256 + $bytes->[6];
|
||||
my $train = $bytes->[7]*256*256 + $bytes->[8]*256 + $bytes->[9];
|
||||
|
||||
push @res, {
|
||||
device => $dev_str,
|
||||
type => 'rain',
|
||||
current => $rain,
|
||||
units => 'mm/h',
|
||||
} ;
|
||||
push @res, {
|
||||
device => $dev_str,
|
||||
type => 'train',
|
||||
current => $train,
|
||||
units => 'mm',
|
||||
};
|
||||
battery($bytes, $dev_str, \@res, 10);
|
||||
return @res;
|
||||
}
|
||||
|
||||
sub raw {
|
||||
$_[0]->{raw} or $_[0]->{raw} = pack 'H*', $_[0]->{hex};
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
|
||||
sub
|
||||
TRX_WEATHER_Parse($$)
|
||||
{
|
||||
my ($iohash, $hexline) = @_;
|
||||
|
||||
#my $hashname = $iohash->{NAME};
|
||||
#my $longid = AttrVal($hashname,"longids","");
|
||||
#Log 1,"2: name=$hashname, attr longids = $longid";
|
||||
|
||||
my $longids = 0;
|
||||
if (defined($attr{$iohash->{NAME}}{longids})) {
|
||||
$longids = $attr{$iohash->{NAME}}{longids};
|
||||
#Log 1,"0: attr longids = $longids";
|
||||
}
|
||||
|
||||
my $time = time();
|
||||
# convert to binary
|
||||
my $msg = pack('H*', $hexline);
|
||||
if ($time_old ==0) {
|
||||
Log 5, "TRX_WEATHER: decoding delay=0 hex=$hexline";
|
||||
} else {
|
||||
my $time_diff = $time - $time_old ;
|
||||
Log 5, "TRX_WEATHER: decoding delay=$time_diff hex=$hexline";
|
||||
}
|
||||
$time_old = $time;
|
||||
|
||||
# convert string to array of bytes. Skip length byte
|
||||
my @rfxcom_data_array = ();
|
||||
foreach (split(//, substr($msg,1))) {
|
||||
push (@rfxcom_data_array, ord($_) );
|
||||
}
|
||||
|
||||
my $num_bytes = ord($msg);
|
||||
|
||||
if ($num_bytes < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
my $type = $rfxcom_data_array[0];
|
||||
|
||||
my $sensor_id = unpack('H*', chr $type);
|
||||
#Log 1, "TRX_WEATHER: sensor_id=$sensor_id";
|
||||
|
||||
my $key = type_length_key($type, $num_bytes);
|
||||
|
||||
my $rec = $types{$key} || $types{$key&0xfffff};
|
||||
unless ($rec) {
|
||||
#Log 3, "TRX_WEATHER: ERROR: Unknown sensor_id=$sensor_id num_bytes=$num_bytes message='$hexline'.";
|
||||
Log 4, "TRX_WEATHER: ERROR: Unknown sensor_id=$sensor_id message='$hexline'";
|
||||
Log 1, "TRX_WEATHER: ERROR: Unknown sensor_id=$sensor_id message='$hexline'";
|
||||
return "TRX_WEATHER: ERROR: Unknown sensor_id=$sensor_id \n";
|
||||
}
|
||||
|
||||
my $method = $rec->{method};
|
||||
unless ($method) {
|
||||
Log 4, "TRX_WEATHER: Possible message from Oregon part '$rec->{part}'";
|
||||
Log 4, "TRX_WEATHER: sensor_id=$sensor_id";
|
||||
return;
|
||||
}
|
||||
|
||||
my @res;
|
||||
|
||||
if (! defined(&$method)) {
|
||||
Log 4, "TRX_WEATHER: Error: Unknown function=$method. Please define it in file $0";
|
||||
Log 4, "TRX_WEATHER: sensor_id=$sensor_id\n";
|
||||
return "TRX_WEATHER: Error: Unknown function=$method. Please define it in file $0";
|
||||
} else {
|
||||
#Log 1, "TRX_WEATHER: parsing sensor_id=$sensor_id message='$hexline'";
|
||||
@res = $method->($rec->{part}, $longids, \@rfxcom_data_array);
|
||||
}
|
||||
|
||||
# get device name from first entry
|
||||
my $device_name = $res[0]->{device};
|
||||
#Log 1, "device_name=$device_name";
|
||||
|
||||
if (! defined($device_name)) {
|
||||
Log 4, "TRX_WEATHER: error device_name undefined\n";
|
||||
return "TRX_WEATHER: Error: Unknown devicename.";
|
||||
}
|
||||
|
||||
my $def = $modules{TRX_WEATHER}{defptr}{"$device_name"};
|
||||
if(!$def) {
|
||||
Log 3, "TRX_WEATHER: Unknown device $device_name, please define it";
|
||||
return "UNDEFINED $device_name TRX_WEATHER $device_name";
|
||||
}
|
||||
# Use $def->{NAME}, because the device may be renamed:
|
||||
my $name = $def->{NAME};
|
||||
#Log 1, "name=$new_name";
|
||||
|
||||
my $n = 0;
|
||||
my $tm = TimeNow();
|
||||
|
||||
my $i;
|
||||
my $val = "";
|
||||
my $sensor = "";
|
||||
foreach $i (@res){
|
||||
#print "!> i=".$i."\n";
|
||||
#printf "%s\t",$i->{device};
|
||||
if ($i->{type} eq "temp") {
|
||||
#printf "Temperatur %2.1f %s ; ",$i->{current},$i->{units};
|
||||
$val .= "T: ".$i->{current}." ";
|
||||
|
||||
$sensor = "temperature";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{current};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{current};
|
||||
}
|
||||
elsif ($i->{type} eq "humidity") {
|
||||
#printf "Luftfeuchtigkeit %d%s, %s ;",$i->{current},$i->{units},$i->{string};
|
||||
$val .= "H: ".$i->{current}." ";
|
||||
|
||||
$sensor = "humidity";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{current};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{current};;
|
||||
}
|
||||
elsif ($i->{type} eq "battery") {
|
||||
#printf "Batterie %d%s; ",$i->{current},$i->{units};
|
||||
my $tmp_battery = $i->{current};
|
||||
my @words = split(/\s+/,$i->{current});
|
||||
$val .= "BAT: ".$words[0]." "; #user only first word
|
||||
|
||||
$sensor = "battery";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{current};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{current};;
|
||||
}
|
||||
elsif ($i->{type} eq "pressure") {
|
||||
#printf "Luftdruck %d %s, Vorhersage=%s ; ",$i->{current},$i->{units},$i->{forecast};
|
||||
# do not add it due to problems with hms.gplot
|
||||
$val .= "P: ".$i->{current}." ";
|
||||
|
||||
$sensor = "pressure";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{current};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{current};;
|
||||
|
||||
$sensor = "forecast";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{forecast};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{forecast};;
|
||||
}
|
||||
elsif ($i->{type} eq "speed") {
|
||||
$val .= "W: ".$i->{current}." ";
|
||||
$val .= "WA: ".$i->{average}." ";
|
||||
|
||||
$sensor = "wind_speed";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{current};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{current};;
|
||||
|
||||
$sensor = "wind_avspeed";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{average};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{average};;
|
||||
}
|
||||
elsif ($i->{type} eq "direction") {
|
||||
$val .= "WD: ".$i->{current}." ";
|
||||
$val .= "WDN: ".$i->{string}." ";
|
||||
|
||||
$sensor = "wind_dir";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{current} . " " . $i->{string};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{current} . " " . $i->{string};;
|
||||
}
|
||||
elsif ($i->{type} eq "rain") {
|
||||
$val .= "RR: ".$i->{current}." ";
|
||||
|
||||
$sensor = "rain_rate";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{current};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{current};;
|
||||
}
|
||||
elsif ($i->{type} eq "train") {
|
||||
$val .= "TR: ".$i->{current}." ";
|
||||
|
||||
$sensor = "rain_total";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{current};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{current};;
|
||||
}
|
||||
elsif ($i->{type} eq "flip") {
|
||||
$val .= "F: ".$i->{current}." ";
|
||||
|
||||
$sensor = "rain_flip";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{current};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{current};;
|
||||
}
|
||||
elsif ($i->{type} eq "uv") {
|
||||
$val .= "UV: ".$i->{current}." ";
|
||||
$val .= "UVR: ".$i->{risk}." ";
|
||||
|
||||
$sensor = "uv_val";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{current};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{current};;
|
||||
|
||||
$sensor = "uv_risk";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{risk};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{risk};;
|
||||
}
|
||||
elsif ($i->{type} eq "hexline") {
|
||||
$sensor = "hexline";
|
||||
$def->{READINGS}{$sensor}{TIME} = $tm;
|
||||
$def->{READINGS}{$sensor}{VAL} = $i->{current};
|
||||
$def->{CHANGED}[$n++] = $sensor . ": " . $i->{current};;
|
||||
}
|
||||
else {
|
||||
print "\nTRX_WEATHER: Unknown: ";
|
||||
print "Type: ".$i->{type}.", ";
|
||||
print "Value: ".$i->{current}."\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ("$val" ne "") {
|
||||
# remove heading and trailing space chars from $val
|
||||
$val =~ s/^\s+|\s+$//g;
|
||||
|
||||
$def->{STATE} = $val;
|
||||
$def->{TIME} = $tm;
|
||||
$def->{CHANGED}[$n++] = $val;
|
||||
}
|
||||
|
||||
#
|
||||
#$def->{READINGS}{state}{TIME} = $tm;
|
||||
#$def->{READINGS}{state}{VAL} = $val;
|
||||
#$def->{CHANGED}[$n++] = "state: ".$val;
|
||||
|
||||
DoTrigger($name, undef);
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
1;
|
@ -489,4 +489,8 @@
|
||||
- Sun Jan 29 2012 (Maz Rashid)
|
||||
- Improving 10_EIB.pm by introducing Get and interpreting received value according
|
||||
to the selected model (based on datapoint types.)
|
||||
- Introduced documentation for TUL / EIB modules.
|
||||
- Introduced documentation for TUL / EIB modules.
|
||||
|
||||
- Fr Feb 24 2012 (Willi)
|
||||
- New modules TRX for RFXCOM RFXtrx transceiver
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user