| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- # $Id: 50_WS300.pm 8178 2015-03-09 00:55:07Z dirkho $
- ################################################################
- #
- # Copyright notice
- #
- # (c) 2007 Copyright: Martin Klerx (Martin at klerx dot de)
- # All rights reserved
- #
- # This script free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # The GNU General Public License can be found at
- # http://www.gnu.org/copyleft/gpl.html.
- # A copy is found in the textfile GPL.txt and important notices to the license
- # from the author is found in LICENSE.txt distributed with these scripts.
- #
- # 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. See the
- # GNU General Public License for more details.
- #
- # This copyright notice MUST APPEAR in all copies of the script!
- #
- ################################################################
- # examples:
- # define WS300Device WS300 /dev/ttyUSB1 (fixed name, must be first)
- # define ash2200-1 WS300 0
- # define ash2200-2 WS300 1
- # ...
- # define ash2200-8 WS300 7
- # define ks300 WS300 8 (always 8)
- # define ws300 WS300 9 (always 9)
- # set WS300Device <interval(5-60 min.)> <height(0-2000 m)> <rainvalume(ml)>
- ################################################################
- package main;
- use strict;
- use warnings;
- my $DeviceName="";
- my $inbuf="";
- my $config;
- my $cmd=0x32;
- my $errcount=0;
- my $ir="no";
- my $willi=0;
- my $oldwind=0.0;
- my $polling=0;
- my $acthour=99;
- my $actday=99;
- my $actmonth=99;
- my $oldrain=0;
- my $rain_hour=0;
- my $rain_day=0;
- my $rain_month=0;
- #####################################
- sub
- WS300_Initialize($)
- {
- my ($hash) = @_;
- # Provider
- $hash->{AttrList} = "do_not_notify:0,1 showtime:0,1 model:ws300 ".
- $readingFnAttributes;
- $hash->{DefFn} = "WS300_Define";
- $hash->{GetFn} = "WS300_Get";
- $hash->{ParseFn} = "WS300_Parse";
- $hash->{SetFn} = "WS300_Set";
- $hash->{UndefFn} = "WS300_Undef";
- $hash->{Clients} = ":WS300:"; # Not needed
- $hash->{Match} = "^WS300.*"; # Not needed
- $hash->{ReadFn} = "WS300_Read"; # Not needed
- $hash->{Type} = "FHZ1000"; # Not needed
- $hash->{WriteFn} = "WS300_Write"; # Not needed
- }
- ###################################
- sub
- WS300_Set($@)
- {
- my ($hash, @a) = @_;
- if($hash->{NAME} eq "WS300Device")
- {
- return "wrong syntax: set WS300Device <Interval(5-60 min.)> <height(0-2000 m)> <rainvolume(ml)>" if(int(@a) < 4 || int($a[1]) < 5 || int($a[1]) > 60 || int($a[2]) > 2000);
- my $bstring = sprintf("%c%c%c%c%c%c%c%c",0xfe,0x30,(int($a[1])&0xff),((int($a[2])>>8)&0xff),(int($a[2])&0xff),((int($a[3])>>8)&0xff),(int($a[3])&0xff),0xfc);
- $hash->{PortObj}->write($bstring);
- Log 1,"WS300 synchronization started (".unpack('H*',$bstring).")";
- return "the ws300pc will now synchronize for 10 minutes";
- }
- return "No set function implemented";
- }
- ###################################
- sub
- WS300_Get(@)
- {
- my ($hash, @a) = @_;
- if($hash->{NAME} eq "WS300Device")
- {
- Log 5,"WS300_Get $a[0] $a[1]";
- WS300_Poll($hash);
- return undef;
- }
- return "No get function implemented";
- }
- #####################################
- sub
- WS300_Define($$)
- {
- my ($hash, $def) = @_;
- my @a = split("[ \t][ \t]*", $def);
- my $po;
- if($a[0] eq "WS300Device")
- {
- $modules{WS300}{defptr}{10} = $hash;
- return "wrong syntax: define WS300Device WS300 <DeviceName>" if(int(@a) < 3);
- $DeviceName = $a[2];
- $hash->{STATE} = "Initializing";
- $hash->{SENSOR} = 10;
- $hash->{READINGS}{WS300Device}{VAL} = "Initializing";
- $hash->{READINGS}{WS300Device}{TIME} = TimeNow;
-
- if ($^O=~/Win/) {
- eval ("use Win32::SerialPort;");
- $po = new Win32::SerialPort ($DeviceName);
- }else{
- eval ("use Device::SerialPort;");
- $po = new Device::SerialPort ($DeviceName);
- }
- if(!$po)
- {
- $hash->{STATE} = "error opening device";
- $hash->{READINGS}{WS300Device}{VAL} = "error opening device";
- $hash->{READINGS}{WS300Device}{TIME} = TimeNow;
- Log 1,"Error opening WS300 Device $a[2]";
- return "Can't open $a[2]: $!\n";
- }
- $po->reset_error();
- $po->baudrate(19200);
- $po->databits(8);
- $po->parity('even');
- $po->stopbits(1);
- $po->handshake('none');
- $po->rts_active(1);
- $po->dtr_active(1);
- sleep(1);
- $po->rts_active(0);
- $po->write_settings;
- $hash->{PortObj} = $po;
- $hash->{DeviceName} = $a[2];
- $hash->{STATE} = "opened";
- $hash->{READINGS}{WS300Device}{VAL} = "opened";
- $hash->{READINGS}{WS300Device}{TIME} = TimeNow;
- CommandDefine(undef,"WS300Device_timer at +*00:00:05 get WS300Device data");
- Log 1,"WS300 Device $a[2] opened";
- return undef;
- }
- return "wrong syntax: define <name> WS300 <sensor (0-9)>\n0-7=ASH2200\n8=KS300\n9=WS300" if(int(@a) < 3);
- return "no device: define WS300Device WS300 <DeviceName> first" if($DeviceName eq "");
- return "Define $a[0]: wrong sensor number." if($a[2] !~ m/^[0-9]$/);
- $hash->{SENSOR} = $a[2];
- $modules{WS300}{defptr}{$a[2]} = $hash;
- return undef;
- }
- #####################################
- sub
- WS300_Undef($$)
- {
- my ($hash, $name) = @_;
- return undef if(!defined($hash->{SENSOR}));
- delete($modules{WS300}{defptr}{$hash->{SENSOR}});
- return undef;
- }
- #####################################
- sub
- WS300_Parse($$)
- {
- my ($hash, $msg) = @_;
- my $ll = GetLogLevel("WS300Device");
- $ll = 5 if($ll == 2);
- my @c = split("", $config);
- my @cmsg = split("",unpack('H*',$config));
- my $dmsg = unpack('H*',$msg);
- my @a = split("", $dmsg);
- my $val = "";
- my $tm;
- my $h;
- my $t;
- my $b;
- my $l;
- my $value;
- my $offs=0;
- my $ref;
- my $def;
- my $zeit;
- my @txt = ( "temperature", "humidity", "wind", "rain_raw", "israining", "battery", "lost_receives", "pressure", "rain_cum", "rain_hour", "rain_day", "rain_month");
- # 1 2 3 4 5 6 7 8
- # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
- # 3180800001005d4e00000000000000000000000000000000000000000000594a0634001e00f62403f1fc stored
- # aaaatttthhtttthhtttthhtttthhtttthhtttthhtttthhtttthhtttthhrrrrwwwwtttthhpppp
- # 3300544a0000000000000000000000000000000000000000000057470634002c00f32303ee32fc current
- # tttthhtttthhtttthhtttthhtttthhtttthhtttthhtttthhtttthhrrrrwwwwtttthhppppss
- # 3210000000000000001005003a0127fc config
- # 001122334455667788iihhhhmmmm
- $offs = 2 if(hex($a[0].$a[1]) == 0x33);
- $offs = 10 if(hex($a[0].$a[1]) == 0x31);
- if($offs == 0)
- {
- Log 1,"WS300 illegal data in WS300_Parse";
- return undef;
- }
- $zeit = time;
- my $wind = hex($a[58+$offs].$a[59+$offs].$a[60+$offs].$a[61+$offs]);
- $wind /= 10.0;
- if(hex($a[0].$a[1]) == 0x33)
- {
- return undef if(hex($a[74].$a[75]) == $willi && $wind == $oldwind );
- $willi = hex($a[74].$a[75]);
- $ir="no";
- $ir="yes" if(($willi&0x80));
- }
- else
- {
- $zeit -= (hex($a[6].$a[7].$a[8].$a[9])*60);
- }
- my @lt = localtime($zeit);
- $tm = sprintf("%04d-%02d-%02d %02d:%02d:%02d",$lt[5]+1900, $lt[4]+1, $lt[3], $lt[2], $lt[1], $lt[0]);
- $oldwind = $wind;
- my $press = hex($a[68+$offs].$a[69+$offs].$a[70+$offs].$a[71+$offs]);
- my $hpress = hex($cmsg[22].$cmsg[23].$cmsg[24].$cmsg[25]);
- $hpress /= 8.5;
- $press += $hpress;
- $press = sprintf("%.1f",$press);
- my $rainc = hex($a[54+$offs].$a[55+$offs].$a[56+$offs].$a[57+$offs]);
- my $rain = hex($cmsg[26].$cmsg[27].$cmsg[28].$cmsg[29]);
- $rain *= $rainc;
- $rain /= 1000;
- $rain = sprintf("%.1f",$rain);
-
- for(my $s=0;$s<9;$s++)
- {
- if((ord($c[$s+1])&0x10))
- {
- my $p=($s*6)+$offs;
- Log $ll,"Sensor $s vorhanden";
- if(!defined($modules{WS300}{defptr}{$s}))
- {
- Log 3, "WS300 Unknown device $s, please define it";
- return "UNDEFINED WS300_$s WS300 $s";
- }
- else
- {
- $def = $modules{WS300}{defptr}{$s};
- $def->{READINGS}{$txt[0]}{VAL} = 0 if(!$def->{READINGS});
- $ref = $def->{READINGS};
- $t = hex($a[$p].$a[$p+1].$a[$p+2].$a[$p+3]);
- $t -= 65535 if( $t > 32767 );
- $t /= 10.0;
- $h = hex($a[$p+4].$a[$p+5]);
- if((ord($c[$s+1])&0xe0))
- {
- $b = "Empty"
- }
- else
- {
- $b = "Ok"
- }
- $l = (ord($c[$s+1])&0x0f);
-
- if($s < 8)
- {
- readingsBeginUpdate($def);
- # state
- $val = "T: $t H: $h Bat: $b LR: $l";
- $def->{STATE} = $val;
- $hash->{".updateTimestamp"};
- readingsBulkUpdate($def, 'state', $val);
- $def->{CHANGETIME}[0] = $tm;
- # temperature
- readingsBulkUpdate($def, $txt[0], $t);
- # humidity
- readingsBulkUpdate($def, $txt[1], $h);
- # battery
- readingsBulkUpdate($def, $txt[5], $b);
- # lost receives
- readingsBulkUpdate($def, $txt[6], $l);
-
- Log $ll, "WS300 $def->{NAME}: $val";
- readingsEndUpdate($def, 1);
- }
- else
- {
- readingsBeginUpdate($def);
- # state
- $val = "T: $t H: $h W: $wind R: $rain IR: $ir Bat: $b LR: $l";
- $def->{STATE} = $val;
- $hash->{".updateTimestamp"};
- readingsBulkUpdate($def, 'state', $val);
- $def->{CHANGETIME}[0] = $tm;
- # temperature
- readingsBulkUpdate($def, $txt[0], $t);
- # humidity
- readingsBulkUpdate($def, $txt[1], $h);
- # wind
- readingsBulkUpdate($def, $txt[2], $wind);
- # rain counter
- readingsBulkUpdate($def, $txt[3], $rainc);
- # is raining
- readingsBulkUpdate($def, $txt[4], $ir);
- # battery
- readingsBulkUpdate($def, $txt[5], $b);
- # lost receives
- readingsBulkUpdate($def, $txt[6], $l);
- # rain cumulative
- readingsBulkUpdate($def, $txt[8], $rain);
- # statistics
- if($actday == 99)
- {
- $oldrain = $rain;
- $acthour = $ref->{acthour}{VAL} if(defined($ref->{acthour}{VAL}));
- $actday = $ref->{actday}{VAL} if(defined($ref->{actday}{VAL}));
- $actmonth = $ref->{actmonth}{VAL} if(defined($ref->{actmonth}{VAL}));
- $rain_day = $ref->{rain_day}{VAL} if(defined($ref->{rain_day}{VAL}));
- $rain_month = $ref->{rain_month}{VAL} if(defined($ref->{rain_month}{VAL}));
- $rain_hour = $ref->{rain_hour}{VAL} if(defined($ref->{rain_hour}{VAL}));
- }
- if($acthour != $lt[2])
- {
- $acthour = $lt[2];
- $rain_hour = sprintf("%.1f",$rain_hour);
- $rain_day = sprintf("%.1f",$rain_day);
- $rain_month = sprintf("%.1f",$rain_month);
- $ref->{acthour}{TIME} = $tm;
- $ref->{acthour}{VAL} = "$acthour";
- readingsBulkUpdate($def, $txt[9], $rain_hour);
- readingsBulkUpdate($def, $txt[10], $rain_day);
- readingsBulkUpdate($def, $txt[11], $rain_month);
- $rain_hour=0;
- }
- if($actday != $lt[3])
- {
- $actday = $lt[3];
- $ref->{actday}{TIME} = $tm;
- $ref->{actday}{VAL} = "$actday";
- $rain_day=0;
- }
- if($actmonth != $lt[4]+1)
- {
- $actmonth = $lt[4]+1;
- $ref->{actmonth}{TIME} = $tm;
- $ref->{actmonth}{VAL} = "$actmonth";
- $rain_month=0;
- }
- if($rain != $oldrain)
- {
- $rain_hour += ($rain-$oldrain);
- $rain_hour = sprintf("%.1f",$rain_hour);
- $rain_day += ($rain-$oldrain);
- $rain_day = sprintf("%.1f",$rain_day);
- $rain_month += ($rain-$oldrain);
- $rain_month = sprintf("%.1f",$rain_month);
- $oldrain = $rain;
- $ref->{acthour}{TIME} = $tm;
- $ref->{acthour}{VAL} = "$acthour";
- readingsBulkUpdate($def, $txt[9], $rain_hour);
- readingsBulkUpdate($def, $txt[10], $rain_day);
- readingsBulkUpdate($def, $txt[11], $rain_month);
- }
- Log $ll,"WS300 $def->{NAME}: $val";
- readingsEndUpdate($def, 1);
-
- }
-
- }
- }
- }
- if(!defined($modules{WS300}{defptr}{9}))
- {
- Log 3, "WS300 Unknown device 9, please define it";
- return "UNDEFINED WS300_9 WS300 9";
- }
- else
- {
- $def = $modules{WS300}{defptr}{9};
- $def->{READINGS}{$txt[0]}{VAL} = 0 if(!$def->{READINGS});
- $ref = $def->{READINGS};
- readingsBeginUpdate($def);
- $t = hex($a[62+$offs].$a[63+$offs].$a[64+$offs].$a[65+$offs]);
- $t -= 65535 if( $t > 32767 );
- $t /= 10.0;
- $h = hex($a[66+$offs].$a[67+$offs]);
- # state
- $val = "T: $t H: $h P: $press Willi: $willi";
- $def->{STATE} = $val;
- $hash->{".updateTimestamp"};
- $def->{CHANGETIME}[0] = $tm;
- readingsBulkUpdate($def, 'state', $val);
- # temperature
- readingsBulkUpdate($def, $txt[0], $t);
- # humidity
- readingsBulkUpdate($def, $txt[1], $h);
- # pressure
- readingsBulkUpdate($def, $txt[7], $press);
- # willi
- readingsBulkUpdate($def, 'willi', $willi);
-
- Log $ll,"WS300 $def->{NAME}: $val";
- readingsEndUpdate($def, 1);
- }
- return undef;
- }
- #####################################
- sub
- WS300_Read($)
- {
- my ($hash) = @_;
- }
- #####################################
- sub
- WS300_Write($$$)
- {
- my ($hash,$fn,$msg) = @_;
- }
- #####################################
- sub
- WS300_Poll($)
- {
- my $hash = shift;
- my $bstring=" ";
- my $count;
- my $po;
- my $inchar='';
- my $escape=0;
- my $ll = GetLogLevel("WS300Device");
- $ll = 5 if($ll == 2);
-
- if(!$hash || !defined($hash->{PortObj}))
- {
- return;
- }
- return if($polling);
- $polling=1;
- NEXTPOLL:
- $inbuf = $hash->{PortObj}->input();
- $bstring = sprintf("%c%c%c",0xfe,$cmd,0xfc);
-
- my $ret = $hash->{PortObj}->write($bstring);
- if($ret <= 0)
- {
- my $devname = $hash->{DeviceName};
- Log 1, "USB device $devname disconnected, waiting to reappear";
- $hash->{PortObj}->close();
- $hash->{STATE} = "disconnected";
- $hash->{READINGS}{WS300Device}{VAL} = "disconnected";
- $hash->{READINGS}{WS300Device}{TIME} = TimeNow;
- sleep(1);
- if ($^O=~/Win/) {
- $po = new Win32::SerialPort ($devname);
- }else{
- $po = new Device::SerialPort ($devname);
- }
- if($po)
- {
- $po->reset_error();
- $po->baudrate(19200);
- $po->databits(8);
- $po->parity('even');
- $po->stopbits(1);
- $po->handshake('none');
- $po->rts_active(1);
- $po->dtr_active(1);
- sleep(1);
- $po->rts_active(0);
- $po->write_settings;
- Log 1, "USB device $devname reappeared";
- $hash->{PortObj} = $po;
- $hash->{STATE} = "opened";
- $hash->{READINGS}{WS300Device}{VAL} = "opened";
- $hash->{READINGS}{WS300Device}{TIME} = TimeNow;
- $polling=0;
- return;
- }
- }
- $inbuf = "";
- my $start=0;
- my $tout=time();
- my $rcount=0;
- my $ic=0;
- for(;;)
- {
- ($count,$inchar) = $hash->{PortObj}->read(1);
- if($count == 0)
- {
- last if($tout < time());
- }
- else
- {
- $ic = hex(unpack('H*',$inchar));
- if(!$start)
- {
- if($ic == 0xfe)
- {
- $start = 1;
- }
- }
- else
- {
- if($ic == 0xf8)
- {
- $escape = 1;
- $count = 0;
- }
- else
- {
- if($escape)
- {
- $ic--;
- $inbuf .= chr($ic);
- $escape = 0;
- }
- else
- {
- $inbuf .= $inchar;
- last if($ic == 0xfc);
- }
- }
- }
- $rcount += $count;
- $tout=time();
- }
- }
-
- Log($ll,"WS300/RAW: ".$rcount." ".unpack('H*',$inbuf));
- if($ic != 0xfc)
- {
- $errcount++ if($errcount < 10);
- if($errcount == 10)
- {
- $hash->{STATE} = "timeout";
- $hash->{READINGS}{WS300Device}{VAL} = "timeout";
- $hash->{READINGS}{WS300Device}{TIME} = TimeNow;
- $errcount++;
- }
- Log 1,"WS300: no data" if($rcount == 0);
- Log 1,"WS300: wrong data ".unpack('H*',$inbuf) if($rcount > 0);
- $polling=0;
- return;
- }
- if($hash->{STATE} ne "connected" && $errcount > 10)
- {
- $hash->{STATE} = "connected";
- $hash->{READINGS}{WS300Device}{VAL} = "connected";
- $hash->{READINGS}{WS300Device}{TIME} = TimeNow;
- }
- $errcount = 0;
- $ic = ord(substr($inbuf,0,1));
- if($ic == 0x32)
- {
- $config = $inbuf if($rcount == 16);
- $cmd=0x31;
- goto NEXTPOLL;
- }
- if($ic == 0x31)
- {
- if($rcount == 42)
- {
- WS300_Parse($hash, $inbuf);
- goto NEXTPOLL;
- }
- else
- {
- $cmd=0x33;
- goto NEXTPOLL;
- }
- }
- if($ic == 0x33)
- {
- WS300_Parse($hash, $inbuf) if($rcount == 39);
- $cmd=0x32;
- }
- $polling=0;
- }
- 1;
- =pod
- =begin html
- <a name="WS300"></a>
- <h3>WS300</h3>
- <ul>
- <br>
- <a name="WS300define"></a>
- <b>Define</b>
- <ul>
- <code>define WS300Device WS300 <serial device></code><br>
- or<br>
- <code>define <devname> WS300 [0-9]</code><br>
- <br>
- The first line is mandatory if you have a WS300 device: it defines the
- input device with its USB port. The name of this device is fixed and must
- be WS300Device. It must be the first defined WS300 device.<br>
- For each additional device (with number 0 to 9) you have to define another
- WS300 device, with an arbitrary name. The WS300 device which reports the
- readings will be defined with the port number 9, an optional KS300 with the
- port number 8.<br><br>
- Examples:
- <pre>
- define WS300Device WS300 /dev/ttyUSB1
- define ash2200.1 WS300 0
- define ks300 WS300 8
- define ws300 WS300 9
- </pre>
- </ul>
- <br>
- <a name="WS300set"></a>
- <b>Set </b>
- <ul>
- <code>set WS300Device <interval(min.)> <height(m)> <rainvalume(ml)></code>
- <br><br>
- Set some WS300 configuration parameters.
- </ul>
- <a name="WS300get"></a>
- <b>Get</b>
- <ul>
- N/A
- </ul>
- <br>
- <a name="WS300attr"></a>
- <b>Attributes</b>
- <ul>
- <li><a href="#do_not_notify">do_not_notify</a></li>
- <li><a href="#model">model</a> (ws300)</li>
- <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
- </ul>
- <br>
- </ul>
- =end html
- =cut
|