mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-12 22:56:34 +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: FHEMWEB redirectCmds attribute added
|
||||||
- feature: CUL_TX minsecs attribute (by Arno)
|
- feature: CUL_TX minsecs attribute (by Arno)
|
||||||
- feature: webCmd in smallScreen added
|
- feature: webCmd in smallScreen added
|
||||||
|
- feature: TRX modules by Willi
|
||||||
|
|
||||||
- 2011-12-31 (5.2)
|
- 2011-12-31 (5.2)
|
||||||
- bugfix: applying smallscreen attributes to firefox/opera
|
- 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)
|
- Sun Jan 29 2012 (Maz Rashid)
|
||||||
- Improving 10_EIB.pm by introducing Get and interpreting received value according
|
- Improving 10_EIB.pm by introducing Get and interpreting received value according
|
||||||
to the selected model (based on datapoint types.)
|
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