ws2000_reader.pl 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. #!/usr/bin/perl
  2. #
  3. # read_ws2000 from device (elv art-Nr. 390-61) and provides socket service (like XPORT),
  4. # or act as client for this service
  5. # licence GPL2
  6. # Thomas Dressler 2008
  7. # $Id: ws2000_reader.pl,v 1.2 2010-08-01 13:33:13 rudolfkoenig Exp $
  8. use Switch;
  9. use strict;
  10. use IO::Socket;
  11. use IO::Select;
  12. our $PortObj;
  13. my $server;
  14. our $xport;
  15. our $sel;
  16. our $clients;
  17. our %sockets;
  18. my ($datum,$data,$lastdate,$lastdata);
  19. $SIG{INT}=$SIG{TERM}=\&signalhandler;
  20. $|=1;
  21. PortOpen($ARGV[0]);
  22. my $ServerPort=$ARGV[1];
  23. if ($ServerPort) {
  24. $server=IO::Socket::INET->new(LocalPort=>$ServerPort,
  25. ReuseAddr=>1,
  26. Listen=>10,
  27. timeout=>1,
  28. blocking=>0
  29. );
  30. die "ServerStart-Error: $@ \n" if !$server;
  31. $clients=IO::Select->new($server);
  32. }
  33. MAINLOOP:
  34. for(;;) {
  35. if($server) {
  36. #only for server mode
  37. my %message=undef;
  38. my $fh;
  39. while(my @ready=$clients->can_read(1)) {
  40. foreach $fh (@ready) {
  41. if ($fh==$server) {
  42. #new connection waiting
  43. my $new=$server->accept;
  44. $new->autoflush(1);
  45. $new->blocking(0);
  46. $new->timeout(1);
  47. $clients->add($new);
  48. my $host=$new->peerhost;
  49. $sockets{$new}=$host;
  50. print "\nNew Client:".$host."\n";
  51. #}else{
  52. # my $out=undef;
  53. # $fh->read($out,1);
  54. # $message{$fh}=$out;
  55. }
  56. }
  57. }
  58. #check living connections
  59. foreach my $fh($clients->handles) {
  60. next if $fh==$server;
  61. next if ($fh->peerhost);
  62. print "Terminate ".$sockets{$fh}. " by Check1\n";
  63. Client_disconnect($fh);
  64. }
  65. }
  66. $data=get_data();
  67. next if ! $data;
  68. $datum = time();
  69. next if ($data eq $lastdata) && (($datum - $lastdate) < 30);
  70. my $result=decode_data($data);
  71. print scalar localtime().":".$result."\n";
  72. $lastdata = $data;
  73. $lastdate = $datum;
  74. }
  75. PortClose();
  76. exit 0;
  77. #--------SUBs -----------------------------
  78. sub Clientdisconnect{
  79. my $fh=shift;
  80. print "\n Client ".$sockets{$fh}." disconnected!\n";
  81. $clients->remove($fh);
  82. delete $sockets{$fh};
  83. $fh->shutdown(2);
  84. $fh->close;
  85. }
  86. sub PortOpen{
  87. my $PortName=shift;
  88. my $quiet=shift ||undef;
  89. if ($PortName=~/^\/dev|^COM/) {
  90. #normal devices (/dev)
  91. my $OS=$^O;
  92. if ($OS eq 'MSWin32') {
  93. eval ("use Win32::SerialPort;");
  94. die "$@\n" if ($@);
  95. $PortObj = new Win32::SerialPort ($PortName, $quiet)
  96. || die "Can't open $PortName: $^E\n"; # $quiet is optional
  97. } else {
  98. eval ("use Device::SerialPort;");
  99. die "$@\n" if ($@);
  100. $PortObj = new Device::SerialPort ($PortName, $quiet)
  101. || die "Can't open $PortName: $^E\n"; # $quiet is optional
  102. }
  103. #Parameter 19200,8,2,Odd,None
  104. $PortObj->baudrate(19200);
  105. $PortObj->databits(8);
  106. $PortObj->parity("odd");
  107. $PortObj->stopbits(2);
  108. $PortObj->handshake("none");
  109. if (! $PortObj->write_settings) {
  110. undef $PortObj;
  111. die "Write Settings failed!\n";
  112. }
  113. $sel=IO::Select->new($PortObj->{FD} );
  114. }elsif($PortName=~/([\w.]+):(\d{1,5})/){
  115. #Sockets(hostname:port)
  116. my $host=$1;
  117. my $port=$2;
  118. $xport=IO::Socket::INET->new(PeerAddr=>$host,
  119. PeerPort=>$port,
  120. timeout=>1,
  121. blocking=>0
  122. );
  123. die "Cannot connect to $PortName -> $@ ( $!) \n" if ! $xport;
  124. $xport->autoflush(1);
  125. $sel=IO::Select->new($xport);
  126. }else{
  127. die "$PortName is no device and not implemented!\n";
  128. }
  129. }
  130. sub PortClose {
  131. $PortObj->close if ($PortObj);
  132. if ($xport) {
  133. $clients->remove($xport) if $clients;
  134. $xport->shutdown(2);
  135. $xport->close;
  136. }
  137. if ($clients) {
  138. foreach my $socket($clients->handles) {
  139. Clientdisconnect($socket);
  140. }
  141. }
  142. }
  143. sub signalhandler {
  144. my $signal=shift;
  145. PortClose();
  146. print "\nTerminated by Signal $signal!\n";
  147. exit;
  148. }
  149. sub get_data {
  150. my $STX=2;
  151. my $ETX=3;
  152. my $retval='';
  153. my $status='';
  154. my $out=undef;
  155. my $message;
  156. my $byte;
  157. for(;;) {
  158. #sleep 1 if(!defined($out) || length($out) == 0);
  159. $out=undef;
  160. if ($xport) {
  161. #my @readable=$select->can_read(1);
  162. #next if $#readable<0;
  163. #my $fh;
  164. #foreach $fh (@readable) {
  165. next if ! $sel->can_read(1);
  166. $xport->read($out,1);
  167. #if ($xport->eof) {
  168. # print "Xport eof\n";
  169. # print "Server disconnected, terminate!\n";
  170. # PortClose();
  171. # exit 1;
  172. #}
  173. }elsif($PortObj) {
  174. $out = $PortObj->read(1);
  175. }
  176. next if(!defined($out) || length($out) == 0) ;
  177. $byte=ord($out);
  178. if($byte eq $STX) {
  179. #Log 4, "M232: return value \'" . $retval . "\'";
  180. $status= "STX";
  181. $message=$out;
  182. } elsif($byte eq $ETX) {
  183. $status= "ETX";
  184. $message .=$out;
  185. } elsif ($status eq "STX"){
  186. $byte=$byte & 0x7F;
  187. $retval .= chr($byte);
  188. $message .=$out;
  189. }
  190. last if($status eq "ETX");
  191. }
  192. if ($server) {
  193. foreach my $client($clients->can_write(1)) {
  194. next if $client == $server;
  195. if (!$client->send($message)){
  196. Clientdisconnect($client);
  197. next;
  198. }
  199. }
  200. }
  201. return $retval;
  202. }
  203. sub decode_data {
  204. my ($sensor,$daten1,$einheit1,$daten2,$einheit2,$daten3,$einheit3,$result);
  205. my $data=shift;
  206. my ($typ,$w1,$w2,$w3,$w4,$w5)=unpack("U*",$data);
  207. my $group = ($typ & 0x70)/16 ;#/slash for komodo syntax checker!
  208. my $snr = $typ % 16;
  209. switch ( $group ){
  210. case 7 {
  211. $sensor = "Fernbedienung";
  212. $daten1 = $w1 * 10000 + $w2 * 1000 + $w3 * 100 + $w4 * 10 + $w5;
  213. $result = $sensor . "=" . $daten1 . $einheit1;
  214. }
  215. case 0 {
  216. if ($snr < 8) {
  217. $sensor = "Temperatursensor V1.1(" . $snr . ")";
  218. }else{
  219. $sensor = "Temperatursensor V1.2(" .($snr - 8). ")";
  220. }
  221. if ($w1 >= 64) {
  222. $daten1 = ((255 - $w1 - $w2) / 10) * (-1);
  223. }else{
  224. $daten1 = (($w1 * 128 + $w2) / 10);
  225. }
  226. $einheit1 = " °C";
  227. $result = $sensor . "=" . $daten1 . $einheit1;
  228. }
  229. case 1 {
  230. if ($snr <8) {
  231. $sensor = "Temperatursensor mit Feuchte V1.1(" . $snr . ")";
  232. }else{
  233. $sensor = "Temperatursensor mit Feuchte V1.2(" . ($snr - 8) . ")";
  234. }
  235. if ($w1 >= 64) {
  236. $daten1 = ((255 - $w1 - $w2) / 10) * (-1);
  237. }else{
  238. $daten1 = (($w1 * 128 + $w2) / 10);
  239. }
  240. $daten2 = $w3;
  241. $daten3 = 0;
  242. $einheit1 = " °C";
  243. $einheit2 = " %";
  244. $result = $sensor . "=" . $daten1 . $einheit1 . " " . $daten2 .$einheit2;
  245. }
  246. case 2 {
  247. if ( $snr < 8 ) {
  248. $sensor = "Regensensor V1.1(" . $snr . ")";
  249. }else{
  250. $sensor = "Regensensor V1.2(" . ($snr - 8) . ")"
  251. }
  252. $daten1 = ($w1 * 128 + $w2) * 0.36;
  253. $einheit1 = " l/m²";
  254. $result = $sensor . "=" . $daten1 . $einheit1;
  255. }
  256. case 3 {
  257. if ($snr < 8) {
  258. $sensor = "Windsensor V1.1(" . $snr . ")";
  259. }else{
  260. $sensor = "Windsensor V1.2(" & ($snr - 8) . ")";
  261. }
  262. switch( $w3) {
  263. case 0 { $einheit3 = "±0 °";}
  264. case 1 { $einheit3 = "± 22,5 °";}
  265. case 2 { $einheit3 = "± 45 °";}
  266. case 3 { $einheit3 = "± 67,5 °";}
  267. }
  268. $daten1 = ($w1 * 128 + $w2) / 10;
  269. $daten2 = $w4 * 128 + $w5;
  270. $einheit1 = " km/h";
  271. $einheit2 = " °";
  272. $result = $sensor . "=" . $daten1 . $einheit1 . " " . $daten2 . $einheit2 . " " . $einheit3;
  273. }
  274. case 4 {
  275. if ($snr < 8) {
  276. $sensor = "Innensensor V1.1(" . $snr . ")";
  277. }else{
  278. $sensor = "Innensensor V1.2(" . ($snr - 8) . ")";
  279. }
  280. if ($w1 >= 64) {
  281. $daten1 = ((255 - $w1 - $w2) / 10) * (-1);
  282. }else{
  283. $daten1 = (($w1 * 128 + $w2) / 10);
  284. }
  285. $daten2 = $w3;
  286. $daten3 = $w4 * 128 + $w5;
  287. $einheit1 = " °C";
  288. $einheit2 = " %";
  289. $einheit3 = " hPa";
  290. $result = $sensor . "=" . $daten1 . $einheit1 . " " . $daten2 . $einheit2 . " " . $daten3 . $einheit3;
  291. }
  292. case 5 {
  293. $sensor = "Helligkeitssensor V1.2(" . ($snr - 8) . ")";
  294. switch ($w3) {
  295. case 0 {$daten1 = 1;}
  296. case 1 {$daten1 = 10;}
  297. case 2 {$daten1 = 100;}
  298. case 3 {$daten1 = 1000;}
  299. }
  300. $daten1 = $daten1 * ($w1 * 128 + $w2);
  301. $einheit1 = "Lux";
  302. $result = $sensor . "=" . $daten1 . $einheit1;
  303. }
  304. case 6 {
  305. $sensor = "Pyranometer V1.2(" . ($snr - 8) . ")";
  306. switch ($w3) {
  307. case 0 {$daten1 = 1;}
  308. case 1 {$daten1 = 10;}
  309. case 2 {$daten1 = 100;}
  310. case 3 {$daten1 = 1000;}
  311. }
  312. $daten1 = $daten1 * ($w1 * 128 + $w2);
  313. $einheit1 = " W/m²";
  314. $result = $sensor . "=" . $daten1 . $einheit1;
  315. }
  316. else {
  317. $sensor = "Störung";
  318. $daten1 = $typ;
  319. $result = $sensor . "(Group:" . $group . "/Typ:" . $typ . ")";
  320. }#switch else
  321. }#switch
  322. return $result;
  323. }