5 use Device::SerialPort;
8 my $devname = "/dev/davis";
14 my $connectionInfo="dbi:$dbsort:$db";
15 $connectionInfo .= ":$host" if $host;
17 # make connection to database
18 my %attr = ( PrintError => 0, RaiseError => 0 );
19 my $dbh = DBI->connect($connectionInfo,$userid,$passwd,\%attr) or die "Couldn't connect to database: " . DBI->errstr;
28 my $ob = Device::SerialPort->new ($devname) || die;
30 $ob->user_msg(1); # misc. warnings
31 $ob->error_msg(1); # hardware and data errors
35 #$ob->parity_enable(1); # for any parity except "none"
38 $ob->handshake('none');
39 $ob->read_const_time(15000); # ultimate timeout (15 seconds)
40 $ob->write_settings||die"setting failed";
45 $ob->write("\n"); # initial wake
48 $ob->write("\n"); # wake for real
49 $ob->read_interval(600); # wait for a max of 600ms
50 ($count, $result) = $ob->read(10); # read up to 10 chars
51 if ($result eq "\n\r") {
52 print "awoke on attempt $attempts :)\n";
55 print "wake error on attempt $attempts :(\n";
58 dienice("failed to wake device - tried $attempts times") unless $attempts<6;
61 $ob->write("LAMPS 0\n");
62 $ob->read_interval(300); # wait for a max of 300ms
63 ($count, $result) = $ob->read(8); # read up to 8 chars
64 $result=~s/(\r|\n)//g;
65 if ($result eq "OK") {
66 print "lamps on :)\n";
68 dienice("lamp error '$result'");
75 print "$ref->[2]:$ref->[1]:$ref->[0] $ref->[3]/$ref->[4]/$ref->[5]\n";
82 get_loop(); # if you do anything after here - you need to wake up the device again
83 print "** do something else\n";
85 $ob->write("\r"); # wake
86 $ob->read_interval(500); # wait for a max of 300ms
87 my ($count, $result) = $ob->read(4096); # read any crap up to 4096 chars
90 #print "count=$count $result\n";
91 #for(my $i=0; $i<$count; $i++)
92 #{ printf("%02d ",ord(substr($result,$i,1))); }
94 #$ob->write("WRD\x12\x4d\n");
110 my $loo = substr $blk,0,3;
111 unless ( $loo eq 'LOO') {
112 warn("Block invalid loo -> $loo\n"); return "";
116 #$hsh{'next_rec'} = unpack("s", substr $blk,5,2);
118 $hsh{'Barometric_Trend'} = unpack("C", substr $blk,3,1);
119 $hsh{'Barometric_Trend_txt'} = $bar_trend{$hsh{'Barometric_Trend'}};
120 $t = unpack("s", substr $blk,7,2) / 1000;
121 # $hsh{'Barometric_Press_hg'} = $t;
122 $hsh{'Barometric_Press_mb'} = sprintf("%.2f",$t*33.8637526);
125 $t = unpack("s", substr $blk,9,2) / 10;
126 # $hsh{'Air_Temp_Inside_f'} = $t;
127 $hsh{'Air_Temp_Inside_c'} = sprintf("%.1f",($t - 32) * 5/9);
128 my $tf = unpack("s", substr $blk,12,2) / 10;
129 # $hsh{'Air_Temp_Outside_f'} = $tf;
130 $hsh{'Air_Temp_Outside_c'} = sprintf("%.1f",($tf - 32) * 5/9);
132 $hsh{'Wind_Speed_mph'} = unpack("C", substr $blk,14,1);
133 # $hsh{'Wind_Speed_mps'} = sprintf("%.1f",$hsh{'Wind_Speed_mph'}*0.44704);
134 $hsh{'Wind_Speed_10min_Avg_mph'} = unpack("C", substr $blk,15,1);
135 # $hsh{'Wind_Speed_10min_Avg_mps'} = sprintf("%.1f",$hsh{'Wind_Speed_10min_Avg_mph'}*0.44704);
136 $hsh{'Wind_Dir'} = unpack("s", substr $blk,16,2);
139 $hsh{'Humidity_Outside'} = unpack("C", substr $blk,33,1);
140 $hsh{'Humidity_Inside'} = unpack("C", substr $blk,11,1);
141 $hsh{'Dew_Point'} = dew_point($tf, $hsh{'Humidity_Outside'});
143 # $hsh{'UV'} = unpack("C", substr $blk,43,1);
144 # $hsh{'Solar'} = unpack("s", substr $blk,44,2); # watt/m**2
146 $hsh{'Rain_Rate'} = (unpack("s", substr $blk,41,2) / 100) * 25.4; # Inches per hr converted to mm
147 $hsh{'Rain_Storm'} = (unpack("s", substr $blk,46,2) / 100) * 25.4; # Inches per storm
148 #$hsh{'Storm_Date'} = unpack("s", substr $blk,48,2); # Need to parse data (not sure what this is)
149 $hsh{'Rain_Day'} = (unpack("s", substr $blk,50,2)/100) * 25.4;
150 $hsh{'Rain_Month'} = (unpack("s", substr $blk,52,2)/100) * 25.4;
151 $hsh{'Rain_Year'} = (unpack("s", substr $blk,54,2)/100) * 25.4;
153 $hsh{'ET_Day'} = unpack("s", substr $blk,56,2)/1000;
154 $hsh{'ET_Month'} = unpack("s", substr $blk,58,2)/100;
155 $hsh{'ET_Year'} = unpack("s", substr $blk,60,2)/100;
157 #$hsh{'Alarms_Inside'} = unpack("b8", substr $blk,70,1);
158 #$hsh{'Alarms_Rain'} = unpack("b8", substr $blk,70,1);
159 #$hsh{'Alarms_Outside'} = unpack("b8", substr $blk,70,1);
161 $hsh{'Batt_Transmitter'} = unpack("C", substr $blk,86,1); # * 0.005859375
162 $hsh{'Batt_Console'} = unpack("s", substr $blk,87,2) * 0.005859375;
164 $hsh{'Forecast_Icon'} = unpack("C", substr $blk,89,1);
165 $hsh{'Forecast_Rule'} = unpack("C", substr $blk,90,1);
167 $hsh{'Sunrise'} = sprintf( "%04d", unpack("S", substr $blk,91,2) );
168 $hsh{'Sunrise'} =~ s/(\d{2})(\d{2})/$1:$2/;
169 $hsh{'Sunset'} = sprintf( "%04d", unpack("S", substr $blk,93,2) );
170 $hsh{'Sunset'} =~ s/(\d{2})(\d{2})/$1:$2/;
172 #my $nl = ord substr $blk,95,1;
173 #my $cr = ord substr $blk,96,1;
175 my $crc = unpack "%n", substr($blk,97,2);
176 my $crc_calc = CRC_CCITT($blk);
182 print "CRC check failed for LOOP data!\n";
185 #delete @hsh{'crc', 'crc_calc', 'next_rec'};
186 #delete($hsh{crc})||die"cant delete crc";
187 #delete($hsh{crc_calc})||die"cant delete crc_calc";
188 #delete($hsh{next_rec})||die"cant delete next_rec";
197 # Using the simplified approximation for dew point
198 # Accurate to 1 degree C for humidities > 50 %
199 # http://en.wikipedia.org/wiki/Dew_point
201 my $dew_point = $temp - ( (100 - $rh)/5 );
208 # Expects packed data...
209 my $data_str = shift @_;
212 my @lst = split //, $data_str;
213 foreach my $data (@lst) {
214 my $data = unpack("c",$data);
217 my $index = $crc >> 8 ^ $data;
218 my $lhs = $crc_table[$index];
219 #print "lhs=$lhs, crc=$crc\n";
220 my $rhs = ($crc << 8) & 0xFFFF;
233 0x0, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
234 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
235 0x1231, 0x210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
236 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
237 0x2462, 0x3443, 0x420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
238 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
239 0x3653, 0x2672, 0x1611, 0x630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
240 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
241 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x840, 0x1861, 0x2802, 0x3823,
242 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
243 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0xa50, 0x3a33, 0x2a12,
244 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
245 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0xc60, 0x1c41,
246 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
247 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0xe70,
248 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
249 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
250 0x1080, 0xa1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
251 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
252 0x2b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
253 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
254 0x34e2, 0x24c3, 0x14a0, 0x481, 0x7466, 0x6447, 0x5424, 0x4405,
255 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
256 0x26d3, 0x36f2, 0x691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
257 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
258 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x8e1, 0x3882, 0x28a3,
259 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
260 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0xaf1, 0x1ad0, 0x2ab3, 0x3a92,
261 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
262 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0xcc1,
263 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
264 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0xed1, 0x1ef0
267 $bar_trend{-60} = "Falling Rapidly";
268 $bar_trend{196} = "Falling Rapidly";
269 $bar_trend{-20} = "Falling Slowly";
270 $bar_trend{236} = "Falling Slowly";
271 $bar_trend{0} = "Steady";
272 $bar_trend{20} = "Rising Slowly";
273 $bar_trend{60} = "Rising Rapidly";
278 $ob->write("GETTIME\n");
279 $ob->read_interval(200);
280 my($cnt_in, $str) = $ob->read(9);
282 dienice("read error cnt_in=$cnt_in, str='$str'");
285 my $ck = CRC_CCITT(substr($str,1,9));
287 warn "checksum error"; return 0;
289 my @rsp_lst = split //, $str;
291 @rsp_lst = map ord, @rsp_lst;
297 my $s_time = [ localtime() ];
300 $ob->write("SETTIME\n");
301 $ob->read_interval(300);
302 my ($cnt_in, $str) = $ob->read(1);
305 warn "SETTIME not set ack $ack !"; return 0;
307 my ($sec, $min, $hour, $day, $mon, $yr) = @{$s_time};
308 $str = join "", map chr, ($sec, $min, $hour, $day, $mon, $yr);
309 my $ck = CRC_CCITT($str);
310 $str = $str . pack("n",$ck);
312 ($cnt_in, $str) = $ob->read(1);
313 if ( ord($str) != 6 ) {
314 warn "SETTIME not set!"; return 0;
316 sleep 3; # The console seems to need to some time here...
321 print "** get loop at ", scalar localtime, "\n";
323 $ob->write("LOOP $loops\n");
324 $ob->read_interval(0);
325 ($count, $result) = $ob->read(1);
326 for (my $i=0; $i<$loops; $i+=1) {
338 $ob->read_interval(0);
339 ($count, $result) = $ob->read(99);
341 print "loop error - got $count bytes, expected 99\n";
344 print "LOOP data received\n";
346 if (ord(substr($result,0,1))==6) {
347 $result=substr($result,1);
350 my $rc=parse_loop_blck($result);
353 } # bad crc so goto next
354 foreach my $key (sort keys %hsh) {
355 print "$key = $hsh{$key}\n";
358 my $stmt = 'INSERT INTO current (Date_Time,' . join(',', keys %hsh) . ') VALUES (NOW(),' . join(',', ('?') x keys %hsh) . ')';
360 $dbh->do( $stmt, undef, values %hsh);
369 #my $self = shift @_;
370 open(DMP,">dump.txt");
371 my $vDateStamp = shift @_;
372 my $vTimeStamp = shift @_;
374 # If not date/time stamp then assume 0 which will down load the entire archive
375 unless ( $vDateStamp ) {
378 unless ( $vTimeStamp ) {
382 #my $port_obj = $self->{'port_obj'};
384 my $datetime = pack("ss",$vDateStamp, $vTimeStamp);
386 my $crc = CRC_CCITT($datetime);
387 my $cmd = pack("ssn",$vDateStamp,$vTimeStamp,$crc);
389 #-----------------------
390 #my $str = unpack("H*", $cmd);
391 #$str =~ s/(\w{2})/$1 /g;
392 # Documentation is wrong! The example should be <0xC6><0x06><0xA2><0x03> in section X
393 #print "cmd : $str \n";exit;
394 #-----------------------
396 #sleep 2; # Needed after loop
399 # Ok let's start the communication sequence....
400 my $cnt_out = $ob->write("DMPAFT\n");
402 warn "write failed\n";
406 $ob->read_interval(300);
407 my ($cnt_in, $str) = $ob->read(1);
411 warn "Ack not received on DMPAFT command: $ack"; exit -1;
414 $cnt_out = $ob->write($cmd);
416 warn "write failed\n";
419 ($cnt_in, $str) = $ob->read(7);
421 $ack = ord substr($str,0,1);
423 my $ls = unpack("H20",substr($str,1,4) );
424 $ls =~ s/(\w{2})/$1 /g;
426 my $pages = unpack("s",substr($str,1,2) );
427 my $rec_start = unpack("s",substr($str,3,2) );
429 $crc = CRC_CCITT(substr($str,1,6) );
431 print "Pages = $pages : rec = $rec_start Datestamp $vDateStamp $crc\n";
433 $cnt_out = $ob->write( pack("h", 0x06) );
435 #if ($pages == 513 ) { return -1 }
438 foreach my $page (1..$pages) {
440 $ob->read_interval(0);
441 my ($cnt_in, $str) = $ob->read($page_sz); #,3
442 printf("len=%s\n",length($str));
443 if ($cnt_in!=$page_sz) {
444 dienice("hmm, dmpaft only got $cnt_in bytes. was expecting $page_sz");
446 print "Page $page\n";
447 #print DMP $str,"\n";
448 #print "ACK receipt of page $page\n";
449 #$ob->write( pack("h", 0x06) );
451 my $calc_crc = CRC_CCITT($str);
452 my $crc = unpack "%n", substr($str,265,2);
453 print "page crc=$crc, calc_crc=$calc_crc\n";
458 foreach my $rec ( 0..4 ) {
459 if ( ($page == 1) && ($rec < $rec_start ) ) {
461 } # Find the right starting point...
463 my $start_ptr = 1 + ($rec * $rec_sz );
464 my $rec_str = substr($str, $start_ptr ,52);
466 #print "$start_ptr \t > " . unpack( "h*", $rec_str) . "\n";
468 my $date = substr($rec_str,0,2);
469 my $date_curr = unpack "s", $date;
471 # Check if we have wrapped...
472 if ( $date_curr < $date_prev ) {
475 $date_prev = $date_curr;
477 $hsh{'date_stamp'} = $date_curr;
478 $hsh{'time_stamp'} = unpack "s", substr($rec_str,2,2);
480 $hsh{'day'} = unpack( "c", $date & pack("c",0x1F) );
481 $hsh{'month'} = ( $hsh{'date_stamp'} >> 5) & 0xF;
482 $hsh{'year'} = ( $hsh{'date_stamp'} >> 9) + 2000;
484 $hsh{'hour'} = sprintf("%02d", int ( $hsh{'time_stamp'} / 100 ));
486 $hsh{'min'} = $hsh{'time_stamp'} - ($hsh{'hour'} * 100);
487 $hsh{'min'} = sprintf("%02d", $hsh{'min'});
489 $hsh{'time_stamp_fmt'} = "$hsh{'hour'}:$hsh{'min'}:00";
490 $hsh{'date_stamp_fmt'} = "$hsh{'year'}_$hsh{'month'}_$hsh{'day'}";
492 #$hsh{'unixtime'} = timelocal(0,$hsh{min}, $hsh{hour}, $hsh{day}, $hsh{month}-1, $hsh{year}-1900);
494 $hsh{'Air_Temp'} = unpack("s", substr($rec_str,4,2)) / 10;
495 $hsh{'Air_Temp_Hi'} = unpack("s", substr($rec_str,6,2)) / 10;
496 $hsh{'Air_Temp_Lo'} = unpack("s", substr($rec_str,8,2)) / 10;
497 $hsh{'Rain_Clicks'} = unpack("s", substr($rec_str,10,2));
498 $hsh{'Rain_Rate'} = unpack("s", substr($rec_str,12,2)) / 100; # Inches per hour
499 $hsh{'Barometric_Press'} = unpack("s", substr $rec_str,14,2) / 1000;
500 $hsh{'Solar'} = unpack("s", substr $rec_str,16,2); # watt/m**2
501 $hsh{'Wind_Samples'} = unpack("s", substr $rec_str,18,2);
502 $hsh{'Air_Temp_Inside'} = unpack("s", substr $rec_str,20,2) / 10;
504 $hsh{'Relative_Humidity_Inside'} = unpack("C", substr $rec_str,22,1);
505 $hsh{'Relative_Humidity'} = unpack("C", substr $rec_str,23,1);
507 $hsh{'Wind_Speed'} = unpack("C", substr($rec_str,24,1));
508 $hsh{'Wind_Gust_Max'} = unpack("C", substr($rec_str,25,1));
509 $hsh{'Wind_Dir_Max'} = unpack("C", substr($rec_str,26,1));
510 $hsh{'Wind_Dir'} = unpack("C", substr($rec_str,27,1));
512 $hsh{'UV'} = unpack("C", substr($rec_str,28,1)) / 10;
513 $hsh{'ET'} = unpack("C", substr($rec_str,29,1)) / 1000;
515 $hsh{'Solar_Max'} = unpack("s", substr($rec_str,30,2));
516 $hsh{'UV_Max'} = unpack("C", substr($rec_str,32,1));
518 $hsh{'Forecast_Rule'} = unpack("C", substr($rec_str,33,1));
520 # $hsh{'Dew_Point'} = _dew_point($hsh{'Air_Temp'},$hsh{'Relative_Humidity'});
522 # Miscellaneous others omitted for now
524 print "date> $hsh{'Air_Temp'} $hsh{'time_stamp'} $hsh{'time_stamp_fmt'} $hsh{'date_stamp'} $hsh{'date_stamp_fmt'}\n";
527 push @arc_rec_lst, {%hsh};
530 #$in = <STDIN>; # Testing step through facility
531 #if ($in =~ /q/i ) { $port_obj->write( pack("h", 0x1B) ); last; }
532 #else { $port_obj->write( pack("h", 0x06) ); }
533 print "ACK receipt of page\n";
534 $ob->write( pack("h", 0x06) );
540 package Device::SerialPort;