mirror of
https://github.com/fhem/fhem-mirror.git
synced 2024-11-22 09:49:50 +00:00
06169df608
git-svn-id: https://svn.fhem.de/fhem/trunk@660 2b470e98-0d58-463d-a4d8-8e2adae1ed80
354 lines
10 KiB
Perl
354 lines
10 KiB
Perl
#!/usr/bin/perl
|
||
#
|
||
# read_ws2000 from device (elv art-Nr. 390-61) and provides socket service (like XPORT),
|
||
# or act as client for this service
|
||
# licence GPL2
|
||
# Thomas Dressler 2008
|
||
# $Id: ws2000_reader.pl,v 1.2 2010-08-01 13:33:13 rudolfkoenig Exp $
|
||
|
||
use Switch;
|
||
use strict;
|
||
use IO::Socket;
|
||
use IO::Select;
|
||
|
||
our $PortObj;
|
||
my $server;
|
||
our $xport;
|
||
our $sel;
|
||
our $clients;
|
||
our %sockets;
|
||
my ($datum,$data,$lastdate,$lastdata);
|
||
$SIG{INT}=$SIG{TERM}=\&signalhandler;
|
||
$|=1;
|
||
|
||
PortOpen($ARGV[0]);
|
||
|
||
my $ServerPort=$ARGV[1];
|
||
if ($ServerPort) {
|
||
$server=IO::Socket::INET->new(LocalPort=>$ServerPort,
|
||
ReuseAddr=>1,
|
||
Listen=>10,
|
||
timeout=>1,
|
||
blocking=>0
|
||
);
|
||
die "ServerStart-Error: $@ \n" if !$server;
|
||
$clients=IO::Select->new($server);
|
||
}
|
||
|
||
|
||
MAINLOOP:
|
||
for(;;) {
|
||
if($server) {
|
||
#only for server mode
|
||
my %message=undef;
|
||
my $fh;
|
||
while(my @ready=$clients->can_read(1)) {
|
||
foreach $fh (@ready) {
|
||
if ($fh==$server) {
|
||
#new connection waiting
|
||
my $new=$server->accept;
|
||
$new->autoflush(1);
|
||
$new->blocking(0);
|
||
$new->timeout(1);
|
||
$clients->add($new);
|
||
my $host=$new->peerhost;
|
||
$sockets{$new}=$host;
|
||
print "\nNew Client:".$host."\n";
|
||
#}else{
|
||
# my $out=undef;
|
||
# $fh->read($out,1);
|
||
# $message{$fh}=$out;
|
||
}
|
||
}
|
||
}
|
||
#check living connections
|
||
foreach my $fh($clients->handles) {
|
||
next if $fh==$server;
|
||
next if ($fh->peerhost);
|
||
print "Terminate ".$sockets{$fh}. " by Check1\n";
|
||
Client_disconnect($fh);
|
||
}
|
||
|
||
}
|
||
$data=get_data();
|
||
next if ! $data;
|
||
$datum = time();
|
||
next if ($data eq $lastdata) && (($datum - $lastdate) < 30);
|
||
my $result=decode_data($data);
|
||
print scalar localtime().":".$result."\n";
|
||
$lastdata = $data;
|
||
$lastdate = $datum;
|
||
}
|
||
PortClose();
|
||
exit 0;
|
||
#--------SUBs -----------------------------
|
||
sub Clientdisconnect{
|
||
my $fh=shift;
|
||
print "\n Client ".$sockets{$fh}." disconnected!\n";
|
||
$clients->remove($fh);
|
||
delete $sockets{$fh};
|
||
$fh->shutdown(2);
|
||
$fh->close;
|
||
}
|
||
sub PortOpen{
|
||
my $PortName=shift;
|
||
my $quiet=shift ||undef;
|
||
|
||
if ($PortName=~/^\/dev|^COM/) {
|
||
#normal devices (/dev)
|
||
my $OS=$^O;
|
||
if ($OS eq 'MSWin32') {
|
||
eval ("use Win32::SerialPort;");
|
||
die "$@\n" if ($@);
|
||
$PortObj = new Win32::SerialPort ($PortName, $quiet)
|
||
|| die "Can't open $PortName: $^E\n"; # $quiet is optional
|
||
} else {
|
||
eval ("use Device::SerialPort;");
|
||
die "$@\n" if ($@);
|
||
$PortObj = new Device::SerialPort ($PortName, $quiet)
|
||
|| die "Can't open $PortName: $^E\n"; # $quiet is optional
|
||
|
||
}
|
||
#Parameter 19200,8,2,Odd,None
|
||
$PortObj->baudrate(19200);
|
||
$PortObj->databits(8);
|
||
$PortObj->parity("odd");
|
||
$PortObj->stopbits(2);
|
||
$PortObj->handshake("none");
|
||
if (! $PortObj->write_settings) {
|
||
undef $PortObj;
|
||
die "Write Settings failed!\n";
|
||
}
|
||
$sel=IO::Select->new($PortObj->{FD} );
|
||
}elsif($PortName=~/([\w.]+):(\d{1,5})/){
|
||
#Sockets(hostname:port)
|
||
my $host=$1;
|
||
my $port=$2;
|
||
$xport=IO::Socket::INET->new(PeerAddr=>$host,
|
||
PeerPort=>$port,
|
||
timeout=>1,
|
||
blocking=>0
|
||
);
|
||
die "Cannot connect to $PortName -> $@ ( $!) \n" if ! $xport;
|
||
$xport->autoflush(1);
|
||
$sel=IO::Select->new($xport);
|
||
}else{
|
||
die "$PortName is no device and not implemented!\n";
|
||
}
|
||
}
|
||
sub PortClose {
|
||
$PortObj->close if ($PortObj);
|
||
if ($xport) {
|
||
$clients->remove($xport) if $clients;
|
||
$xport->shutdown(2);
|
||
$xport->close;
|
||
}
|
||
if ($clients) {
|
||
foreach my $socket($clients->handles) {
|
||
Clientdisconnect($socket);
|
||
}
|
||
}
|
||
}
|
||
sub signalhandler {
|
||
my $signal=shift;
|
||
PortClose();
|
||
print "\nTerminated by Signal $signal!\n";
|
||
exit;
|
||
}
|
||
|
||
sub get_data {
|
||
|
||
my $STX=2;
|
||
my $ETX=3;
|
||
my $retval='';
|
||
my $status='';
|
||
my $out=undef;
|
||
my $message;
|
||
my $byte;
|
||
for(;;) {
|
||
#sleep 1 if(!defined($out) || length($out) == 0);
|
||
$out=undef;
|
||
if ($xport) {
|
||
|
||
#my @readable=$select->can_read(1);
|
||
#next if $#readable<0;
|
||
|
||
|
||
#my $fh;
|
||
#foreach $fh (@readable) {
|
||
|
||
next if ! $sel->can_read(1);
|
||
$xport->read($out,1);
|
||
#if ($xport->eof) {
|
||
# print "Xport eof\n";
|
||
# print "Server disconnected, terminate!\n";
|
||
# PortClose();
|
||
# exit 1;
|
||
|
||
#}
|
||
|
||
|
||
|
||
}elsif($PortObj) {
|
||
$out = $PortObj->read(1);
|
||
}
|
||
next if(!defined($out) || length($out) == 0) ;
|
||
|
||
|
||
$byte=ord($out);
|
||
if($byte eq $STX) {
|
||
#Log 4, "M232: return value \'" . $retval . "\'";
|
||
$status= "STX";
|
||
$message=$out;
|
||
} elsif($byte eq $ETX) {
|
||
$status= "ETX";
|
||
$message .=$out;
|
||
} elsif ($status eq "STX"){
|
||
$byte=$byte & 0x7F;
|
||
$retval .= chr($byte);
|
||
$message .=$out;
|
||
}
|
||
last if($status eq "ETX");
|
||
|
||
}
|
||
if ($server) {
|
||
foreach my $client($clients->can_write(1)) {
|
||
next if $client == $server;
|
||
if (!$client->send($message)){
|
||
Clientdisconnect($client);
|
||
next;
|
||
}
|
||
|
||
}
|
||
}
|
||
return $retval;
|
||
}
|
||
|
||
|
||
sub decode_data {
|
||
my ($sensor,$daten1,$einheit1,$daten2,$einheit2,$daten3,$einheit3,$result);
|
||
my $data=shift;
|
||
my ($typ,$w1,$w2,$w3,$w4,$w5)=unpack("U*",$data);
|
||
my $group = ($typ & 0x70)/16 ;#/slash for komodo syntax checker!
|
||
my $snr = $typ % 16;
|
||
|
||
|
||
switch ( $group ){
|
||
case 7 {
|
||
$sensor = "Fernbedienung";
|
||
$daten1 = $w1 * 10000 + $w2 * 1000 + $w3 * 100 + $w4 * 10 + $w5;
|
||
$result = $sensor . "=" . $daten1 . $einheit1;
|
||
}
|
||
case 0 {
|
||
if ($snr < 8) {
|
||
$sensor = "Temperatursensor V1.1(" . $snr . ")";
|
||
}else{
|
||
$sensor = "Temperatursensor V1.2(" .($snr - 8). ")";
|
||
}
|
||
if ($w1 >= 64) {
|
||
$daten1 = ((255 - $w1 - $w2) / 10) * (-1);
|
||
}else{
|
||
$daten1 = (($w1 * 128 + $w2) / 10);
|
||
}
|
||
$einheit1 = " <20>C";
|
||
$result = $sensor . "=" . $daten1 . $einheit1;
|
||
}
|
||
case 1 {
|
||
if ($snr <8) {
|
||
$sensor = "Temperatursensor mit Feuchte V1.1(" . $snr . ")";
|
||
}else{
|
||
$sensor = "Temperatursensor mit Feuchte V1.2(" . ($snr - 8) . ")";
|
||
}
|
||
if ($w1 >= 64) {
|
||
$daten1 = ((255 - $w1 - $w2) / 10) * (-1);
|
||
}else{
|
||
$daten1 = (($w1 * 128 + $w2) / 10);
|
||
}
|
||
|
||
$daten2 = $w3;
|
||
$daten3 = 0;
|
||
$einheit1 = " <20>C";
|
||
$einheit2 = " %";
|
||
|
||
$result = $sensor . "=" . $daten1 . $einheit1 . " " . $daten2 .$einheit2;
|
||
}
|
||
case 2 {
|
||
if ( $snr < 8 ) {
|
||
$sensor = "Regensensor V1.1(" . $snr . ")";
|
||
}else{
|
||
$sensor = "Regensensor V1.2(" . ($snr - 8) . ")"
|
||
}
|
||
$daten1 = ($w1 * 128 + $w2) * 0.36;
|
||
$einheit1 = " l/m<>";
|
||
$result = $sensor . "=" . $daten1 . $einheit1;
|
||
}
|
||
case 3 {
|
||
if ($snr < 8) {
|
||
$sensor = "Windsensor V1.1(" . $snr . ")";
|
||
}else{
|
||
$sensor = "Windsensor V1.2(" & ($snr - 8) . ")";
|
||
}
|
||
switch( $w3) {
|
||
case 0 { $einheit3 = "<22>0 <20>";}
|
||
case 1 { $einheit3 = "<22> 22,5 <20>";}
|
||
case 2 { $einheit3 = "<22> 45 <20>";}
|
||
case 3 { $einheit3 = "<22> 67,5 <20>";}
|
||
}
|
||
$daten1 = ($w1 * 128 + $w2) / 10;
|
||
$daten2 = $w4 * 128 + $w5;
|
||
$einheit1 = " km/h";
|
||
$einheit2 = " <20>";
|
||
$result = $sensor . "=" . $daten1 . $einheit1 . " " . $daten2 . $einheit2 . " " . $einheit3;
|
||
}
|
||
case 4 {
|
||
if ($snr < 8) {
|
||
$sensor = "Innensensor V1.1(" . $snr . ")";
|
||
}else{
|
||
$sensor = "Innensensor V1.2(" . ($snr - 8) . ")";
|
||
}
|
||
if ($w1 >= 64) {
|
||
$daten1 = ((255 - $w1 - $w2) / 10) * (-1);
|
||
}else{
|
||
$daten1 = (($w1 * 128 + $w2) / 10);
|
||
}
|
||
$daten2 = $w3;
|
||
$daten3 = $w4 * 128 + $w5;
|
||
$einheit1 = " <20>C";
|
||
$einheit2 = " %";
|
||
$einheit3 = " hPa";
|
||
$result = $sensor . "=" . $daten1 . $einheit1 . " " . $daten2 . $einheit2 . " " . $daten3 . $einheit3;
|
||
}
|
||
case 5 {
|
||
$sensor = "Helligkeitssensor V1.2(" . ($snr - 8) . ")";
|
||
switch ($w3) {
|
||
case 0 {$daten1 = 1;}
|
||
case 1 {$daten1 = 10;}
|
||
case 2 {$daten1 = 100;}
|
||
case 3 {$daten1 = 1000;}
|
||
}
|
||
$daten1 = $daten1 * ($w1 * 128 + $w2);
|
||
$einheit1 = "Lux";
|
||
$result = $sensor . "=" . $daten1 . $einheit1;
|
||
}
|
||
case 6 {
|
||
$sensor = "Pyranometer V1.2(" . ($snr - 8) . ")";
|
||
switch ($w3) {
|
||
case 0 {$daten1 = 1;}
|
||
case 1 {$daten1 = 10;}
|
||
case 2 {$daten1 = 100;}
|
||
case 3 {$daten1 = 1000;}
|
||
}
|
||
$daten1 = $daten1 * ($w1 * 128 + $w2);
|
||
$einheit1 = " W/m<>";
|
||
$result = $sensor . "=" . $daten1 . $einheit1;
|
||
}
|
||
else {
|
||
$sensor = "St<53>rung";
|
||
$daten1 = $typ;
|
||
$result = $sensor . "(Group:" . $group . "/Typ:" . $typ . ")";
|
||
}#switch else
|
||
|
||
}#switch
|
||
return $result;
|
||
}
|